From 1a81958928f07b45f170427647876ba5d49f9fb9 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 6 Mar 2018 13:42:36 +0000 Subject: [PATCH] tests/x86emul: Helpers to save and restore FPU state Introduce common helpers for saving and restoring FPU state. During emul_test_init(), calculate whether to use xsave or fxsave, and tweak the existing mxcsr_mask logic to avoid using another large static buffer. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich --- tools/tests/x86_emulator/x86-emulate.c | 72 +++++++++++++++++++++----- tools/tests/x86_emulator/x86-emulate.h | 4 ++ 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/tools/tests/x86_emulator/x86-emulate.c b/tools/tests/x86_emulator/x86-emulate.c index 9056610907..c731ba4f8e 100644 --- a/tools/tests/x86_emulator/x86-emulate.c +++ b/tools/tests/x86_emulator/x86-emulate.c @@ -26,26 +26,70 @@ uint32_t mxcsr_mask = 0x0000ffbf; +static char fpu_save_area[4096] __attribute__((__aligned__((64)))); +static bool use_xsave; + +void emul_save_fpu_state(void) +{ + if ( use_xsave ) + asm volatile ( "xsave %[ptr]" + : [ptr] "=m" (fpu_save_area) + : "a" (~0ul), "d" (~0ul) ); + else + asm volatile ( "fxsave %0" : "=m" (fpu_save_area) ); +} + +void emul_restore_fpu_state(void) +{ + /* Older gcc can't deal with "m" array inputs; make them outputs instead. */ + if ( use_xsave ) + asm volatile ( "xrstor %[ptr]" + : [ptr] "+m" (fpu_save_area) + : "a" (~0ul), "d" (~0ul) ); + else + asm volatile ( "fxrstor %0" : "+m" (fpu_save_area) ); +} + bool emul_test_init(void) { + union { + char x[464]; + struct { + uint32_t other[6]; + uint32_t mxcsr; + uint32_t mxcsr_mask; + /* ... */ + }; + } *fxs = (void *)fpu_save_area; + unsigned long sp; - if ( cpu_has_fxsr ) + if ( cpu_has_xsave ) { - static union __attribute__((__aligned__(16))) { - char x[464]; - struct { - uint32_t other[6]; - uint32_t mxcsr; - uint32_t mxcsr_mask; - /* ... */ - }; - } fxs; - - asm ( "fxsave %0" : "=m" (fxs) ); - if ( fxs.mxcsr_mask ) - mxcsr_mask = fxs.mxcsr_mask; + unsigned int tmp, ebx; + + asm ( "cpuid" + : "=a" (tmp), "=b" (ebx), "=c" (tmp), "=d" (tmp) + : "a" (0xd), "c" (0) ); + + /* + * Sanity check that fpu_save_area[] is large enough. This assertion + * will trip eventually, at which point fpu_save_area[] needs to get + * larger. + */ + assert(ebx < sizeof(fpu_save_area)); + + /* Use xsave if available... */ + use_xsave = true; } + else + /* But use fxsave if xsave isn't available. */ + assert(cpu_has_fxsr); + + /* Reuse the save state buffer to find mcxsr_mask. */ + asm ( "fxsave %0" : "=m" (*fxs) ); + if ( fxs->mxcsr_mask ) + mxcsr_mask = fxs->mxcsr_mask; /* * Mark the entire stack executable so that the stub executions diff --git a/tools/tests/x86_emulator/x86-emulate.h b/tools/tests/x86_emulator/x86-emulate.h index a1c47748d0..45acea495c 100644 --- a/tools/tests/x86_emulator/x86-emulate.h +++ b/tools/tests/x86_emulator/x86-emulate.h @@ -52,6 +52,10 @@ extern uint32_t mxcsr_mask; #define MMAP_SZ 16384 bool emul_test_init(void); +/* Must save and restore FPU state between any call into libc. */ +void emul_save_fpu_state(void); +void emul_restore_fpu_state(void); + #include "x86_emulate/x86_emulate.h" static inline uint64_t xgetbv(uint32_t xcr) -- 2.30.2