[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2 12/13] x86/sysctl: Implement XEN_SYSCTL_get_cpu_policy
From: Sergey Dyasli <sergey.dyasli@xxxxxxxxxx> Provide a SYSCTL for the toolstack to obtain complete system CPUID and MSR policy information. For the XSM side of things, this subop is closely related to {phys,cputopo,numa}info, so shares the physinfo access vector. Extend the xen-cpuid utility to be able to dump the system policies. An example output is: Xen reports there are maximum 113 leaves and 3 MSRs Raw policy: 93 leaves, 3 MSRs CPUID: leaf subleaf -> eax ebx ecx edx 00000000:ffffffff -> 0000000d:756e6547:6c65746e:49656e69 00000001:ffffffff -> 000306c3:00100800:7ffafbff:bfebfbff 00000002:ffffffff -> 76036301:00f0b5ff:00000000:00c10000 00000004:00000000 -> 1c004121:01c0003f:0000003f:00000000 00000004:00000001 -> 1c004122:01c0003f:0000003f:00000000 00000004:00000002 -> 1c004143:01c0003f:000001ff:00000000 00000004:00000003 -> 1c03c163:03c0003f:00001fff:00000006 00000005:ffffffff -> 00000040:00000040:00000003:00042120 00000006:ffffffff -> 00000077:00000002:00000009:00000000 00000007:00000000 -> 00000000:000027ab:00000000:9c000000 0000000a:ffffffff -> 07300403:00000000:00000000:00000603 0000000b:00000000 -> 00000001:00000002:00000100:00000000 0000000b:00000001 -> 00000004:00000008:00000201:00000000 0000000d:00000000 -> 00000007:00000340:00000340:00000000 0000000d:00000001 -> 00000001:00000000:00000000:00000000 0000000d:00000002 -> 00000100:00000240:00000000:00000000 80000000:ffffffff -> 80000008:00000000:00000000:00000000 80000001:ffffffff -> 00000000:00000000:00000021:2c100800 80000002:ffffffff -> 65746e49:2952286c:6f655820:2952286e 80000003:ffffffff -> 55504320:2d334520:30343231:20337620 80000004:ffffffff -> 2e332040:48473034:0000007a:00000000 80000006:ffffffff -> 00000000:00000000:01006040:00000000 80000007:ffffffff -> 00000000:00000000:00000000:00000100 80000008:ffffffff -> 00003027:00000000:00000000:00000000 MSRs: index -> value 000000ce -> 0000000080000000 Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Signed-off-by: Sergey Dyasli <sergey.dyasli@xxxxxxxxxx> Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> --- CC: Jan Beulich <JBeulich@xxxxxxxx> CC: Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx> CC: Wei Liu <wei.liu2@xxxxxxxxxx> CC: Roger Pau Monné <roger.pau@xxxxxxxxxx> CC: Sergey Dyasli <sergey.dyasli@xxxxxxxxxx> CC: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> v2: * Avoid introducing a Spectre V1 gadget --- tools/libxc/include/xenctrl.h | 6 +++ tools/libxc/xc_cpuid_x86.c | 59 +++++++++++++++++++++++++ tools/misc/xen-cpuid.c | 87 +++++++++++++++++++++++++++++++++++-- xen/arch/x86/sysctl.c | 71 ++++++++++++++++++++++++++++++ xen/include/public/sysctl.h | 17 ++++++++ xen/xsm/flask/hooks.c | 1 + xen/xsm/flask/policy/access_vectors | 2 +- 7 files changed, 239 insertions(+), 4 deletions(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index dd7d8a9..ee3ab09 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -2553,6 +2553,12 @@ int xc_get_cpu_levelling_caps(xc_interface *xch, uint32_t *caps); int xc_get_cpu_featureset(xc_interface *xch, uint32_t index, uint32_t *nr_features, uint32_t *featureset); +int xc_get_cpu_policy_size(xc_interface *xch, uint32_t *nr_leaves, + uint32_t *nr_msrs); +int xc_get_system_cpu_policy(xc_interface *xch, uint32_t index, + uint32_t *nr_leaves, xen_cpuid_leaf_t *leaves, + uint32_t *nr_msrs, xen_msr_entry_t *msrs); + uint32_t xc_get_cpu_featureset_size(void); enum xc_static_cpu_featuremask { diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c index cc7300c..8fd04ef 100644 --- a/tools/libxc/xc_cpuid_x86.c +++ b/tools/libxc/xc_cpuid_x86.c @@ -132,6 +132,65 @@ const uint32_t *xc_get_static_cpu_featuremask( } } +int xc_get_cpu_policy_size(xc_interface *xch, uint32_t *nr_leaves, + uint32_t *nr_msrs) +{ + struct xen_sysctl sysctl = {}; + int ret; + + sysctl.cmd = XEN_SYSCTL_get_cpu_policy; + + ret = do_sysctl(xch, &sysctl); + + if ( !ret ) + { + *nr_leaves = sysctl.u.cpu_policy.nr_leaves; + *nr_msrs = sysctl.u.cpu_policy.nr_msrs; + } + + return ret; +} + +int xc_get_system_cpu_policy(xc_interface *xch, uint32_t index, + uint32_t *nr_leaves, xen_cpuid_leaf_t *leaves, + uint32_t *nr_msrs, xen_msr_entry_t *msrs) +{ + struct xen_sysctl sysctl = {}; + DECLARE_HYPERCALL_BOUNCE(leaves, + *nr_leaves * sizeof(*leaves), + XC_HYPERCALL_BUFFER_BOUNCE_OUT); + DECLARE_HYPERCALL_BOUNCE(msrs, + *nr_msrs * sizeof(*msrs), + XC_HYPERCALL_BUFFER_BOUNCE_OUT); + int ret; + + if ( xc_hypercall_bounce_pre(xch, leaves) ) + return -1; + + if ( xc_hypercall_bounce_pre(xch, msrs) ) + return -1; + + sysctl.cmd = XEN_SYSCTL_get_cpu_policy; + sysctl.u.cpu_policy.index = index; + sysctl.u.cpu_policy.nr_leaves = *nr_leaves; + set_xen_guest_handle(sysctl.u.cpu_policy.cpuid_policy, leaves); + sysctl.u.cpu_policy.nr_msrs = *nr_msrs; + set_xen_guest_handle(sysctl.u.cpu_policy.msr_policy, msrs); + + ret = do_sysctl(xch, &sysctl); + + xc_hypercall_bounce_post(xch, leaves); + xc_hypercall_bounce_post(xch, msrs); + + if ( !ret ) + { + *nr_leaves = sysctl.u.cpu_policy.nr_leaves; + *nr_msrs = sysctl.u.cpu_policy.nr_msrs; + } + + return ret; +} + struct cpuid_domain_info { enum diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c index 4a4044a..1c14d93 100644 --- a/tools/misc/xen-cpuid.c +++ b/tools/misc/xen-cpuid.c @@ -277,9 +277,37 @@ static void dump_info(xc_interface *xch, bool detail) free(featuresets[i].fs); } +static void print_policy(const char *name, + xen_cpuid_leaf_t *leaves, uint32_t nr_leaves, + xen_msr_entry_t *msrs, uint32_t nr_msrs) +{ + unsigned int l; + + printf("%s policy: %u leaves, %u MSRs\n", name, nr_leaves, nr_msrs); + printf(" CPUID:\n"); + printf(" %-8s %-8s -> %-8s %-8s %-8s %-8s\n", + "leaf", "subleaf", "eax", "ebx", "ecx", "edx"); + for ( l = 0; l < nr_leaves; ++l ) + { + /* Skip empty leaves. */ + if ( !leaves[l].a && !leaves[l].b && !leaves[l].c && !leaves[l].d ) + continue; + + printf(" %08x:%08x -> %08x:%08x:%08x:%08x\n", + leaves[l].leaf, leaves[l].subleaf, + leaves[l].a, leaves[l].b, leaves[l].c, leaves[l].d); + } + + printf(" MSRs:\n"); + printf(" %-8s -> %-16s\n", "index", "value"); + for ( l = 0; l < nr_msrs; ++l ) + printf(" %08x -> %016lx\n", + msrs[l].idx, msrs[l].val); +} + int main(int argc, char **argv) { - enum { MODE_UNKNOWN, MODE_INFO, MODE_DETAIL, MODE_INTERPRET } + enum { MODE_UNKNOWN, MODE_INFO, MODE_DETAIL, MODE_INTERPRET, MODE_POLICY } mode = MODE_UNKNOWN; nr_features = xc_get_cpu_featureset_size(); @@ -293,10 +321,11 @@ int main(int argc, char **argv) { "info", no_argument, NULL, 'i' }, { "detail", no_argument, NULL, 'd' }, { "verbose", no_argument, NULL, 'v' }, + { "policy", no_argument, NULL, 'p' }, { NULL, 0, NULL, 0 }, }; - c = getopt_long(argc, argv, "hidv", long_options, &option_index); + c = getopt_long(argc, argv, "hidvp", long_options, &option_index); if ( c == -1 ) break; @@ -314,6 +343,10 @@ int main(int argc, char **argv) mode = MODE_INFO; break; + case 'p': + mode = MODE_POLICY; + break; + case 'd': case 'v': mode = MODE_DETAIL; @@ -344,7 +377,55 @@ int main(int argc, char **argv) mode = MODE_INTERPRET; } - if ( mode == MODE_INFO || mode == MODE_DETAIL ) + if ( mode == MODE_POLICY ) + { + static const char *const sys_policies[] = { + [ XEN_SYSCTL_cpu_policy_raw ] = "Raw", + [ XEN_SYSCTL_cpu_policy_host ] = "Host", + [ XEN_SYSCTL_cpu_policy_pv_max ] = "PV Max", + [ XEN_SYSCTL_cpu_policy_hvm_max ] = "HVM Max", + [ XEN_SYSCTL_cpu_policy_pv_default ] = "PV Default", + [ XEN_SYSCTL_cpu_policy_hvm_default ] = "HVM Default", + }; + xen_cpuid_leaf_t *leaves; + xen_msr_entry_t *msrs; + uint32_t pol, max_leaves, max_msrs; + + xc_interface *xch = xc_interface_open(0, 0, 0); + + if ( !xch ) + err(1, "xc_interface_open"); + + if ( xc_get_cpu_policy_size(xch, &max_leaves, &max_msrs) ) + err(1, "xc_get_cpu_policy_size(...)"); + printf("Xen reports there are maximum %u leaves and %u MSRs\n", + max_leaves, max_msrs); + + leaves = calloc(max_leaves, sizeof(xen_cpuid_leaf_t)); + if ( !leaves ) + err(1, "calloc(max_leaves)"); + msrs = calloc(max_msrs, sizeof(xen_msr_entry_t)); + if ( !msrs ) + err(1, "calloc(max_msrs)"); + + for ( pol = 0; pol < ARRAY_SIZE(sys_policies); ++pol ) + { + uint32_t nr_leaves = max_leaves; + uint32_t nr_msrs = max_msrs; + + if ( xc_get_system_cpu_policy(xch, pol, &nr_leaves, leaves, + &nr_msrs, msrs) ) + err(1, "xc_get_system_cpu_policy(, %s,,)", + sys_policies[pol]); + + print_policy(sys_policies[pol], leaves, nr_leaves, msrs, nr_msrs); + } + + free(leaves); + free(msrs); + xc_interface_close(xch); + } + else if ( mode == MODE_INFO || mode == MODE_DETAIL ) { xc_interface *xch = xc_interface_open(0, 0, 0); diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c index 9986393..29d403c 100644 --- a/xen/arch/x86/sysctl.c +++ b/xen/arch/x86/sysctl.c @@ -9,6 +9,7 @@ #include <xen/types.h> #include <xen/lib.h> #include <xen/mm.h> +#include <xen/nospec.h> #include <xen/guest_access.h> #include <xen/hypercall.h> #include <public/sysctl.h> @@ -322,6 +323,76 @@ long arch_do_sysctl( break; } + case XEN_SYSCTL_get_cpu_policy: + { + const struct cpu_policy *policy; + + /* Bad policy index? */ + if ( sysctl->u.cpu_policy.index >= ARRAY_SIZE(system_policies) ) + { + ret = -EINVAL; + break; + } + policy = &system_policies[ + array_index_nospec(sysctl->u.cpu_policy.index, + ARRAY_SIZE(system_policies))]; + + /* Request for maximum number of leaves/MSRs? */ + if ( guest_handle_is_null(sysctl->u.cpu_policy.cpuid_policy) ) + { + sysctl->u.cpu_policy.nr_leaves = CPUID_MAX_SERIALISED_LEAVES; + if ( __copy_field_to_guest(u_sysctl, sysctl, + u.cpu_policy.nr_leaves) ) + { + ret = -EFAULT; + break; + } + } + if ( guest_handle_is_null(sysctl->u.cpu_policy.msr_policy) ) + { + sysctl->u.cpu_policy.nr_msrs = MSR_MAX_SERIALISED_ENTRIES; + if ( __copy_field_to_guest(u_sysctl, sysctl, + u.cpu_policy.nr_msrs) ) + { + ret = -EFAULT; + break; + } + } + + /* Serialise the information the caller wants. */ + if ( !guest_handle_is_null(sysctl->u.cpu_policy.cpuid_policy) ) + { + if ( (ret = x86_cpuid_copy_to_buffer( + policy->cpuid, + sysctl->u.cpu_policy.cpuid_policy, + &sysctl->u.cpu_policy.nr_leaves)) ) + break; + + if ( __copy_field_to_guest(u_sysctl, sysctl, + u.cpu_policy.nr_leaves) ) + { + ret = -EFAULT; + break; + } + } + if ( !guest_handle_is_null(sysctl->u.cpu_policy.msr_policy) ) + { + if ( (ret = x86_msr_copy_to_buffer( + policy->msr, + sysctl->u.cpu_policy.msr_policy, + &sysctl->u.cpu_policy.nr_msrs)) ) + break; + + if ( __copy_field_to_guest(u_sysctl, sysctl, + u.cpu_policy.nr_msrs) ) + { + ret = -EFAULT; + break; + } + } + break; + } + default: ret = -ENOSYS; break; diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index 7ec2dd9..64648bd 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -1075,12 +1075,25 @@ struct xen_sysctl_set_parameter { * - Default_*: Default set of features a PV or HVM guest can use. This is * the security supported set. */ +struct xen_sysctl_cpu_policy { #define XEN_SYSCTL_cpu_policy_raw 0 #define XEN_SYSCTL_cpu_policy_host 1 #define XEN_SYSCTL_cpu_policy_pv_max 2 #define XEN_SYSCTL_cpu_policy_hvm_max 3 #define XEN_SYSCTL_cpu_policy_pv_default 4 #define XEN_SYSCTL_cpu_policy_hvm_default 5 + uint32_t index; /* IN: Which policy to query? */ + uint32_t nr_leaves; /* IN/OUT: Number of leaves in/written to + * 'cpuid_policy', or the maximum number of leaves + * if the guest handle is NULL. */ + uint32_t nr_msrs; /* IN/OUT: Number of MSRs in/written to + * 'msr_policy', or the maximum number of MSRs if + * the guest handle is NULL. */ + XEN_GUEST_HANDLE_64(xen_cpuid_leaf_t) cpuid_policy; /* OUT: */ + XEN_GUEST_HANDLE_64(xen_msr_entry_t) msr_policy; /* OUT: */ +}; +typedef struct xen_sysctl_cpu_policy xen_sysctl_cpu_policy_t; +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_cpu_policy_t); #endif struct xen_sysctl { @@ -1112,6 +1125,7 @@ struct xen_sysctl { #define XEN_SYSCTL_get_cpu_featureset 26 #define XEN_SYSCTL_livepatch_op 27 #define XEN_SYSCTL_set_parameter 28 +#define XEN_SYSCTL_get_cpu_policy 29 uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */ union { struct xen_sysctl_readconsole readconsole; @@ -1141,6 +1155,9 @@ struct xen_sysctl { struct xen_sysctl_cpu_featureset cpu_featureset; struct xen_sysctl_livepatch_op livepatch; struct xen_sysctl_set_parameter set_parameter; +#if defined(__i386__) || defined(__x86_64__) + struct xen_sysctl_cpu_policy cpu_policy; +#endif uint8_t pad[128]; } u; }; diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 78bc326..f614272 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -801,6 +801,7 @@ static int flask_sysctl(int cmd) case XEN_SYSCTL_cputopoinfo: case XEN_SYSCTL_numainfo: case XEN_SYSCTL_pcitopoinfo: + case XEN_SYSCTL_get_cpu_policy: return domain_has_xen(current->domain, XEN__PHYSINFO); case XEN_SYSCTL_psr_cmt_op: diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors index c5d8548..8c5baff 100644 --- a/xen/xsm/flask/policy/access_vectors +++ b/xen/xsm/flask/policy/access_vectors @@ -28,7 +28,7 @@ class xen # XENPF_microcode_update microcode # XEN_SYSCTL_physinfo, XEN_SYSCTL_cputopoinfo, XEN_SYSCTL_numainfo -# XEN_SYSCTL_pcitopoinfo +# XEN_SYSCTL_pcitopoinfo, XEN_SYSCTL_get_cpu_policy physinfo # XENPF_platform_quirk quirk -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |