aboutsummaryrefslogtreecommitdiff
path: root/sys/x86
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2015-08-03 12:14:42 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2015-08-03 12:14:42 +0000
commitf94cc234751d709ff77d849d9cf35661abbafe21 (patch)
tree8808f62dbb04c4b1e243fcfa9bba1dc90c84a48e /sys/x86
parentff9b006d61dcf000f044dbaee56954be204137f4 (diff)
downloadsrc-f94cc234751d709ff77d849d9cf35661abbafe21.tar.gz
src-f94cc234751d709ff77d849d9cf35661abbafe21.zip
Clear the IA32_MISC_ENABLE MSR bit, which limits the max CPUID
reported, on APs. We already did this on BSP. Otherwise, the userspace software which depends on the features reported by the high CPUID levels is misbehaving. In particular, AVX detection is non-functional, depending on which CPU thread happens to execute when doing CPUID. Another victim is the libthr signal handlers interposer, which needs to save full FPU extended state. Reported and tested by: Andre Meiser <ortadur@web.de> Sponsored by: The FreeBSD Foundation MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=286228
Diffstat (limited to 'sys/x86')
-rw-r--r--sys/x86/x86/identcpu.c46
1 files changed, 30 insertions, 16 deletions
diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c
index 548da4a0e10a..4fe3e3cbe99d 100644
--- a/sys/x86/x86/identcpu.c
+++ b/sys/x86/x86/identcpu.c
@@ -1295,6 +1295,33 @@ identify_hypervisor(void)
}
/*
+ * 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__
@@ -1328,22 +1355,9 @@ identify_cpu(void)
identify_hypervisor();
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) {