xen: mask XSAVE from cpuid
Xen leaves XSAVE set in cpuid, but doesn't allow cr4.OSXSAVE to be set. This confuses the kernel and it ends up crashing on an xsetbv instruction. At boot time, try to set cr4.OSXSAVE, and mask XSAVE out of cpuid it we can't. This will produce a spurious error from Xen, but allows us to support XSAVE if/when Xen does. This also factors out the cpuid mask decisions to boot time. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
This commit is contained in:
parent
1207cf8eb9
commit
191216b928
|
@ -168,21 +168,23 @@ static void __init xen_banner(void)
|
|||
xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
|
||||
}
|
||||
|
||||
static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0;
|
||||
static __read_mostly unsigned int cpuid_leaf1_ecx_mask = ~0;
|
||||
|
||||
static void xen_cpuid(unsigned int *ax, unsigned int *bx,
|
||||
unsigned int *cx, unsigned int *dx)
|
||||
{
|
||||
unsigned maskecx = ~0;
|
||||
unsigned maskedx = ~0;
|
||||
|
||||
/*
|
||||
* Mask out inconvenient features, to try and disable as many
|
||||
* unsupported kernel subsystems as possible.
|
||||
*/
|
||||
if (*ax == 1)
|
||||
maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */
|
||||
(1 << X86_FEATURE_ACPI) | /* disable ACPI */
|
||||
(1 << X86_FEATURE_MCE) | /* disable MCE */
|
||||
(1 << X86_FEATURE_MCA) | /* disable MCA */
|
||||
(1 << X86_FEATURE_ACC)); /* thermal monitoring */
|
||||
if (*ax == 1) {
|
||||
maskecx = cpuid_leaf1_ecx_mask;
|
||||
maskedx = cpuid_leaf1_edx_mask;
|
||||
}
|
||||
|
||||
asm(XEN_EMULATE_PREFIX "cpuid"
|
||||
: "=a" (*ax),
|
||||
|
@ -190,9 +192,43 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
|
|||
"=c" (*cx),
|
||||
"=d" (*dx)
|
||||
: "0" (*ax), "2" (*cx));
|
||||
|
||||
*cx &= maskecx;
|
||||
*dx &= maskedx;
|
||||
}
|
||||
|
||||
static __init void xen_init_cpuid_mask(void)
|
||||
{
|
||||
unsigned int ax, bx, cx, dx;
|
||||
|
||||
cpuid_leaf1_edx_mask =
|
||||
~((1 << X86_FEATURE_MCE) | /* disable MCE */
|
||||
(1 << X86_FEATURE_MCA) | /* disable MCA */
|
||||
(1 << X86_FEATURE_ACC)); /* thermal monitoring */
|
||||
|
||||
if (!xen_initial_domain())
|
||||
cpuid_leaf1_edx_mask &=
|
||||
~((1 << X86_FEATURE_APIC) | /* disable local APIC */
|
||||
(1 << X86_FEATURE_ACPI)); /* disable ACPI */
|
||||
|
||||
ax = 1;
|
||||
xen_cpuid(&ax, &bx, &cx, &dx);
|
||||
|
||||
/* cpuid claims we support xsave; try enabling it to see what happens */
|
||||
if (cx & (1 << (X86_FEATURE_XSAVE % 32))) {
|
||||
unsigned long cr4;
|
||||
|
||||
set_in_cr4(X86_CR4_OSXSAVE);
|
||||
|
||||
cr4 = read_cr4();
|
||||
|
||||
if ((cr4 & X86_CR4_OSXSAVE) == 0)
|
||||
cpuid_leaf1_ecx_mask &= ~(1 << (X86_FEATURE_XSAVE % 32));
|
||||
|
||||
clear_in_cr4(X86_CR4_OSXSAVE);
|
||||
}
|
||||
}
|
||||
|
||||
static void xen_set_debugreg(int reg, unsigned long val)
|
||||
{
|
||||
HYPERVISOR_set_debugreg(reg, val);
|
||||
|
@ -903,6 +939,8 @@ asmlinkage void __init xen_start_kernel(void)
|
|||
|
||||
xen_init_irq_ops();
|
||||
|
||||
xen_init_cpuid_mask();
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
/*
|
||||
* set up the basic apic ops.
|
||||
|
|
Loading…
Reference in New Issue