x86/cpu: Context switch cpuid masks and faulting state in context_switch()
authorAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 26 Nov 2015 18:36:52 +0000 (18:36 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Fri, 8 Apr 2016 20:54:35 +0000 (21:54 +0100)
A single ctxt_switch_levelling() function pointer is provided
(defaulting to an empty nop), which is overridden in the appropriate
$VENDOR_init_levelling().

set_cpuid_faulting() is made private and included within
intel_ctxt_switch_levelling().

One (attempted) functional change is that the faulting configuration should
not be special cased for dom0.  It turns out that the toolstack relies on the
special case (and indeed, on being a PV domain in the first place) to
correctly build HVM domains.

For now, the control domain is left as a special case, until futher work can
be completed to remove the restriction.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <JBeulich@suse.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
xen/arch/x86/cpu/amd.c
xen/arch/x86/cpu/common.c
xen/arch/x86/cpu/intel.c
xen/arch/x86/crash.c
xen/arch/x86/domain.c
xen/include/asm-x86/processor.h

index 93a8a5e6a7d18d718fbba22a63fe31c2a0666335..3e2f4a8f45ea0a4dad15bef39f750610123cbed6 100644 (file)
@@ -331,6 +331,9 @@ static void __init noinline amd_init_levelling(void)
                       (uint32_t)cpuidmask_defaults._7ab0,
                       (uint32_t)cpuidmask_defaults._6c);
        }
+
+       if (levelling_caps)
+               ctxt_switch_levelling = amd_ctxt_switch_levelling;
 }
 
 /*
index 7ef75b08e59dc9b0f3b8d236bdd1a5cb4c7e2d7d..fe6eab49cc542dea65c74768a4f6f371e7de1d63 100644 (file)
@@ -88,6 +88,13 @@ static const struct cpu_dev default_cpu = {
 };
 static const struct cpu_dev *this_cpu = &default_cpu;
 
+static void default_ctxt_switch_levelling(const struct domain *nextd)
+{
+       /* Nop */
+}
+void (* __read_mostly ctxt_switch_levelling)(const struct domain *nextd) =
+       default_ctxt_switch_levelling;
+
 bool_t opt_cpu_info;
 boolean_param("cpuinfo", opt_cpu_info);
 
index 6e1fbbb784dd33ee8fa339c3d5e55866f22b7693..e21c32d695c33bc38f6ab45e0cd07c94868bd3c2 100644 (file)
@@ -32,13 +32,15 @@ static bool_t __init probe_intel_cpuid_faulting(void)
        return 1;
 }
 
-static DEFINE_PER_CPU(bool_t, cpuid_faulting_enabled);
-void set_cpuid_faulting(bool_t enable)
+static void set_cpuid_faulting(bool_t enable)
 {
+       static DEFINE_PER_CPU(bool_t, cpuid_faulting_enabled);
+       bool_t *this_enabled = &this_cpu(cpuid_faulting_enabled);
        uint32_t hi, lo;
 
-       if (!cpu_has_cpuid_faulting ||
-           this_cpu(cpuid_faulting_enabled) == enable )
+       ASSERT(cpu_has_cpuid_faulting);
+
+       if (*this_enabled == enable)
                return;
 
        rdmsr(MSR_INTEL_MISC_FEATURES_ENABLES, lo, hi);
@@ -47,7 +49,7 @@ void set_cpuid_faulting(bool_t enable)
                lo |= MSR_MISC_FEATURES_CPUID_FAULTING;
        wrmsr(MSR_INTEL_MISC_FEATURES_ENABLES, lo, hi);
 
-       this_cpu(cpuid_faulting_enabled) = enable;
+       *this_enabled = enable;
 }
 
 /*
@@ -154,6 +156,28 @@ static void intel_ctxt_switch_levelling(const struct domain *nextd)
        struct cpuidmasks *these_masks = &this_cpu(cpuidmasks);
        const struct cpuidmasks *masks = &cpuidmask_defaults;
 
+       if (cpu_has_cpuid_faulting) {
+               /*
+                * We *should* be enabling faulting for the control domain.
+                *
+                * Unfortunately, the domain builder (having only ever been a
+                * PV guest) expects to be able to see host cpuid state in a
+                * native CPUID instruction, to correctly build a CPUID policy
+                * for HVM guests (notably the xstate leaves).
+                *
+                * This logic is fundimentally broken for HVM toolstack
+                * domains, and faulting causes PV guests to behave like HVM
+                * guests from their point of view.
+                *
+                * Future development plans will move responsibility for
+                * generating the maximum full cpuid policy into Xen, at which
+                * this problem will disappear.
+                */
+               set_cpuid_faulting(nextd && is_pv_domain(nextd) &&
+                                  !is_control_domain(nextd));
+               return;
+       }
+
 #define LAZY(msr, field)                                               \
        ({                                                              \
                if (unlikely(these_masks->field != masks->field) &&     \
@@ -227,6 +251,9 @@ static void __init noinline intel_init_levelling(void)
                               (uint32_t)cpuidmask_defaults.e1cd,
                               (uint32_t)cpuidmask_defaults.Da1);
        }
+
+       if (levelling_caps)
+               ctxt_switch_levelling = intel_ctxt_switch_levelling;
 }
 
 static void early_init_intel(struct cpuinfo_x86 *c)
index 888a214c3843ab84c80aa86f823d536c22775ca0..f28f527912b80d5ca03d5697856dbbc16cb0c4f0 100644 (file)
@@ -189,6 +189,9 @@ void machine_crash_shutdown(void)
 
     nmi_shootdown_cpus();
 
+    /* Reset CPUID masking and faulting to the host's default. */
+    ctxt_switch_levelling(NULL);
+
     info = kexec_crash_save_info();
     info->xen_phys_start = xen_phys_start;
     info->dom0_pfn_to_mfn_frame_list_list =
index 9e436efcefe9cc1fb240dd54be7b9336e1897f8a..d7b6c2bf451f549072d20a0b74cbe86d638d2f0f 100644 (file)
@@ -2087,9 +2087,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
             load_segments(next);
         }
 
-        set_cpuid_faulting(is_pv_domain(nextd) &&
-                           !is_control_domain(nextd) &&
-                           !is_hardware_domain(nextd));
+        ctxt_switch_levelling(nextd);
     }
 
     context_saved(prev);
index a9505548014ebbe7b9e2366f4e1ac15adabac481..f29d37046fd3f71f9d9717f804f72327f9aa84fe 100644 (file)
@@ -209,7 +209,7 @@ extern struct cpuinfo_x86 boot_cpu_data;
 extern struct cpuinfo_x86 cpu_data[];
 #define current_cpu_data cpu_data[smp_processor_id()]
 
-extern void set_cpuid_faulting(bool_t enable);
+extern void (*ctxt_switch_levelling)(const struct domain *nextd);
 
 extern u64 host_pat;
 extern bool_t opt_cpu_info;