|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |