[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.