svn commit: r286228 - in head/sys: amd64/amd64 amd64/include i386/i386 i386/include x86/x86

Konstantin Belousov kib at FreeBSD.org
Mon Aug 3 12:14:45 UTC 2015


Author: kib
Date: Mon Aug  3 12:14:42 2015
New Revision: 286228
URL: https://svnweb.freebsd.org/changeset/base/286228

Log:
  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 at web.de>
  Sponsored by:	The FreeBSD Foundation
  MFC after:	2 weeks

Modified:
  head/sys/amd64/amd64/mp_machdep.c
  head/sys/amd64/include/md_var.h
  head/sys/i386/i386/mp_machdep.c
  head/sys/i386/include/md_var.h
  head/sys/x86/x86/identcpu.c

Modified: head/sys/amd64/amd64/mp_machdep.c
==============================================================================
--- head/sys/amd64/amd64/mp_machdep.c	Mon Aug  3 12:13:54 2015	(r286227)
+++ head/sys/amd64/amd64/mp_machdep.c	Mon Aug  3 12:14:42 2015	(r286228)
@@ -252,6 +252,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);
 

Modified: head/sys/amd64/include/md_var.h
==============================================================================
--- head/sys/amd64/include/md_var.h	Mon Aug  3 12:13:54 2015	(r286227)
+++ head/sys/amd64/include/md_var.h	Mon Aug  3 12:14:42 2015	(r286228)
@@ -114,6 +114,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);

Modified: head/sys/i386/i386/mp_machdep.c
==============================================================================
--- head/sys/i386/i386/mp_machdep.c	Mon Aug  3 12:13:54 2015	(r286227)
+++ head/sys/i386/i386/mp_machdep.c	Mon Aug  3 12:14:42 2015	(r286228)
@@ -247,6 +247,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;
 

Modified: head/sys/i386/include/md_var.h
==============================================================================
--- head/sys/i386/include/md_var.h	Mon Aug  3 12:13:54 2015	(r286227)
+++ head/sys/i386/include/md_var.h	Mon Aug  3 12:14:42 2015	(r286228)
@@ -118,6 +118,7 @@ void	fillw(int /*u_short*/ pat, void *ba
 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);

Modified: head/sys/x86/x86/identcpu.c
==============================================================================
--- head/sys/x86/x86/identcpu.c	Mon Aug  3 12:13:54 2015	(r286227)
+++ head/sys/x86/x86/identcpu.c	Mon Aug  3 12:14:42 2015	(r286228)
@@ -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) {


More information about the svn-src-all mailing list