[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH] tools/libxc: Improve efficiency of xc_cpuid_apply_policy()
Having the internals of xc_cpuid_policy() make hypercalls to collect domain information causes xc_cpuid_apply_policy() to be very inefficient. Re-order operations to collect all information at once at the outermost layer, and pass a structure in to all cpuid policy generation functions. This removes several hypercalls (4 from HVM, 3 from PV) for each of the up-to 108 leaves processed. No change in the eventual policy provided, although all the information gathering how has (or has correct) error checking. Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- CC: Ian Campbell <Ian.Campbell@xxxxxxxxxx> CC: Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx> CC: Wei Liu <wei.liu2@xxxxxxxxxx> --- tools/libxc/xc_cpuid_x86.c | 245 +++++++++++++++++++++++++------------------- 1 file changed, 141 insertions(+), 104 deletions(-) diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c index e146a3e..715f30c 100644 --- a/tools/libxc/xc_cpuid_x86.c +++ b/tools/libxc/xc_cpuid_x86.c @@ -33,6 +33,27 @@ #define DEF_MAX_INTELEXT 0x80000008u #define DEF_MAX_AMDEXT 0x8000001cu +struct cpuid_domain_info +{ + enum + { + VENDOR_UNKNOWN, + VENDOR_INTEL, + VENDOR_AMD, + } vendor; + + bool hvm; + bool pvh; + uint64_t xfeature_mask; + + /* PV-only information. */ + bool pv64; + + /* HVM-only infomation. */ + bool pae; + bool nestedhvm; +}; + static void cpuid(const unsigned int *input, unsigned int *regs) { unsigned int count = (input[1] == XEN_CPUID_INPUT_UNUSED) ? 0 : input[1]; @@ -55,24 +76,75 @@ static void cpuid(const unsigned int *input, unsigned int *regs) #endif } -/* Get the manufacturer brand name of the host processor. */ -static void xc_cpuid_brand_get(char *str) +static int get_cpuid_domain_info(xc_interface *xch, domid_t domid, + struct cpuid_domain_info *info) { - unsigned int input[2] = { 0, 0 }; - unsigned int regs[4]; + struct xen_domctl domctl = {}; + xc_dominfo_t di; + unsigned int in[2] = { 0, ~0U }, regs[4]; + int rc; - cpuid(input, regs); + cpuid(in, regs); + if ( regs[1] == 0x756e6547U && /* "GenuineIntel" */ + regs[2] == 0x6c65746eU && + regs[3] == 0x49656e69U ) + info->vendor = VENDOR_INTEL; + else if ( regs[1] == 0x68747541U && /* "AuthenticAMD" */ + regs[2] == 0x444d4163U && + regs[3] == 0x69746e65U ) + info->vendor = VENDOR_AMD; + else + info->vendor = VENDOR_UNKNOWN; + + if ( xc_domain_getinfo(xch, domid, 1, &di) != 1 || + di.domid != domid ) + return -ESRCH; + + info->hvm = di.hvm; + info->pvh = di.pvh; + + /* Get xstate information. */ + domctl.cmd = XEN_DOMCTL_getvcpuextstate; + domctl.domain = domid; + rc = do_domctl(xch, &domctl); + if ( rc ) + return rc; + + info->xfeature_mask = domctl.u.vcpuextstate.xfeature_mask; + + if ( di.hvm ) + { + uint64_t val; + + rc = xc_hvm_param_get(xch, domid, HVM_PARAM_PAE_ENABLED, &val); + if ( rc ) + return rc; + + info->pae = !!val; + + rc = xc_hvm_param_get(xch, domid, HVM_PARAM_NESTEDHVM, &val); + if ( rc ) + return rc; + + info->nestedhvm = !!val; + } + else + { + unsigned int width; + + rc = xc_domain_get_guest_width(xch, domid, &width); + if ( rc ) + return rc; + + info->pv64 = (width == 8); + } - *(uint32_t *)(str + 0) = regs[1]; - *(uint32_t *)(str + 4) = regs[3]; - *(uint32_t *)(str + 8) = regs[2]; - str[12] = '\0'; + return 0; } -static void amd_xc_cpuid_policy( - xc_interface *xch, domid_t domid, - const unsigned int *input, unsigned int *regs, - int is_pae, int is_nestedhvm) +static void amd_xc_cpuid_policy(xc_interface *xch, + const struct cpuid_domain_info *info, + const unsigned int *input, unsigned int *regs) { switch ( input[0] ) { @@ -87,13 +159,13 @@ static void amd_xc_cpuid_policy( break; case 0x80000001: { - if ( !is_pae ) + 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) | - (is_nestedhvm ? bitmaskof(X86_FEATURE_SVM) : 0) | + (info->nestedhvm ? bitmaskof(X86_FEATURE_SVM) : 0) | bitmaskof(X86_FEATURE_CR8_LEGACY) | bitmaskof(X86_FEATURE_ABM) | bitmaskof(X86_FEATURE_SSE4A) | @@ -127,7 +199,8 @@ static void amd_xc_cpuid_policy( break; case 0x8000000a: { - if (!is_nestedhvm) { + if ( !info->nestedhvm ) + { regs[0] = regs[1] = regs[2] = regs[3] = 0; break; } @@ -157,16 +230,15 @@ static void amd_xc_cpuid_policy( } } -static void intel_xc_cpuid_policy( - xc_interface *xch, domid_t domid, - const unsigned int *input, unsigned int *regs, - int is_pae, int is_nestedhvm) +static void intel_xc_cpuid_policy(xc_interface *xch, + const struct cpuid_domain_info *info, + const unsigned int *input, unsigned int *regs) { switch ( input[0] ) { case 0x00000001: /* ECX[5] is availability of VMX */ - if (is_nestedhvm) + if ( info->nestedhvm ) set_bit(X86_FEATURE_VMXE, regs[2]); break; @@ -211,11 +283,11 @@ static void intel_xc_cpuid_policy( #define XSAVEOPT (1 << 0) /* Configure extended state enumeration leaves (0x0000000D for xsave) */ -static void xc_cpuid_config_xsave( - xc_interface *xch, domid_t domid, uint64_t xfeature_mask, - const unsigned int *input, unsigned int *regs) +static void xc_cpuid_config_xsave(xc_interface *xch, + const struct cpuid_domain_info *info, + const unsigned int *input, unsigned int *regs) { - if ( xfeature_mask == 0 ) + if ( info->xfeature_mask == 0 ) { regs[0] = regs[1] = regs[2] = regs[3] = 0; return; @@ -225,9 +297,9 @@ static void xc_cpuid_config_xsave( { case 0: /* EAX: low 32bits of xfeature_enabled_mask */ - regs[0] = xfeature_mask & 0xFFFFFFFF; + regs[0] = info->xfeature_mask & 0xFFFFFFFF; /* EDX: high 32bits of xfeature_enabled_mask */ - regs[3] = (xfeature_mask >> 32) & 0xFFFFFFFF; + regs[3] = (info->xfeature_mask >> 32) & 0xFFFFFFFF; /* ECX: max size required by all HW features */ { unsigned int _input[2] = {0xd, 0x0}, _regs[4]; @@ -250,7 +322,7 @@ static void xc_cpuid_config_xsave( regs[1] = regs[2] = regs[3] = 0; break; case 2 ... 63: /* sub-leaves */ - if ( !(xfeature_mask & (1ULL << input[1])) ) + if ( !(info->xfeature_mask & (1ULL << input[1])) ) { regs[0] = regs[1] = regs[2] = regs[3] = 0; break; @@ -261,29 +333,10 @@ static void xc_cpuid_config_xsave( } } -static void xc_cpuid_hvm_policy( - xc_interface *xch, domid_t domid, - const unsigned int *input, unsigned int *regs) +static void xc_cpuid_hvm_policy(xc_interface *xch, + const struct cpuid_domain_info *info, + const unsigned int *input, unsigned int *regs) { - DECLARE_DOMCTL; - char brand[13]; - uint64_t val; - int is_pae, is_nestedhvm; - uint64_t xfeature_mask; - - xc_hvm_param_get(xch, domid, HVM_PARAM_PAE_ENABLED, &val); - is_pae = !!val; - - /* Detecting Xen's atitude towards XSAVE */ - memset(&domctl, 0, sizeof(domctl)); - domctl.cmd = XEN_DOMCTL_getvcpuextstate; - domctl.domain = domid; - do_domctl(xch, &domctl); - xfeature_mask = domctl.u.vcpuextstate.xfeature_mask; - - xc_hvm_param_get(xch, domid, HVM_PARAM_NESTEDHVM, &val); - is_nestedhvm = !!val; - switch ( input[0] ) { case 0x00000000: @@ -311,7 +364,7 @@ static void xc_cpuid_hvm_policy( bitmaskof(X86_FEATURE_AES) | bitmaskof(X86_FEATURE_F16C) | bitmaskof(X86_FEATURE_RDRAND) | - ((xfeature_mask != 0) ? + ((info->xfeature_mask != 0) ? (bitmaskof(X86_FEATURE_AVX) | bitmaskof(X86_FEATURE_XSAVE)) : 0)); @@ -346,7 +399,8 @@ static void xc_cpuid_hvm_policy( /* We always support MTRR MSRs. */ regs[3] |= bitmaskof(X86_FEATURE_MTRR); - if ( !is_pae ) { + if ( !info->pae ) + { clear_bit(X86_FEATURE_PAE, regs[3]); clear_bit(X86_FEATURE_PSE36, regs[3]); } @@ -373,7 +427,7 @@ static void xc_cpuid_hvm_policy( break; case 0x0000000d: - xc_cpuid_config_xsave(xch, domid, xfeature_mask, input, regs); + xc_cpuid_config_xsave(xch, info, input, regs); break; case 0x80000000: @@ -381,7 +435,7 @@ static void xc_cpuid_hvm_policy( break; case 0x80000001: - if ( !is_pae ) + if ( !info->pae ) { clear_bit(X86_FEATURE_LAHF_LM, regs[2]); clear_bit(X86_FEATURE_LM, regs[3]); @@ -422,40 +476,21 @@ static void xc_cpuid_hvm_policy( break; } - xc_cpuid_brand_get(brand); - if ( strstr(brand, "AMD") ) - amd_xc_cpuid_policy(xch, domid, input, regs, is_pae, is_nestedhvm); + if ( info->vendor == VENDOR_AMD ) + amd_xc_cpuid_policy(xch, info, input, regs); else - intel_xc_cpuid_policy(xch, domid, input, regs, is_pae, is_nestedhvm); - + intel_xc_cpuid_policy(xch, info, input, regs); } -static void xc_cpuid_pv_policy( - xc_interface *xch, domid_t domid, - const unsigned int *input, unsigned int *regs, bool pvh) +static void xc_cpuid_pv_policy(xc_interface *xch, + const struct cpuid_domain_info *info, + const unsigned int *input, unsigned int *regs) { - DECLARE_DOMCTL; - unsigned int guest_width; - int guest_64bit; - char brand[13]; - uint64_t xfeature_mask; - - xc_cpuid_brand_get(brand); - - xc_domain_get_guest_width(xch, domid, &guest_width); - guest_64bit = (guest_width == 8); - - /* Detecting Xen's atitude towards XSAVE */ - memset(&domctl, 0, sizeof(domctl)); - domctl.cmd = XEN_DOMCTL_getvcpuextstate; - domctl.domain = domid; - do_domctl(xch, &domctl); - xfeature_mask = domctl.u.vcpuextstate.xfeature_mask; - if ( (input[0] & 0x7fffffff) == 0x00000001 ) { clear_bit(X86_FEATURE_VME, regs[3]); - if ( !pvh ) { + if ( !info->pvh ) + { clear_bit(X86_FEATURE_PSE, regs[3]); clear_bit(X86_FEATURE_PGE, regs[3]); } @@ -468,7 +503,7 @@ static void xc_cpuid_pv_policy( switch ( input[0] ) { case 0x00000001: - if ( strstr(brand, "AMD") ) + if ( info->vendor == VENDOR_AMD ) clear_bit(X86_FEATURE_SEP, regs[3]); clear_bit(X86_FEATURE_DS, regs[3]); clear_bit(X86_FEATURE_ACC, regs[3]); @@ -481,9 +516,9 @@ static void xc_cpuid_pv_policy( clear_bit(X86_FEATURE_SMXE, regs[2]); clear_bit(X86_FEATURE_EST, regs[2]); clear_bit(X86_FEATURE_TM2, regs[2]); - if ( !guest_64bit ) + if ( !info->pv64 ) clear_bit(X86_FEATURE_CX16, regs[2]); - if ( xfeature_mask == 0 ) + if ( info->xfeature_mask == 0 ) { clear_bit(X86_FEATURE_XSAVE, regs[2]); clear_bit(X86_FEATURE_AVX, regs[2]); @@ -512,22 +547,22 @@ static void xc_cpuid_pv_policy( break; case 0x0000000d: - xc_cpuid_config_xsave(xch, domid, xfeature_mask, input, regs); + xc_cpuid_config_xsave(xch, info, input, regs); break; case 0x80000001: - if ( !guest_64bit ) + if ( !info->pv64 ) { clear_bit(X86_FEATURE_LM, regs[3]); clear_bit(X86_FEATURE_LAHF_LM, regs[2]); - if ( !strstr(brand, "AMD") ) + if ( info->vendor != VENDOR_AMD ) clear_bit(X86_FEATURE_SYSCALL, regs[3]); } else { set_bit(X86_FEATURE_SYSCALL, regs[3]); } - if ( !pvh ) + if ( !info->pvh ) clear_bit(X86_FEATURE_PAGE1GB, regs[3]); clear_bit(X86_FEATURE_RDTSCP, regs[3]); @@ -553,12 +588,10 @@ static void xc_cpuid_pv_policy( } } -static int xc_cpuid_policy( - xc_interface *xch, domid_t domid, - const unsigned int *input, unsigned int *regs) +static int xc_cpuid_policy(xc_interface *xch, + const struct cpuid_domain_info *info, + const unsigned int *input, unsigned int *regs) { - xc_dominfo_t info; - /* * For hypervisor leaves (0x4000XXXX) only 0x4000xx00.EAX[7:0] bits (max * number of leaves) can be set by user. Hypervisor will enforce this so @@ -570,13 +603,10 @@ static int xc_cpuid_policy( return 0; } - if ( xc_domain_getinfo(xch, domid, 1, &info) == 0 ) - return -EINVAL; - - if ( info.hvm ) - xc_cpuid_hvm_policy(xch, domid, input, regs); + if ( info->hvm ) + xc_cpuid_hvm_policy(xch, info, input, regs); else - xc_cpuid_pv_policy(xch, domid, input, regs, info.pvh); + xc_cpuid_pv_policy(xch, info, input, regs); return 0; } @@ -625,19 +655,21 @@ void xc_cpuid_to_str(const unsigned int *regs, char **strs) int xc_cpuid_apply_policy(xc_interface *xch, domid_t domid) { + struct cpuid_domain_info info = {}; unsigned int input[2] = { 0, 0 }, regs[4]; unsigned int base_max, ext_max; - char brand[13]; int rc; + rc = get_cpuid_domain_info(xch, domid, &info); + if ( rc ) + return rc; cpuid(input, regs); base_max = (regs[0] <= DEF_MAX_BASE) ? regs[0] : DEF_MAX_BASE; input[0] = 0x80000000; cpuid(input, regs); - xc_cpuid_brand_get(brand); - if ( strstr(brand, "AMD") ) + if ( info.vendor == VENDOR_AMD ) ext_max = (regs[0] <= DEF_MAX_AMDEXT) ? regs[0] : DEF_MAX_AMDEXT; else ext_max = (regs[0] <= DEF_MAX_INTELEXT) ? regs[0] : DEF_MAX_INTELEXT; @@ -647,7 +679,7 @@ int xc_cpuid_apply_policy(xc_interface *xch, domid_t domid) for ( ; ; ) { cpuid(input, regs); - xc_cpuid_policy(xch, domid, input, regs); + xc_cpuid_policy(xch, &info, input, regs); if ( regs[0] || regs[1] || regs[2] || regs[3] ) { @@ -766,13 +798,18 @@ int xc_cpuid_set( { int rc; unsigned int i, j, regs[4], polregs[4]; + struct cpuid_domain_info info = {}; memset(config_transformed, 0, 4 * sizeof(*config_transformed)); + rc = get_cpuid_domain_info(xch, domid, &info); + if ( rc ) + return rc; + cpuid(input, regs); memcpy(polregs, regs, sizeof(regs)); - xc_cpuid_policy(xch, domid, input, polregs); + xc_cpuid_policy(xch, &info, input, polregs); for ( i = 0; i < 4; i++ ) { -- 1.7.10.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |