x86 FP exception/error parsing
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 23 Apr 2013 23:52:15 +0000 (16:52 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 24 Apr 2013 22:19:10 +0000 (15:19 -0700)
We don't handle any FP errors in software, but we will tell you why we
killed your program!  (These errors are more likely due to system
software not restoring your FPU state properly).

kern/arch/i686/trap.c
kern/arch/i686/trap.h

index 29e9794..45330b3 100644 (file)
@@ -253,6 +253,43 @@ static void fake_rdtscp(struct hw_trapframe *hw_tf)
        hw_tf->tf_regs.reg_ecx = core_id();
 }
 
+static void handle_fperr(struct hw_trapframe *hw_tf)
+{
+       uint16_t fpcw, fpsw;
+       uint32_t mxcsr;
+       asm volatile ("fnstcw %0" : "=m"(fpcw));
+       asm volatile ("fnstsw %0" : "=m"(fpsw));
+       asm volatile ("stmxcsr %0" : "=m"(mxcsr));
+       print_trapframe(hw_tf);
+       printk("Core %d: FP ERR, CW: 0x%04x, SW: 0x%04x, MXCSR 0x%08x\n", core_id(),
+              fpcw, fpsw, mxcsr);
+       printk("Core %d: The following faults are unmasked:\n", core_id());
+       if (fpsw & ~fpcw & FP_EXCP_IE) {
+               printk("\tInvalid Operation: ");
+               if (fpsw & FP_SW_SF) {
+                       if (fpsw & FP_SW_C1)
+                               printk("Stack overflow\n");
+                       else
+                               printk("Stack underflow\n");
+               } else {
+                       printk("invalid arithmetic operand\n");
+               }
+       }
+       if (fpsw & ~fpcw & FP_EXCP_DE)
+               printk("\tDenormalized operand\n");
+       if (fpsw & ~fpcw & FP_EXCP_ZE)
+               printk("\tDivide by zero\n");
+       if (fpsw & ~fpcw & FP_EXCP_OE)
+               printk("\tNumeric Overflow\n");
+       if (fpsw & ~fpcw & FP_EXCP_UE)
+               printk("\tNumeric Underflow\n");
+       if (fpsw & ~fpcw & FP_EXCP_PE)
+               printk("\tInexact result (precision)\n");
+       printk("Killing the process.\n");
+       enable_irq();
+       proc_destroy(current);
+}
+
 /* Certain traps want IRQs enabled, such as the syscall.  Others can't handle
  * it, like the page fault handler.  Turn them on on a case-by-case basis. */
 static void trap_dispatch(struct hw_trapframe *hw_tf)
@@ -306,6 +343,9 @@ static void trap_dispatch(struct hw_trapframe *hw_tf)
                case T_PGFLT:
                        page_fault_handler(hw_tf);
                        break;
+               case T_FPERR:
+                       handle_fperr(hw_tf);
+                       break;
                case T_SYSCALL:
                        enable_irq();
                        // check for userspace, for now
index b1d179e..5163f5c 100644 (file)
 #define PF_ERROR_WRITE                         0x02
 #define PF_ERROR_USER                  0x04
 
+/* Floating point constants */
+#define FP_EXCP_IE                             (1 << 0)        /* invalid op */
+#define FP_EXCP_DE                             (1 << 1)        /* denormalized op */
+#define FP_EXCP_ZE                             (1 << 2)        /* div by zero */
+#define FP_EXCP_OE                             (1 << 3)        /* numeric overflow */
+#define FP_EXCP_UE                             (1 << 4)        /* numeric underflow */
+#define FP_EXCP_PE                             (1 << 5)        /* precision */
+
+#define FP_SW_SF                               (1 << 6)        /* stack fault */
+#define FP_SW_ES                               (1 << 7)        /* error summary status */
+#define FP_SW_C0                               (1 << 8)        /* condition codes */
+#define FP_SW_C1                               (1 << 9)
+#define FP_SW_C2                               (1 << 10)
+#define FP_SW_C3                               (1 << 14)
+#define FP_CW_TOP_SHIFT                        (11)
+#define FP_CW_TOP_MASK                 (7 << FP_CW_TOP_SHIFT)
+
+#define FP_CW_PC_SHIFT                 (8)
+#define FP_CW_PC_MASK                  (3 << FP_CW_PC_SHIFT)
+#define FP_CW_RC_SHIFT                 (10)
+#define FP_CW_RC_MASK                  (3 << FP_CW_RC_SHIFT)
+#define FP_CW_IC                               (1 << 12)
+
 /* IPIs */
 /* Testing IPI (used in testing.c) */
 #define I_TESTING              230