]> xenbits.xensource.com Git - people/iwj/xen.git/commitdiff
xen/x86: support per-domain flag for xpti
authorJuergen Gross <jgross@suse.com>
Thu, 26 Apr 2018 11:33:12 +0000 (13:33 +0200)
committerWei Liu <wei.liu2@citrix.com>
Fri, 4 May 2018 14:55:06 +0000 (15:55 +0100)
Instead of switching XPTI globally on or off add a per-domain flag for
that purpose. This allows to modify the xpti boot parameter to support
running dom0 without Meltdown mitigations. Using "xpti=no-dom0" as boot
parameter will achieve that.

Move the xpti boot parameter handling to xen/arch/x86/pv/domain.c as
it is pv-domain specific.

Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
docs/misc/xen-command-line.markdown
xen/arch/x86/mm.c
xen/arch/x86/pv/dom0_build.c
xen/arch/x86/pv/domain.c
xen/arch/x86/setup.c
xen/arch/x86/smpboot.c
xen/arch/x86/spec_ctrl.c
xen/include/asm-x86/current.h
xen/include/asm-x86/domain.h
xen/include/asm-x86/flushtlb.h
xen/include/asm-x86/spec_ctrl.h

index 7ce50ed7da89e0a6cf8af840c0e14b1852a0e96f..29e84c4a18e4ff0a234da3833ace0704853c20f6 100644 (file)
@@ -1955,14 +1955,24 @@ minimum of 32M, subject to a suitably aligned and sized contiguous
 region of memory being available.
 
 ### xpti
-> `= <boolean>`
+> `= List of [ default | <boolean> | dom0=<bool> | domu=<bool> ]`
 
-> Default: `false` on AMD hardware
+> Default: `false` on hardware not to be vulnerable to Meltdown (e.g. AMD)
 > Default: `true` everywhere else
 
 Override default selection of whether to isolate 64-bit PV guest page
 tables.
 
+`true` activates page table isolation even on hardware not vulnerable by
+Meltdown for all domains.
+
+`false` deactivates page table isolation on all systems for all domains.
+
+`default` sets the default behaviour.
+
+With `dom0` and `domu` it is possible to control page table isolation
+for dom0 or guest domains only.
+
 ### xsave
 > `= <boolean>`
 
index 7e2cc924fd591bf2a6457d544321cda0bd31ab53..b1e8133d92ad0c127547829f3b17a433b5709f9d 100644 (file)
@@ -502,8 +502,21 @@ void make_cr3(struct vcpu *v, mfn_t mfn)
 
 void write_ptbase(struct vcpu *v)
 {
-    get_cpu_info()->root_pgt_changed = true;
-    switch_cr3(v->arch.cr3);
+    struct cpu_info *cpu_info = get_cpu_info();
+
+    if ( is_pv_vcpu(v) && v->domain->arch.pv_domain.xpti )
+    {
+        cpu_info->root_pgt_changed = true;
+        cpu_info->pv_cr3 = __pa(this_cpu(root_pgt));
+        switch_cr3(v->arch.cr3);
+    }
+    else
+    {
+        /* Make sure to clear xen_cr3 before pv_cr3; switch_cr3() serializes. */
+        cpu_info->xen_cr3 = 0;
+        switch_cr3(v->arch.cr3);
+        cpu_info->pv_cr3 = 0;
+    }
 }
 
 /*
index 5b4325b87ff8dba9a224ead91e25524e8733d150..d148395919351ecbd4ba3c8f99a28b2394572d58 100644 (file)
@@ -387,6 +387,7 @@ int __init dom0_construct_pv(struct domain *d,
     if ( compat32 )
     {
         d->arch.is_32bit_pv = d->arch.has_32bit_shinfo = 1;
+        d->arch.pv_domain.xpti = false;
         v->vcpu_info = (void *)&d->shared_info->compat.vcpu_info[0];
         if ( setup_compat_arg_xlat(v) != 0 )
             BUG();
index be40843b051e07501c79abbaad12a837f0902066..ce1a1a9d358e2c48ca97f59c0c00a9dfcc893c75 100644 (file)
@@ -9,6 +9,7 @@
 #include <xen/lib.h>
 #include <xen/sched.h>
 
+#include <asm/spec_ctrl.h>
 #include <asm/pv/domain.h>
 
 static void noreturn continue_nonidle_domain(struct vcpu *v)
@@ -75,6 +76,8 @@ int switch_compat(struct domain *d)
 
     d->arch.x87_fip_width = 4;
 
+    d->arch.pv_domain.xpti = false;
+
     return 0;
 
  undo_and_fail:
@@ -205,6 +208,9 @@ int pv_domain_initialise(struct domain *d)
     /* 64-bit PV guest by default. */
     d->arch.is_32bit_pv = d->arch.has_32bit_shinfo = 0;
 
+    d->arch.pv_domain.xpti = opt_xpti & (is_hardware_domain(d)
+                                         ? OPT_XPTI_DOM0 : OPT_XPTI_DOMU);
+
     return 0;
 
   fail:
index b2baee3d2cbc146e021c5fb393182a790e68799f..f803980b97e7ffe68256a9a58cd981cf975d7ef9 100644 (file)
@@ -169,9 +169,6 @@ static int __init parse_smap_param(const char *s)
 }
 custom_param("smap", parse_smap_param);
 
-static int8_t __initdata opt_xpti = -1;
-boolean_param("xpti", opt_xpti);
-
 bool __read_mostly acpi_disabled;
 bool __initdata acpi_force;
 static char __initdata acpi_param[10] = "";
@@ -1546,22 +1543,6 @@ void __init noreturn __start_xen(unsigned long mbi_p)
 
     cr4_pv32_mask = mmu_cr4_features & XEN_CR4_PV32_BITS;
 
-    if ( opt_xpti < 0 )
-    {
-        uint64_t caps = 0;
-
-        if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
-            caps = ARCH_CAPABILITIES_RDCL_NO;
-        else if ( boot_cpu_has(X86_FEATURE_ARCH_CAPS) )
-            rdmsrl(MSR_ARCH_CAPABILITIES, caps);
-
-        opt_xpti = !(caps & ARCH_CAPABILITIES_RDCL_NO);
-    }
-    if ( opt_xpti )
-        setup_clear_cpu_cap(X86_FEATURE_NO_XPTI);
-    else
-        setup_force_cpu_cap(X86_FEATURE_NO_XPTI);
-
     if ( cpu_has_fsgsbase )
         set_in_cr4(X86_CR4_FSGSBASE);
 
index 0c38061896716f7d1dff5fe6feadce94bb1ff646..48aecdd17fe97e1da1e544fafd227e9d0cb9c90e 100644 (file)
@@ -337,7 +337,7 @@ void start_secondary(void *unused)
     spin_debug_disable();
 
     get_cpu_info()->xen_cr3 = 0;
-    get_cpu_info()->pv_cr3 = this_cpu(root_pgt) ? __pa(this_cpu(root_pgt)) : 0;
+    get_cpu_info()->pv_cr3 = 0;
 
     load_system_tables();
 
@@ -1056,7 +1056,7 @@ void __init smp_prepare_cpus(void)
         panic("Error %d setting up PV root page table\n", rc);
     if ( per_cpu(root_pgt, 0) )
     {
-        get_cpu_info()->pv_cr3 = __pa(per_cpu(root_pgt, 0));
+        get_cpu_info()->pv_cr3 = 0;
 
         /*
          * All entry points which may need to switch page tables have to start
index fab3c1dc0e671055cc7b2e98deecd1ce4b0692c5..037e84dc134ca6e3e34d72525b49a3915ffa8a1d 100644 (file)
@@ -136,8 +136,9 @@ static void __init print_details(enum ind_thunk thunk)
            boot_cpu_has(X86_FEATURE_RSB_NATIVE)      ? " RSB_NATIVE" : "",
            boot_cpu_has(X86_FEATURE_RSB_VMEXIT)      ? " RSB_VMEXIT" : "");
 
-    printk("XPTI: %s\n",
-           boot_cpu_has(X86_FEATURE_NO_XPTI) ? "disabled" : "enabled");
+    printk("XPTI (64-bit PV only): Dom0 %s, DomU %s\n",
+           opt_xpti & OPT_XPTI_DOM0 ? "enabled" : "disabled",
+           opt_xpti & OPT_XPTI_DOMU ? "enabled" : "disabled");
 }
 
 /* Calculate whether Retpoline is known-safe on this CPU. */
@@ -230,6 +231,70 @@ static bool __init retpoline_safe(void)
     }
 }
 
+#define OPT_XPTI_DEFAULT  0xff
+uint8_t __read_mostly opt_xpti = OPT_XPTI_DEFAULT;
+
+static __init void xpti_init_default(bool force)
+{
+    uint64_t caps = 0;
+
+    if ( !force && (opt_xpti != OPT_XPTI_DEFAULT) )
+        return;
+
+    if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
+        caps = ARCH_CAPABILITIES_RDCL_NO;
+    else if ( boot_cpu_has(X86_FEATURE_ARCH_CAPS) )
+        rdmsrl(MSR_ARCH_CAPABILITIES, caps);
+
+    if ( caps & ARCH_CAPABILITIES_RDCL_NO )
+        opt_xpti = 0;
+    else
+        opt_xpti = OPT_XPTI_DOM0 | OPT_XPTI_DOMU;
+}
+
+static __init int parse_xpti(const char *s)
+{
+    const char *ss;
+    int val, rc = 0;
+
+    xpti_init_default(false);
+
+    do {
+        ss = strchr(s, ',');
+        if ( !ss )
+            ss = strchr(s, '\0');
+
+        switch ( parse_bool(s, ss) )
+        {
+        case 0:
+            opt_xpti = 0;
+            break;
+
+        case 1:
+            opt_xpti = OPT_XPTI_DOM0 | OPT_XPTI_DOMU;
+            break;
+
+        default:
+            if ( !strcmp(s, "default") )
+                xpti_init_default(true);
+            else if ( (val = parse_boolean("dom0", s, ss)) >= 0 )
+                opt_xpti = (opt_xpti & ~OPT_XPTI_DOM0) |
+                           (val ? OPT_XPTI_DOM0 : 0);
+            else if ( (val = parse_boolean("domu", s, ss)) >= 0 )
+                opt_xpti = (opt_xpti & ~OPT_XPTI_DOMU) |
+                           (val ? OPT_XPTI_DOMU : 0);
+            else
+                rc = -EINVAL;
+            break;
+        }
+
+        s = ss + 1;
+    } while ( *ss );
+
+    return rc;
+}
+custom_param("xpti", parse_xpti);
+
 void __init init_speculation_mitigations(void)
 {
     enum ind_thunk thunk = THUNK_DEFAULT;
@@ -347,6 +412,12 @@ void __init init_speculation_mitigations(void)
     /* (Re)init BSP state now that default_bti_ist_info has been calculated. */
     init_shadow_spec_ctrl_state();
 
+    xpti_init_default(false);
+    if ( opt_xpti == 0 )
+        setup_force_cpu_cap(X86_FEATURE_NO_XPTI);
+    else
+        setup_clear_cpu_cap(X86_FEATURE_NO_XPTI);
+
     print_details(thunk);
 }
 
index f2491b442346c2920bcb8bafa8d72a05509012b1..b2475783f85b7b32f3c46049e0aedbaa654d7e9c 100644 (file)
@@ -44,7 +44,8 @@ struct cpu_info {
     /*
      * Of the two following fields the latter is being set to the CR3 value
      * to be used on the given pCPU for loading whenever 64-bit PV guest
-     * context is being entered. The value never changes once set.
+     * context is being entered. A value of zero indicates no setting of CR3
+     * is to be performed.
      * The former is the value to restore when re-entering Xen, if any. IOW
      * its value being zero means there's nothing to restore. However, its
      * value can also be negative, indicating to the exit-to-Xen code that
index a12ae47f1bb9328a6528e2b4c4e8764c91b30037..ed4199931ae336262e274da07f5a037928074da9 100644 (file)
@@ -253,6 +253,9 @@ struct pv_domain
 
     atomic_t nr_l4_pages;
 
+    /* XPTI active? */
+    bool xpti;
+
     /* map_domain_page() mapping cache. */
     struct mapcache_domain mapcache;
 
index d27906c0ae4898f318b8b1d57c72f3e0341784b9..fe48c89de7bf9a2382f9342dc27ccea4b66cb915 100644 (file)
@@ -138,7 +138,7 @@ void flush_area_mask(const cpumask_t *, const void *va, unsigned int flags);
 
 #define flush_root_pgtbl_domain(d)                                       \
 {                                                                        \
-    if ( !cpu_has_no_xpti && is_pv_domain(d) && !is_pv_32bit_domain(d) ) \
+    if ( is_pv_domain(d) && (d)->arch.pv_domain.xpti )                   \
         flush_mask((d)->dirty_cpumask, FLUSH_ROOT_PGTBL);                \
 }
 
index 5ab4ff3f68c73d74b41365f45442d6c8f6e6b2dc..b4fa43269e780d8cfd81d8ed32535f6399bf079e 100644 (file)
@@ -29,6 +29,10 @@ void init_speculation_mitigations(void);
 extern bool opt_ibpb;
 extern uint8_t default_bti_ist_info;
 
+extern uint8_t opt_xpti;
+#define OPT_XPTI_DOM0  0x01
+#define OPT_XPTI_DOMU  0x02
+
 static inline void init_shadow_spec_ctrl_state(void)
 {
     struct cpu_info *info = get_cpu_info();