diff mbox

[v3,21/28] xen+tools: Export maximum host and guest cpu featuresets via SYSCTL

Message ID 1458056124-8024-22-git-send-email-andrew.cooper3@citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

Andrew Cooper March 15, 2016, 3:35 p.m. UTC
And provide stubs for toolstack use.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Tim Deegan <tim@xen.org>
CC: Wei Liu <wei.liu2@citrix.com>
CC: David Scott <dave@recoil.org>
CC: Rob Hoes <Rob.Hoes@citrix.com>

v3:
 * Provide libxc implementation for XEN_SYSCTL_get_cpu_levelling_caps as well.
v2:
 * Rebased to use libxencall
 * Improve hypercall documentation
---
 tools/libxc/include/xenctrl.h       |  4 +++
 tools/libxc/xc_cpuid_x86.c          | 41 +++++++++++++++++++++++++++++
 tools/ocaml/libs/xc/xenctrl.ml      |  3 +++
 tools/ocaml/libs/xc/xenctrl.mli     |  4 +++
 tools/ocaml/libs/xc/xenctrl_stubs.c | 35 +++++++++++++++++++++++++
 xen/arch/x86/sysctl.c               | 51 +++++++++++++++++++++++++++++++++++++
 xen/include/public/sysctl.h         | 27 ++++++++++++++++++++
 7 files changed, 165 insertions(+)

Comments

Wei Liu March 16, 2016, 6:23 p.m. UTC | #1
On Tue, Mar 15, 2016 at 03:35:17PM +0000, Andrew Cooper wrote:
> And provide stubs for toolstack use.
> 
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> ---
> CC: Jan Beulich <JBeulich@suse.com>
> CC: Tim Deegan <tim@xen.org>
> CC: Wei Liu <wei.liu2@citrix.com>
> CC: David Scott <dave@recoil.org>
> CC: Rob Hoes <Rob.Hoes@citrix.com>
> 
> v3:
>  * Provide libxc implementation for XEN_SYSCTL_get_cpu_levelling_caps as well.
> v2:
>  * Rebased to use libxencall
>  * Improve hypercall documentation
> ---
>  tools/libxc/include/xenctrl.h       |  4 +++
>  tools/libxc/xc_cpuid_x86.c          | 41 +++++++++++++++++++++++++++++

Acked-by: Wei Liu <wei.liu2@citrix.com>

>  tools/ocaml/libs/xc/xenctrl.ml      |  3 +++
>  tools/ocaml/libs/xc/xenctrl.mli     |  4 +++
>  tools/ocaml/libs/xc/xenctrl_stubs.c | 35 +++++++++++++++++++++++++

The ocaml wrappers also look sensible. But admittedly my ocaml skill is
limited so I will defer those to Dave or Rob.
David Scott March 16, 2016, 8:38 p.m. UTC | #2
> On 16 Mar 2016, at 18:23, Wei Liu <wei.liu2@citrix.com> wrote:
> 
> On Tue, Mar 15, 2016 at 03:35:17PM +0000, Andrew Cooper wrote:
>> And provide stubs for toolstack use.
>> 
>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>> ---
>> CC: Jan Beulich <JBeulich@suse.com>
>> CC: Tim Deegan <tim@xen.org>
>> CC: Wei Liu <wei.liu2@citrix.com>
>> CC: David Scott <dave@recoil.org>
>> CC: Rob Hoes <Rob.Hoes@citrix.com>
>> 
>> v3:
>> * Provide libxc implementation for XEN_SYSCTL_get_cpu_levelling_caps as well.
>> v2:
>> * Rebased to use libxencall
>> * Improve hypercall documentation
>> ---
>> tools/libxc/include/xenctrl.h       |  4 +++
>> tools/libxc/xc_cpuid_x86.c          | 41 +++++++++++++++++++++++++++++
> 
> Acked-by: Wei Liu <wei.liu2@citrix.com>
> 
>> tools/ocaml/libs/xc/xenctrl.ml      |  3 +++
>> tools/ocaml/libs/xc/xenctrl.mli     |  4 +++
>> tools/ocaml/libs/xc/xenctrl_stubs.c | 35 +++++++++++++++++++++++++
> 
> The ocaml wrappers also look sensible. But admittedly my ocaml skill is
> limited so I will defer those to Dave or Rob.

The OCaml stubs look safe to me

Acked-by: David Scott <dave@recoil.org>

Cheers,
Dave
Jan Beulich March 22, 2016, 8:43 a.m. UTC | #3
>>> On 15.03.16 at 16:35, <andrew.cooper3@citrix.com> wrote:
> @@ -196,6 +197,56 @@ long arch_do_sysctl(
>              ret = -EFAULT;
>          break;
>  
> +    case XEN_SYSCTL_get_cpu_featureset:
> +    {
> +        static const uint32_t *featureset_table[] = {

Being static, this should imo gain a second const. With that added
Acked-by: Jan Beulich <jbeulich@suse.com>

However, there's still the not fully settled discussion on whether
the HVM feature set should be just one, or two (HAP and shadow
separately). Back then you said

>> A guest booted with hap and a guest booted with shadow will see
>> different features when booted on the same host.  Hap includes 1GB
>> superpages, PCID, etc.
>> 
>> The problem comes with a shadow guest booted on a hap-capable host. 
>> Such a guest can safely be migrated to a non-hap capable host, but only
>> if the toolstack knows that the guest saw a reduced featureset.
>> 
>> As there is still no interface to query what a guest can actually see
>> (depends on full per-domain policys and no dynamic hiding), the shadow
>> featuremask is used by the toolstack as a promise of what the Xen
>> dynamic checks will do.

As said in reply, I still don't really see why you don't use a
HAP/shadow dependent mask to take care of those
differences instead of elsewhere doing dynamic adjustments
(the more that such dynamic adjustments are easy to get out
of sync with the static annotations in the public header).

The last half sentence, btw, makes me even wonder how you
suppose the tool stack to know of the shadow mask on a HAP
capable system, and hence how it could take this as any kind
of promise.

Going through the HAP-only features, btw, revealed another
possible dependency missing from patch 10: I would think that
INVPCID depends on PCID.

Jan
Andrew Cooper March 22, 2016, 8:39 p.m. UTC | #4
On 22/03/16 08:43, Jan Beulich wrote:
>
> Going through the HAP-only features, btw, revealed another
> possible dependency missing from patch 10: I would think that
> INVPCID depends on PCID.

And, as it turns out PCID on LM.

Attempting to set CR4.PCIDE while IA32_EFER.LMA = 0 is specified to
incur a #GP fault.

~Andrew
diff mbox

Patch

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 150d727..c136aa8 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2529,6 +2529,10 @@  int xc_psr_cat_get_domain_data(xc_interface *xch, uint32_t domid,
 int xc_psr_cat_get_l3_info(xc_interface *xch, uint32_t socket,
                            uint32_t *cos_max, uint32_t *cbm_len,
                            bool *cdp_enabled);
+
+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);
 #endif
 
 /* Compat shims */
diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c
index 733add4..5780397 100644
--- a/tools/libxc/xc_cpuid_x86.c
+++ b/tools/libxc/xc_cpuid_x86.c
@@ -33,6 +33,47 @@ 
 #define DEF_MAX_INTELEXT  0x80000008u
 #define DEF_MAX_AMDEXT    0x8000001cu
 
+int xc_get_cpu_levelling_caps(xc_interface *xch, uint32_t *caps)
+{
+    DECLARE_SYSCTL;
+    int ret;
+
+    sysctl.cmd = XEN_SYSCTL_get_cpu_levelling_caps;
+    ret = do_sysctl(xch, &sysctl);
+
+    if ( !ret )
+        *caps = sysctl.u.cpu_levelling_caps.caps;
+
+    return ret;
+}
+
+int xc_get_cpu_featureset(xc_interface *xch, uint32_t index,
+                          uint32_t *nr_features, uint32_t *featureset)
+{
+    DECLARE_SYSCTL;
+    DECLARE_HYPERCALL_BOUNCE(featureset,
+                             *nr_features * sizeof(*featureset),
+                             XC_HYPERCALL_BUFFER_BOUNCE_OUT);
+    int ret;
+
+    if ( xc_hypercall_bounce_pre(xch, featureset) )
+        return -1;
+
+    sysctl.cmd = XEN_SYSCTL_get_cpu_featureset;
+    sysctl.u.cpu_featureset.index = index;
+    sysctl.u.cpu_featureset.nr_features = *nr_features;
+    set_xen_guest_handle(sysctl.u.cpu_featureset.features, featureset);
+
+    ret = do_sysctl(xch, &sysctl);
+
+    xc_hypercall_bounce_post(xch, featureset);
+
+    if ( !ret )
+        *nr_features = sysctl.u.cpu_featureset.nr_features;
+
+    return ret;
+}
+
 struct cpuid_domain_info
 {
     enum
diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml
index 58a53a1..75006e7 100644
--- a/tools/ocaml/libs/xc/xenctrl.ml
+++ b/tools/ocaml/libs/xc/xenctrl.ml
@@ -242,6 +242,9 @@  external version_changeset: handle -> string = "stub_xc_version_changeset"
 external version_capabilities: handle -> string =
   "stub_xc_version_capabilities"
 
+type featureset_index = Featureset_raw | Featureset_host | Featureset_pv | Featureset_hvm
+external get_cpu_featureset : handle -> featureset_index -> int64 array = "stub_xc_get_cpu_featureset"
+
 external watchdog : handle -> int -> int32 -> int
   = "stub_xc_watchdog"
 
diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli
index 16443df..720e4b2 100644
--- a/tools/ocaml/libs/xc/xenctrl.mli
+++ b/tools/ocaml/libs/xc/xenctrl.mli
@@ -147,6 +147,10 @@  external version_compile_info : handle -> compile_info
 external version_changeset : handle -> string = "stub_xc_version_changeset"
 external version_capabilities : handle -> string
   = "stub_xc_version_capabilities"
+
+type featureset_index = Featureset_raw | Featureset_host | Featureset_pv | Featureset_hvm
+external get_cpu_featureset : handle -> featureset_index -> int64 array = "stub_xc_get_cpu_featureset"
+
 type core_magic = Magic_hvm | Magic_pv
 type core_header = {
   xch_magic : core_magic;
diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c b/tools/ocaml/libs/xc/xenctrl_stubs.c
index 74928e9..e7adf37 100644
--- a/tools/ocaml/libs/xc/xenctrl_stubs.c
+++ b/tools/ocaml/libs/xc/xenctrl_stubs.c
@@ -1214,6 +1214,41 @@  CAMLprim value stub_xc_domain_deassign_device(value xch, value domid, value desc
 	CAMLreturn(Val_unit);
 }
 
+CAMLprim value stub_xc_get_cpu_featureset(value xch, value idx)
+{
+	CAMLparam2(xch, idx);
+	CAMLlocal1(bitmap_val);
+
+	/* Safe, because of the global ocaml lock. */
+	static uint32_t fs_len;
+
+	if (fs_len == 0)
+	{
+		int ret = xc_get_cpu_featureset(_H(xch), 0, &fs_len, NULL);
+
+		if (ret || (fs_len == 0))
+			failwith_xc(_H(xch));
+	}
+
+	{
+		/* To/from hypervisor to retrieve actual featureset */
+		uint32_t fs[fs_len], len = fs_len;
+		unsigned int i;
+
+		int ret = xc_get_cpu_featureset(_H(xch), Int_val(idx), &len, fs);
+
+		if (ret)
+			failwith_xc(_H(xch));
+
+		bitmap_val = caml_alloc(len, 0);
+
+		for (i = 0; i < len; ++i)
+			Store_field(bitmap_val, i, caml_copy_int64(fs[i]));
+	}
+
+	CAMLreturn(bitmap_val);
+}
+
 CAMLprim value stub_xc_watchdog(value xch, value domid, value timeout)
 {
 	CAMLparam3(xch, domid, timeout);
diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
index f68cbec..cb9590e 100644
--- a/xen/arch/x86/sysctl.c
+++ b/xen/arch/x86/sysctl.c
@@ -30,6 +30,7 @@ 
 #include <xen/cpu.h>
 #include <xsm/xsm.h>
 #include <asm/psr.h>
+#include <asm/cpuid.h>
 
 struct l3_cache_info {
     int ret;
@@ -196,6 +197,56 @@  long arch_do_sysctl(
             ret = -EFAULT;
         break;
 
+    case XEN_SYSCTL_get_cpu_featureset:
+    {
+        static const uint32_t *featureset_table[] = {
+            [XEN_SYSCTL_cpu_featureset_raw]  = raw_featureset,
+            [XEN_SYSCTL_cpu_featureset_host] = host_featureset,
+            [XEN_SYSCTL_cpu_featureset_pv]   = pv_featureset,
+            [XEN_SYSCTL_cpu_featureset_hvm]  = hvm_featureset,
+        };
+        const uint32_t *featureset = NULL;
+        unsigned int nr;
+
+        /* Request for maximum number of features? */
+        if ( guest_handle_is_null(sysctl->u.cpu_featureset.features) )
+        {
+            sysctl->u.cpu_featureset.nr_features = FSCAPINTS;
+            if ( __copy_field_to_guest(u_sysctl, sysctl,
+                                       u.cpu_featureset.nr_features) )
+                ret = -EFAULT;
+            break;
+        }
+
+        /* Clip the number of entries. */
+        nr = min(sysctl->u.cpu_featureset.nr_features, FSCAPINTS);
+
+        /* Look up requested featureset. */
+        if ( sysctl->u.cpu_featureset.index < ARRAY_SIZE(featureset_table) )
+            featureset = featureset_table[sysctl->u.cpu_featureset.index];
+
+        /* Bad featureset index? */
+        if ( !featureset )
+            ret = -EINVAL;
+
+        /* Copy the requested featureset into place. */
+        if ( !ret && copy_to_guest(sysctl->u.cpu_featureset.features,
+                                   featureset, nr) )
+            ret = -EFAULT;
+
+        /* Inform the caller of how many features we wrote. */
+        sysctl->u.cpu_featureset.nr_features = nr;
+        if ( !ret && __copy_field_to_guest(u_sysctl, sysctl,
+                                           u.cpu_featureset.nr_features) )
+            ret = -EFAULT;
+
+        /* Inform the caller if there was more data to provide. */
+        if ( !ret && nr < FSCAPINTS )
+            ret = -ENOBUFS;
+
+        break;
+    }
+
     default:
         ret = -ENOSYS;
         break;
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index 0dacca2..780a857 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -787,6 +787,31 @@  struct xen_sysctl_cpu_levelling_caps {
 typedef struct xen_sysctl_cpu_levelling_caps xen_sysctl_cpu_levelling_caps_t;
 DEFINE_XEN_GUEST_HANDLE(xen_sysctl_cpu_levelling_caps_t);
 
+/*
+ * XEN_SYSCTL_get_cpu_featureset (x86 specific)
+ *
+ * Return information about featuresets available on this host.
+ *  -  Raw: The real cpuid values.
+ *  - Host: The values Xen is using, (after command line overrides, etc).
+ *  -   PV: Maximum set of features which can be given to a PV guest.
+ *  -  HVM: Maximum set of features which can be given to a HVM guest.
+ */
+struct xen_sysctl_cpu_featureset {
+#define XEN_SYSCTL_cpu_featureset_raw      0
+#define XEN_SYSCTL_cpu_featureset_host     1
+#define XEN_SYSCTL_cpu_featureset_pv       2
+#define XEN_SYSCTL_cpu_featureset_hvm      3
+    uint32_t index;       /* IN: Which featureset to query? */
+    uint32_t nr_features; /* IN/OUT: Number of entries in/written to
+                           * 'features', or the maximum number of features if
+                           * the guest handle is NULL.  NB. All featuresets
+                           * come from the same numberspace, so have the same
+                           * maximum length. */
+    XEN_GUEST_HANDLE_64(uint32) features; /* OUT: */
+};
+typedef struct xen_sysctl_featureset xen_sysctl_featureset_t;
+DEFINE_XEN_GUEST_HANDLE(xen_sysctl_featureset_t);
+
 struct xen_sysctl {
     uint32_t cmd;
 #define XEN_SYSCTL_readconsole                    1
@@ -813,6 +838,7 @@  struct xen_sysctl {
 #define XEN_SYSCTL_psr_cat_op                    23
 #define XEN_SYSCTL_tmem_op                       24
 #define XEN_SYSCTL_get_cpu_levelling_caps        25
+#define XEN_SYSCTL_get_cpu_featureset            26
     uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */
     union {
         struct xen_sysctl_readconsole       readconsole;
@@ -839,6 +865,7 @@  struct xen_sysctl {
         struct xen_sysctl_psr_cat_op        psr_cat_op;
         struct xen_sysctl_tmem_op           tmem_op;
         struct xen_sysctl_cpu_levelling_caps cpu_levelling_caps;
+        struct xen_sysctl_cpu_featureset    cpu_featureset;
         uint8_t                             pad[128];
     } u;
 };