diff options
author | cracauer <cracauer@FreeBSD.org> | 1999-07-25 13:16:09 +0000 |
---|---|---|
committer | cracauer <cracauer@FreeBSD.org> | 1999-07-25 13:16:09 +0000 |
commit | 36a7b829a04919c4ca14a6e4fe1bf3797c135a82 (patch) | |
tree | 8748ed38e03651976646062add8e82dac5601f42 /sys/i386/isa/npx.c | |
parent | 1c17b991d77a8dc353f1efc23d293b80176cb18b (diff) | |
download | FreeBSD-src-36a7b829a04919c4ca14a6e4fe1bf3797c135a82.zip FreeBSD-src-36a7b829a04919c4ca14a6e4fe1bf3797c135a82.tar.gz |
On FPU exceptions, pass a useful error code (one of the FPE_...
macros) to the signal handler, for old-style BSD signal handlers as
the second (int) argument, for SA_SIGINFO signal handlers as
siginfo_t->si_code. This is source-compatible with Solaris, except
that we have no <siginfo.h> (which isn't even mentioned in POSIX
1003.1b).
An rather complete example program is at
http://www3.cons.org/cracauer/freebsd-signal.c
This will be added to the regression tests in src/.
This commit also adds code to disable the (hardware) FPU from
userconfig, so that you can use a software FP emulator on a machine
that has hardware floating point. See LINT.
Diffstat (limited to 'sys/i386/isa/npx.c')
-rw-r--r-- | sys/i386/isa/npx.c | 226 |
1 files changed, 202 insertions, 24 deletions
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c index ce4a077..2f2709d 100644 --- a/sys/i386/isa/npx.c +++ b/sys/i386/isa/npx.c @@ -32,7 +32,7 @@ * SUCH DAMAGE. * * from: @(#)npx.c 7.2 (Berkeley) 5/12/91 - * $Id: npx.c,v 1.72 1999/05/11 16:29:18 luoqi Exp $ + * $Id: npx.c,v 1.73 1999/05/15 17:58:58 peter Exp $ */ #include "npx.h" @@ -86,6 +86,7 @@ #define NPX_DISABLE_I586_OPTIMIZED_BCOPY (1 << 0) #define NPX_DISABLE_I586_OPTIMIZED_BZERO (1 << 1) #define NPX_DISABLE_I586_OPTIMIZED_COPYIO (1 << 2) +#define NPX_PREFER_EMULATOR (1 << 3) #ifdef __GNUC__ @@ -396,34 +397,44 @@ int npx_attach(dev) device_t dev; { -#ifdef I586_CPU int flags; -#endif + + if (resource_int_value("npx", 0, "flags", &flags) != 0) + flags = 0; device_print_prettyname(dev); if (npx_irq13) { printf("using IRQ 13 interface\n"); } else { - if (npx_ex16) - printf("INT 16 interface\n"); #if defined(MATH_EMULATE) || defined(GPL_MATH_EMULATE) - else if (npx_exists) { + if (npx_ex16) { + if (!(flags & NPX_PREFER_EMULATOR)) + printf("INT 16 interface\n"); + else { + printf("FPU exists, but flags request " + "emulator\n"); + hw_float = npx_exists = 0; + } + } else if (npx_exists) { printf("error reporting broken; using 387 emulator\n"); hw_float = npx_exists = 0; } else printf("387 emulator\n"); #else - else - printf("no 387 emulator in kernel!\n"); + if (npx_ex16) { + printf("INT 16 interface\n"); + if (flags & NPX_PREFER_EMULATOR) { + printf("emulator requested, but none compiled " + "into kernel, using FPU\n"); + } + } else + printf("no 387 emulator in kernel and no FPU!\n"); #endif } npxinit(__INITIAL_NPXCW__); #ifdef I586_CPU - if (resource_int_value("npx", 0, "flags", &flags) != 0) - flags = 0; - - if (cpu_class == CPUCLASS_586 && npx_ex16 && + if (cpu_class == CPUCLASS_586 && npx_ex16 && npx_exists && timezero("i586_bzero()", i586_bzero) < timezero("bzero()", bzero) * 4 / 5) { if (!(flags & NPX_DISABLE_I586_OPTIMIZED_BCOPY)) { @@ -494,6 +505,179 @@ npxexit(p) #endif } +/* + * The following mechanism is used to ensure that the FPE_... value + * that is passed as a trapcode to the signal handler of the user + * process does not have more than one bit set. + * + * Multiple bits may be set if the user process modifies the control + * word while a status word bit is already set. While this is a sign + * of bad coding, we have no choise than to narrow them down to one + * bit, since we must not send a trapcode that is not exactly one of + * the FPE_ macros. + * + * The mechanism has a static table with 127 entries. Each combination + * of the 7 FPU status word exception bits directly translates to a + * position in this table, where a single FPE_... value is stored. + * This FPE_... value stored there is considered the "most important" + * of the exception bits and will be sent as the signal code. The + * precedence of the bits is based upon Intel Document "Numerical + * Applications", Chapter "Special Computational Situations". + * + * The macro to choose one of these values does these steps: 1) Throw + * away status word bits that cannot be masked. 2) Throw away the bits + * currently masked in the control word, assuming the user isn't + * interested in them anymore. 3) Reinsert status word bit 7 (stack + * fault) if it is set, which cannot be masked but must be presered. + * 4) Use the remaining bits to point into the trapcode table. + * + * The 6 maskable bits in order of their preference, as stated in the + * above referenced Intel manual: + * 1 Invalid operation (FP_X_INV) + * 1a Stack underflow + * 1b Stack overflow + * 1c Operand of unsupported format + * 1d SNaN operand. + * 2 QNaN operand (not an exception, irrelavant here) + * 3 Any other invalid-operation not mentioned above or zero divide + * (FP_X_INV, FP_X_DZ) + * 4 Denormal operand (FP_X_DNML) + * 5 Numeric over/underflow (FP_X_OFL, FP_X_UFL) + * 6 Inexact result (FP_X_IMP) */ + +static char fpetable[128] = { + 0, + FPE_FLTINV, /* 1 - INV */ + FPE_FLTUND, /* 2 - DNML */ + FPE_FLTINV, /* 3 - INV | DNML */ + FPE_FLTDIV, /* 4 - DZ */ + FPE_FLTINV, /* 5 - INV | DZ */ + FPE_FLTDIV, /* 6 - DNML | DZ */ + FPE_FLTINV, /* 7 - INV | DNML | DZ */ + FPE_FLTOVF, /* 8 - OFL */ + FPE_FLTINV, /* 9 - INV | OFL */ + FPE_FLTUND, /* A - DNML | OFL */ + FPE_FLTINV, /* B - INV | DNML | OFL */ + FPE_FLTDIV, /* C - DZ | OFL */ + FPE_FLTINV, /* D - INV | DZ | OFL */ + FPE_FLTDIV, /* E - DNML | DZ | OFL */ + FPE_FLTINV, /* F - INV | DNML | DZ | OFL */ + FPE_FLTUND, /* 10 - UFL */ + FPE_FLTINV, /* 11 - INV | UFL */ + FPE_FLTUND, /* 12 - DNML | UFL */ + FPE_FLTINV, /* 13 - INV | DNML | UFL */ + FPE_FLTDIV, /* 14 - DZ | UFL */ + FPE_FLTINV, /* 15 - INV | DZ | UFL */ + FPE_FLTDIV, /* 16 - DNML | DZ | UFL */ + FPE_FLTINV, /* 17 - INV | DNML | DZ | UFL */ + FPE_FLTOVF, /* 18 - OFL | UFL */ + FPE_FLTINV, /* 19 - INV | OFL | UFL */ + FPE_FLTUND, /* 1A - DNML | OFL | UFL */ + FPE_FLTINV, /* 1B - INV | DNML | OFL | UFL */ + FPE_FLTDIV, /* 1C - DZ | OFL | UFL */ + FPE_FLTINV, /* 1D - INV | DZ | OFL | UFL */ + FPE_FLTDIV, /* 1E - DNML | DZ | OFL | UFL */ + FPE_FLTINV, /* 1F - INV | DNML | DZ | OFL | UFL */ + FPE_FLTRES, /* 20 - IMP */ + FPE_FLTINV, /* 21 - INV | IMP */ + FPE_FLTUND, /* 22 - DNML | IMP */ + FPE_FLTINV, /* 23 - INV | DNML | IMP */ + FPE_FLTDIV, /* 24 - DZ | IMP */ + FPE_FLTINV, /* 25 - INV | DZ | IMP */ + FPE_FLTDIV, /* 26 - DNML | DZ | IMP */ + FPE_FLTINV, /* 27 - INV | DNML | DZ | IMP */ + FPE_FLTOVF, /* 28 - OFL | IMP */ + FPE_FLTINV, /* 29 - INV | OFL | IMP */ + FPE_FLTUND, /* 2A - DNML | OFL | IMP */ + FPE_FLTINV, /* 2B - INV | DNML | OFL | IMP */ + FPE_FLTDIV, /* 2C - DZ | OFL | IMP */ + FPE_FLTINV, /* 2D - INV | DZ | OFL | IMP */ + FPE_FLTDIV, /* 2E - DNML | DZ | OFL | IMP */ + FPE_FLTINV, /* 2F - INV | DNML | DZ | OFL | IMP */ + FPE_FLTUND, /* 30 - UFL | IMP */ + FPE_FLTINV, /* 31 - INV | UFL | IMP */ + FPE_FLTUND, /* 32 - DNML | UFL | IMP */ + FPE_FLTINV, /* 33 - INV | DNML | UFL | IMP */ + FPE_FLTDIV, /* 34 - DZ | UFL | IMP */ + FPE_FLTINV, /* 35 - INV | DZ | UFL | IMP */ + FPE_FLTDIV, /* 36 - DNML | DZ | UFL | IMP */ + FPE_FLTINV, /* 37 - INV | DNML | DZ | UFL | IMP */ + FPE_FLTOVF, /* 38 - OFL | UFL | IMP */ + FPE_FLTINV, /* 39 - INV | OFL | UFL | IMP */ + FPE_FLTUND, /* 3A - DNML | OFL | UFL | IMP */ + FPE_FLTINV, /* 3B - INV | DNML | OFL | UFL | IMP */ + FPE_FLTDIV, /* 3C - DZ | OFL | UFL | IMP */ + FPE_FLTINV, /* 3D - INV | DZ | OFL | UFL | IMP */ + FPE_FLTDIV, /* 3E - DNML | DZ | OFL | UFL | IMP */ + FPE_FLTINV, /* 3F - INV | DNML | DZ | OFL | UFL | IMP */ + FPE_FLTSUB, /* 40 - STK */ + FPE_FLTSUB, /* 41 - INV | STK */ + FPE_FLTUND, /* 42 - DNML | STK */ + FPE_FLTSUB, /* 43 - INV | DNML | STK */ + FPE_FLTDIV, /* 44 - DZ | STK */ + FPE_FLTSUB, /* 45 - INV | DZ | STK */ + FPE_FLTDIV, /* 46 - DNML | DZ | STK */ + FPE_FLTSUB, /* 47 - INV | DNML | DZ | STK */ + FPE_FLTOVF, /* 48 - OFL | STK */ + FPE_FLTSUB, /* 49 - INV | OFL | STK */ + FPE_FLTUND, /* 4A - DNML | OFL | STK */ + FPE_FLTSUB, /* 4B - INV | DNML | OFL | STK */ + FPE_FLTDIV, /* 4C - DZ | OFL | STK */ + FPE_FLTSUB, /* 4D - INV | DZ | OFL | STK */ + FPE_FLTDIV, /* 4E - DNML | DZ | OFL | STK */ + FPE_FLTSUB, /* 4F - INV | DNML | DZ | OFL | STK */ + FPE_FLTUND, /* 50 - UFL | STK */ + FPE_FLTSUB, /* 51 - INV | UFL | STK */ + FPE_FLTUND, /* 52 - DNML | UFL | STK */ + FPE_FLTSUB, /* 53 - INV | DNML | UFL | STK */ + FPE_FLTDIV, /* 54 - DZ | UFL | STK */ + FPE_FLTSUB, /* 55 - INV | DZ | UFL | STK */ + FPE_FLTDIV, /* 56 - DNML | DZ | UFL | STK */ + FPE_FLTSUB, /* 57 - INV | DNML | DZ | UFL | STK */ + FPE_FLTOVF, /* 58 - OFL | UFL | STK */ + FPE_FLTSUB, /* 59 - INV | OFL | UFL | STK */ + FPE_FLTUND, /* 5A - DNML | OFL | UFL | STK */ + FPE_FLTSUB, /* 5B - INV | DNML | OFL | UFL | STK */ + FPE_FLTDIV, /* 5C - DZ | OFL | UFL | STK */ + FPE_FLTSUB, /* 5D - INV | DZ | OFL | UFL | STK */ + FPE_FLTDIV, /* 5E - DNML | DZ | OFL | UFL | STK */ + FPE_FLTSUB, /* 5F - INV | DNML | DZ | OFL | UFL | STK */ + FPE_FLTRES, /* 60 - IMP | STK */ + FPE_FLTSUB, /* 61 - INV | IMP | STK */ + FPE_FLTUND, /* 62 - DNML | IMP | STK */ + FPE_FLTSUB, /* 63 - INV | DNML | IMP | STK */ + FPE_FLTDIV, /* 64 - DZ | IMP | STK */ + FPE_FLTSUB, /* 65 - INV | DZ | IMP | STK */ + FPE_FLTDIV, /* 66 - DNML | DZ | IMP | STK */ + FPE_FLTSUB, /* 67 - INV | DNML | DZ | IMP | STK */ + FPE_FLTOVF, /* 68 - OFL | IMP | STK */ + FPE_FLTSUB, /* 69 - INV | OFL | IMP | STK */ + FPE_FLTUND, /* 6A - DNML | OFL | IMP | STK */ + FPE_FLTSUB, /* 6B - INV | DNML | OFL | IMP | STK */ + FPE_FLTDIV, /* 6C - DZ | OFL | IMP | STK */ + FPE_FLTSUB, /* 6D - INV | DZ | OFL | IMP | STK */ + FPE_FLTDIV, /* 6E - DNML | DZ | OFL | IMP | STK */ + FPE_FLTSUB, /* 6F - INV | DNML | DZ | OFL | IMP | STK */ + FPE_FLTUND, /* 70 - UFL | IMP | STK */ + FPE_FLTSUB, /* 71 - INV | UFL | IMP | STK */ + FPE_FLTUND, /* 72 - DNML | UFL | IMP | STK */ + FPE_FLTSUB, /* 73 - INV | DNML | UFL | IMP | STK */ + FPE_FLTDIV, /* 74 - DZ | UFL | IMP | STK */ + FPE_FLTSUB, /* 75 - INV | DZ | UFL | IMP | STK */ + FPE_FLTDIV, /* 76 - DNML | DZ | UFL | IMP | STK */ + FPE_FLTSUB, /* 77 - INV | DNML | DZ | UFL | IMP | STK */ + FPE_FLTOVF, /* 78 - OFL | UFL | IMP | STK */ + FPE_FLTSUB, /* 79 - INV | OFL | UFL | IMP | STK */ + FPE_FLTUND, /* 7A - DNML | OFL | UFL | IMP | STK */ + FPE_FLTSUB, /* 7B - INV | DNML | OFL | UFL | IMP | STK */ + FPE_FLTDIV, /* 7C - DZ | OFL | UFL | IMP | STK */ + FPE_FLTSUB, /* 7D - INV | DZ | OFL | UFL | IMP | STK */ + FPE_FLTDIV, /* 7E - DNML | DZ | OFL | UFL | IMP | STK */ + FPE_FLTSUB, /* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */ +}; + +#define ENCODE(_sw, _cw) (fpetable[(_sw & ~_cw & 0x3f) | (_sw & 0x40)]) + /* * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE. * @@ -501,13 +685,9 @@ npxexit(p) * depend on longjmp() restoring a usable state. Restoring the state * or examining it might fail if we didn't clear exceptions. * - * XXX there is no standard way to tell SIGFPE handlers about the error - * state. The old interface: - * - * void handler(int sig, int code, struct sigcontext *scp); - * - * is broken because it is non-ANSI and because the FP state is not in - * struct sigcontext. + * 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 + * "siginfo_t->si_code" (second argument) to SA_SIGINFO signal handlers. * * XXX the FP state is not preserved across signal handlers. So signal * handlers cannot afford to do FP unless they preserve the state or @@ -520,6 +700,7 @@ npx_intr(dummy) void *dummy; { int code; + u_long cw; struct intrframe *frame; if (npxproc == NULL || !npx_exists) { @@ -535,6 +716,7 @@ npx_intr(dummy) outb(0xf0, 0); fnstsw(&curpcb->pcb_savefpu.sv_ex_sw); + fnstcw(&cw); fnclex(); /* @@ -554,15 +736,11 @@ npx_intr(dummy) * just before it is used). */ curproc->p_md.md_regs = INTR_TO_TRAPFRAME(frame); -#ifdef notyet /* * Encode the appropriate code for detailed information on * this exception. */ - code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw); -#else - code = 0; /* XXX */ -#endif + code = ENCODE(curpcb->pcb_savefpu.sv_ex_sw, cw); trapsignal(curproc, SIGFPE, code); } else { /* |