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
This commit is contained in:
parent
ff9b006d61
commit
f94cc23475
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -118,6 +118,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);
|
||||
|
@ -1294,6 +1294,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.
|
||||
*/
|
||||
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user