Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/amd64/amd64 Steal the table from i386/isa/npx.c tha...
details: https://anonhg.NetBSD.org/src/rev/28db58015cf9
branches: trunk
changeset: 326655:28db58015cf9
user: dsl <dsl%NetBSD.org@localhost>
date: Sun Feb 09 23:02:25 2014 +0000
description:
Steal the table from i386/isa/npx.c than selects the highest priority
floating point error when raising a signal.
Multiple errors bits can easily be set if different sub-fields of an
xmm simd operation generate different errors.
diffstat:
sys/arch/amd64/amd64/fpu.c | 106 +++++++++++++++++++++++++++++++++-----------
1 files changed, 80 insertions(+), 26 deletions(-)
diffs (138 lines):
diff -r b8cd77a2ceec -r 28db58015cf9 sys/arch/amd64/amd64/fpu.c
--- a/sys/arch/amd64/amd64/fpu.c Sun Feb 09 22:47:04 2014 +0000
+++ b/sys/arch/amd64/amd64/fpu.c Sun Feb 09 23:02:25 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu.c,v 1.47 2014/02/09 22:19:02 dsl Exp $ */
+/* $NetBSD: fpu.c,v 1.48 2014/02/09 23:02:25 dsl Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc. All
@@ -100,7 +100,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.47 2014/02/09 22:19:02 dsl Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.48 2014/02/09 23:02:25 dsl Exp $");
#include "opt_multiprocessor.h"
@@ -144,7 +144,83 @@
*/
void fpudna(struct cpu_info *);
-static int x86fpflags_to_ksiginfo(uint32_t);
+
+/*
+ * The following table 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 SSE simd instructions generate errors
+ * on more than one value or if the user process modifies the control
+ * word while a status word bit is already set (which 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 code 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.
+ * 'Stack fault' is a sub-class of 'invalid operation'.
+ * 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)
+ *
+ * NB: the above seems to mix up the mxscr error bits and the x87 ones.
+ * They are in the same order, but there is no EN_SW_STACK_FAULT in the mmx
+ * status.
+ *
+ * The table is nearly, but not quite, in bit order (ZERODIV and DENORM
+ * are swapped).
+ *
+ * This table assumes that any stack fault is cleared - so that an INVOP
+ * fault will only be reported as FLTSUB once.
+ * This might not happen if the mask is being changed.
+ */
+#define FPE_xxx1(f) (f & EN_SW_INVOP \
+ ? (f & EN_SW_STACK_FAULT ? FPE_FLTSUB : FPE_FLTINV) \
+ : f & EN_SW_ZERODIV ? FPE_FLTDIV \
+ : f & EN_SW_DENORM ? FPE_FLTUND \
+ : f & EN_SW_OVERFLOW ? FPE_FLTOVF \
+ : f & EN_SW_UNDERFLOW ? FPE_FLTUND \
+ : f & EN_SW_PRECLOSS ? FPE_FLTRES \
+ : f & EN_SW_STACK_FAULT ? FPE_FLTSUB : 0)
+#define FPE_xxx2(f) FPE_xxx1(f), FPE_xxx1((f + 1))
+#define FPE_xxx4(f) FPE_xxx2(f), FPE_xxx2((f + 2))
+#define FPE_xxx8(f) FPE_xxx4(f), FPE_xxx4((f + 4))
+#define FPE_xxx16(f) FPE_xxx8(f), FPE_xxx8((f + 8))
+#define FPE_xxx32(f) FPE_xxx16(f), FPE_xxx16((f + 16))
+static const uint8_t fpetable[128] = {
+ FPE_xxx32(0), FPE_xxx32(32), FPE_xxx32(64), FPE_xxx32(96)
+};
+#undef FPE_xxx1
+#undef FPE_xxx2
+#undef FPE_xxx4
+#undef FPE_xxx8
+#undef FPE_xxx16
+#undef FPE_xxx32
/*
* Init the FPU.
@@ -225,33 +301,11 @@
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGFPE;
ksi.ksi_addr = (void *)frame->tf_rip;
- ksi.ksi_code = x86fpflags_to_ksiginfo(statbits);
+ ksi.ksi_code = fpetable[statbits & 0x7f];
ksi.ksi_trap = statbits;
(*curlwp->l_proc->p_emul->e_trapsignal)(curlwp, &ksi);
}
-static int
-x86fpflags_to_ksiginfo(uint32_t flags)
-{
- static int x86fp_ksiginfo_table[] = {
- FPE_FLTINV, /* bit 0 - invalid operation */
- FPE_FLTRES, /* bit 1 - denormal operand */
- FPE_FLTDIV, /* bit 2 - divide by zero */
- FPE_FLTOVF, /* bit 3 - fp overflow */
- FPE_FLTUND, /* bit 4 - fp underflow */
- FPE_FLTRES, /* bit 5 - fp precision */
- FPE_FLTINV, /* bit 6 - stack fault */
- };
-
- for (u_int i = 0; i < __arraycount(x86fp_ksiginfo_table); i++) {
- if (flags & (1U << i))
- return x86fp_ksiginfo_table[i];
- }
-
- /* Punt if flags not set. */
- return FPE_FLTINV;
-}
-
/*
* Implement device not available (DNA) exception
*
Home |
Main Index |
Thread Index |
Old Index