summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/mp_machdep.c1
-rw-r--r--sys/amd64/include/md_var.h1
-rw-r--r--sys/i386/i386/mp_machdep.c2
-rw-r--r--sys/i386/include/md_var.h1
-rw-r--r--sys/x86/x86/identcpu.c46
5 files changed, 35 insertions, 16 deletions
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index cb36175..43bb023 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -682,6 +682,7 @@ init_secondary(void)
wrmsr(MSR_FSBASE, 0); /* User value */
wrmsr(MSR_GSBASE, (u_int64_t)pc);
wrmsr(MSR_KGSBASE, (u_int64_t)pc); /* XXX User value while we're in the kernel */
+ intel_fix_cpuid();
lidt(&r_idt);
diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h
index 3c611c0..cc95db1 100644
--- a/sys/amd64/include/md_var.h
+++ b/sys/amd64/include/md_var.h
@@ -112,6 +112,7 @@ void dump_drop_page(vm_paddr_t);
void identify_cpu(void);
void initializecpu(void);
void initializecpucache(void);
+bool intel_fix_cpuid(void);
void fillw(int /*u_short*/ pat, void *base, size_t cnt);
void fpstate_drop(struct thread *td);
int is_physical_memory(vm_paddr_t addr);
diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c
index 6636cc0..7b27265 100644
--- a/sys/i386/i386/mp_machdep.c
+++ b/sys/i386/i386/mp_machdep.c
@@ -684,6 +684,8 @@ init_secondary(void)
pc->pc_prvspace = pc;
pc->pc_curthread = 0;
+ intel_fix_cpuid();
+
gdt_segs[GPRIV_SEL].ssd_base = (int) pc;
gdt_segs[GPROC0_SEL].ssd_base = (int) &pc->pc_common_tss;
diff --git a/sys/i386/include/md_var.h b/sys/i386/include/md_var.h
index 6c5aaea3..892b30a 100644
--- a/sys/i386/include/md_var.h
+++ b/sys/i386/include/md_var.h
@@ -116,6 +116,7 @@ void fillw(int /*u_short*/ pat, void *base, size_t cnt);
void fill_based_sd(struct segment_descriptor *sdp, uint32_t base);
void initializecpu(void);
void initializecpucache(void);
+bool intel_fix_cpuid(void);
void i686_pagezero(void *addr);
void sse2_pagezero(void *addr);
void init_AMD_Elan_sc520(void);
diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c
index f61035c..8e5f5c3 100644
--- a/sys/x86/x86/identcpu.c
+++ b/sys/x86/x86/identcpu.c
@@ -1297,6 +1297,33 @@ identify_hypervisor(void)
#endif
/*
+ * Clear "Limit CPUID Maxval" bit and return true if the caller should
+ * get the largest standard CPUID function number again if it is set
+ * from BIOS. It is necessary for probing correct CPU topology later
+ * and for the correct operation of the AVX-aware userspace.
+ */
+bool
+intel_fix_cpuid(void)
+{
+ uint64_t msr;
+
+ if (cpu_vendor_id != CPU_VENDOR_INTEL)
+ return (false);
+ if ((CPUID_TO_FAMILY(cpu_id) == 0xf &&
+ CPUID_TO_MODEL(cpu_id) >= 0x3) ||
+ (CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+ CPUID_TO_MODEL(cpu_id) >= 0xe)) {
+ msr = rdmsr(MSR_IA32_MISC_ENABLE);
+ if ((msr & IA32_MISC_EN_LIMCPUID) != 0) {
+ msr &= ~IA32_MISC_EN_LIMCPUID;
+ wrmsr(MSR_IA32_MISC_ENABLE, msr);
+ return (true);
+ }
+ }
+ return (false);
+}
+
+/*
* Final stage of CPU identification.
*/
#ifdef __i386__
@@ -1332,22 +1359,9 @@ identify_cpu(void)
#endif
cpu_vendor_id = find_cpu_vendor_id();
- /*
- * Clear "Limit CPUID Maxval" bit and get the largest standard CPUID
- * function number again if it is set from BIOS. It is necessary
- * for probing correct CPU topology later.
- * XXX This is only done on the BSP package.
- */
- if (cpu_vendor_id == CPU_VENDOR_INTEL && cpu_high > 0 && cpu_high < 4 &&
- ((CPUID_TO_FAMILY(cpu_id) == 0xf && CPUID_TO_MODEL(cpu_id) >= 0x3) ||
- (CPUID_TO_FAMILY(cpu_id) == 0x6 && CPUID_TO_MODEL(cpu_id) >= 0xe))) {
- uint64_t msr;
- msr = rdmsr(MSR_IA32_MISC_ENABLE);
- if ((msr & 0x400000ULL) != 0) {
- wrmsr(MSR_IA32_MISC_ENABLE, msr & ~0x400000ULL);
- do_cpuid(0, regs);
- cpu_high = regs[0];
- }
+ if (intel_fix_cpuid()) {
+ do_cpuid(0, regs);
+ cpu_high = regs[0];
}
if (cpu_high >= 5 && (cpu_feature2 & CPUID2_MON) != 0) {
OpenPOWER on IntegriCloud