diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-06-25 01:20:01 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-06-25 01:20:01 +0000 |
commit | 3797ba0b62debb71af4606910acacc9896a9ae3b (patch) | |
tree | 414eea76253c7871bfdf3bd9d1817771eb40917c /arch/ia64/ia32/ia32_traps.c | |
parent | 2b6c0c580795a4404f72d2a794214dd9e080709d (diff) |
Merge with Linux 2.4.0-test2.
Diffstat (limited to 'arch/ia64/ia32/ia32_traps.c')
-rw-r--r-- | arch/ia64/ia32/ia32_traps.c | 83 |
1 files changed, 80 insertions, 3 deletions
diff --git a/arch/ia64/ia32/ia32_traps.c b/arch/ia64/ia32/ia32_traps.c index de99a65b3..2cfc9ae02 100644 --- a/arch/ia64/ia32/ia32_traps.c +++ b/arch/ia64/ia32/ia32_traps.c @@ -1,3 +1,9 @@ +/* + * IA32 exceptions handler + * + * 06/16/00 A. Mallick added siginfo for most cases (close to IA32) + */ + #include <linux/kernel.h> #include <linux/sched.h> @@ -9,9 +15,11 @@ ia32_exception (struct pt_regs *regs, unsigned long isr) { struct siginfo siginfo; + siginfo.si_errno = 0; switch ((isr >> 16) & 0xff) { case 1: case 2: + siginfo.si_signo = SIGTRAP; if (isr == 0) siginfo.si_code = TRAP_TRACE; else if (isr & 0x4) @@ -21,27 +29,96 @@ ia32_exception (struct pt_regs *regs, unsigned long isr) break; case 3: + siginfo.si_signo = SIGTRAP; siginfo.si_code = TRAP_BRKPT; break; case 0: /* Divide fault */ + siginfo.si_signo = SIGFPE; + siginfo.si_code = FPE_INTDIV; + break; + case 4: /* Overflow */ case 5: /* Bounds fault */ + siginfo.si_signo = SIGFPE; + siginfo.si_code = 0; + break; + case 6: /* Invalid Op-code */ + siginfo.si_signo = SIGILL; + siginfo.si_code = ILL_ILLOPN; + break; + case 7: /* FP DNA */ case 8: /* Double Fault */ case 9: /* Invalid TSS */ case 11: /* Segment not present */ case 12: /* Stack fault */ case 13: /* General Protection Fault */ + siginfo.si_signo = SIGSEGV; + siginfo.si_code = 0; + break; + case 16: /* Pending FP error */ + { + unsigned long fsr, fcr; + + asm ("mov %0=ar.fsr;" + "mov %1=ar.fcr;" + : "=r"(fsr), "=r"(fcr)); + + siginfo.si_signo = SIGFPE; + /* + * (~cwd & swd) will mask out exceptions that are not set to unmasked + * status. 0x3f is the exception bits in these regs, 0x200 is the + * C1 reg you need in case of a stack fault, 0x040 is the stack + * fault bit. We should only be taking one exception at a time, + * so if this combination doesn't produce any single exception, + * then we have a bad program that isn't syncronizing its FPU usage + * and it will suffer the consequences since we won't be able to + * fully reproduce the context of the exception + */ + switch(((~fcr) & (fsr & 0x3f)) | (fsr & 0x240)) { + case 0x000: + default: + siginfo.si_code = 0; + break; + case 0x001: /* Invalid Op */ + case 0x040: /* Stack Fault */ + case 0x240: /* Stack Fault | Direction */ + siginfo.si_code = FPE_FLTINV; + break; + case 0x002: /* Denormalize */ + case 0x010: /* Underflow */ + siginfo.si_code = FPE_FLTUND; + break; + case 0x004: /* Zero Divide */ + siginfo.si_code = FPE_FLTDIV; + break; + case 0x008: /* Overflow */ + siginfo.si_code = FPE_FLTOVF; + break; + case 0x020: /* Precision */ + siginfo.si_code = FPE_FLTRES; + break; + } + + break; + } + case 17: /* Alignment check */ + siginfo.si_signo = SIGSEGV; + siginfo.si_code = BUS_ADRALN; + break; + case 19: /* SSE Numeric error */ + siginfo.si_signo = SIGFPE; + siginfo.si_code = 0; + break; + default: return -1; } - siginfo.si_signo = SIGTRAP; - siginfo.si_errno = 0; - send_sig_info(SIGTRAP, &siginfo, current); + force_sig_info(SIGTRAP, &siginfo, current); return 0; } |