From patchwork Wed Mar 15 10:29:53 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Beulich X-Patchwork-Id: 9625203 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E67E1604A9 for ; Wed, 15 Mar 2017 10:32:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E6B1128343 for ; Wed, 15 Mar 2017 10:32:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DB6E62843C; Wed, 15 Mar 2017 10:32:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D66DC28343 for ; Wed, 15 Mar 2017 10:32:24 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1co6Bt-0002FN-9E; Wed, 15 Mar 2017 10:30:01 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1co6Br-0002DU-SP for xen-devel@lists.xenproject.org; Wed, 15 Mar 2017 10:30:00 +0000 Received: from [85.158.139.211] by server-15.bemta-5.messagelabs.com id A9/35-01896-7A719C85; Wed, 15 Mar 2017 10:29:59 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrJIsWRWlGSWpSXmKPExsXS6fjDS3eZ+Mk Ig5YGDovvWyYzOTB6HP5whSWAMYo1My8pvyKBNWPmn1bWgsOzGSs6z/9gamC8VtLFyMkhJJAn 8WrTciYQm1fATuLohJ/MILaEgKHE0/fX2UBsFgFViU9T/rOD2GwC6hJtz7azgtgiAvoS8z/9B LI5OJgFDCTufjcBCQsLWEr8OLCCHWJ8kcTWWWvARnIK2EtcW/yJEaScV0BQ4u8OYZAwM9DWSd Pus01g5JmFkJmFJANha0k8/HWLBcLWlli28DXzLLC90hLL/3FAmCYSN9vNUFWA2PYSnXcWsCx g5FjFqFGcWlSWWqRrZKyXVJSZnlGSm5iZo2toYKqXm1pcnJiempOYVKyXnJ+7iREYrPUMDIw7 GHe0+x1ilORgUhLlLf9xIkKILyk/pTIjsTgjvqg0J7X4EKMMB4eSBO9/sZMRQoJFqempFWmZO cC4gUlLcPAoifCWgKR5iwsSc4sz0yFSpxh1OebM3v2GSYglLz8vVUqcdw1IkQBIUUZpHtwIWA xfYpSVEuZlZGBgEOIpSC3KzSxBlX/FKM7BqCTMuwtkCk9mXgncpldARzABHfH2wwmQI0oSEVJ SDYxCvWElWz2er9YSXGmmd+Bgx4WZ85gmPa1feuI62xynx47xz74seSSxmTmOVWBhk5jbKzWu Zvv786ZFsmZGtJ7sELfbLX3aqmT/xk2HVtjfnrBaQHPZ0nXHpkcxssdrLU0QP/LBeIJeka23t oVFdAzTk/c6WWcqfvO1v7SSSVm8aaOtAoegt4USS3FGoqEWc1FxIgDNPrID3AIAAA== X-Env-Sender: JBeulich@suse.com X-Msg-Ref: server-6.tower-206.messagelabs.com!1489573795!89348317!1 X-Originating-IP: [137.65.248.74] X-SpamReason: No, hits=0.5 required=7.0 tests=BODY_RANDOM_LONG X-StarScan-Received: X-StarScan-Version: 9.2.3; banners=-,-,- X-VirusChecked: Checked Received: (qmail 31284 invoked from network); 15 Mar 2017 10:29:57 -0000 Received: from prv-mh.provo.novell.com (HELO prv-mh.provo.novell.com) (137.65.248.74) by server-6.tower-206.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 15 Mar 2017 10:29:57 -0000 Received: from INET-PRV-MTA by prv-mh.provo.novell.com with Novell_GroupWise; Wed, 15 Mar 2017 04:29:55 -0600 Message-Id: <58C925B102000078001433B8@prv-mh.provo.novell.com> X-Mailer: Novell GroupWise Internet Agent 14.2.1 Date: Wed, 15 Mar 2017 04:29:53 -0600 From: "Jan Beulich" To: "Andrew Cooper" References: <58C924240200007800143399@prv-mh.provo.novell.com> <58C924240200007800143399@prv-mh.provo.novell.com> In-Reply-To: <58C924240200007800143399@prv-mh.provo.novell.com> Mime-Version: 1.0 Cc: xen-devel Subject: [Xen-devel] [PATCH v2][XTF] add FPU/SIMD register state test X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP 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 --- v2: Introduce and use x87.h. Tolerate VCVTPS2PH misbehavior on Intel hardware. Tolerate AMD oddities in probe_fstp() and probe_fistp(). 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 (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 --- v2: Introduce and use x87.h. Tolerate VCVTPS2PH misbehavior on Intel hardware. Tolerate AMD oddities in probe_fstp() and probe_fistp(). --- a/include/arch/x86/cpuid.h +++ b/include/arch/x86/cpuid.h @@ -77,6 +77,7 @@ static inline bool cpu_has(unsigned int #define cpu_has_pcid cpu_has(X86_FEATURE_PCID) #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/include/arch/x86/x87.h @@ -0,0 +1,27 @@ +#ifndef XTF_X86_X87_H +#define XTF_X86_X87_H + +#include + +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/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,212 @@ +/** + * @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 + +#include +#include + +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) ); + + 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) ); + + 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: + */ --- a/include/arch/x86/cpuid.h +++ b/include/arch/x86/cpuid.h @@ -77,6 +77,7 @@ static inline bool cpu_has(unsigned int #define cpu_has_pcid cpu_has(X86_FEATURE_PCID) #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/include/arch/x86/x87.h @@ -0,0 +1,27 @@ +#ifndef XTF_X86_X87_H +#define XTF_X86_X87_H + +#include + +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/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,212 @@ +/** + * @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 + +#include +#include + +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) ); + + 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) ); + + 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: + */