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

[Xen-devel] [PATCH v5 1/2][XTF] add FPU/SIMD register state test



Add tests to verify that
- FPU insns leave correct (guest) values in FIP/FDP/FOP/FCS/FDS (at the
  example for FSTPS),
- FPU insns writing memory don't update FPU register state when the
  write faults (at the example of FISTPS),
- VCVTPS2PH doesn't update MXCSR if its write faults (VCVTPS2PH is one
  of the very few SIMD insns writing to memory _and_ updating register
  state; the scatter family of insns also falls into this category).

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
v5: Add AVX512F variant of VCVTPS2PH test. Guard FDP check with
    !cpu_has_fdp_excp_only.
v3: Re-base. Add entry to all-tests.dox.
v2: Introduce and use x87.h. Tolerate VCVTPS2PH misbehavior on Intel
    hardware. Tolerate AMD oddities in probe_fstp() and probe_fistp().

--- a/arch/x86/include/arch/cpuid.h
+++ b/arch/x86/include/arch/cpuid.h
@@ -80,6 +80,7 @@ static inline bool cpu_has(unsigned int
 #define cpu_has_x2apic          cpu_has(X86_FEATURE_X2APIC)
 #define cpu_has_xsave           cpu_has(X86_FEATURE_XSAVE)
 #define cpu_has_avx             cpu_has(X86_FEATURE_AVX)
+#define cpu_has_f16c            cpu_has(X86_FEATURE_F16C)
 
 #define cpu_has_syscall         cpu_has(X86_FEATURE_SYSCALL)
 #define cpu_has_nx              cpu_has(X86_FEATURE_NX)
@@ -90,6 +91,8 @@ static inline bool cpu_has(unsigned int
 
 #define cpu_has_fsgsbase        cpu_has(X86_FEATURE_FSGSBASE)
 #define cpu_has_smep            cpu_has(X86_FEATURE_SMEP)
+#define cpu_has_fdp_excp_only   cpu_has(X86_FEATURE_FDP_EXCP_ONLY)
+#define cpu_has_avx512f         cpu_has(X86_FEATURE_AVX512F)
 #define cpu_has_smap            cpu_has(X86_FEATURE_SMAP)
 
 #define cpu_has_umip            cpu_has(X86_FEATURE_UMIP)
--- /dev/null
+++ b/arch/x86/include/arch/x87.h
@@ -0,0 +1,27 @@
+#ifndef XTF_X86_X87_H
+#define XTF_X86_X87_H
+
+#include <xtf/types.h>
+
+struct x87_env_pm32 {
+    uint16_t cw, :16;
+    uint16_t sw, :16;
+    uint16_t tw, :16;
+    uint32_t ip;
+    uint16_t cs;
+    uint16_t op:11, :5;
+    uint32_t dp;
+    uint16_t ds, :16;
+};
+
+#endif /* XTF_X86_X87_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- a/docs/all-tests.dox
+++ b/docs/all-tests.dox
@@ -20,6 +20,8 @@ and functionality.
 
 @subpage test-fpu-exception-emulation - FPU Exception Emulation.  Covers 
XSA-190.
 
+@subpage test-fpu-state - FPU state Emulation.
+
 @subpage test-invlpg - `invlpg` instruction behaviour.
 
 @subpage test-lbr-tsx-vmentry - Haswell and later LBR/TSX Vmentry failure test.
--- a/include/xen/arch-x86/cpufeatureset.h
+++ b/include/xen/arch-x86/cpufeatureset.h
@@ -134,6 +134,7 @@
 #define X86_FEATURE_NO_FPU_SEL    (5*32+13) /* FPU CS/DS stored as zero */
 #define X86_FEATURE_MPX           (5*32+14) /* Memory Protection Extensions */
 #define X86_FEATURE_PQE           (5*32+15) /* Platform QoS Enforcement */
+#define X86_FEATURE_AVX512F       (5*32+16) /* AVX-512 Foundation Instructions 
*/
 #define X86_FEATURE_RDSEED        (5*32+18) /* RDSEED instruction */
 #define X86_FEATURE_ADX           (5*32+19) /* ADCX, ADOX instructions */
 #define X86_FEATURE_SMAP          (5*32+20) /* Supervisor Mode Access 
Prevention */
--- a/include/xen/arch-x86/xen.h
+++ b/include/xen/arch-x86/xen.h
@@ -15,6 +15,16 @@
 
 #include "cpuid.h"
 
+/*
+ * A number of GDT entries are reserved by Xen. These are not situated at the
+ * start of the GDT because some stupid OSes export hard-coded selector values
+ * in their ABI. These hard-coded values are always near the start of the GDT,
+ * so Xen places itself out of the way, at the far end of the GDT.
+ *
+ * NB The LDT is set using the MMUEXT_SET_LDT op of HYPERVISOR_mmuext_op
+ */
+#define FIRST_RESERVED_GDT_PAGE  14
+
 #ifndef __ASSEMBLY__
 typedef unsigned long xen_pfn_t;
 
--- /dev/null
+++ b/tests/fpu-state/Makefile
@@ -0,0 +1,9 @@
+include $(ROOT)/build/common.mk
+
+NAME      := fpu-state
+CATEGORY  := functional
+TEST-ENVS := hvm64 hvm32pse
+
+obj-perenv += main.o
+
+include $(ROOT)/build/gen.mk
--- /dev/null
+++ b/tests/fpu-state/main.c
@@ -0,0 +1,272 @@
+/**
+ * @file tests/fpu-state/main.c
+ * @ref test-fpu-state - Emulation of FPU state
+ *
+ * @page test-fpu-state FPU State Emulation
+ *
+ * FPU code/data pointers and opcode must not be the ones resulting
+ * from the stub execution in the hypervisor.
+ *
+ * FPU and SIMD instructions faulting during memory write must not
+ * update the respective register files.
+ *
+ * @see tests/fpu-state/main.c
+ */
+#include <xtf.h>
+
+#include <arch/exinfo.h>
+#include <arch/x87.h>
+
+const char test_title[] = "FPU State";
+
+void probe_fstp(bool force)
+{
+    const uint8_t *fstp_offs;
+    uint32_t flt;
+    struct x87_env_pm32 fenv;
+
+    fenv.cw = 0x35f; /* unmask PE */
+    asm volatile ( "fninit;"
+                   "fldcw %[cw];"
+                   "fldpi;"
+                   "mov $1f, %[offs];"
+                   "test %[fep], %[fep];"
+                   "jz 1f;"
+                   _ASM_XEN_FEP
+                   "1: fstps %[data]; 2:"
+                   : [offs] "=&g" (fstp_offs), [data] "=m" (flt)
+                   : [cw] "m" (fenv.cw), [fep] "q" (force) );
+
+    asm ( "fnstenv %0" : "=m" (fenv) );
+    if ( fenv.ip != (unsigned long)fstp_offs )
+        xtf_failure("Fail: FIP wrong (%08x)\n", fenv.ip);
+    if ( fenv.cs && fenv.cs != __KERN_CS )
+    {
+#ifdef __x86_64__
+        /*
+         * Tolerate CS being in the hypervisor reserved selector range on
+         * AMD hardware, as their 64-bit {F,}XRSTOR do not appear to clear
+         * FCS/FDS.
+         */
+        if ( vendor_is_amd && !(fenv.cs & X86_SEL_LDT) &&
+             (fenv.cs >> PAGE_SHIFT) == FIRST_RESERVED_GDT_PAGE )
+            xtf_warning("Warning: FCS wrong (%04x)\n", fenv.cs);
+        else
+#endif
+            xtf_failure("Fail: FCS wrong (%04x)\n", fenv.cs);
+    }
+    if ( !cpu_has_fdp_excp_only && fenv.dp != (unsigned long)&flt )
+        xtf_failure("Fail: FDP wrong (%08x)\n", fenv.dp);
+    if ( fenv.ds && fenv.ds != __KERN_DS )
+        xtf_failure("Fail: FDS wrong (%04x)\n", fenv.ds);
+    /* Skip possible opcode prefixes before checking the opcode. */
+    while ( (fstp_offs[0] & ~7) != 0xd8 )
+        ++fstp_offs;
+    if ( fenv.op && fenv.op != (((fstp_offs[0] & 7) << 8) | fstp_offs[1]) )
+        xtf_failure("Fail: FOP wrong (%03x)\n", fenv.op);
+}
+
+void probe_fistp(bool force)
+{
+    unsigned long fldpi_offs;
+    exinfo_t fault = 0;
+    uint16_t fsw;
+    struct x87_env_pm32 fenv;
+    typeof(xtf_failure) *diagfn;
+    const char *prefix;
+
+    asm volatile ( "fninit;"
+                   "0: fldpi;"
+                   "mov $0b, %[offs];"
+                   "test %[fep], %[fep];"
+                   "jz 1f;"
+                   _ASM_XEN_FEP
+                   "1: fistps (%[ptr]); 2:"
+                   _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
+                   : [offs] "=&g" (fldpi_offs), "+a" (fault)
+                   : [ptr] "r" (0), [fep] "q" (force),
+                     "X" (ex_record_fault_eax) );
+
+    if ( !fault )
+        xtf_error("Error: FISTP to NULL did not fault\n");
+
+    asm ( "fnstsw %0" : "=am" (fsw) );
+    if ( fsw != 0x3800 )
+        xtf_failure("Fail: FSW changed unexpectedly (%04x)\n", fsw);
+
+    asm ( "fnstenv %0" : "=m" (fenv) );
+    /*
+     * The AMD-specific FPU pointer leak workaround in Xen (using FISTPL,
+     * which we check for below) causes all the remaining checks to fail.
+     */
+    if ( !vendor_is_amd || (fenv.op & 0x738) != 0x300 )
+    {
+        diagfn = xtf_failure;
+        prefix = "Fail";
+    }
+    else
+    {
+        diagfn = xtf_warning;
+        prefix = "Warning";
+    }
+    if ( fenv.ip != fldpi_offs )
+        diagfn("%s: FIP changed unexpectedly (%08x)\n", prefix, fenv.ip);
+    if ( fenv.cs && fenv.cs != __KERN_CS )
+        diagfn("%s: FCS changed unexpectedly (%04x)\n", prefix, fenv.cs);
+    if ( fenv.dp )
+        diagfn("%s: FDP changed unexpectedly (%08x)\n", prefix, fenv.dp);
+    if ( fenv.ds )
+        diagfn("%s: FDS changed unexpectedly (%04x)\n", prefix, fenv.ds);
+    if ( fenv.op && fenv.op != 0x1eb )
+        diagfn("%s: FOP changed unexpectedly (%03x)\n", prefix, fenv.op);
+}
+
+void probe_vcvtps2ph_vex(bool force)
+{
+    exinfo_t fault = 0;
+    uint32_t mxcsr = 0x1f80;
+
+    asm volatile ( "vldmxcsr %[mxcsr];"
+                   "vpcmpeqb %%xmm0, %%xmm0, %%xmm0;"
+                   "vpcmpgtb %%xmm0, %%xmm0, %%xmm1;"
+                   "vpunpcklbw %%xmm1, %%xmm0, %%xmm2;"
+                   "test %[fep], %[fep];"
+                   "jz 1f;"
+                   _ASM_XEN_FEP
+                   "1: vcvtps2ph $0, %%xmm2, (%[ptr]); 2:"
+                   _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
+                   : "+a" (fault)
+                   : [ptr] "r" (0), [mxcsr] "m" (mxcsr), [fep] "q" (force),
+                     "X" (ex_record_fault_eax) );
+
+    if ( !fault )
+        xtf_error("Error: VCVTPS2PH (VEX) to NULL did not fault\n");
+    else if ( exinfo_vec(fault) == X86_EXC_UD )
+    {
+        if ( force )
+            xtf_skip("Emulator does not support VCVTPS2PH (VEX)\n");
+        else
+            xtf_failure("Fail: VCVTPS2PH (VEX) did #UD\n");
+    }
+
+    asm ( "vstmxcsr %0" : "=m" (mxcsr) );
+    if ( mxcsr != 0x1f80 )
+    {
+        /*
+         * Expect AMD hardware and emulation to behave correctly, but tolerate
+         * unexpected behavior on Intel hardware.
+         */
+        if ( force || vendor_is_amd )
+            xtf_failure("Fail: MXCSR changed unexpectedly (%08x)\n", mxcsr);
+        else
+            xtf_warning("Warning: MXCSR changed unexpectedly (%08x)\n", mxcsr);
+    }
+}
+
+void probe_vcvtps2ph_evex(bool force)
+{
+    exinfo_t fault = 0;
+    uint32_t mxcsr = 0x1f80;
+
+    asm volatile ( "vldmxcsr %[mxcsr];"
+                   "vpbroadcastd %[in], %%zmm7;"
+                   "kxnorw %%k0, %%k0, %%k7;"
+                   "test %[fep], %[fep];"
+                   "jz 1f;"
+                   _ASM_XEN_FEP
+                   "1: vcvtps2ph $0,%%zmm7,(%[ptr])%{%%k7%}; 2:"
+                   _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
+                   : "+a" (fault)
+                   : [ptr] "r" (0), [mxcsr] "m" (mxcsr), [in] "r" (0xff00ff00),
+                     [fep] "q" (force), "X" (ex_record_fault_eax) );
+
+    if ( !fault )
+        xtf_error("Error: VCVTPS2PH (EVEX) to NULL did not fault\n");
+    else if ( exinfo_vec(fault) == X86_EXC_UD )
+    {
+        if ( force )
+            xtf_skip("Emulator does not support VCVTPS2PH (EVEX)\n");
+        else
+            xtf_failure("Fail: VCVTPS2PH (EVEX) did #UD\n");
+    }
+
+    asm ( "vstmxcsr %0" : "=m" (mxcsr) );
+    if ( mxcsr != 0x1f80 )
+    {
+        /*
+         * Expect AMD hardware and emulation to behave correctly, but tolerate
+         * unexpected behavior on Intel hardware.
+         */
+        if ( force || vendor_is_amd )
+            xtf_failure("Fail: MXCSR changed unexpectedly (%08x)\n", mxcsr);
+        else
+            xtf_warning("Warning: MXCSR changed unexpectedly (%08x)\n", mxcsr);
+    }
+}
+
+void run_tests(bool force)
+{
+    if ( cpu_has_fpu )
+    {
+        printk("Testing%s FSTP\n", force ? " emulated" : "");
+        probe_fstp(force);
+
+        printk("Testing%s FISTP (to NULL)\n", force ? " emulated" : "");
+        probe_fistp(force);
+    }
+
+    if ( cpu_has_f16c )
+    {
+        unsigned long cr4 = read_cr4();
+        unsigned long xcr0;
+
+        write_cr4(cr4 | X86_CR4_OSXSAVE);
+        xcr0 = read_xcr0();
+        write_xcr0(xcr0 | XSTATE_SSE | XSTATE_YMM);
+
+        printk("Testing%s VCVTPS2PH (VEX) (to NULL)\n", force ? " emulated" : 
"");
+        probe_vcvtps2ph_vex(force);
+
+        write_xcr0(xcr0);
+        write_cr4(cr4);
+    }
+
+    if ( cpu_has_avx512f )
+    {
+        unsigned long cr4 = read_cr4();
+        unsigned long xcr0;
+
+        write_cr4(cr4 | X86_CR4_OSXSAVE);
+        xcr0 = read_xcr0();
+        write_xcr0(xcr0 | XSTATE_SSE | XSTATE_YMM | XSTATE_OPMASK |
+                   XSTATE_ZMM | XSTATE_HI_ZMM);
+
+        printk("Testing%s VCVTPS2PH (EVEX) (to NULL)\n", force ? " emulated" : 
"");
+        probe_vcvtps2ph_evex(force);
+
+        write_xcr0(xcr0);
+        write_cr4(cr4);
+    }
+}
+
+void test_main(void)
+{
+    run_tests(false);
+
+    if ( !xtf_has_fep )
+        xtf_skip("FEP support not detected - some tests will be skipped\n");
+    else
+        run_tests(true);
+
+    xtf_success(NULL);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */




_______________________________________________
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®.