From b24de3ac40d551330d249a7bf4e5828876328d6f Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Mon, 29 Jun 2015 12:06:36 +0000 Subject: [PATCH] Provide npx_get_fsave(9) and npx_set_fsave(9) functions to obtain and restore the FPU state from the format of machine FSAVE area. The intended use is for ABI emulators to provide FSAVE-formatted FPU state to usermode requiring it, while kernel could use FXSAVE due to XMM/XSAVE. The core functionality to convert from/to FXSAVE format is shared with the fill_fpregs_xmm() and set_fpregs_xmm(). Move the later functions to npx.c and rename them to npx_fill_fpregs_xmm() and npx_set_fpregs_xmm(). They differ from nptx_get/set_fsave(9) since our mcontext contains padding to be zeroed or ignored. fill_fpregs() and set_fpregs() could be converted to use the new interface, but there are small differences to handle. Sponsored by: The FreeBSD Foundation MFC after: 1 week --- sys/i386/i386/machdep.c | 60 +------------------------- sys/i386/include/npx.h | 5 +++ sys/i386/isa/npx.c | 96 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 58 deletions(-) diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index f0a06a828513..e014a785f908 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -176,10 +176,6 @@ static void get_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpusave, size_t xfpusave_len); static int set_fpcontext(struct thread *td, mcontext_t *mcp, char *xfpustate, size_t xfpustate_len); -#ifdef CPU_ENABLE_SSE -static void set_fpregs_xmm(struct save87 *, struct savexmm *); -static void fill_fpregs_xmm(struct savexmm *, struct save87 *); -#endif /* CPU_ENABLE_SSE */ SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); /* Intel ICH registers */ @@ -2952,58 +2948,6 @@ set_regs(struct thread *td, struct reg *regs) return (0); } -#ifdef CPU_ENABLE_SSE -static void -fill_fpregs_xmm(sv_xmm, sv_87) - struct savexmm *sv_xmm; - struct save87 *sv_87; -{ - register struct env87 *penv_87 = &sv_87->sv_env; - register struct envxmm *penv_xmm = &sv_xmm->sv_env; - int i; - - bzero(sv_87, sizeof(*sv_87)); - - /* FPU control/status */ - penv_87->en_cw = penv_xmm->en_cw; - penv_87->en_sw = penv_xmm->en_sw; - penv_87->en_tw = penv_xmm->en_tw; - penv_87->en_fip = penv_xmm->en_fip; - penv_87->en_fcs = penv_xmm->en_fcs; - penv_87->en_opcode = penv_xmm->en_opcode; - penv_87->en_foo = penv_xmm->en_foo; - penv_87->en_fos = penv_xmm->en_fos; - - /* FPU registers */ - for (i = 0; i < 8; ++i) - sv_87->sv_ac[i] = sv_xmm->sv_fp[i].fp_acc; -} - -static void -set_fpregs_xmm(sv_87, sv_xmm) - struct save87 *sv_87; - struct savexmm *sv_xmm; -{ - register struct env87 *penv_87 = &sv_87->sv_env; - register struct envxmm *penv_xmm = &sv_xmm->sv_env; - int i; - - /* FPU control/status */ - penv_xmm->en_cw = penv_87->en_cw; - penv_xmm->en_sw = penv_87->en_sw; - penv_xmm->en_tw = penv_87->en_tw; - penv_xmm->en_fip = penv_87->en_fip; - penv_xmm->en_fcs = penv_87->en_fcs; - penv_xmm->en_opcode = penv_87->en_opcode; - penv_xmm->en_foo = penv_87->en_foo; - penv_xmm->en_fos = penv_87->en_fos; - - /* FPU registers */ - for (i = 0; i < 8; ++i) - sv_xmm->sv_fp[i].fp_acc = sv_87->sv_ac[i]; -} -#endif /* CPU_ENABLE_SSE */ - int fill_fpregs(struct thread *td, struct fpreg *fpregs) { @@ -3018,7 +2962,7 @@ fill_fpregs(struct thread *td, struct fpreg *fpregs) #endif #ifdef CPU_ENABLE_SSE if (cpu_fxsr) - fill_fpregs_xmm(&get_pcb_user_save_td(td)->sv_xmm, + npx_fill_fpregs_xmm(&get_pcb_user_save_td(td)->sv_xmm, (struct save87 *)fpregs); else #endif /* CPU_ENABLE_SSE */ @@ -3033,7 +2977,7 @@ set_fpregs(struct thread *td, struct fpreg *fpregs) #ifdef CPU_ENABLE_SSE if (cpu_fxsr) - set_fpregs_xmm((struct save87 *)fpregs, + npx_set_fpregs_xmm((struct save87 *)fpregs, &get_pcb_user_save_td(td)->sv_xmm); else #endif /* CPU_ENABLE_SSE */ diff --git a/sys/i386/include/npx.h b/sys/i386/include/npx.h index 66f432aa7ebc..05572285cde2 100644 --- a/sys/i386/include/npx.h +++ b/sys/i386/include/npx.h @@ -67,6 +67,11 @@ void npxsuspend(union savefpu *addr); int npxtrap_x87(void); int npxtrap_sse(void); void npxuserinited(struct thread *); +void npx_get_fsave(void *); +int npx_set_fsave(void *); +void npx_fill_fpregs_xmm(struct savexmm *, struct save87 *); +void npx_set_fpregs_xmm(struct save87 *, struct savexmm *); + struct fpu_kern_ctx *fpu_kern_alloc_ctx(u_int flags); void fpu_kern_free_ctx(struct fpu_kern_ctx *ctx); int fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c index a7113e20da27..61356cc22738 100644 --- a/sys/i386/isa/npx.c +++ b/sys/i386/isa/npx.c @@ -1159,6 +1159,102 @@ fpusave(addr) fnsave(addr); } +#ifdef CPU_ENABLE_SSE +static void +npx_fill_fpregs_xmm1(struct savexmm *sv_xmm, struct save87 *sv_87) +{ + struct env87 *penv_87; + struct envxmm *penv_xmm; + int i; + + penv_87 = &sv_87->sv_env; + penv_xmm = &sv_xmm->sv_env; + + /* FPU control/status */ + penv_87->en_cw = penv_xmm->en_cw; + penv_87->en_sw = penv_xmm->en_sw; + penv_87->en_tw = penv_xmm->en_tw; + penv_87->en_fip = penv_xmm->en_fip; + penv_87->en_fcs = penv_xmm->en_fcs; + penv_87->en_opcode = penv_xmm->en_opcode; + penv_87->en_foo = penv_xmm->en_foo; + penv_87->en_fos = penv_xmm->en_fos; + + /* FPU registers */ + for (i = 0; i < 8; ++i) + sv_87->sv_ac[i] = sv_xmm->sv_fp[i].fp_acc; +} + +void +npx_fill_fpregs_xmm(struct savexmm *sv_xmm, struct save87 *sv_87) +{ + + bzero(sv_87, sizeof(*sv_87)); + npx_fill_fpregs_xmm1(sv_xmm, sv_87); +} + +void +npx_set_fpregs_xmm(struct save87 *sv_87, struct savexmm *sv_xmm) +{ + struct env87 *penv_87; + struct envxmm *penv_xmm; + int i; + + penv_87 = &sv_87->sv_env; + penv_xmm = &sv_xmm->sv_env; + + /* FPU control/status */ + penv_xmm->en_cw = penv_87->en_cw; + penv_xmm->en_sw = penv_87->en_sw; + penv_xmm->en_tw = penv_87->en_tw; + penv_xmm->en_fip = penv_87->en_fip; + penv_xmm->en_fcs = penv_87->en_fcs; + penv_xmm->en_opcode = penv_87->en_opcode; + penv_xmm->en_foo = penv_87->en_foo; + penv_xmm->en_fos = penv_87->en_fos; + + /* FPU registers */ + for (i = 0; i < 8; ++i) + sv_xmm->sv_fp[i].fp_acc = sv_87->sv_ac[i]; +} +#endif /* CPU_ENABLE_SSE */ + +void +npx_get_fsave(void *addr) +{ + struct thread *td; + union savefpu *sv; + + td = curthread; + npxgetregs(td); + sv = get_pcb_user_save_td(td); +#ifdef CPU_ENABLE_SSE + if (cpu_fxsr) + npx_fill_fpregs_xmm1(&sv->sv_xmm, addr); + else +#endif + bcopy(sv, addr, sizeof(struct env87) + + sizeof(struct fpacc87[8])); +} + +int +npx_set_fsave(void *addr) +{ + union savefpu sv; + int error; + + bzero(&sv, sizeof(sv)); +#ifdef CPU_ENABLE_SSE + if (cpu_fxsr) + npx_set_fpregs_xmm(addr, &sv.sv_xmm); + else +#endif + bcopy(addr, &sv, sizeof(struct env87) + + sizeof(struct fpacc87[8])); + error = npxsetregs(curthread, &sv, NULL, 0); + return (error); +} + #ifdef CPU_ENABLE_SSE /* * On AuthenticAMD processors, the fxrstor instruction does not restore