[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 09/13] x86/sysctl: Implement XEN_SYSCTL_get_cpumsr_policy



From: Sergey Dyasli <sergey.dyasli@xxxxxxxxxx>

Provide a SYSCTL for the toolstack to obtain complete system CPUID and MSR
policy information.  The split of default vs max policies is introduced into
the API, including a description of the intended behaviour.  For now, max is
the default, but this is intended to change moving forwards.

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
      00000048 -> 0000000000000000
      00000140 -> 0000000000000000

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>
---
 tools/libxc/include/xenctrl.h       |  6 +++
 tools/libxc/xc_cpuid_x86.c          | 59 ++++++++++++++++++++++++
 tools/misc/xen-cpuid.c              | 89 +++++++++++++++++++++++++++++++++++--
 xen/arch/x86/sysctl.c               | 86 +++++++++++++++++++++++++++++++++--
 xen/include/public/sysctl.h         | 41 +++++++++++++++++
 xen/xsm/flask/hooks.c               |  1 +
 xen/xsm/flask/policy/access_vectors |  2 +-
 7 files changed, 275 insertions(+), 9 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 70f54e6..d1f0925c 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2536,6 +2536,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_cpumsr_policy_size(xc_interface *xch, uint32_t *nr_leaves,
+                              uint32_t *nr_msrs);
+int xc_get_system_cpumsr_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 900c639..ce2a584 100644
--- a/tools/libxc/xc_cpuid_x86.c
+++ b/tools/libxc/xc_cpuid_x86.c
@@ -134,6 +134,65 @@ const uint32_t *xc_get_static_cpu_featuremask(
     }
 }
 
+int xc_get_cpumsr_policy_size(xc_interface *xch, uint32_t *nr_leaves,
+                              uint32_t *nr_msrs)
+{
+    struct xen_sysctl sysctl = {};
+    int ret;
+
+    sysctl.cmd = XEN_SYSCTL_get_cpumsr_policy;
+
+    ret = do_sysctl(xch, &sysctl);
+
+    if ( !ret )
+    {
+        *nr_leaves = sysctl.u.cpumsr_policy.nr_leaves;
+        *nr_msrs = sysctl.u.cpumsr_policy.nr_msrs;
+    }
+
+    return ret;
+}
+
+int xc_get_system_cpumsr_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_cpumsr_policy;
+    sysctl.u.cpumsr_policy.index = index;
+    sysctl.u.cpumsr_policy.nr_leaves = *nr_leaves;
+    set_xen_guest_handle(sysctl.u.cpumsr_policy.cpuid_policy, leaves);
+    sysctl.u.cpumsr_policy.nr_msrs = *nr_msrs;
+    set_xen_guest_handle(sysctl.u.cpumsr_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.cpumsr_policy.nr_leaves;
+        *nr_msrs = sysctl.u.cpumsr_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 e116339..a5b3004 100644
--- a/tools/misc/xen-cpuid.c
+++ b/tools/misc/xen-cpuid.c
@@ -276,9 +276,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();
@@ -292,10 +320,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;
@@ -313,6 +342,10 @@ int main(int argc, char **argv)
             mode = MODE_INFO;
             break;
 
+        case 'p':
+            mode = MODE_POLICY;
+            break;
+
         case 'd':
         case 'v':
             mode = MODE_DETAIL;
@@ -343,7 +376,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_cpumsr_policy_raw ]          = "Raw",
+            [ XEN_SYSCTL_cpumsr_policy_host ]         = "Host",
+            [ XEN_SYSCTL_cpumsr_policy_pv_max ]       = "PV Max",
+            [ XEN_SYSCTL_cpumsr_policy_hvm_max ]      = "HVM Max",
+            [ XEN_SYSCTL_cpumsr_policy_pv_default ]   = "PV Default",
+            [ XEN_SYSCTL_cpumsr_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_cpumsr_policy_size(xch, &max_leaves, &max_msrs) )
+            err(1, "xc_get_cpumsr_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_cpumsr_policy(xch, pol, &nr_leaves, leaves,
+                                             &nr_msrs, msrs) )
+                err(1, "xc_get_system_cpumsr_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);
 
@@ -377,7 +458,7 @@ int main(int argc, char **argv)
                 if ( i == nr_features )
                     break;
 
-                if ( *ptr == ':' )
+                if ( *ptr == ':' || *ptr == '-' )
                 {
                     ptr++; continue;
                 }
diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
index c5c00d0..067fc86 100644
--- a/xen/arch/x86/sysctl.c
+++ b/xen/arch/x86/sysctl.c
@@ -32,22 +32,32 @@
 #include <asm/cpuid.h>
 
 const struct policy_group system_policies[] = {
-    {
+    [ XEN_SYSCTL_cpumsr_policy_raw ] = {
         &raw_cpuid_policy,
         &raw_msr_domain_policy,
         &raw_msr_vcpu_policy,
     },
-    {
+    [ XEN_SYSCTL_cpumsr_policy_host ] = {
         &host_cpuid_policy,
         &host_msr_domain_policy,
         &host_msr_vcpu_policy,
     },
-    {
+    [ XEN_SYSCTL_cpumsr_policy_pv_max ] = {
         &pv_max_cpuid_policy,
         &pv_max_msr_domain_policy,
         &pv_max_msr_vcpu_policy,
     },
-    {
+    [ XEN_SYSCTL_cpumsr_policy_hvm_max ] = {
+        &hvm_max_cpuid_policy,
+        &hvm_max_msr_domain_policy,
+        &hvm_max_msr_vcpu_policy,
+    },
+    [ XEN_SYSCTL_cpumsr_policy_pv_default ] = {
+        &pv_max_cpuid_policy,
+        &pv_max_msr_domain_policy,
+        &pv_max_msr_vcpu_policy,
+    },
+    [ XEN_SYSCTL_cpumsr_policy_hvm_default ] = {
         &hvm_max_cpuid_policy,
         &hvm_max_msr_domain_policy,
         &hvm_max_msr_vcpu_policy,
@@ -318,6 +328,74 @@ long arch_do_sysctl(
         break;
     }
 
+    case XEN_SYSCTL_get_cpumsr_policy:
+    {
+        const struct policy_group *group;
+
+        /* Bad policy index? */
+        if ( sysctl->u.cpumsr_policy.index >= ARRAY_SIZE(system_policies) )
+        {
+            ret = -EINVAL;
+            break;
+        }
+        group = &system_policies[sysctl->u.cpumsr_policy.index];
+
+        /* Request for maximum number of leaves/MSRs? */
+        if ( guest_handle_is_null(sysctl->u.cpumsr_policy.cpuid_policy) )
+        {
+            sysctl->u.cpumsr_policy.nr_leaves = CPUID_MAX_SERIALISED_LEAVES;
+            if ( __copy_field_to_guest(u_sysctl, sysctl,
+                                       u.cpumsr_policy.nr_leaves) )
+            {
+                ret = -EFAULT;
+                break;
+            }
+        }
+        if ( guest_handle_is_null(sysctl->u.cpumsr_policy.msr_policy) )
+        {
+            sysctl->u.cpumsr_policy.nr_msrs = MSR_MAX_SERIALISED_ENTRIES;
+            if ( __copy_field_to_guest(u_sysctl, sysctl,
+                                       u.cpumsr_policy.nr_msrs) )
+            {
+                ret = -EFAULT;
+                break;
+            }
+        }
+
+        /* Serialise the information the caller wants. */
+        if ( !guest_handle_is_null(sysctl->u.cpumsr_policy.cpuid_policy) )
+        {
+            if ( (ret = x86_cpuid_copy_to_buffer(
+                      group->cp,
+                      sysctl->u.cpumsr_policy.cpuid_policy,
+                      &sysctl->u.cpumsr_policy.nr_leaves)) )
+                break;
+
+            if ( __copy_field_to_guest(u_sysctl, sysctl,
+                                       u.cpumsr_policy.nr_leaves)  )
+            {
+                ret = -EFAULT;
+                break;
+            }
+        }
+        if ( !guest_handle_is_null(sysctl->u.cpumsr_policy.msr_policy) )
+        {
+            if ( (ret = x86_msr_copy_to_buffer(
+                      group->dp, group->vp,
+                      sysctl->u.cpumsr_policy.msr_policy,
+                      &sysctl->u.cpumsr_policy.nr_msrs)) )
+                break;
+
+            if ( __copy_field_to_guest(u_sysctl, sysctl,
+                                       u.cpumsr_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 839c1b9..f04bfa8 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -1063,6 +1063,43 @@ struct xen_sysctl_set_parameter {
     uint16_t pad[3];                        /* IN: MUST be zero. */
 };
 
+#if defined(__i386__) || defined(__x86_64__)
+/*
+ * XEN_SYSCTL_get_cpumsr_policy (x86 specific)
+ *
+ * Return information about CPUID and MSR policies available on this host.
+ *  -       Raw: The real H/W values.
+ *  -      Host: The values Xen is using, (after command line overrides, etc).
+ *  -     Max_*: Maximum set of features a PV or HVM guest can use.  Includes
+ *               experimental features outside of security support.
+ *  - Default_*: Default set of features a PV or HVM guest can use.  This is
+ *               the security supported set.
+ */
+struct xen_sysctl_cpumsr_policy {
+#define XEN_SYSCTL_cpumsr_policy_raw          0
+#define XEN_SYSCTL_cpumsr_policy_host         1
+#define XEN_SYSCTL_cpumsr_policy_pv_max       2
+#define XEN_SYSCTL_cpumsr_policy_hvm_max      3
+#define XEN_SYSCTL_cpumsr_policy_pv_default   4
+#define XEN_SYSCTL_cpumsr_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
+                           * any of the guest handles is NULL.
+                           * NB. All policies come from the same space,
+                           * so have the same maximum length. */
+    uint32_t nr_msrs;     /* IN/OUT: Number of MSRs in/written to
+                           * 'msr_domain_policy', or the maximum number of MSRs
+                           * if any of the guest handles is NULL.
+                           * NB. All policies come from the same space,
+                           * so have the same maximum length. */
+    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_cpumsr_policy xen_sysctl_cpumsr_policy_t;
+DEFINE_XEN_GUEST_HANDLE(xen_sysctl_cpumsr_policy_t);
+#endif
+
 struct xen_sysctl {
     uint32_t cmd;
 #define XEN_SYSCTL_readconsole                    1
@@ -1092,6 +1129,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_cpumsr_policy             29
     uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */
     union {
         struct xen_sysctl_readconsole       readconsole;
@@ -1121,6 +1159,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_cpumsr_policy     cpumsr_policy;
+#endif
         uint8_t                             pad[128];
     } u;
 };
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index 78bc326..1d30b0e 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_cpumsr_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..b5bc7a2 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_cpumsr_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®.