[PATCH 2/2] cpu: intel, amd: mask cleared cpuid features

From: Vladimir Davydov
Date: Fri Jul 20 2012 - 12:37:46 EST


If 'clearcpuid=N' is specified in boot options, CPU feature #N won't be
reported in /proc/cpuinfo and used by the kernel. However, if a
userpsace process checks CPU features directly using the cpuid
instruction, it will be reported about all features supported by the CPU
irrespective of what features are cleared.

The patch makes the clearcpuid boot option not only clear CPU features
in kernel but also mask them in hardware for Intel and AMD CPUs that
support it so that the features cleared won't be reported even by the
cpuid instruction.

This can be useful for migration of virtual machines managed by
hypervisors that do not support/use Intel VT/AMD-V hardware-assisted
virtualization technology.

If CPUID masking is supported, this will be reported in
/proc/cpuinfo:flags as 'cpuidmask'.
---
arch/x86/include/asm/cpufeature.h | 1 +
arch/x86/kernel/cpu/amd.c | 22 ++++++++++++++
arch/x86/kernel/cpu/intel.c | 59 +++++++++++++++++++++++++++++++++++++
3 files changed, 82 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index f91e80f..6f061ea 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -97,6 +97,7 @@
#define X86_FEATURE_EXTD_APICID (3*32+26) /* has extended APICID (8 bits) */
#define X86_FEATURE_AMD_DCM (3*32+27) /* multi-node processor */
#define X86_FEATURE_APERFMPERF (3*32+28) /* APERFMPERF */
+#define X86_FEATURE_CPUIDMASK (3*32+29) /* CPUID feature masking */

/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
#define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 146bb62..ddc8ea2 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -482,6 +482,26 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
#endif
}

+#define MSR_AMD_CPUID_FEATURES_OVERRIDE 0xc0011004
+#define MSR_AMD_EXT_CPUID_FEATURES_OVERRIDE 0xc0011005
+
+static void __cpuinit amd_mask_cpu_caps(struct cpuinfo_x86 *c)
+{
+ u64 val;
+
+ if (c->x86 >= 0x0f) {
+ set_cpu_cap(c, X86_FEATURE_CPUIDMASK);
+
+ rdmsrl_amd_safe(MSR_AMD_CPUID_FEATURES_OVERRIDE, &val);
+ val &= ~((u64)cpu_caps_cleared[4] << 32 | cpu_caps_cleared[0]);
+ wrmsrl_amd_safe(MSR_AMD_CPUID_FEATURES_OVERRIDE, val);
+
+ rdmsrl_amd_safe(MSR_AMD_EXT_CPUID_FEATURES_OVERRIDE, &val);
+ val &= ~((u64)cpu_caps_cleared[6] << 32 | cpu_caps_cleared[1]);
+ wrmsrl_amd_safe(MSR_AMD_EXT_CPUID_FEATURES_OVERRIDE, val);
+ }
+}
+
static void __cpuinit init_amd(struct cpuinfo_x86 *c)
{
u32 dummy;
@@ -684,6 +704,8 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
}

rdmsr_safe(MSR_AMD64_PATCH_LEVEL, &c->microcode, &dummy);
+
+ amd_mask_cpu_caps(c);
}

#ifdef CONFIG_X86_32
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 3e6ff6c..1df1da5 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -358,6 +358,63 @@ static void __cpuinit detect_vmx_virtcap(struct cpuinfo_x86 *c)
}
}

+static unsigned int __cpuinit intel_cpuid_mask_msr(struct cpuinfo_x86 *c,
+ unsigned int *msr_ext_cpuid_mask)
+{
+ unsigned int msr, msr_ext;
+
+ msr = msr_ext = 0;
+
+ switch (c->x86_model) {
+ case 0x17:
+ case 0x1D:
+ msr = 0x478;
+ break;
+ case 0x1A:
+ case 0x1E:
+ case 0x1F:
+ case 0x25:
+ case 0x2C:
+ case 0x2E:
+ case 0x2F:
+ msr = 0x130;
+ msr_ext = 0x131;
+ break;
+ case 0x2A:
+ msr = 0x132;
+ msr_ext = 0x133;
+ break;
+ }
+
+ if (msr_ext_cpuid_mask)
+ *msr_ext_cpuid_mask = msr_ext;
+
+ return msr;
+}
+
+static void __cpuinit intel_mask_cpu_caps(struct cpuinfo_x86 *c)
+{
+ u32 low, high;
+ unsigned int msr_cpuid_mask, msr_ext_cpuid_mask;
+
+ msr_cpuid_mask = intel_cpuid_mask_msr(c, &msr_ext_cpuid_mask);
+ if (msr_cpuid_mask) {
+ set_cpu_cap(c, X86_FEATURE_CPUIDMASK);
+
+ rdmsr(msr_cpuid_mask, low, high);
+ low &= ~cpu_caps_cleared[4];
+ high &= ~cpu_caps_cleared[0];
+ wrmsr(msr_cpuid_mask, low, high);
+
+ if (msr_ext_cpuid_mask != 0) {
+ rdmsr(msr_ext_cpuid_mask, low, high);
+ low &= ~cpu_caps_cleared[6];
+ high &= ~cpu_caps_cleared[1];
+ wrmsr(msr_ext_cpuid_mask, low, high);
+ }
+ }
+}
+
static void __cpuinit init_intel(struct cpuinfo_x86 *c)
{
unsigned int l2 = 0;
@@ -474,6 +531,8 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
}
}
+
+ intel_mask_cpu_caps(c);
}

#ifdef CONFIG_X86_32
--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/