All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/2][XTF] FPU test improvements
@ 2018-02-28 13:15 Jan Beulich
  2018-02-28 13:26 ` [PATCH v4 1/2][XTF] add FPU/SIMD register state test Jan Beulich
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Jan Beulich @ 2018-02-28 13:15 UTC (permalink / raw)
  To: Andrew Cooper; +Cc: xen-devel

1: add FPU/SIMD register state test
2: extend FPU exception tests

Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
v4: Just re-basing, no other feedback was received.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v4 1/2][XTF] add FPU/SIMD register state test
  2018-02-28 13:15 [PATCH v4 0/2][XTF] FPU test improvements Jan Beulich
@ 2018-02-28 13:26 ` Jan Beulich
  2018-02-28 13:26 ` [PATCH v4 2/2][XTF] x86: extend FPU exception tests Jan Beulich
  2018-02-28 16:49 ` [PATCH v4 0/2][XTF] FPU test improvements Andrew Cooper
  2 siblings, 0 replies; 4+ messages in thread
From: Jan Beulich @ 2018-02-28 13:26 UTC (permalink / raw)
  To: Andrew Cooper, Jan Beulich; +Cc: xen-devel

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 (once implemented in the emulator) 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 fall into this category, but we're quite far yet from
  supporting AVX-512 insns).

Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
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
@@ -79,6 +79,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)
--- /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/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,214 @@
+/**
+ * @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 ( 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(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 to NULL did not fault\n");
+    else if ( exinfo_vec(fault) == X86_EXC_UD )
+    {
+        if ( force )
+            xtf_skip("Emulator does not support VCVTPS2PH\n");
+        else
+            xtf_failure("Fail: VCVTPS2PH 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 (to NULL)\n", force ? " emulated" : "");
+        probe_vcvtps2ph(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@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v4 2/2][XTF] x86: extend FPU exception tests
  2018-02-28 13:15 [PATCH v4 0/2][XTF] FPU test improvements Jan Beulich
  2018-02-28 13:26 ` [PATCH v4 1/2][XTF] add FPU/SIMD register state test Jan Beulich
@ 2018-02-28 13:26 ` Jan Beulich
  2018-02-28 16:49 ` [PATCH v4 0/2][XTF] FPU test improvements Andrew Cooper
  2 siblings, 0 replies; 4+ messages in thread
From: Jan Beulich @ 2018-02-28 13:26 UTC (permalink / raw)
  To: Andrew Cooper; +Cc: xen-devel

Also test #MF and #XM handling.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
v4: Re-base.
v3: New.

--- /dev/null
+++ b/arch/x86/include/arch/simd.h
@@ -0,0 +1,32 @@
+#ifndef XTF_X86_SIMD_H
+#define XTF_X86_SIMD_H
+
+#define X86_MXCSR_IE      0x00000001
+#define X86_MXCSR_DE      0x00000002
+#define X86_MXCSR_ZE      0x00000004
+#define X86_MXCSR_OE      0x00000008
+#define X86_MXCSR_UE      0x00000010
+#define X86_MXCSR_PE      0x00000020
+#define X86_MXCSR_DAZ     0x00000040
+#define X86_MXCSR_IM      0x00000080
+#define X86_MXCSR_DM      0x00000100
+#define X86_MXCSR_ZM      0x00000200
+#define X86_MXCSR_OM      0x00000400
+#define X86_MXCSR_UM      0x00000800
+#define X86_MXCSR_PM      0x00001000
+#define X86_MXCSR_RC_MASK 0x00006000
+#define X86_MXCSR_FZ      0x00008000
+
+#define X86_MXCSR_DEFAULT 0x1f80
+
+#endif /* XTF_X86_SIMD_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--- a/arch/x86/include/arch/x87.h
+++ b/arch/x86/include/arch/x87.h
@@ -3,6 +3,27 @@
 
 #include <xtf/types.h>
 
+#define X86_FCW_IM      0x0001
+#define X86_FCW_DM      0x0002
+#define X86_FCW_ZM      0x0004
+#define X86_FCW_OM      0x0008
+#define X86_FCW_UM      0x0010
+#define X86_FCW_PM      0x0020
+#define X86_FCW_PC_MASK 0x0300
+#define X86_FCW_RC_MASK 0x0c00
+
+#define X86_PC_SINGLE   0
+#define X86_PC_DOUBLE   2
+#define X86_PC_EXTENDED 3
+
+/* These also apply to MXCSR. */
+#define X86_RC_NEAREST  0
+#define X86_RC_DOWN     1
+#define X86_RC_UP       2
+#define X86_RC_ZERO     3
+
+#define X86_FCW_DEFAULT 0x037f
+
 struct x87_env_pm32 {
     uint16_t cw, :16;
     uint16_t sw, :16;
--- a/tests/fpu-exception-emulation/main.c
+++ b/tests/fpu-exception-emulation/main.c
@@ -22,27 +22,37 @@
  * checking that appropriate exceptions are raised (@#NM or @#UD), or that no
  * exception is raised.
  *
+ * Additionally #MF and #XM behavior is being tested.
+ *
  * Each test is run against real hardware, and forced through the x86
  * instruction emulator (if FEP is available).
  *
  * This test covers XSA-190, where @#NM was not being raised appropriately,
  * therefore interfering with lazy FPU task switching in the guest.
  *
- * @todo Extend to include unmasked pending exceptions.  There is definitely
- * work required in the instruction emulator to support this properly.
- *
  * @see tests/fpu-exception-emulation/main.c
  */
 #include <xtf.h>
+#include <arch/simd.h>
+#include <arch/x87.h>
 
 const char test_title[] = "FPU Exception Emulation";
 
 #define CR0_SYM(...) TOK_OR(X86_CR0_, ##__VA_ARGS__)
-#define CR0_MASK CR0_SYM(EM, MP, TS)
+#define CR0_MASK CR0_SYM(EM, MP, TS, NE)
+
+#define CR4_SYM(...) TOK_OR(X86_CR4_OS, ##__VA_ARGS__)
+#define CR4_MASK CR4_SYM(FXSR, XMMEXCPT, XSAVE)
+
+#define FCW_SYM(...) TOK_OR(X86_FCW_, ##__VA_ARGS__)
+
+#define MXCSR_SYM(...) TOK_OR(X86_MXCSR_, ##__VA_ARGS__)
 
 struct test_cfg
 {
     unsigned long cr0;
+    unsigned long cr4;
+    unsigned int control;
     exinfo_t fault;
 };
 
@@ -54,20 +64,27 @@ static unsigned long default_cr0;
  */
 static const struct test_cfg x87[] =
 {
-    { CR0_SYM(          ), 0 },
-    { CR0_SYM(        TS), EXINFO_SYM(NM, 0) },
-    { CR0_SYM(    MP    ), 0 },
-    { CR0_SYM(    MP, TS), EXINFO_SYM(NM, 0) },
-    { CR0_SYM(EM        ), EXINFO_SYM(NM, 0) },
-    { CR0_SYM(EM,     TS), EXINFO_SYM(NM, 0) },
-    { CR0_SYM(EM, MP    ), EXINFO_SYM(NM, 0) },
-    { CR0_SYM(EM, MP, TS), EXINFO_SYM(NM, 0) },
+    { CR0_SYM(          ), 0, 0,           0 },
+    { CR0_SYM(        TS), 0, 0,           EXINFO_SYM(NM, 0) },
+    { CR0_SYM(    MP    ), 0, 0,           0 },
+    { CR0_SYM(    MP, TS), 0, 0,           EXINFO_SYM(NM, 0) },
+    { CR0_SYM(EM        ), 0, 0,           EXINFO_SYM(NM, 0) },
+    { CR0_SYM(EM,     TS), 0, 0,           EXINFO_SYM(NM, 0) },
+    { CR0_SYM(EM, MP    ), 0, 0,           EXINFO_SYM(NM, 0) },
+    { CR0_SYM(EM, MP, TS), 0, 0,           EXINFO_SYM(NM, 0) },
+    { CR0_SYM(NE),         0, FCW_SYM(IM), EXINFO_SYM(MF, 0) },
 };
 
-exinfo_t probe_x87(bool force)
+exinfo_t probe_x87(unsigned int control, bool force)
 {
     exinfo_t fault = 0;
 
+    if ( control )
+    {
+        control = X86_FCW_DEFAULT & ~control;
+        asm volatile ("fninit; fldcw %0; faddp" :: "m" (control));
+    }
+
     asm volatile ("test %[fep], %[fep];"
                   "jz 1f;"
                   _ASM_XEN_FEP
@@ -77,6 +94,9 @@ exinfo_t probe_x87(bool force)
                   : [fep] "q" (force),
                     "X" (ex_record_fault_eax));
 
+    if ( control )
+        asm volatile ("fnclex");
+
     return fault;
 }
 
@@ -87,20 +107,27 @@ exinfo_t probe_x87(bool force)
  */
 static const struct test_cfg x87_wait[] =
 {
-    { CR0_SYM(          ), 0 },
-    { CR0_SYM(        TS), 0 },
-    { CR0_SYM(    MP    ), 0 },
-    { CR0_SYM(    MP, TS), EXINFO_SYM(NM, 0) },
-    { CR0_SYM(EM        ), 0 },
-    { CR0_SYM(EM,     TS), 0 },
-    { CR0_SYM(EM, MP    ), 0 },
-    { CR0_SYM(EM, MP, TS), EXINFO_SYM(NM, 0) },
+    { CR0_SYM(          ), 0, 0,           0 },
+    { CR0_SYM(        TS), 0, 0,           0 },
+    { CR0_SYM(    MP    ), 0, 0,           0 },
+    { CR0_SYM(    MP, TS), 0, 0,           EXINFO_SYM(NM, 0) },
+    { CR0_SYM(EM        ), 0, 0,           0 },
+    { CR0_SYM(EM,     TS), 0, 0,           0 },
+    { CR0_SYM(EM, MP    ), 0, 0,           0 },
+    { CR0_SYM(EM, MP, TS), 0, 0,           EXINFO_SYM(NM, 0) },
+    { CR0_SYM(NE),         0, FCW_SYM(IM), EXINFO_SYM(MF, 0) },
 };
 
-exinfo_t probe_x87_wait(bool force)
+exinfo_t probe_x87_wait(unsigned int control, bool force)
 {
     exinfo_t fault = 0;
 
+    if ( control )
+    {
+        control = X86_FCW_DEFAULT & ~control;
+        asm volatile ("fninit; fldcw %0; faddp" :: "m" (control));
+    }
+
     asm volatile ("test %[fep], %[fep];"
                   "jz 1f;"
                   _ASM_XEN_FEP
@@ -110,26 +137,29 @@ exinfo_t probe_x87_wait(bool force)
                   : [fep] "q" (force),
                     "X" (ex_record_fault_eax));
 
+    if ( control )
+        asm volatile ("fnclex");
+
     return fault;
 }
 
 /**
- * MMX and SSE instructions.  Emulation is unsupported (thus raising @#UD),
+ * MMX instructions.  Emulation is unsupported (thus raising @#UD),
  * but @#NM should be raised if the task has been switched.
  */
-static const struct test_cfg mmx_sse[] =
+static const struct test_cfg mmx[] =
 {
-    { CR0_SYM(          ), 0 },
-    { CR0_SYM(        TS), EXINFO_SYM(NM, 0) },
-    { CR0_SYM(    MP    ), 0 },
-    { CR0_SYM(    MP, TS), EXINFO_SYM(NM, 0) },
-    { CR0_SYM(EM        ), EXINFO_SYM(UD, 0) },
-    { CR0_SYM(EM,     TS), EXINFO_SYM(UD, 0) },
-    { CR0_SYM(EM, MP    ), EXINFO_SYM(UD, 0) },
-    { CR0_SYM(EM, MP, TS), EXINFO_SYM(UD, 0) },
+    { CR0_SYM(          ), 0, 0, 0 },
+    { CR0_SYM(        TS), 0, 0, EXINFO_SYM(NM, 0) },
+    { CR0_SYM(    MP    ), 0, 0, 0 },
+    { CR0_SYM(    MP, TS), 0, 0, EXINFO_SYM(NM, 0) },
+    { CR0_SYM(EM        ), 0, 0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM,     TS), 0, 0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM, MP    ), 0, 0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM, MP, TS), 0, 0, EXINFO_SYM(UD, 0) },
 };
 
-exinfo_t probe_mmx(bool force)
+exinfo_t probe_mmx(unsigned int control, bool force)
 {
     exinfo_t fault = 0;
 
@@ -145,10 +175,56 @@ exinfo_t probe_mmx(bool force)
     return fault;
 }
 
-exinfo_t probe_sse(bool force)
+/**
+ * SSE instructions.  Emulation is unsupported (thus raising @#UD),
+ * but @#NM should be raised if the task has been switched.
+ */
+static const struct test_cfg sse[] =
+{
+    { CR0_SYM(          ), 0,             0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(        TS), 0,             0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(    MP    ), 0,             0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(    MP, TS), 0,             0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM        ), 0,             0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM,     TS), 0,             0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM, MP    ), 0,             0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM, MP, TS), 0,             0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(          ), CR4_SYM(FXSR), 0, 0 },
+    { CR0_SYM(        TS), CR4_SYM(FXSR), 0, EXINFO_SYM(NM, 0) },
+    { CR0_SYM(    MP    ), CR4_SYM(FXSR), 0, 0 },
+    { CR0_SYM(    MP, TS), CR4_SYM(FXSR), 0, EXINFO_SYM(NM, 0) },
+    { CR0_SYM(EM        ), CR4_SYM(FXSR), 0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM,     TS), CR4_SYM(FXSR), 0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM, MP    ), CR4_SYM(FXSR), 0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM, MP, TS), CR4_SYM(FXSR), 0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(    MP    ), CR4_SYM(FXSR),
+      MXCSR_SYM(IM),                         EXINFO_SYM(UD, 0) },
+    { CR0_SYM(    MP    ), CR4_SYM(FXSR, XMMEXCPT),
+      MXCSR_SYM(IM),                         EXINFO_SYM(XM, 0) },
+};
+
+exinfo_t probe_sse(unsigned int control, bool force)
 {
     exinfo_t fault = 0;
 
+    if ( control )
+    {
+        control = X86_MXCSR_DEFAULT & ~control;
+        asm volatile ("0: xorps %%xmm0, %%xmm0;"
+                      "ldmxcsr %[mxcsr];"
+                      "test %[fep], %[fep];"
+                      "jz 1f;"
+                      _ASM_XEN_FEP
+                      "1: divps %%xmm0, %%xmm0; 2:"
+                      _ASM_EXTABLE_HANDLER(0b, 2b, ex_record_fault_eax)
+                      _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
+                      : "+a" (fault)
+                      : [mxcsr] "m" (control),
+                        [fep] "q" (force),
+                        "X" (ex_record_fault_eax));
+        return fault;
+    }
+
     asm volatile ("test %[fep], %[fep];"
                   "jz 1f;"
                   _ASM_XEN_FEP
@@ -167,17 +243,25 @@ exinfo_t probe_sse(bool force)
  */
 static const struct test_cfg avx[] =
 {
-    { CR0_SYM(          ), 0 },
-    { CR0_SYM(        TS), EXINFO_SYM(NM, 0) },
-    { CR0_SYM(    MP    ), 0 },
-    { CR0_SYM(    MP, TS), EXINFO_SYM(NM, 0) },
-    { CR0_SYM(EM        ), 0 },
-    { CR0_SYM(EM,     TS), EXINFO_SYM(NM, 0) },
-    { CR0_SYM(EM, MP    ), 0 },
-    { CR0_SYM(EM, MP, TS), EXINFO_SYM(NM, 0) },
+    { CR0_SYM(          ), 0,              0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(        TS), 0,              0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(    MP    ), 0,              0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(    MP, TS), 0,              0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM        ), 0,              0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM,     TS), 0,              0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM, MP    ), 0,              0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(EM, MP, TS), 0,              0, EXINFO_SYM(UD, 0) },
+    { CR0_SYM(          ), CR4_SYM(XSAVE), 0, 0 },
+    { CR0_SYM(        TS), CR4_SYM(XSAVE), 0, EXINFO_SYM(NM, 0) },
+    { CR0_SYM(    MP    ), CR4_SYM(XSAVE), 0, 0 },
+    { CR0_SYM(    MP, TS), CR4_SYM(XSAVE), 0, EXINFO_SYM(NM, 0) },
+    { CR0_SYM(EM        ), CR4_SYM(XSAVE), 0, 0 },
+    { CR0_SYM(EM,     TS), CR4_SYM(XSAVE), 0, EXINFO_SYM(NM, 0) },
+    { CR0_SYM(EM, MP    ), CR4_SYM(XSAVE), 0, 0 },
+    { CR0_SYM(EM, MP, TS), CR4_SYM(XSAVE), 0, EXINFO_SYM(NM, 0) },
 };
 
-static exinfo_t probe_avx(bool force)
+static exinfo_t probe_avx(unsigned int control, bool force)
 {
     exinfo_t fault = 0;
 
@@ -194,29 +278,41 @@ static exinfo_t probe_avx(bool force)
 }
 
 void run_sequence(const struct test_cfg *seq, unsigned int nr,
-                  unsigned int (*fn)(bool), bool force, exinfo_t override)
+                  unsigned int (*fn)(unsigned int, bool), bool force,
+                  exinfo_t override)
 {
     unsigned int i;
 
     for ( i = 0; i < nr; ++i )
     {
         const struct test_cfg *t = &seq[i];
+        unsigned long cr4 = read_cr4();
         exinfo_t res, exp = override ?: t->fault;
 
         write_cr0((default_cr0 & ~CR0_MASK) | t->cr0);
-        res = fn(force);
+        write_cr4((cr4 & ~CR4_MASK) | t->cr4);
+
+        res = fn(t->control, force);
+
+        write_cr4(cr4);
 
         if ( res != exp )
         {
-            char cr0str[12];
+            char cr0str[12], cr4str[24];
 
             snprintf(cr0str, sizeof(cr0str), "%s%s%s",
                      t->cr0 & X86_CR0_EM ? " EM" : "",
                      t->cr0 & X86_CR0_MP ? " MP" : "",
                      t->cr0 & X86_CR0_TS ? " TS" : "");
 
-            xtf_failure("  Expected %pe, got %pe (cr0:%s)\n",
-                        _p(exp), _p(res), cr0str[0] ? cr0str : " - ");
+            snprintf(cr4str, sizeof(cr4str), "%s%s%s",
+                     t->cr4 & X86_CR4_OSFXSR     ? " FXSR"    : "",
+                     t->cr4 & X86_CR4_OSXMMEXCPT ? " XMMXCPT" : "",
+                     t->cr4 & X86_CR4_OSXSAVE    ? " XSAVE"   : "");
+
+            xtf_failure("  Expected %pe, got %pe (cr0:%s cr4:%s ctrl:%04x)\n",
+                        _p(exp), _p(res), cr0str[0] ? cr0str : " - ",
+                        cr4str[0] ? cr4str : " - ", t->control);
         }
     }
 }
@@ -235,23 +331,13 @@ void run_tests(bool force)
     if ( cpu_has_mmx )
     {
         printk("Testing%s MMX\n", force ? " emulated" : "");
-        run_sequence(mmx_sse, ARRAY_SIZE(mmx_sse), probe_mmx, force, 0);
+        run_sequence(mmx, ARRAY_SIZE(mmx), probe_mmx, force, 0);
     }
 
     if ( cpu_has_sse )
     {
-        unsigned long cr4 = read_cr4();
-
         printk("Testing%s SSE\n", force ? " emulated" : "");
-        write_cr4(cr4 & ~X86_CR4_OSFXSR);
-        run_sequence(mmx_sse, ARRAY_SIZE(mmx_sse), probe_sse, force,
-                     EXINFO_SYM(UD, 0));
-
-        printk("Testing%s SSE (CR4.OSFXSR)\n", force ? " emulated" : "");
-        write_cr4(cr4 | X86_CR4_OSFXSR);
-        run_sequence(mmx_sse, ARRAY_SIZE(mmx_sse), probe_sse, force, 0);
-
-        write_cr4(cr4);
+        run_sequence(sse, ARRAY_SIZE(sse), probe_sse, force, 0);
     }
 
     if ( cpu_has_avx )
@@ -259,19 +345,15 @@ void run_tests(bool force)
         unsigned long cr4 = read_cr4();
         unsigned long xcr0;
 
-        printk("Testing%s AVX\n", force ? " emulated" : "");
-        write_cr4(cr4 & ~X86_CR4_OSXSAVE);
-        run_sequence(avx, ARRAY_SIZE(avx), probe_avx, force,
-                     EXINFO_SYM(UD, 0));
-
-        printk("Testing%s AVX (CR4.OSXSAVE)\n", force ? " emulated" : "");
         write_cr4(cr4 | X86_CR4_OSXSAVE);
         xcr0 = read_xcr0();
+
+        printk("Testing%s AVX\n", force ? " emulated" : "");
         write_xcr0(xcr0 & ~XSTATE_YMM);
         run_sequence(avx, ARRAY_SIZE(avx), probe_avx, force,
                      EXINFO_SYM(UD, 0));
 
-        printk("Testing%s AVX (CR4.OSXSAVE+XCR0.YMM)\n", force ? " emulated" : "");
+        printk("Testing%s AVX (XCR0.YMM)\n", force ? " emulated" : "");
         write_xcr0(xcr0 | XSTATE_SSE | XSTATE_YMM);
         run_sequence(avx, ARRAY_SIZE(avx), probe_avx, force, 0);
 



_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v4 0/2][XTF] FPU test improvements
  2018-02-28 13:15 [PATCH v4 0/2][XTF] FPU test improvements Jan Beulich
  2018-02-28 13:26 ` [PATCH v4 1/2][XTF] add FPU/SIMD register state test Jan Beulich
  2018-02-28 13:26 ` [PATCH v4 2/2][XTF] x86: extend FPU exception tests Jan Beulich
@ 2018-02-28 16:49 ` Andrew Cooper
  2 siblings, 0 replies; 4+ messages in thread
From: Andrew Cooper @ 2018-02-28 16:49 UTC (permalink / raw)
  To: Jan Beulich; +Cc: xen-devel

On 28/02/18 13:15, Jan Beulich wrote:
> 1: add FPU/SIMD register state test
> 2: extend FPU exception tests
>
> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> ---
> v4: Just re-basing, no other feedback was received.

In principle, this is all fine, but I cannot commit it until the test
revision logic is sorted.  Otherwise, it will will break OSSTests
bisection logic and either cause XTF updates to be rejected, or
staging-$X.$Y updates to be rejected.

~Andrew

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2018-02-28 17:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-28 13:15 [PATCH v4 0/2][XTF] FPU test improvements Jan Beulich
2018-02-28 13:26 ` [PATCH v4 1/2][XTF] add FPU/SIMD register state test Jan Beulich
2018-02-28 13:26 ` [PATCH v4 2/2][XTF] x86: extend FPU exception tests Jan Beulich
2018-02-28 16:49 ` [PATCH v4 0/2][XTF] FPU test improvements Andrew Cooper

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.