]> xenbits.xensource.com Git - xen.git/commitdiff
x86/cmdline: Introduce a command line option to disable IBRS/IBPB, STIBP and IBPB
authorAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 8 Feb 2018 11:50:16 +0000 (12:50 +0100)
committerJan Beulich <jbeulich@suse.com>
Thu, 8 Feb 2018 11:50:16 +0000 (12:50 +0100)
Instead of gaining yet another top level boolean, introduce a more generic
cpuid= option.  Also introduce a helper function to parse a generic boolean
value.

This is part of XSA-254.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
xen/cmdline: Fix parse_boolean() for unadorned values

A command line such as "cpuid=no-ibrsb,no-stibp" tickles a bug in
parse_boolean() because the separating comma fails the NUL case.

Instead, check for slen == nlen which accounts for the boundary (if any)
passed via the 'e' parameter.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: 7850b1c00749df834ea2ad0c1f5d9364c4838795
master date: 2018-01-16 17:45:50 +0000
master commit: ac37ec1ddef234eeba6f438c29ff687c64962ebd
master date: 2018-01-31 10:47:12 +0000

docs/misc/xen-command-line.markdown
xen/arch/x86/cpuid.c
xen/common/kernel.c
xen/include/xen/lib.h

index 5ecb5eb1f8b1f2c92c4569bf6d5ff7570d9a83ab..709e4de66a2a54f06b9b981770c09919aedb2c3a 100644 (file)
@@ -434,6 +434,18 @@ choice of `dom0-kernel` is deprecated and not supported by all Dom0 kernels.
   respectively.
 * `verbose` option can be included as a string or also as `verbose=<integer>`
 
+### cpuid (x86)
+> `= List of comma separated booleans`
+
+This option allows for fine tuning of the facilities Xen will use, after
+accounting for hardware capabilities as enumerated via CPUID.
+
+Currently accepted:
+
+The Speculation Control hardware features `ibrsb`, `stibp`, `ibpb` are used by
+default if avaiable.  They can be ignored, e.g. `no-ibrsb`, at which point Xen
+won't use them itself, and won't offer them to guests.
+
 ### cpuid\_mask\_cpu (AMD only)
 > `= fam_0f_rev_c | fam_0f_rev_d | fam_0f_rev_e | fam_0f_rev_f | fam_0f_rev_g | fam_10_rev_b | fam_10_rev_c | fam_11_rev_b`
 
index 63b2db99b86475deac6822946c2c1356d36d9d74..7a7c8de4899ad16d01388bbdf3e00fd84b73620b 100644 (file)
@@ -17,6 +17,41 @@ uint32_t __read_mostly raw_featureset[FSCAPINTS];
 uint32_t __read_mostly pv_featureset[FSCAPINTS];
 uint32_t __read_mostly hvm_featureset[FSCAPINTS];
 
+static int __init parse_xen_cpuid(const char *s)
+{
+    const char *ss;
+    int val, rc = 0;
+
+    do {
+        ss = strchr(s, ',');
+        if ( !ss )
+            ss = strchr(s, '\0');
+
+        if ( (val = parse_boolean("ibpb", s, ss)) >= 0 )
+        {
+            if ( !val )
+                setup_clear_cpu_cap(X86_FEATURE_IBPB);
+        }
+        else if ( (val = parse_boolean("ibrsb", s, ss)) >= 0 )
+        {
+            if ( !val )
+                setup_clear_cpu_cap(X86_FEATURE_IBRSB);
+        }
+        else if ( (val = parse_boolean("stibp", s, ss)) >= 0 )
+        {
+            if ( !val )
+                setup_clear_cpu_cap(X86_FEATURE_STIBP);
+        }
+        else
+            rc = -EINVAL;
+
+        s = ss + 1;
+    } while ( *ss );
+
+    return rc;
+}
+custom_param("cpuid", parse_xen_cpuid);
+
 static void __init sanitise_featureset(uint32_t *fs)
 {
     /* for_each_set_bit() uses unsigned longs.  Extend with zeroes. */
index d0edb13d4bb273a845a8bac3a572d006f8f50358..ed49c62a4672fb85168abcfaa0714770b63c4872 100644 (file)
@@ -166,6 +166,42 @@ int __init parse_bool(const char *s)
     return -1;
 }
 
+int parse_boolean(const char *name, const char *s, const char *e)
+{
+    size_t slen, nlen;
+    int val = !!strncmp(s, "no-", 3);
+
+    if ( !val )
+        s += 3;
+
+    slen = e ? ({ ASSERT(e >= s); e - s; }) : strlen(s);
+    nlen = strlen(name);
+
+    /* Does s now start with name? */
+    if ( slen < nlen || strncmp(s, name, nlen) )
+        return -1;
+
+    /* Exact, unadorned name?  Result depends on the 'no-' prefix. */
+    if ( slen == nlen )
+        return val;
+
+    /* =$SOMETHING?  Defer to the regular boolean parsing. */
+    if ( s[nlen] == '=' )
+    {
+        char buf[8];
+
+        s += nlen + 1;
+        if ( e <= s || e - s >= ARRAY_SIZE(buf) )
+            return -1;
+        memcpy(buf, s, e - s);
+        buf[e - s] = 0;
+        return parse_bool(buf);
+    }
+
+    /* Unrecognised.  Give up. */
+    return -1;
+}
+
 unsigned int tainted;
 
 /**
index d1171b774b13003837cdcd1647ec619f489569c6..b9d1c87ffd09beb5a17c830b17c91247f55f51ab 100644 (file)
@@ -68,6 +68,13 @@ struct domain;
 void cmdline_parse(const char *cmdline);
 int parse_bool(const char *s);
 
+/**
+ * Given a specific name, parses a string of the form:
+ *   [no-]$NAME[=...]
+ * returning 0 or 1 for a recognised boolean, or -1 for an error.
+ */
+int parse_boolean(const char *name, const char *s, const char *e);
+
 /*#define DEBUG_TRACE_DUMP*/
 #ifdef DEBUG_TRACE_DUMP
 extern void debugtrace_dump(void);