aboutsummaryrefslogtreecommitdiff
path: root/arch/ia64/ia32/ia32_traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ia64/ia32/ia32_traps.c')
-rw-r--r--arch/ia64/ia32/ia32_traps.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/arch/ia64/ia32/ia32_traps.c b/arch/ia64/ia32/ia32_traps.c
new file mode 100644
index 00000000000..e486042672f
--- /dev/null
+++ b/arch/ia64/ia32/ia32_traps.c
@@ -0,0 +1,156 @@
+/*
+ * IA-32 exception handlers
+ *
+ * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 2001-2002 Hewlett-Packard Co
+ * David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * 06/16/00 A. Mallick added siginfo for most cases (close to IA32)
+ * 09/29/00 D. Mosberger added ia32_intercept()
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include "ia32priv.h"
+
+#include <asm/intrinsics.h>
+#include <asm/ptrace.h>
+
+int
+ia32_intercept (struct pt_regs *regs, unsigned long isr)
+{
+ switch ((isr >> 16) & 0xff) {
+ case 0: /* Instruction intercept fault */
+ case 4: /* Locked Data reference fault */
+ case 1: /* Gate intercept trap */
+ return -1;
+
+ case 2: /* System flag trap */
+ if (((isr >> 14) & 0x3) >= 2) {
+ /* MOV SS, POP SS instructions */
+ ia64_psr(regs)->id = 1;
+ return 0;
+ } else
+ return -1;
+ }
+ return -1;
+}
+
+int
+ia32_exception (struct pt_regs *regs, unsigned long isr)
+{
+ struct siginfo siginfo;
+
+ /* initialize these fields to avoid leaking kernel bits to user space: */
+ siginfo.si_errno = 0;
+ siginfo.si_flags = 0;
+ siginfo.si_isr = 0;
+ siginfo.si_imm = 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)
+ siginfo.si_code = TRAP_BRANCH;
+ else
+ siginfo.si_code = TRAP_BRKPT;
+ 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;
+
+ fsr = ia64_getreg(_IA64_REG_AR_FSR);
+ fcr = ia64_getreg(_IA64_REG_AR_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 synchronizing its FPU usage
+ * and it will suffer the consequences since we won't be able to
+ * fully reproduce the context of the exception
+ */
+ siginfo.si_isr = isr;
+ siginfo.si_flags = __ISR_VALID;
+ 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;
+ }
+ force_sig_info(siginfo.si_signo, &siginfo, current);
+ return 0;
+}