amd64/169927: siginfo,
si_code for fpe errors when error occurs using the SSE math
processor
Konstantin Belousov
kostikbel at gmail.com
Tue Jul 17 13:50:10 UTC 2012
The following reply was made to PR amd64/169927; it has been noted by GNATS.
From: Konstantin Belousov <kostikbel at gmail.com>
To: Bruce Evans <brde at optusnet.com.au>
Cc: Ed Alley <wea at llnl.gov>, freebsd-gnats-submit at freebsd.org,
freebsd-amd64 at freebsd.org
Subject: Re: amd64/169927: siginfo, si_code for fpe errors when error occurs using the SSE math processor
Date: Tue, 17 Jul 2012 16:44:26 +0300
--IJFRpmOek+ZRSQoz
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
It was on my TODO list for long time. Lets handle amd64 first, both for
native and compat32.
I think the following should be somewhat better variant. I do leave
the fnclex there for x87.
diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c
index a7812b7..34cf8d4 100644
--- a/sys/amd64/amd64/fpu.c
+++ b/sys/amd64/amd64/fpu.c
@@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
#define fxrstor(addr) __asm __volatile("fxrstor %0" : : "m" (*(addr)))
#define fxsave(addr) __asm __volatile("fxsave %0" : "=3Dm" (*(addr)))
#define ldmxcsr(csr) __asm __volatile("ldmxcsr %0" : : "m" (csr))
+#define stmxcsr(addr) __asm __volatile("stmxcsr %0" : : "m" (*(addr)))
=20
static __inline void
xrstor(char *addr, uint64_t mask)
@@ -105,6 +106,7 @@ void fnstsw(caddr_t addr);
void fxsave(caddr_t addr);
void fxrstor(caddr_t addr);
void ldmxcsr(u_int csr);
+void stmxcsr(u_int csr);
void xrstor(char *addr, uint64_t mask);
void xsave(char *addr, uint64_t mask);
=20
@@ -113,9 +115,6 @@ void xsave(char *addr, uint64_t mask);
#define start_emulating() load_cr0(rcr0() | CR0_TS)
#define stop_emulating() clts()
=20
-#define GET_FPU_CW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_cw)
-#define GET_FPU_SW(thread) ((thread)->td_pcb->pcb_save->sv_env.en_sw)
-
CTASSERT(sizeof(struct savefpu) =3D=3D 512);
CTASSERT(sizeof(struct xstate_hdr) =3D=3D 64);
CTASSERT(sizeof(struct savefpu_ymm) =3D=3D 832);
@@ -514,11 +513,15 @@ static char fpetable[128] =3D {
};
=20
/*
- * Preserve the FP status word, clear FP exceptions, then generate a SIGFP=
E.
+ * Preserve the FP status word, clear FP exceptions for x87, then
+ * generate a SIGFPE.
+ *
+ * Clearing exceptions was necessary mainly to avoid IRQ13 bugs and is
+ * engraved in our i386 ABI. We now depend on longjmp() restoring a
+ * usable state. Restoring the state or examining it might fail if we
+ * didn't clear exceptions.
*
- * Clearing exceptions is necessary mainly to avoid IRQ13 bugs. We now
- * depend on longjmp() restoring a usable state. Restoring the state
- * or examining it might fail if we didn't clear exceptions.
+ * For SSE exceptions, the exceptions are not cleared.
*
* The error code chosen will be one of the FPE_... macros. It will be
* sent as the second argument to old BSD-style signal handlers and as
@@ -531,8 +534,9 @@ static char fpetable[128] =3D {
* solution for signals other than SIGFPE.
*/
int
-fputrap()
+fputrap_x87(void)
{
+ struct savefpu *pcb_save;
u_short control, status;
=20
critical_enter();
@@ -543,19 +547,43 @@ fputrap()
* wherever they are.
*/
if (PCPU_GET(fpcurthread) !=3D curthread) {
- control =3D GET_FPU_CW(curthread);
- status =3D GET_FPU_SW(curthread);
+ pcb_save =3D curthread->td_pcb->pcb_save;
+ control =3D pcb_save->sv_env.en_cw;
+ status =3D pcb_save->sv_env.en_sw;
} else {
fnstcw(&control);
fnstsw(&status);
+ fnclex();
}
=20
- if (PCPU_GET(fpcurthread) =3D=3D curthread)
- fnclex();
critical_exit();
return (fpetable[status & ((~control & 0x3f) | 0x40)]);
}
=20
+int
+fputrap_sse(void)
+{
+ u_int mxcsr;
+ u_short control, status;
+
+ critical_enter();
+
+ /*
+ * Coomparing with the x87 #MF handler, we do not clear
+ * exceptions from the mxcsr.
+ */
+ if (PCPU_GET(fpcurthread) !=3D curthread)
+ mxcsr =3D curthread->td_pcb->pcb_save->sv_env.en_mxcsr;
+ else
+ stmxcsr(&mxcsr);
+
+ critical_exit();
+
+ status =3D mxcsr & 0x3f;
+ control =3D (mxcsr >> 16) & 0x3f;
+ return (fpetable[status & (~control | 0x40)]);
+}
+
/*
* Implement device not available (DNA) exception
*
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index 75e15e0..57d1cc2 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -328,7 +328,7 @@ trap(struct trapframe *frame)
break;
=20
case T_ARITHTRAP: /* arithmetic trap */
- ucode =3D fputrap();
+ ucode =3D fputrap_x87();
if (ucode =3D=3D -1)
goto userout;
i =3D SIGFPE;
@@ -442,7 +442,9 @@ trap(struct trapframe *frame)
break;
=20
case T_XMMFLT: /* SIMD floating-point exception */
- ucode =3D 0; /* XXX */
+ ucode =3D fputrap_sse();
+ if (ucode =3D=3D -1)
+ goto userout;
i =3D SIGFPE;
break;
}
diff --git a/sys/amd64/include/fpu.h b/sys/amd64/include/fpu.h
index 98a016b..7d0f0ea 100644
--- a/sys/amd64/include/fpu.h
+++ b/sys/amd64/include/fpu.h
@@ -62,7 +62,8 @@ int fpusetregs(struct thread *td, struct savefpu *addr,
char *xfpustate, size_t xfpustate_size);
int fpusetxstate(struct thread *td, char *xfpustate,
size_t xfpustate_size);
-int fputrap(void);
+int fputrap_sse(void);
+int fputrap_x87(void);
void fpuuserinited(struct thread *td);
struct fpu_kern_ctx *fpu_kern_alloc_ctx(u_int flags);
void fpu_kern_free_ctx(struct fpu_kern_ctx *ctx);
--IJFRpmOek+ZRSQoz
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (FreeBSD)
iEYEARECAAYFAlAFbDkACgkQC3+MBN1Mb4gPfgCeI7OF9u6tfuHgPoVp/bUfG1kc
iksAn1q9GtduJNGtll0dZd2X336LRijE
=kkdY
-----END PGP SIGNATURE-----
--IJFRpmOek+ZRSQoz--
More information about the freebsd-amd64
mailing list