[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2 05/25] x86/cpuid: Recalculate a domains CPUID policy when appropriate
Introduce recalculate_cpuid_policy() which clamps a CPUID policy based on the domains current restrictions. Each adjustment introduced here mirrors what currently happens in {pv,hvm}_cpuid(), although some logic is expressed differently. * The clearing X86_FEATURE_LM for 32bit PV guests, sanitise_featureset() takes out all 64bit-dependent features in one go. * The toolstacks choice of X86_FEATURE_ITSC in (by default) clobbered in domain_cpuid(), but {pv,hvm}_cpuid() needed to account for the host ITSC value when masking the toolstack value. This now requires that sanitise_featureset(), lookup_deep_deps() and associated data needs to be available at runtime, so moves out of __init. Recalculate the cpuid policy when: * The domain is first created * Switching a PV guest to being compat * Setting disable_migrate or vTSC modes * The toolstack sets new policy data The disable_migrate code was previously common. To compensate, move the code to each archs arch_do_domctl(), as the implementations now differ. From this point on, domains have full and correct feature-leaf information in their CPUID policies, allowing for substantial cleanup and improvements. Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- CC: Jan Beulich <JBeulich@xxxxxxxx> CC: Stefano Stabellini <sstabellini@xxxxxxxxxx> CC: Julien Grall <julien.grall@xxxxxxx> v2: * Rewrite the commit message * Recalculate on disable_migrate/vTSC changes * Reorder and comment the logic better in recalculate_cpuid_policy() --- xen/arch/arm/domctl.c | 5 +++ xen/arch/x86/cpuid.c | 70 ++++++++++++++++++++++++++++++++++++---- xen/arch/x86/domain.c | 1 + xen/arch/x86/domctl.c | 29 +++++++++++++++++ xen/arch/x86/time.c | 2 ++ xen/common/domctl.c | 4 --- xen/include/asm-x86/cpufeature.h | 1 + xen/include/asm-x86/cpuid.h | 10 +++--- 8 files changed, 105 insertions(+), 17 deletions(-) diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c index 09d9959..fee4b17 100644 --- a/xen/arch/arm/domctl.c +++ b/xen/arch/arm/domctl.c @@ -115,6 +115,11 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, return 0; } + + case XEN_DOMCTL_disable_migrate: + d->disable_migrate = domctl->u.disable_migrate.disable; + break; + default: { int rc; diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c index 6c95b7f..0d54465 100644 --- a/xen/arch/x86/cpuid.c +++ b/xen/arch/x86/cpuid.c @@ -9,10 +9,10 @@ const uint32_t known_features[] = INIT_KNOWN_FEATURES; const uint32_t special_features[] = INIT_SPECIAL_FEATURES; -static const uint32_t __initconst pv_featuremask[] = INIT_PV_FEATURES; -static const uint32_t __initconst hvm_shadow_featuremask[] = INIT_HVM_SHADOW_FEATURES; -static const uint32_t __initconst hvm_hap_featuremask[] = INIT_HVM_HAP_FEATURES; -static const uint32_t __initconst deep_features[] = INIT_DEEP_FEATURES; +static const uint32_t pv_featuremask[] = INIT_PV_FEATURES; +static const uint32_t hvm_shadow_featuremask[] = INIT_HVM_SHADOW_FEATURES; +static const uint32_t hvm_hap_featuremask[] = INIT_HVM_HAP_FEATURES; +static const uint32_t deep_features[] = INIT_DEEP_FEATURES; #define EMPTY_LEAF ((struct cpuid_leaf){}) @@ -32,7 +32,7 @@ static void cpuid_count_leaf(uint32_t leaf, uint32_t subleaf, cpuid_count(leaf, subleaf, &data->a, &data->b, &data->c, &data->d); } -static void __init sanitise_featureset(uint32_t *fs) +static void sanitise_featureset(uint32_t *fs) { /* for_each_set_bit() uses unsigned longs. Extend with zeroes. */ uint32_t disabled_features[ @@ -231,12 +231,12 @@ void __init init_guest_cpuid(void) calculate_hvm_max_policy(); } -const uint32_t * __init lookup_deep_deps(uint32_t feature) +const uint32_t *lookup_deep_deps(uint32_t feature) { static const struct { uint32_t feature; uint32_t fs[FSCAPINTS]; - } deep_deps[] __initconst = INIT_DEEP_DEPS; + } deep_deps[] = INIT_DEEP_DEPS; unsigned int start = 0, end = ARRAY_SIZE(deep_deps); BUILD_BUG_ON(ARRAY_SIZE(deep_deps) != NR_DEEP_DEPS); @@ -261,6 +261,60 @@ const uint32_t * __init lookup_deep_deps(uint32_t feature) return NULL; } +void recalculate_cpuid_policy(struct domain *d) +{ + struct cpuid_policy *p = d->arch.cpuid; + const struct cpuid_policy *max = + is_pv_domain(d) ? &pv_max_policy : &hvm_max_policy; + uint32_t fs[FSCAPINTS], max_fs[FSCAPINTS]; + unsigned int i; + + cpuid_policy_to_featureset(p, fs); + memcpy(max_fs, max->fs, sizeof(max_fs)); + + /* + * HVM domains using Shadow paging have further restrictions on their + * available paging features. + */ + if ( is_hvm_domain(d) && !hap_enabled(d) ) + { + for ( i = 0; i < ARRAY_SIZE(max_fs); i++ ) + max_fs[i] &= hvm_shadow_featuremask[i]; + } + + /* + * 32bit PV domains can't use any Long Mode features, and cannot use + * SYSCALL on non-AMD hardware. + */ + if ( is_pv_32bit_domain(d) ) + { + __clear_bit(X86_FEATURE_LM, max_fs); + if ( boot_cpu_data.x86_vendor != X86_VENDOR_AMD ) + __clear_bit(X86_FEATURE_SYSCALL, max_fs); + } + + /* + * ITSC is masked by default (so domains are safe to migrate), but a + * toolstack which has configured disable_migrate or vTSC for a domain may + * safely select it, and needs a way of doing so. + */ + if ( cpu_has_itsc && (d->disable_migrate || d->arch.vtsc) ) + __set_bit(X86_FEATURE_ITSC, max_fs); + + /* Clamp the toolstacks choices to reality. */ + for ( i = 0; i < ARRAY_SIZE(fs); i++ ) + fs[i] &= max_fs[i]; + + sanitise_featureset(fs); + + /* Fold host's FDP_EXCP_ONLY and NO_FPU_SEL into guest's view. */ + fs[FEATURESET_7b0] &= ~special_features[FEATURESET_7b0]; + fs[FEATURESET_7b0] |= (host_featureset[FEATURESET_7b0] & + special_features[FEATURESET_7b0]); + + cpuid_featureset_to_policy(fs, p); +} + int init_domain_cpuid_policy(struct domain *d) { d->arch.cpuid = xmalloc(struct cpuid_policy); @@ -270,6 +324,8 @@ int init_domain_cpuid_policy(struct domain *d) *d->arch.cpuid = is_pv_domain(d) ? pv_max_policy : hvm_max_policy; + recalculate_cpuid_policy(d); + return 0; } diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index c1f95cc..7d33c41 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -352,6 +352,7 @@ int switch_compat(struct domain *d) } domain_set_alloc_bitsize(d); + recalculate_cpuid_policy(d); d->arch.x87_fip_width = 4; diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index ab141b1..a3b2b72 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -51,6 +51,30 @@ static int gdbsx_guest_mem_io(domid_t domid, struct xen_domctl_gdbsx_memio *iop) static void update_domain_cpuid_info(struct domain *d, const xen_domctl_cpuid_t *ctl) { + struct cpuid_policy *p = d->arch.cpuid; + const struct cpuid_leaf leaf = { ctl->eax, ctl->ebx, ctl->ecx, ctl->edx }; + + /* Insert ctl data into cpuid_policy. */ + if ( ctl->input[0] < ARRAY_SIZE(p->basic.raw) ) + { + if ( ctl->input[0] == 7 ) + { + if ( ctl->input[1] < ARRAY_SIZE(p->feat.raw) ) + p->feat.raw[ctl->input[1]] = leaf; + } + else if ( ctl->input[0] == 0xd ) + { + if ( ctl->input[1] < ARRAY_SIZE(p->xstate.raw) ) + p->xstate.raw[ctl->input[1]] = leaf; + } + else + p->basic.raw[ctl->input[0]] = leaf; + } + else if ( (ctl->input[0] - 0x80000000) < ARRAY_SIZE(p->extd.raw) ) + p->extd.raw[ctl->input[0] - 0x80000000] = leaf; + + recalculate_cpuid_policy(d); + switch ( ctl->input[0] ) { case 0: { @@ -1409,6 +1433,11 @@ long arch_do_domctl( } break; + case XEN_DOMCTL_disable_migrate: + d->disable_migrate = domctl->u.disable_migrate.disable; + recalculate_cpuid_policy(d); + break; + default: ret = iommu_do_domctl(domctl, d, u_domctl); break; diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index b89fa13..e17da1b 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -2106,6 +2106,8 @@ void tsc_set_info(struct domain *d, d->arch.hvm_domain.sync_tsc); } } + + recalculate_cpuid_policy(d); } /* vtsc may incur measurable performance degradation, diagnose with this */ diff --git a/xen/common/domctl.c b/xen/common/domctl.c index b0ee961..12cf4a9 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -1103,10 +1103,6 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) copyback = 1; break; - case XEN_DOMCTL_disable_migrate: - d->disable_migrate = op->u.disable_migrate.disable; - break; - #ifdef CONFIG_HAS_MEM_ACCESS case XEN_DOMCTL_set_access_required: if ( unlikely(current->domain == d) ) /* no domain_pause() */ diff --git a/xen/include/asm-x86/cpufeature.h b/xen/include/asm-x86/cpufeature.h index 9326616..f34d01c 100644 --- a/xen/include/asm-x86/cpufeature.h +++ b/xen/include/asm-x86/cpufeature.h @@ -71,6 +71,7 @@ #define cpu_has_eist boot_cpu_has(X86_FEATURE_EIST) #define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR) #define cpu_has_cmp_legacy boot_cpu_has(X86_FEATURE_CMP_LEGACY) +#define cpu_has_itsc boot_cpu_has(X86_FEATURE_ITSC) enum _cache_type { CACHE_TYPE_NULL = 0, diff --git a/xen/include/asm-x86/cpuid.h b/xen/include/asm-x86/cpuid.h index 77a467a..0592b38 100644 --- a/xen/include/asm-x86/cpuid.h +++ b/xen/include/asm-x86/cpuid.h @@ -86,13 +86,8 @@ struct cpuid_policy * * Per-domain objects: * - * - Host accurate: - * - max_{,sub}leaf - * - {xcr0,xss}_{high,low} - * - All FEATURESET_* words - * * - Guest accurate: - * - Nothing + * - All FEATURESET_* words * * Everything else should be considered inaccurate, and not necesserily 0. */ @@ -202,6 +197,9 @@ extern struct cpuid_policy raw_policy, host_policy, pv_max_policy, /* Allocate and initialise a CPUID policy suitable for the domain. */ int init_domain_cpuid_policy(struct domain *d); +/* Clamp the CPUID policy to reality. */ +void recalculate_cpuid_policy(struct domain *d); + void guest_cpuid(const struct vcpu *v, uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *res); -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |