diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2015-03-21 20:42:39 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2015-03-21 20:42:39 +0000 |
commit | b8a02069f2ae5667457a451120a4a47cde3a0109 (patch) | |
tree | a0bf2ed5c5f4aaa7c917bda68b35df7dd988ff8c /sys | |
parent | bd6281f45e9398ee93925ee986b745ecf0dded96 (diff) |
Add support for saving/restoring FPU state using the XSAVE/XRSTOR. Limit
support to the X87, SSE and AVX state.
This gives us (almost) full AVX support. The AVX state isn't saved by
signal handlers yet, and ptrace(2) support is still missing.
ok guenther@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/cpu.c | 15 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/fpu.c | 52 | ||||
-rw-r--r-- | sys/arch/amd64/include/cpufunc.h | 12 | ||||
-rw-r--r-- | sys/arch/amd64/include/fpu.h | 11 | ||||
-rw-r--r-- | sys/arch/amd64/include/specialreg.h | 9 |
5 files changed, 84 insertions, 15 deletions
diff --git a/sys/arch/amd64/amd64/cpu.c b/sys/arch/amd64/amd64/cpu.c index 3de99fce1de..1457db0e151 100644 --- a/sys/arch/amd64/amd64/cpu.c +++ b/sys/arch/amd64/amd64/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.79 2015/02/11 00:54:39 dlg Exp $ */ +/* $OpenBSD: cpu.c,v 1.80 2015/03/21 20:42:38 kettenis Exp $ */ /* $NetBSD: cpu.c,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */ /*- @@ -502,6 +502,8 @@ cpu_attach(struct device *parent, struct device *self, void *aux) void cpu_init(struct cpu_info *ci) { + extern uint64_t xsave_mask; + /* configure the CPU if needed */ if (ci->cpu_setup != NULL) (*ci->cpu_setup)(ci); @@ -519,6 +521,17 @@ cpu_init(struct cpu_info *ci) lcr4(rcr4() | CR4_SMAP); #endif + if (cpu_ecxfeature & CPUIDECX_XSAVE) { + u_int32_t eax, ebx, ecx, edx; + + lcr4(rcr4() | CR4_OSXSAVE); + xsave_mask = XCR0_X87 | XCR0_SSE; + CPUID_LEAF(0xd, 0, eax, ebx, ecx, edx); + if (eax & XCR0_AVX) + xsave_mask |= XCR0_AVX; + xsetbv(0, xsave_mask); + } + #ifdef MULTIPROCESSOR ci->ci_flags |= CPUF_RUNNING; tlbflushg(); diff --git a/sys/arch/amd64/amd64/fpu.c b/sys/arch/amd64/amd64/fpu.c index 4ebfdf0be6c..af905db0b33 100644 --- a/sys/arch/amd64/amd64/fpu.c +++ b/sys/arch/amd64/amd64/fpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fpu.c,v 1.30 2015/03/14 03:38:46 jsg Exp $ */ +/* $OpenBSD: fpu.c,v 1.31 2015/03/21 20:42:38 kettenis Exp $ */ /* $NetBSD: fpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ /*- @@ -84,6 +84,29 @@ #define clts() __asm("clts") #define stts() lcr0(rcr0() | CR0_TS) +uint64_t xsave_mask; + +static inline void +xsave(struct savefpu *addr, uint64_t mask) +{ + uint32_t lo, hi; + + lo = mask; + hi = mask >> 32; + __asm volatile("xsave %0" : "=m" (*addr) : "a" (lo), "d" (hi) : + "memory"); +} + +static inline void +xrstor(struct savefpu *addr, uint64_t mask) +{ + uint32_t lo, hi; + + lo = mask; + hi = mask >> 32; + __asm volatile("xrstor %0" : : "m" (*addr), "a" (lo), "d" (hi)); +} + void fpudna(struct cpu_info *); static int x86fpflags_to_siginfo(u_int32_t); @@ -253,15 +276,19 @@ fpudna(struct cpu_info *ci) fxrstor(&sfp->fp_fxsave); p->p_md.md_flags |= MDP_USEDFPU; } else { - static double zero = 0.0; - - /* - * amd fpu does not restore fip, fdp, fop on fxrstor - * thus leaking other process's execution history. - */ - fnclex(); - __asm volatile("ffree %%st(7)\n\tfldl %0" : : "m" (zero)); - fxrstor(sfp); + if (xsave_mask) { + xrstor(sfp, xsave_mask); + } else { + static double zero = 0.0; + + /* + * amd fpu does not restore fip, fdp, fop on fxrstor + * thus leaking other process's execution history. + */ + fnclex(); + __asm volatile("ffree %%st(7)\n\tfldl %0" : : "m" (zero)); + fxrstor(sfp); + } } } @@ -290,7 +317,10 @@ fpusave_cpu(struct cpu_info *ci, int save) */ clts(); ci->ci_fpsaving = 1; - fxsave(&p->p_addr->u_pcb.pcb_savefpu); + if (xsave_mask) + xsave(&p->p_addr->u_pcb.pcb_savefpu, xsave_mask); + else + fxsave(&p->p_addr->u_pcb.pcb_savefpu); ci->ci_fpsaving = 0; } diff --git a/sys/arch/amd64/include/cpufunc.h b/sys/arch/amd64/include/cpufunc.h index 23f1d51d6b9..b5eeacaec53 100644 --- a/sys/arch/amd64/include/cpufunc.h +++ b/sys/arch/amd64/include/cpufunc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpufunc.h,v 1.11 2014/03/29 18:09:28 guenther Exp $ */ +/* $OpenBSD: cpufunc.h,v 1.12 2015/03/21 20:42:38 kettenis Exp $ */ /* $NetBSD: cpufunc.h,v 1.3 2003/05/08 10:27:43 fvdl Exp $ */ /*- @@ -309,6 +309,16 @@ mwait(u_long extensions, u_int hints) __asm volatile("mwait" : : "a" (hints), "c" (extensions)); } +static __inline void +xsetbv(uint32_t reg, uint64_t mask) +{ + uint32_t lo, hi; + + lo = mask; + hi = mask >> 32; + __asm volatile("xsetbv" :: "c" (reg), "a" (lo), "d" (hi) : "memory"); +} + /* Break into DDB/KGDB. */ static __inline void breakpoint(void) diff --git a/sys/arch/amd64/include/fpu.h b/sys/arch/amd64/include/fpu.h index bda8f0521d0..54af4bb707d 100644 --- a/sys/arch/amd64/include/fpu.h +++ b/sys/arch/amd64/include/fpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: fpu.h,v 1.9 2011/03/23 16:54:34 pirofti Exp $ */ +/* $OpenBSD: fpu.h,v 1.10 2015/03/21 20:42:38 kettenis Exp $ */ /* $NetBSD: fpu.h,v 1.1 2003/04/26 18:39:40 fvdl Exp $ */ #ifndef _MACHINE_FPU_H_ @@ -28,8 +28,17 @@ struct fxsave64 { u_int8_t fx_unused3[96]; } __packed; +struct xstate_hdr { + uint64_t xstate_bv; + uint64_t xstate_xcomp_bv; + uint8_t xstate_rsrv0[0]; + uint8_t xstate_rsrv[40]; +} __packed; + struct savefpu { struct fxsave64 fp_fxsave; /* see above */ + struct xstate_hdr fp_xstate; + u_int64_t fp_ymm[16][2]; u_int16_t fp_ex_sw; /* saved status from last exception */ u_int16_t fp_ex_tw; /* saved tag from last exception */ }; diff --git a/sys/arch/amd64/include/specialreg.h b/sys/arch/amd64/include/specialreg.h index f35fcdeaddf..f10ced1bae5 100644 --- a/sys/arch/amd64/include/specialreg.h +++ b/sys/arch/amd64/include/specialreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: specialreg.h,v 1.32 2015/01/19 16:01:43 jsg Exp $ */ +/* $OpenBSD: specialreg.h,v 1.33 2015/03/21 20:42:38 kettenis Exp $ */ /* $NetBSD: specialreg.h,v 1.1 2003/04/26 18:39:48 fvdl Exp $ */ /* $NetBSD: x86/specialreg.h,v 1.2 2003/04/25 21:54:30 fvdl Exp $ */ @@ -92,6 +92,13 @@ #define CR4_SMAP 0x00200000 /* supervisor mode access prevention */ /* + * Extended Control Register XCR0 + */ +#define XCR0_X87 0x00000001 /* x87 FPU/MMX state */ +#define XCR0_SSE 0x00000002 /* SSE state */ +#define XCR0_AVX 0x00000004 /* AVX state */ + +/* * CPUID "features" bits (CPUID function 0x1): * EDX bits, then ECX bits */ |