x86/cpu changes for v4.5
Subsystems (3)
Linus,
Please pull the latest x86-cpu-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86-cpu-for-linus
# HEAD: 0007bccc3cfd1e69deb0fd73ccc426b4cedb061d x86: Replace RDRAND forced-reseed with simple sanity check
The main changes in this cycle were:
- Improved CPU ID handling code and related enhancements (Borislav Petkov)
- RDRAND fix (Len Brown)
Thanks,
Ingo
------------------>
Borislav Petkov (5):
x86/cpu: Unify CPU family, model, stepping calculation
kvm: Add accessors for guest CPU's family, model, stepping x86/cpu/amd, kvm: Satisfy guest kernel reads of IC_CFG MSR x86/cpu: Fix MSR value truncation issue
x86/MSR: Chop off lower 32-bit value
Len Brown (1):
x86: Replace RDRAND forced-reseed with simple sanity check
arch/x86/include/asm/cpu.h | 3 +++ arch/x86/include/asm/microcode.h | 39 +++++++---------------------------- arch/x86/include/asm/msr-index.h | 1 + arch/x86/include/asm/msr.h | 2 +- arch/x86/kernel/cpu/amd.c | 4 ++-- arch/x86/kernel/cpu/common.c | 13 ++++-------- arch/x86/kernel/cpu/microcode/core.c | 12 +++++------ arch/x86/kernel/cpu/microcode/intel.c | 16 ++++++-------- arch/x86/kernel/cpu/rdrand.c | 25 +++++++++++----------- arch/x86/kvm/cpuid.h | 34 ++++++++++++++++++++++++++++++ arch/x86/kvm/svm.c | 17 +++++++++++++++ arch/x86/lib/Makefile | 2 +- arch/x86/lib/cpu.c | 35 +++++++++++++++++++++++++++++++ 13 files changed, 129 insertions(+), 74 deletions(-) create mode 100644 arch/x86/lib/cpu.c
arch/x86/include/asm/cpu.h +3 -0
@@ -36,4 +36,7 @@ extern int _debug_hotplug_cpu(int cpu, int action);int mwait_usable (const struct cpuinfo_x86 *); +unsigned int x86_family (unsigned int sig); +unsigned int x86_model (unsigned int sig); +unsigned int x86_stepping (unsigned int sig);#endif /* _ASM_X86_CPU_H */
arch/x86/include/asm/microcode.h +7 -32
@@ -1,6 +1,7 @@#ifndef _ASM_X86_MICROCODE_H#define _ASM_X86_MICROCODE_H +#include <asm/cpu.h> #include <linux/earlycpio.h> #define native_rdmsr (msr, val1, val2) \
@@ -95,14 +96,14 @@ static inline void __exit exit_amd_microcode(void) {}/* * In early loading microcode phase on BSP, boot_cpu_data is not set up yet. -* x86_vendor() gets vendor id for BSP. +* x86_cpuid_vendor() gets vendor id for BSP. * * In 32 bit AP case, accessing boot_cpu_data needs linear address. To simplify -* coding, we still use x86_vendor() to get vendor id for AP. +* coding, we still use x86_cpuid_vendor() to get vendor id for AP. * -* x86_vendor() gets vendor information directly from CPUID. +* x86_cpuid_vendor() gets vendor information directly from CPUID. */ -static inline int x86_vendor (void ) +static inline int x86_cpuid_vendor (void ) {u32 eax =0x00000000 ;u32 ebx, ecx =0 , edx;
@@ -118,40 +119,14 @@ static inline int x86_vendor(void)return X86_VENDOR_UNKNOWN ; } -static inline unsigned int __x86_family (unsigned int sig) -{ -unsigned int x86; - - x86 = (sig >>8 ) &0xf ; - -if (x86 ==0xf ) - x86 += (sig >>20 ) &0xff ; - -return x86; -} - -static inline unsigned int x86_family (void ) +static inline unsigned int x86_cpuid_family (void ) {u32 eax =0x00000001 ;u32 ebx, ecx =0 , edx;native_cpuid (&eax, &ebx, &ecx, &edx); -return __x86_family (eax); -} - -static inline unsigned int x86_model (unsigned int sig) -{ -unsigned int x86, model; - - x86 =__x86_family (sig); - - model = (sig >>4 ) &0xf ; - -if (x86 ==0x6 || x86 ==0xf ) - model += ((sig >>16 ) &0xf ) <<4 ; - -return model; +return x86_family (eax); }#ifdef CONFIG_MICROCODE
arch/x86/include/asm/msr-index.h +1 -0
@@ -321,6 +321,7 @@#define MSR_F15H_PERF_CTR 0xc0010201#define MSR_F15H_NB_PERF_CTL 0xc0010240#define MSR_F15H_NB_PERF_CTR 0xc0010241 +#define MSR_F15H_IC_CFG 0xc0011021/* Fam 10h MSRs */ #define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058
arch/x86/include/asm/msr.h +1 -1
@@ -190,7 +190,7 @@ static inline void wrmsr(unsigned msr, unsigned low, unsigned high)static inline void wrmsrl (unsigned msr,u64 val) { -native_write_msr (msr, (u32 )val, (u32)(val >>32 )); +native_write_msr (msr, (u32)(val &0xffffffffULL ), (u32)(val >>32 )); }/* wrmsr with exception handling */
arch/x86/kernel/cpu/amd.c +2 -2
@@ -678,9 +678,9 @@ static void init_amd_bd(struct cpuinfo_x86 *c)* Disable it on the affected CPUs. */ if ((c->x86_model >=0x02 ) && (c->x86_model <0x20 )) { -if (!rdmsrl_safe (0xc0011021 , &value) && !(value &0x1E )) { +if (!rdmsrl_safe (MSR_F15H_IC_CFG , &value) && !(value &0x1E )) { value |=0x1E ; -wrmsrl_safe (0xc0011021 , value); +wrmsrl_safe (MSR_F15H_IC_CFG , value); } } }
arch/x86/kernel/cpu/common.c +4 -9
@@ -581,14 +581,9 @@ void cpu_detect(struct cpuinfo_x86 *c)u32 junk, tfms, cap0, misc;cpuid (0x00000001 , &tfms, &misc, &junk, &cap0); - c->x86 = (tfms >>8 ) &0xf ; - c->x86_model = (tfms >>4 ) &0xf ; - c->x86_mask = tfms &0xf ; - -if (c->x86 ==0xf ) - c->x86 += (tfms >>20 ) &0xff ; -if (c->x86 >=0x6 ) - c->x86_model += ((tfms >>16 ) &0xf ) <<4 ; + c->x86 =x86_family (tfms); + c->x86_model =x86_model (tfms); + c->x86_mask =x86_stepping (tfms);if (cap0 & (1 <<19 )) { c->x86_clflush_size = ((misc >>8 ) &0xff ) *8 ;
@@ -1185,7 +1180,7 @@ void syscall_init(void)* They both write to the same internal register. STAR allows to * set CS/DS but only a 32bit target. LSTAR sets the 64bit rip. */ -wrmsrl (MSR_STAR , ((u64 )__USER32_CS)<<48 | ((u64 )__KERNEL_CS)<<32 ); +wrmsr (MSR_STAR ,0 , (__USER32_CS <<16 ) | __KERNEL_CS);wrmsrl (MSR_LSTAR , (unsigned long )entry_SYSCALL_64);#ifdef CONFIG_IA32_EMULATION
arch/x86/kernel/cpu/microcode/core.c +6 -6
@@ -129,8 +129,8 @@ void __init load_ucode_bsp(void)if (!have_cpuid_p ())return ; - vendor =x86_vendor (); - family =x86_family (); + vendor =x86_cpuid_vendor (); + family =x86_cpuid_family ();switch (vendor) {case X86_VENDOR_INTEL :
@@ -165,8 +165,8 @@ void load_ucode_ap(void)if (!have_cpuid_p ())return ; - vendor =x86_vendor (); - family =x86_family (); + vendor =x86_cpuid_vendor (); + family =x86_cpuid_family ();switch (vendor) {case X86_VENDOR_INTEL :
@@ -206,8 +206,8 @@ void reload_early_microcode(void) {int vendor, family; - vendor =x86_vendor (); - family =x86_family (); + vendor =x86_cpuid_vendor (); + family =x86_cpuid_family ();switch (vendor) {case X86_VENDOR_INTEL :
arch/x86/kernel/cpu/microcode/intel.c +6 -10
@@ -145,10 +145,10 @@ matching_model_microcode(struct microcode_header_intel *mc_header,int ext_sigcount, i;struct extended_signature *ext_sig; - fam =__x86_family (sig); + fam =x86_family (sig); model =x86_model (sig); - fam_ucode =__x86_family (mc_header->sig); + fam_ucode =x86_family (mc_header->sig); model_ucode =x86_model (mc_header->sig);if (fam == fam_ucode && model == model_ucode)
@@ -163,7 +163,7 @@ matching_model_microcode(struct microcode_header_intel *mc_header, ext_sigcount = ext_header->count;for (i =0 ; i < ext_sigcount; i++) { - fam_ucode =__x86_family (ext_sig->sig); + fam_ucode =x86_family (ext_sig->sig); model_ucode =x86_model (ext_sig->sig);if (fam == fam_ucode && model == model_ucode)
@@ -365,7 +365,7 @@ static int collect_cpu_info_early(struct ucode_cpu_info *uci)native_cpuid (&eax, &ebx, &ecx, &edx); csig.sig = eax; - family =__x86_family (csig.sig); + family =x86_family (csig.sig); model =x86_model (csig.sig);if ((model >=5 ) || (family >6 )) {
@@ -521,16 +521,12 @@ static bool __init load_builtin_intel_microcode(struct cpio_data *cp) {#ifdef CONFIG_X86_64 unsigned int eax =0x00000001 , ebx, ecx =0 , edx; -unsigned int family, model, stepping;char name[30 ];native_cpuid (&eax, &ebx, &ecx, &edx); - family =__x86_family (eax); - model =x86_model (eax); - stepping = eax &0xf ; - -sprintf (name,"intel-ucode/%02x-%02x-%02x" , family, model, stepping); +sprintf (name,"intel-ucode/%02x-%02x-%02x" , +x86_family (eax),x86_model (eax),x86_stepping (eax));return get_builtin_firmware (cp, name);#else
arch/x86/kernel/cpu/rdrand.c +12 -13
@@ -33,28 +33,27 @@ static int __init x86_rdrand_setup(char *s)__setup ("nordrand" , x86_rdrand_setup);/* -* Force a reseed cycle; we are architecturally guaranteed a reseed -* after no more than 512 128-bit chunks of random data. This also -* acts as a test of the CPU capability. +* RDRAND has Built-In-Self-Test (BIST) that runs on every invocation. +* Run the instruction a few times as a sanity check. +* If it fails, it is simple to disable RDRAND here. */ -#define RESEED_LOOP ((512*128)/sizeof(unsigned long)) +#define SANITY_CHECK_LOOPS 8void x86_init_rdrand (struct cpuinfo_x86 *c) {#ifdef CONFIG_ARCH_RANDOM unsigned long tmp; -int i, count, ok; +int i;if (!cpu_has (c,X86_FEATURE_RDRAND )) -return ;/* Nothing to do */ +return ; -for (count = i =0 ; i <RESEED_LOOP ; i++) { - ok =rdrand_long (&tmp); -if (ok) - count++; +for (i =0 ; i <SANITY_CHECK_LOOPS ; i++) { +if (!rdrand_long (&tmp)) { +clear_cpu_cap (c,X86_FEATURE_RDRAND ); +printk_once (KERN_WARNING "rdrand: disabled\n" ); +return ; + } } - -if (count !=RESEED_LOOP ) -clear_cpu_cap (c,X86_FEATURE_RDRAND );#endif }
arch/x86/kvm/cpuid.h +34 -0
@@ -2,6 +2,7 @@#define ARCH_X86_KVM_CPUID_H #include "x86.h" +#include <asm/cpu.h> int kvm_update_cpuid (struct kvm_vcpu *vcpu); struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
@@ -170,4 +171,37 @@ static inline bool guest_cpuid_has_nrips(struct kvm_vcpu *vcpu) }#undef BIT_NRIPS +static inline int guest_cpuid_family (struct kvm_vcpu *vcpu) +{ +struct kvm_cpuid_entry2 *best; + + best =kvm_find_cpuid_entry (vcpu,0x1 ,0 ); +if (!best) +return -1 ; + +return x86_family (best->eax); +} + +static inline int guest_cpuid_model (struct kvm_vcpu *vcpu) +{ +struct kvm_cpuid_entry2 *best; + + best =kvm_find_cpuid_entry (vcpu,0x1 ,0 ); +if (!best) +return -1 ; + +return x86_model (best->eax); +} + +static inline int guest_cpuid_stepping (struct kvm_vcpu *vcpu) +{ +struct kvm_cpuid_entry2 *best; + + best =kvm_find_cpuid_entry (vcpu,0x1 ,0 ); +if (!best) +return -1 ; + +return x86_stepping (best->eax); +} +#endif
arch/x86/kvm/svm.c +17 -0
@@ -3053,6 +3053,23 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)case MSR_IA32_UCODE_REV : msr_info->data =0x01000065 ;break ; +case MSR_F15H_IC_CFG : { + +int family, model; + + family =guest_cpuid_family (vcpu); + model =guest_cpuid_model (vcpu); + +if (family <0 || model <0 ) +return kvm_get_msr_common (vcpu, msr_info); + + msr_info->data =0 ; + +if (family ==0x15 && + (model >=0x2 && model <0x20 )) + msr_info->data =0x1E ; + } +break ;default :return kvm_get_msr_common (vcpu, msr_info); }
arch/x86/lib/Makefile +1 -1
@@ -16,7 +16,7 @@ clean-files := inat-tables.c obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o -lib-y := delay.o misc.o cmdline.o +lib-y := delay.o misc.o cmdline.o cpu.o lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o lib-y += memcpy_$(BITS).o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
arch/x86/lib/cpu.c new file +35 -0
@@ -0,0 +1,35 @@ +#include <linux/module.h> + +unsigned int x86_family (unsigned int sig) +{ +unsigned int x86; + + x86 = (sig >>8 ) &0xf ; + +if (x86 ==0xf ) + x86 += (sig >>20 ) &0xff ; + +return x86; +} +EXPORT_SYMBOL_GPL (x86_family); + +unsigned int x86_model (unsigned int sig) +{ +unsigned int fam, model; + + fam =x86_family (sig); + + model = (sig >>4 ) &0xf ; + +if (fam >=0x6 ) + model += ((sig >>16 ) &0xf ) <<4 ; + +return model; +} +EXPORT_SYMBOL_GPL (x86_model); + +unsigned int x86_stepping (unsigned int sig) +{ +return sig &0xf ; +} +EXPORT_SYMBOL_GPL (x86_stepping);