x86/cpuid: Split update_domain_cpuid_info() in half

update_domain_cpuid_info() currently serves two purposes.  First to merge new
CPUID data from the toolstack, and second, to perform any necessary updating
of derived domain/vcpu settings.

The first part of this is going to be superseded by a new and substantially
more efficient hypercall.

Carve the second part out into a new domain_cpu_policy_changed() helper, and
call this from the remains of update_domain_cpuid_info().

This does drop the call_policy_changed, but with the new hypercall in place,
the common case will be a single call per domain.  Dropping the optimisation
here allows for a cleaner set of following changes.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Release-acked-by: Juergen Gross <jgross@suse.com>
This commit is contained in:
Andrew Cooper committed 2019-09-26 13:40:18 +01:00
1 parent 588a966a57
commit 205f3b6380
1 file changed
+161 -208
+161 -208
View File
@@ -46,14 +46,171 @@ static int gdbsx_guest_mem_io(domid_t domid, struct xen_domctl_gdbsx_memio *iop)
return iop->remain ? -EFAULT : 0;
}
static void domain_cpu_policy_changed(struct domain *d)
{
const struct cpuid_policy *p = d->arch.cpuid;
struct vcpu *v;
if ( is_pv_domain(d) )
{
if ( ((levelling_caps & LCAP_1cd) == LCAP_1cd) )
{
uint64_t mask = cpuidmask_defaults._1cd;
uint32_t ecx = p->basic._1c;
uint32_t edx = p->basic._1d;
/*
* Must expose hosts HTT and X2APIC value so a guest using native
* CPUID can correctly interpret other leaves which cannot be
* masked.
*/
if ( cpu_has_x2apic )
ecx |= cpufeat_mask(X86_FEATURE_X2APIC);
if ( cpu_has_htt )
edx |= cpufeat_mask(X86_FEATURE_HTT);
switch ( boot_cpu_data.x86_vendor )
{
case X86_VENDOR_INTEL:
/*
* Intel masking MSRs are documented as AND masks.
* Experimentally, they are applied after OSXSAVE and APIC
* are fast-forwarded from real hardware state.
*/
mask &= ((uint64_t)edx << 32) | ecx;
if ( ecx & cpufeat_mask(X86_FEATURE_XSAVE) )
ecx = cpufeat_mask(X86_FEATURE_OSXSAVE);
else
ecx = 0;
edx = cpufeat_mask(X86_FEATURE_APIC);
mask |= ((uint64_t)edx << 32) | ecx;
break;
case X86_VENDOR_AMD:
case X86_VENDOR_HYGON:
mask &= ((uint64_t)ecx << 32) | edx;
/*
* AMD masking MSRs are documented as overrides.
* Experimentally, fast-forwarding of the OSXSAVE and APIC
* bits from real hardware state only occurs if the MSR has
* the respective bits set.
*/
if ( ecx & cpufeat_mask(X86_FEATURE_XSAVE) )
ecx = cpufeat_mask(X86_FEATURE_OSXSAVE);
else
ecx = 0;
edx = cpufeat_mask(X86_FEATURE_APIC);
mask |= ((uint64_t)ecx << 32) | edx;
break;
}
d->arch.pv.cpuidmasks->_1cd = mask;
}
if ( ((levelling_caps & LCAP_6c) == LCAP_6c) )
{
uint64_t mask = cpuidmask_defaults._6c;
if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
mask &= (~0ULL << 32) | p->basic.raw[6].c;
d->arch.pv.cpuidmasks->_6c = mask;
}
if ( ((levelling_caps & LCAP_7ab0) == LCAP_7ab0) )
{
uint64_t mask = cpuidmask_defaults._7ab0;
/*
* Leaf 7[0].eax is max_subleaf, not a feature mask. Take it
* wholesale from the policy, but clamp the features in 7[0].ebx
* per usual.
*/
if ( boot_cpu_data.x86_vendor &
(X86_VENDOR_AMD | X86_VENDOR_HYGON) )
mask = (((uint64_t)p->feat.max_subleaf << 32) |
((uint32_t)mask & p->feat._7b0));
d->arch.pv.cpuidmasks->_7ab0 = mask;
}
if ( ((levelling_caps & LCAP_Da1) == LCAP_Da1) )
{
uint64_t mask = cpuidmask_defaults.Da1;
uint32_t eax = p->xstate.Da1;
if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
mask &= (~0ULL << 32) | eax;
d->arch.pv.cpuidmasks->Da1 = mask;
}
if ( ((levelling_caps & LCAP_e1cd) == LCAP_e1cd) )
{
uint64_t mask = cpuidmask_defaults.e1cd;
uint32_t ecx = p->extd.e1c;
uint32_t edx = p->extd.e1d;
/*
* Must expose hosts CMP_LEGACY value so a guest using native
* CPUID can correctly interpret other leaves which cannot be
* masked.
*/
if ( cpu_has_cmp_legacy )
ecx |= cpufeat_mask(X86_FEATURE_CMP_LEGACY);
/*
* If not emulating AMD or Hygon, clear the duplicated features
* in e1d.
*/
if ( !(p->x86_vendor & (X86_VENDOR_AMD | X86_VENDOR_HYGON)) )
edx &= ~CPUID_COMMON_1D_FEATURES;
switch ( boot_cpu_data.x86_vendor )
{
case X86_VENDOR_INTEL:
mask &= ((uint64_t)edx << 32) | ecx;
break;
case X86_VENDOR_AMD:
case X86_VENDOR_HYGON:
mask &= ((uint64_t)ecx << 32) | edx;
/*
* Fast-forward bits - Must be set in the masking MSR for
* fast-forwarding to occur in hardware.
*/
ecx = 0;
edx = cpufeat_mask(X86_FEATURE_APIC);
mask |= ((uint64_t)ecx << 32) | edx;
break;
}
d->arch.pv.cpuidmasks->e1cd = mask;
}
}
for_each_vcpu ( d, v )
{
cpuid_policy_updated(v);
/* If PMU version is zero then the guest doesn't have VPMU */
if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
p->basic.pmu_version == 0 )
vpmu_destroy(v);
}
}
static int update_domain_cpuid_info(struct domain *d,
const struct xen_domctl_cpuid *ctl)
{
struct cpuid_policy *p = d->arch.cpuid;
const struct cpuid_leaf leaf = { ctl->eax, ctl->ebx, ctl->ecx, ctl->edx };
int old_vendor = p->x86_vendor;
unsigned int old_7d0 = p->feat.raw[0].d, old_e8b = p->extd.raw[8].b;
bool call_policy_changed = false; /* Avoid for_each_vcpu() unnecessarily */
/*
* Skip update for leaves we don't care about, to avoid the overhead of
@@ -132,211 +289,7 @@ static int update_domain_cpuid_info(struct domain *d,
}
recalculate_cpuid_policy(d);
switch ( ctl->input[0] )
{
case 0:
call_policy_changed = (p->x86_vendor != old_vendor);
break;
case 1:
if ( is_pv_domain(d) && ((levelling_caps & LCAP_1cd) == LCAP_1cd) )
{
uint64_t mask = cpuidmask_defaults._1cd;
uint32_t ecx = p->basic._1c;
uint32_t edx = p->basic._1d;
/*
* Must expose hosts HTT and X2APIC value so a guest using native
* CPUID can correctly interpret other leaves which cannot be
* masked.
*/
if ( cpu_has_x2apic )
ecx |= cpufeat_mask(X86_FEATURE_X2APIC);
if ( cpu_has_htt )
edx |= cpufeat_mask(X86_FEATURE_HTT);
switch ( boot_cpu_data.x86_vendor )
{
case X86_VENDOR_INTEL:
/*
* Intel masking MSRs are documented as AND masks.
* Experimentally, they are applied after OSXSAVE and APIC
* are fast-forwarded from real hardware state.
*/
mask &= ((uint64_t)edx << 32) | ecx;
if ( ecx & cpufeat_mask(X86_FEATURE_XSAVE) )
ecx = cpufeat_mask(X86_FEATURE_OSXSAVE);
else
ecx = 0;
edx = cpufeat_mask(X86_FEATURE_APIC);
mask |= ((uint64_t)edx << 32) | ecx;
break;
case X86_VENDOR_AMD:
case X86_VENDOR_HYGON:
mask &= ((uint64_t)ecx << 32) | edx;
/*
* AMD masking MSRs are documented as overrides.
* Experimentally, fast-forwarding of the OSXSAVE and APIC
* bits from real hardware state only occurs if the MSR has
* the respective bits set.
*/
if ( ecx & cpufeat_mask(X86_FEATURE_XSAVE) )
ecx = cpufeat_mask(X86_FEATURE_OSXSAVE);
else
ecx = 0;
edx = cpufeat_mask(X86_FEATURE_APIC);
mask |= ((uint64_t)ecx << 32) | edx;
break;
}
d->arch.pv.cpuidmasks->_1cd = mask;
}
break;
case 6:
if ( is_pv_domain(d) && ((levelling_caps & LCAP_6c) == LCAP_6c) )
{
uint64_t mask = cpuidmask_defaults._6c;
if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
mask &= (~0ULL << 32) | ctl->ecx;
d->arch.pv.cpuidmasks->_6c = mask;
}
break;
case 7:
if ( ctl->input[1] != 0 )
break;
if ( is_pv_domain(d) && ((levelling_caps & LCAP_7ab0) == LCAP_7ab0) )
{
uint64_t mask = cpuidmask_defaults._7ab0;
/*
* Leaf 7[0].eax is max_subleaf, not a feature mask. Take it
* wholesale from the policy, but clamp the features in 7[0].ebx
* per usual.
*/
if ( boot_cpu_data.x86_vendor &
(X86_VENDOR_AMD | X86_VENDOR_HYGON) )
mask = (((uint64_t)p->feat.max_subleaf << 32) |
((uint32_t)mask & p->feat._7b0));
d->arch.pv.cpuidmasks->_7ab0 = mask;
}
/*
* If the IBRS/IBPB policy has changed, we need to recalculate the MSR
* interception bitmaps.
*/
call_policy_changed = (is_hvm_domain(d) &&
((old_7d0 ^ p->feat.raw[0].d) &
(cpufeat_mask(X86_FEATURE_IBRSB) |
cpufeat_mask(X86_FEATURE_L1D_FLUSH))));
break;
case 0xa:
if ( boot_cpu_data.x86_vendor != X86_VENDOR_INTEL )
break;
/* If PMU version is zero then the guest doesn't have VPMU */
if ( p->basic.pmu_version == 0 )
{
struct vcpu *v;
for_each_vcpu ( d, v )
vpmu_destroy(v);
}
break;
case 0xd:
if ( ctl->input[1] != 1 )
break;
if ( is_pv_domain(d) && ((levelling_caps & LCAP_Da1) == LCAP_Da1) )
{
uint64_t mask = cpuidmask_defaults.Da1;
uint32_t eax = p->xstate.Da1;
if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
mask &= (~0ULL << 32) | eax;
d->arch.pv.cpuidmasks->Da1 = mask;
}
break;
case 0x80000001:
if ( is_pv_domain(d) && ((levelling_caps & LCAP_e1cd) == LCAP_e1cd) )
{
uint64_t mask = cpuidmask_defaults.e1cd;
uint32_t ecx = p->extd.e1c;
uint32_t edx = p->extd.e1d;
/*
* Must expose hosts CMP_LEGACY value so a guest using native
* CPUID can correctly interpret other leaves which cannot be
* masked.
*/
if ( cpu_has_cmp_legacy )
ecx |= cpufeat_mask(X86_FEATURE_CMP_LEGACY);
/*
* If not emulating AMD or Hygon, clear the duplicated features
* in e1d.
*/
if ( !(p->x86_vendor & (X86_VENDOR_AMD | X86_VENDOR_HYGON)) )
edx &= ~CPUID_COMMON_1D_FEATURES;
switch ( boot_cpu_data.x86_vendor )
{
case X86_VENDOR_INTEL:
mask &= ((uint64_t)edx << 32) | ecx;
break;
case X86_VENDOR_AMD:
case X86_VENDOR_HYGON:
mask &= ((uint64_t)ecx << 32) | edx;
/*
* Fast-forward bits - Must be set in the masking MSR for
* fast-forwarding to occur in hardware.
*/
ecx = 0;
edx = cpufeat_mask(X86_FEATURE_APIC);
mask |= ((uint64_t)ecx << 32) | edx;
break;
}
d->arch.pv.cpuidmasks->e1cd = mask;
}
break;
case 0x80000008:
/*
* If the IBPB policy has changed, we need to recalculate the MSR
* interception bitmaps.
*/
call_policy_changed = (is_hvm_domain(d) &&
((old_e8b ^ p->extd.raw[8].b) &
cpufeat_mask(X86_FEATURE_IBPB)));
break;
}
if ( call_policy_changed )
{
struct vcpu *v;
for_each_vcpu( d, v )
cpuid_policy_updated(v);
}
domain_cpu_policy_changed(d);
return 0;
}
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.