diff options
Diffstat (limited to 'arch/x86/kernel/cpu/intel.c')
| -rw-r--r-- | arch/x86/kernel/cpu/intel.c | 87 | 
1 files changed, 87 insertions, 0 deletions
| diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index c3af167d0a70..b9693b80fc21 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -509,6 +509,90 @@ static void detect_vmx_virtcap(struct cpuinfo_x86 *c)  	}  } +#define MSR_IA32_TME_ACTIVATE		0x982 + +/* Helpers to access TME_ACTIVATE MSR */ +#define TME_ACTIVATE_LOCKED(x)		(x & 0x1) +#define TME_ACTIVATE_ENABLED(x)		(x & 0x2) + +#define TME_ACTIVATE_POLICY(x)		((x >> 4) & 0xf)	/* Bits 7:4 */ +#define TME_ACTIVATE_POLICY_AES_XTS_128	0 + +#define TME_ACTIVATE_KEYID_BITS(x)	((x >> 32) & 0xf)	/* Bits 35:32 */ + +#define TME_ACTIVATE_CRYPTO_ALGS(x)	((x >> 48) & 0xffff)	/* Bits 63:48 */ +#define TME_ACTIVATE_CRYPTO_AES_XTS_128	1 + +/* Values for mktme_status (SW only construct) */ +#define MKTME_ENABLED			0 +#define MKTME_DISABLED			1 +#define MKTME_UNINITIALIZED		2 +static int mktme_status = MKTME_UNINITIALIZED; + +static void detect_tme(struct cpuinfo_x86 *c) +{ +	u64 tme_activate, tme_policy, tme_crypto_algs; +	int keyid_bits = 0, nr_keyids = 0; +	static u64 tme_activate_cpu0 = 0; + +	rdmsrl(MSR_IA32_TME_ACTIVATE, tme_activate); + +	if (mktme_status != MKTME_UNINITIALIZED) { +		if (tme_activate != tme_activate_cpu0) { +			/* Broken BIOS? */ +			pr_err_once("x86/tme: configuration is inconsistent between CPUs\n"); +			pr_err_once("x86/tme: MKTME is not usable\n"); +			mktme_status = MKTME_DISABLED; + +			/* Proceed. We may need to exclude bits from x86_phys_bits. */ +		} +	} else { +		tme_activate_cpu0 = tme_activate; +	} + +	if (!TME_ACTIVATE_LOCKED(tme_activate) || !TME_ACTIVATE_ENABLED(tme_activate)) { +		pr_info_once("x86/tme: not enabled by BIOS\n"); +		mktme_status = MKTME_DISABLED; +		return; +	} + +	if (mktme_status != MKTME_UNINITIALIZED) +		goto detect_keyid_bits; + +	pr_info("x86/tme: enabled by BIOS\n"); + +	tme_policy = TME_ACTIVATE_POLICY(tme_activate); +	if (tme_policy != TME_ACTIVATE_POLICY_AES_XTS_128) +		pr_warn("x86/tme: Unknown policy is active: %#llx\n", tme_policy); + +	tme_crypto_algs = TME_ACTIVATE_CRYPTO_ALGS(tme_activate); +	if (!(tme_crypto_algs & TME_ACTIVATE_CRYPTO_AES_XTS_128)) { +		pr_err("x86/mktme: No known encryption algorithm is supported: %#llx\n", +				tme_crypto_algs); +		mktme_status = MKTME_DISABLED; +	} +detect_keyid_bits: +	keyid_bits = TME_ACTIVATE_KEYID_BITS(tme_activate); +	nr_keyids = (1UL << keyid_bits) - 1; +	if (nr_keyids) { +		pr_info_once("x86/mktme: enabled by BIOS\n"); +		pr_info_once("x86/mktme: %d KeyIDs available\n", nr_keyids); +	} else { +		pr_info_once("x86/mktme: disabled by BIOS\n"); +	} + +	if (mktme_status == MKTME_UNINITIALIZED) { +		/* MKTME is usable */ +		mktme_status = MKTME_ENABLED; +	} + +	/* +	 * KeyID bits effectively lower the number of physical address +	 * bits.  Update cpuinfo_x86::x86_phys_bits accordingly. +	 */ +	c->x86_phys_bits -= keyid_bits; +} +  static void init_intel_energy_perf(struct cpuinfo_x86 *c)  {  	u64 epb; @@ -679,6 +763,9 @@ static void init_intel(struct cpuinfo_x86 *c)  	if (cpu_has(c, X86_FEATURE_VMX))  		detect_vmx_virtcap(c); +	if (cpu_has(c, X86_FEATURE_TME)) +		detect_tme(c); +  	init_intel_energy_perf(c);  	init_intel_misc_features(c); |