From patchwork Tue Mar 15 15:35:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Cooper X-Patchwork-Id: 8590071 Return-Path: X-Original-To: patchwork-xen-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id CB9C39F758 for ; Tue, 15 Mar 2016 16:01:28 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6C43F20306 for ; Tue, 15 Mar 2016 16:01:27 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D936C202F0 for ; Tue, 15 Mar 2016 16:01:23 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1afrN5-0004DL-FA; Tue, 15 Mar 2016 15:58:59 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1afrN3-0004Bh-N5 for xen-devel@lists.xen.org; Tue, 15 Mar 2016 15:58:57 +0000 Received: from [85.158.139.211] by server-13.bemta-5.messagelabs.com id C8/58-03786-14138E65; Tue, 15 Mar 2016 15:58:57 +0000 X-Env-Sender: prvs=87506bf53=Andrew.Cooper3@citrix.com X-Msg-Ref: server-4.tower-206.messagelabs.com!1458057521!29199696!7 X-Originating-IP: [66.165.176.89] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni44OSA9PiAyMDMwMDc=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 8.11; banners=-,-,- X-VirusChecked: Checked Received: (qmail 30831 invoked from network); 15 Mar 2016 15:58:55 -0000 Received: from smtp.citrix.com (HELO SMTP.CITRIX.COM) (66.165.176.89) by server-4.tower-206.messagelabs.com with RC4-SHA encrypted SMTP; 15 Mar 2016 15:58:55 -0000 X-IronPort-AV: E=Sophos;i="5.24,339,1454976000"; d="scan'208";a="339082916" From: Andrew Cooper To: Xen-devel Date: Tue, 15 Mar 2016 15:35:23 +0000 Message-ID: <1458056124-8024-28-git-send-email-andrew.cooper3@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1458056124-8024-1-git-send-email-andrew.cooper3@citrix.com> References: <1458056124-8024-1-git-send-email-andrew.cooper3@citrix.com> MIME-Version: 1.0 X-DLP: MIA1 Cc: Andrew Cooper , Ian Jackson Subject: [Xen-devel] [PATCH v3 27/28] tools/libxc: Use featuresets rather than guesswork X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP It is conceptually wrong to base a VM's featureset on the features visible to the toolstack which happens to construct it. Instead, the featureset used is either an explicit one passed by the toolstack, or the default which Xen believes it can give to the guest. Collect all the feature manipulation into a single function which adjusts the featureset, and perform deep dependency removal. Signed-off-by: Andrew Cooper Acked-by: Wei Liu --- CC: Ian Jackson v3: * Correctly adjust HTT/CMP_LEGACY in the policy. PV guests see host details, so get the host features. HVM guests have their vcpu topology presented in an HTT compatible manor (even if ends up reporting 1 cpu), so have CMP_LEGACY unconditionally cleared. v2: * Join several related patches together. --- tools/libxc/xc_cpuid_x86.c | 355 ++++++++++++++++++--------------------------- 1 file changed, 138 insertions(+), 217 deletions(-) diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c index a92f5e4..290c995 100644 --- a/tools/libxc/xc_cpuid_x86.c +++ b/tools/libxc/xc_cpuid_x86.c @@ -21,7 +21,9 @@ #include #include +#include #include "xc_private.h" +#include "xc_bitops.h" #include enum { @@ -31,12 +33,14 @@ enum { #include "_xc_cpuid_autogen.h" #define bitmaskof(idx) (1u << ((idx) & 31)) -#define clear_bit(idx, dst) ((dst) &= ~bitmaskof(idx)) -#define set_bit(idx, dst) ((dst) |= bitmaskof(idx)) +#define featureword_of(idx) ((idx) >> 5) +#define clear_feature(idx, dst) ((dst) &= ~bitmaskof(idx)) +#define set_feature(idx, dst) ((dst) |= bitmaskof(idx)) #define DEF_MAX_BASE 0x0000000du #define DEF_MAX_INTELEXT 0x80000008u #define DEF_MAX_AMDEXT 0x8000001cu +#define COMMON_1D CPUID_COMMON_1D_FEATURES int xc_get_cpu_levelling_caps(xc_interface *xch, uint32_t *caps) { @@ -322,37 +326,6 @@ static void amd_xc_cpuid_policy(xc_interface *xch, regs[0] = DEF_MAX_AMDEXT; break; - case 0x80000001: { - if ( !info->pae ) - clear_bit(X86_FEATURE_PAE, regs[3]); - - /* Filter all other features according to a whitelist. */ - regs[2] &= (bitmaskof(X86_FEATURE_LAHF_LM) | - bitmaskof(X86_FEATURE_CMP_LEGACY) | - (info->nestedhvm ? bitmaskof(X86_FEATURE_SVM) : 0) | - bitmaskof(X86_FEATURE_CR8_LEGACY) | - bitmaskof(X86_FEATURE_ABM) | - bitmaskof(X86_FEATURE_SSE4A) | - bitmaskof(X86_FEATURE_MISALIGNSSE) | - bitmaskof(X86_FEATURE_3DNOWPREFETCH) | - bitmaskof(X86_FEATURE_OSVW) | - bitmaskof(X86_FEATURE_XOP) | - bitmaskof(X86_FEATURE_LWP) | - bitmaskof(X86_FEATURE_FMA4) | - bitmaskof(X86_FEATURE_TBM) | - bitmaskof(X86_FEATURE_DBEXT)); - regs[3] &= (0x0183f3ff | /* features shared with 0x00000001:EDX */ - bitmaskof(X86_FEATURE_NX) | - bitmaskof(X86_FEATURE_LM) | - bitmaskof(X86_FEATURE_PAGE1GB) | - bitmaskof(X86_FEATURE_SYSCALL) | - bitmaskof(X86_FEATURE_MMXEXT) | - bitmaskof(X86_FEATURE_FFXSR) | - bitmaskof(X86_FEATURE_3DNOW) | - bitmaskof(X86_FEATURE_3DNOWEXT)); - break; - } - case 0x80000008: /* * ECX[15:12] is ApicIdCoreSize: ECX[7:0] is NumberOfCores (minus one). @@ -399,12 +372,6 @@ static void intel_xc_cpuid_policy(xc_interface *xch, { switch ( input[0] ) { - case 0x00000001: - /* ECX[5] is availability of VMX */ - if ( info->nestedhvm ) - set_bit(X86_FEATURE_VMX, regs[2]); - break; - case 0x00000004: /* * EAX[31:26] is Maximum Cores Per Package (minus one). @@ -420,19 +387,6 @@ static void intel_xc_cpuid_policy(xc_interface *xch, regs[0] = DEF_MAX_INTELEXT; break; - case 0x80000001: { - /* Only a few features are advertised in Intel's 0x80000001. */ - regs[2] &= (bitmaskof(X86_FEATURE_LAHF_LM) | - bitmaskof(X86_FEATURE_3DNOWPREFETCH) | - bitmaskof(X86_FEATURE_ABM)); - regs[3] &= (bitmaskof(X86_FEATURE_NX) | - bitmaskof(X86_FEATURE_LM) | - bitmaskof(X86_FEATURE_PAGE1GB) | - bitmaskof(X86_FEATURE_SYSCALL) | - bitmaskof(X86_FEATURE_RDTSCP)); - break; - } - case 0x80000005: regs[0] = regs[1] = regs[2] = 0; break; @@ -484,11 +438,8 @@ static void xc_cpuid_config_xsave(xc_interface *xch, regs[1] = 512 + 64; /* FP/SSE + XSAVE.HEADER */ break; case 1: /* leaf 1 */ - regs[0] &= (XSAVEOPT | XSAVEC | XGETBV1 | XSAVES); - if ( !info->hvm ) - regs[0] &= ~XSAVES; - regs[2] &= info->xfeature_mask; - regs[3] = 0; + regs[0] = info->featureset[featureword_of(X86_FEATURE_XSAVEOPT)]; + regs[1] = regs[2] = regs[3] = 0; break; case 2 ... 63: /* sub-leaves */ if ( !(info->xfeature_mask & (1ULL << input[1])) ) @@ -520,85 +471,22 @@ static void xc_cpuid_hvm_policy(xc_interface *xch, */ regs[1] = (regs[1] & 0x0000ffffu) | ((regs[1] & 0x007f0000u) << 1); - regs[2] &= (bitmaskof(X86_FEATURE_SSE3) | - bitmaskof(X86_FEATURE_PCLMULQDQ) | - bitmaskof(X86_FEATURE_SSSE3) | - bitmaskof(X86_FEATURE_FMA) | - bitmaskof(X86_FEATURE_CX16) | - bitmaskof(X86_FEATURE_PCID) | - bitmaskof(X86_FEATURE_SSE4_1) | - bitmaskof(X86_FEATURE_SSE4_2) | - bitmaskof(X86_FEATURE_MOVBE) | - bitmaskof(X86_FEATURE_POPCNT) | - bitmaskof(X86_FEATURE_AESNI) | - bitmaskof(X86_FEATURE_F16C) | - bitmaskof(X86_FEATURE_RDRAND) | - ((info->xfeature_mask != 0) ? - (bitmaskof(X86_FEATURE_AVX) | - bitmaskof(X86_FEATURE_XSAVE)) : 0)); - - regs[2] |= (bitmaskof(X86_FEATURE_HYPERVISOR) | - bitmaskof(X86_FEATURE_TSC_DEADLINE) | - bitmaskof(X86_FEATURE_X2APIC)); - - regs[3] &= (bitmaskof(X86_FEATURE_FPU) | - bitmaskof(X86_FEATURE_VME) | - bitmaskof(X86_FEATURE_DE) | - bitmaskof(X86_FEATURE_PSE) | - bitmaskof(X86_FEATURE_TSC) | - bitmaskof(X86_FEATURE_MSR) | - bitmaskof(X86_FEATURE_PAE) | - bitmaskof(X86_FEATURE_MCE) | - bitmaskof(X86_FEATURE_CX8) | - bitmaskof(X86_FEATURE_APIC) | - bitmaskof(X86_FEATURE_SEP) | - bitmaskof(X86_FEATURE_MTRR) | - bitmaskof(X86_FEATURE_PGE) | - bitmaskof(X86_FEATURE_MCA) | - bitmaskof(X86_FEATURE_CMOV) | - bitmaskof(X86_FEATURE_PAT) | - bitmaskof(X86_FEATURE_CLFLUSH) | - bitmaskof(X86_FEATURE_PSE36) | - bitmaskof(X86_FEATURE_MMX) | - bitmaskof(X86_FEATURE_FXSR) | - bitmaskof(X86_FEATURE_SSE) | - bitmaskof(X86_FEATURE_SSE2) | - bitmaskof(X86_FEATURE_HTT)); - - /* We always support MTRR MSRs. */ - regs[3] |= bitmaskof(X86_FEATURE_MTRR); - - if ( !info->pae ) - { - clear_bit(X86_FEATURE_PAE, regs[3]); - clear_bit(X86_FEATURE_PSE36, regs[3]); - } + regs[2] = info->featureset[featureword_of(X86_FEATURE_SSE3)]; + regs[3] = (info->featureset[featureword_of(X86_FEATURE_FPU)] | + bitmaskof(X86_FEATURE_HTT)); break; case 0x00000007: /* Intel-defined CPU features */ - if ( input[1] == 0 ) { - regs[1] &= (bitmaskof(X86_FEATURE_TSC_ADJUST) | - bitmaskof(X86_FEATURE_BMI1) | - bitmaskof(X86_FEATURE_HLE) | - bitmaskof(X86_FEATURE_AVX2) | - bitmaskof(X86_FEATURE_SMEP) | - bitmaskof(X86_FEATURE_BMI2) | - bitmaskof(X86_FEATURE_ERMS) | - bitmaskof(X86_FEATURE_INVPCID) | - bitmaskof(X86_FEATURE_RTM) | - ((info->xfeature_mask != 0) ? - bitmaskof(X86_FEATURE_MPX) : 0) | - bitmaskof(X86_FEATURE_RDSEED) | - bitmaskof(X86_FEATURE_ADX) | - bitmaskof(X86_FEATURE_SMAP) | - bitmaskof(X86_FEATURE_FSGSBASE) | - bitmaskof(X86_FEATURE_PCOMMIT) | - bitmaskof(X86_FEATURE_CLWB) | - bitmaskof(X86_FEATURE_CLFLUSHOPT)); - regs[2] &= bitmaskof(X86_FEATURE_PKU); - } else - regs[1] = regs[2] = 0; - + if ( input[1] == 0 ) + { + regs[1] = info->featureset[featureword_of(X86_FEATURE_FSGSBASE)]; + regs[2] = info->featureset[featureword_of(X86_FEATURE_PREFETCHWT1)]; + } + else + { + regs[1] = 0; + regs[2] = 0; + } regs[0] = regs[3] = 0; break; @@ -611,14 +499,9 @@ static void xc_cpuid_hvm_policy(xc_interface *xch, break; case 0x80000001: - if ( !info->pae ) - { - clear_bit(X86_FEATURE_LAHF_LM, regs[2]); - clear_bit(X86_FEATURE_LM, regs[3]); - clear_bit(X86_FEATURE_NX, regs[3]); - clear_bit(X86_FEATURE_PSE36, regs[3]); - clear_bit(X86_FEATURE_PAGE1GB, regs[3]); - } + regs[2] = (info->featureset[featureword_of(X86_FEATURE_LAHF_LM)] & + ~bitmaskof(X86_FEATURE_CMP_LEGACY)); + regs[3] = info->featureset[featureword_of(X86_FEATURE_SYSCALL)]; break; case 0x80000007: @@ -662,68 +545,34 @@ static void xc_cpuid_pv_policy(xc_interface *xch, const struct cpuid_domain_info *info, const unsigned int *input, unsigned int *regs) { - if ( (input[0] & 0x7fffffff) == 0x00000001 ) - { - clear_bit(X86_FEATURE_VME, regs[3]); - if ( !info->pvh ) - { - clear_bit(X86_FEATURE_PSE, regs[3]); - clear_bit(X86_FEATURE_PGE, regs[3]); - } - clear_bit(X86_FEATURE_MCE, regs[3]); - clear_bit(X86_FEATURE_MCA, regs[3]); - clear_bit(X86_FEATURE_MTRR, regs[3]); - clear_bit(X86_FEATURE_PSE36, regs[3]); - } - switch ( input[0] ) { case 0x00000001: - if ( info->vendor == VENDOR_AMD ) - clear_bit(X86_FEATURE_SEP, regs[3]); - clear_bit(X86_FEATURE_DS, regs[3]); - clear_bit(X86_FEATURE_TM1, regs[3]); - clear_bit(X86_FEATURE_PBE, regs[3]); - - clear_bit(X86_FEATURE_DTES64, regs[2]); - clear_bit(X86_FEATURE_MONITOR, regs[2]); - clear_bit(X86_FEATURE_DSCPL, regs[2]); - clear_bit(X86_FEATURE_VMX, regs[2]); - clear_bit(X86_FEATURE_SMX, regs[2]); - clear_bit(X86_FEATURE_EIST, regs[2]); - clear_bit(X86_FEATURE_TM2, regs[2]); - if ( !info->pv64 ) - clear_bit(X86_FEATURE_CX16, regs[2]); - if ( info->xfeature_mask == 0 ) - { - clear_bit(X86_FEATURE_XSAVE, regs[2]); - clear_bit(X86_FEATURE_AVX, regs[2]); - } - clear_bit(X86_FEATURE_XTPR, regs[2]); - clear_bit(X86_FEATURE_PDCM, regs[2]); - clear_bit(X86_FEATURE_PCID, regs[2]); - clear_bit(X86_FEATURE_DCA, regs[2]); - set_bit(X86_FEATURE_HYPERVISOR, regs[2]); + { + /* Host topology exposed to PV guest. Provide host value. */ + bool host_htt = regs[3] & bitmaskof(X86_FEATURE_HTT); + + regs[2] = info->featureset[featureword_of(X86_FEATURE_SSE3)]; + regs[3] = (info->featureset[featureword_of(X86_FEATURE_FPU)] & + ~bitmaskof(X86_FEATURE_HTT)); + + if ( host_htt ) + regs[3] |= bitmaskof(X86_FEATURE_HTT); break; + } case 0x00000007: if ( input[1] == 0 ) { - regs[1] &= (bitmaskof(X86_FEATURE_BMI1) | - bitmaskof(X86_FEATURE_HLE) | - bitmaskof(X86_FEATURE_AVX2) | - bitmaskof(X86_FEATURE_BMI2) | - bitmaskof(X86_FEATURE_ERMS) | - bitmaskof(X86_FEATURE_RTM) | - bitmaskof(X86_FEATURE_RDSEED) | - bitmaskof(X86_FEATURE_ADX) | - bitmaskof(X86_FEATURE_FSGSBASE)); - if ( info->xfeature_mask == 0 ) - clear_bit(X86_FEATURE_MPX, regs[1]); + regs[1] = info->featureset[featureword_of(X86_FEATURE_FSGSBASE)]; + regs[2] = info->featureset[featureword_of(X86_FEATURE_PREFETCHWT1)]; } else + { regs[1] = 0; - regs[0] = regs[2] = regs[3] = 0; + regs[2] = 0; + } + regs[0] = regs[3] = 0; break; case 0x0000000d: @@ -731,30 +580,19 @@ static void xc_cpuid_pv_policy(xc_interface *xch, break; case 0x80000001: - if ( !info->pv64 ) - { - clear_bit(X86_FEATURE_LM, regs[3]); - clear_bit(X86_FEATURE_LAHF_LM, regs[2]); - if ( info->vendor != VENDOR_AMD ) - clear_bit(X86_FEATURE_SYSCALL, regs[3]); - } - else - { - set_bit(X86_FEATURE_SYSCALL, regs[3]); - } - if ( !info->pvh ) - clear_bit(X86_FEATURE_PAGE1GB, regs[3]); - clear_bit(X86_FEATURE_RDTSCP, regs[3]); - - clear_bit(X86_FEATURE_SVM, regs[2]); - clear_bit(X86_FEATURE_OSVW, regs[2]); - clear_bit(X86_FEATURE_IBS, regs[2]); - clear_bit(X86_FEATURE_SKINIT, regs[2]); - clear_bit(X86_FEATURE_WDT, regs[2]); - clear_bit(X86_FEATURE_LWP, regs[2]); - clear_bit(X86_FEATURE_NODEID_MSR, regs[2]); - clear_bit(X86_FEATURE_TOPOEXT, regs[2]); + { + /* Host topology exposed to PV guest. Provide host CMP_LEGACY value. */ + bool host_cmp_legacy = regs[2] & bitmaskof(X86_FEATURE_CMP_LEGACY); + + regs[2] = (info->featureset[featureword_of(X86_FEATURE_LAHF_LM)] & + ~bitmaskof(X86_FEATURE_CMP_LEGACY)); + regs[3] = info->featureset[featureword_of(X86_FEATURE_SYSCALL)]; + + if ( host_cmp_legacy ) + regs[2] |= bitmaskof(X86_FEATURE_CMP_LEGACY); + break; + } case 0x00000005: /* MONITOR/MWAIT */ case 0x0000000a: /* Architectural Performance Monitor Features */ @@ -833,6 +671,87 @@ void xc_cpuid_to_str(const unsigned int *regs, char **strs) } } +static void sanitise_featureset(struct cpuid_domain_info *info) +{ + const uint32_t fs_size = xc_get_cpu_featureset_size(); + uint32_t disabled_features[fs_size]; + static const uint32_t deep_features[] = INIT_DEEP_FEATURES; + unsigned int i, b; + + if ( info->hvm ) + { + /* HVM Guest */ + + if ( !info->pae ) + clear_bit(X86_FEATURE_PAE, info->featureset); + + if ( !info->nestedhvm ) + { + clear_bit(X86_FEATURE_SVM, info->featureset); + clear_bit(X86_FEATURE_VMX, info->featureset); + } + } + else + { + /* PV or PVH Guest */ + + if ( !info->pv64 ) + { + clear_bit(X86_FEATURE_LM, info->featureset); + if ( info->vendor != VENDOR_AMD ) + clear_bit(X86_FEATURE_SYSCALL, info->featureset); + } + + if ( !info->pvh ) + { + clear_bit(X86_FEATURE_PSE, info->featureset); + clear_bit(X86_FEATURE_PSE36, info->featureset); + clear_bit(X86_FEATURE_PGE, info->featureset); + clear_bit(X86_FEATURE_PAGE1GB, info->featureset); + } + } + + if ( info->xfeature_mask == 0 ) + clear_bit(X86_FEATURE_XSAVE, info->featureset); + + /* Disable deep dependencies of disabled features. */ + for ( i = 0; i < ARRAY_SIZE(disabled_features); ++i ) + disabled_features[i] = ~info->featureset[i] & deep_features[i]; + + for ( b = 0; b < sizeof(disabled_features) * CHAR_BIT; ++b ) + { + const uint32_t *dfs; + + if ( !test_bit(b, disabled_features) || + !(dfs = xc_get_feature_deep_deps(b)) ) + continue; + + for ( i = 0; i < ARRAY_SIZE(disabled_features); ++i ) + { + info->featureset[i] &= ~dfs[i]; + disabled_features[i] &= ~dfs[i]; + } + } + + switch ( info->vendor ) + { + case VENDOR_INTEL: + /* Intel clears the common bits in e1d. */ + info->featureset[featureword_of(X86_FEATURE_SYSCALL)] &= ~COMMON_1D; + break; + + case VENDOR_AMD: + /* AMD duplicates the common bits between 1d and e1d. */ + info->featureset[featureword_of(X86_FEATURE_SYSCALL)] = + ((info->featureset[featureword_of(X86_FEATURE_FPU)] & COMMON_1D) | + (info->featureset[featureword_of(X86_FEATURE_SYSCALL)] & ~COMMON_1D)); + break; + + default: + break; + } +} + int xc_cpuid_apply_policy(xc_interface *xch, domid_t domid, uint32_t *featureset, unsigned int nr_features) @@ -856,6 +775,8 @@ int xc_cpuid_apply_policy(xc_interface *xch, domid_t domid, else ext_max = (regs[0] <= DEF_MAX_INTELEXT) ? regs[0] : DEF_MAX_INTELEXT; + sanitise_featureset(&info); + input[0] = 0; input[1] = XEN_CPUID_INPUT_UNUSED; for ( ; ; ) @@ -1027,9 +948,9 @@ int xc_cpuid_set( val = polval; if ( val ) - set_bit(31 - j, regs[i]); + set_feature(31 - j, regs[i]); else - clear_bit(31 - j, regs[i]); + clear_feature(31 - j, regs[i]); config_transformed[i][j] = config[i][j]; if ( config[i][j] == 's' )