x86/PV: hide features dependent on XSAVE when booted with "no-xsave" ... or when the guest has the XSAVE feature hidden by CPUID policy. Not doing so is at best confusing to guests. Signed-off-by: Jan Beulich --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -827,18 +827,22 @@ void pv_cpuid(struct cpu_user_regs *regs uint32_t a, b, c, d; struct vcpu *curr = current; struct domain *currd = curr->domain; + bool_t guest_has_xsave = cpu_has_xsave; a = regs->eax; - b = regs->ebx; c = regs->ecx; - d = regs->edx; if ( !is_control_domain(currd) && !is_hardware_domain(currd) ) { unsigned int cpuid_leaf = a, sub_leaf = c; - if ( !cpuid_hypervisor_leaves(a, c, &a, &b, &c, &d) ) - domain_cpuid(currd, a, c, &a, &b, &c, &d); + if ( guest_has_xsave ) + { + domain_cpuid(currd, 1, 0, &d, &d, &c, &d); + if ( !(c & cpufeat_mask(X86_FEATURE_XSAVE)) ) + guest_has_xsave = 0; + } + domain_cpuid(currd, a, sub_leaf, &a, &b, &c, &d); switch ( cpuid_leaf ) { @@ -860,13 +864,12 @@ void pv_cpuid(struct cpu_user_regs *regs b = _eax + _ebx; } } - goto xstate; + break; } } - goto out; } - - cpuid_count(a, c, &a, &b, &c, &d); + else + cpuid_count(a, c, &a, &b, &c, &d); if ( (regs->eax & 0x7fffffff) == 0x00000001 ) { @@ -907,11 +910,11 @@ void pv_cpuid(struct cpu_user_regs *regs __clear_bit(X86_FEATURE_PDCM % 32, &c); __clear_bit(X86_FEATURE_PCID % 32, &c); __clear_bit(X86_FEATURE_DCA % 32, &c); - if ( !cpu_has_xsave ) - { - __clear_bit(X86_FEATURE_XSAVE % 32, &c); - __clear_bit(X86_FEATURE_AVX % 32, &c); - } + if ( !guest_has_xsave ) + c &= ~(cpufeat_mask(X86_FEATURE_XSAVE) | + cpufeat_mask(X86_FEATURE_OSXSAVE) | + cpufeat_mask(X86_FEATURE_AVX) | + cpufeat_mask(X86_FEATURE_F16C)); if ( !cpu_has_apic ) __clear_bit(X86_FEATURE_X2APIC % 32, &c); __set_bit(X86_FEATURE_HYPERVISOR % 32, &c); @@ -921,7 +924,7 @@ void pv_cpuid(struct cpu_user_regs *regs if ( regs->_ecx == 0 ) b &= (cpufeat_mask(X86_FEATURE_BMI1) | cpufeat_mask(X86_FEATURE_HLE) | - cpufeat_mask(X86_FEATURE_AVX2) | + (guest_has_xsave ? cpufeat_mask(X86_FEATURE_AVX2) : 0) | cpufeat_mask(X86_FEATURE_BMI2) | cpufeat_mask(X86_FEATURE_ERMS) | cpufeat_mask(X86_FEATURE_RTM) | @@ -934,8 +937,7 @@ void pv_cpuid(struct cpu_user_regs *regs break; case XSTATE_CPUID: - xstate: - if ( !cpu_has_xsave ) + if ( !guest_has_xsave ) goto unsupported; if ( regs->_ecx == 1 ) { @@ -966,6 +968,9 @@ void pv_cpuid(struct cpu_user_regs *regs __clear_bit(X86_FEATURE_SKINIT % 32, &c); __clear_bit(X86_FEATURE_WDT % 32, &c); __clear_bit(X86_FEATURE_LWP % 32, &c); + if ( !guest_has_xsave ) + c &= ~(cpufeat_mask(X86_FEATURE_XOP) | + cpufeat_mask(X86_FEATURE_FMA4)); __clear_bit(X86_FEATURE_NODEID_MSR % 32, &c); __clear_bit(X86_FEATURE_TOPOEXT % 32, &c); __clear_bit(X86_FEATURE_MWAITX % 32, &c); @@ -989,7 +994,6 @@ void pv_cpuid(struct cpu_user_regs *regs break; } - out: /* VPMU may decide to modify some of the leaves */ vpmu_do_cpuid(regs->eax, &a, &b, &c, &d);