summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2015-06-29 12:06:36 +0000
committerkib <kib@FreeBSD.org>2015-06-29 12:06:36 +0000
commit623bffc36388de5d5ea6e20d990ba183e36ceb47 (patch)
treee9b0f95911a064282e73cae6af237abbda404d74
parent67042ee4424a0596a3848a68d5576b81daf0b21c (diff)
downloadFreeBSD-src-623bffc36388de5d5ea6e20d990ba183e36ceb47.zip
FreeBSD-src-623bffc36388de5d5ea6e20d990ba183e36ceb47.tar.gz
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
-rw-r--r--sys/i386/i386/machdep.c60
-rw-r--r--sys/i386/include/npx.h5
-rw-r--r--sys/i386/isa/npx.c96
3 files changed, 103 insertions, 58 deletions
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index f0a06a8..e014a78 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 66f432a..0557228 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 a7113e2..61356cc 100644
--- a/sys/i386/isa/npx.c
+++ b/sys/i386/isa/npx.c
@@ -1160,6 +1160,102 @@ fpusave(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
* the x87's stored last instruction pointer, last data pointer, and last
OpenPOWER on IntegriCloud