1 /*
2 * IA-32 exception handlers
3 *
4 * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
5 * Copyright (C) 2001-2002 Hewlett-Packard Co
6 * David Mosberger-Tang <davidm@hpl.hp.com>
7 *
8 * 06/16/00 A. Mallick added siginfo for most cases (close to IA32)
9 * 09/29/00 D. Mosberger added ia32_intercept()
10 */
11
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14
15 #include <asm/ia32.h>
16 #include <asm/ptrace.h>
17
18 int
ia32_intercept(struct pt_regs * regs,unsigned long isr)19 ia32_intercept (struct pt_regs *regs, unsigned long isr)
20 {
21 switch ((isr >> 16) & 0xff) {
22 case 0: /* Instruction intercept fault */
23 case 4: /* Locked Data reference fault */
24 case 1: /* Gate intercept trap */
25 return -1;
26
27 case 2: /* System flag trap */
28 if (((isr >> 14) & 0x3) >= 2) {
29 /* MOV SS, POP SS instructions */
30 ia64_psr(regs)->id = 1;
31 return 0;
32 } else
33 return -1;
34 }
35 return -1;
36 }
37
38 int
ia32_exception(struct pt_regs * regs,unsigned long isr)39 ia32_exception (struct pt_regs *regs, unsigned long isr)
40 {
41 struct siginfo siginfo;
42
43 /* initialize these fields to avoid leaking kernel bits to user space: */
44 siginfo.si_errno = 0;
45 siginfo.si_flags = 0;
46 siginfo.si_isr = 0;
47 siginfo.si_imm = 0;
48 switch ((isr >> 16) & 0xff) {
49 case 1:
50 case 2:
51 siginfo.si_signo = SIGTRAP;
52 if (isr == 0)
53 siginfo.si_code = TRAP_TRACE;
54 else if (isr & 0x4)
55 siginfo.si_code = TRAP_BRANCH;
56 else
57 siginfo.si_code = TRAP_BRKPT;
58 break;
59
60 case 3:
61 siginfo.si_signo = SIGTRAP;
62 siginfo.si_code = TRAP_BRKPT;
63 break;
64
65 case 0: /* Divide fault */
66 siginfo.si_signo = SIGFPE;
67 siginfo.si_code = FPE_INTDIV;
68 break;
69
70 case 4: /* Overflow */
71 case 5: /* Bounds fault */
72 siginfo.si_signo = SIGFPE;
73 siginfo.si_code = 0;
74 break;
75
76 case 6: /* Invalid Op-code */
77 siginfo.si_signo = SIGILL;
78 siginfo.si_code = ILL_ILLOPN;
79 break;
80
81 case 7: /* FP DNA */
82 case 8: /* Double Fault */
83 case 9: /* Invalid TSS */
84 case 11: /* Segment not present */
85 case 12: /* Stack fault */
86 case 13: /* General Protection Fault */
87 siginfo.si_signo = SIGSEGV;
88 siginfo.si_code = 0;
89 break;
90
91 case 16: /* Pending FP error */
92 {
93 unsigned long fsr, fcr;
94
95 asm ("mov %0=ar.fsr;"
96 "mov %1=ar.fcr;"
97 : "=r"(fsr), "=r"(fcr));
98
99 siginfo.si_signo = SIGFPE;
100 /*
101 * (~cwd & swd) will mask out exceptions that are not set to unmasked
102 * status. 0x3f is the exception bits in these regs, 0x200 is the
103 * C1 reg you need in case of a stack fault, 0x040 is the stack
104 * fault bit. We should only be taking one exception at a time,
105 * so if this combination doesn't produce any single exception,
106 * then we have a bad program that isn't syncronizing its FPU usage
107 * and it will suffer the consequences since we won't be able to
108 * fully reproduce the context of the exception
109 */
110 siginfo.si_isr = isr;
111 siginfo.si_flags = __ISR_VALID;
112 switch(((~fcr) & (fsr & 0x3f)) | (fsr & 0x240)) {
113 case 0x000:
114 default:
115 siginfo.si_code = 0;
116 break;
117 case 0x001: /* Invalid Op */
118 case 0x040: /* Stack Fault */
119 case 0x240: /* Stack Fault | Direction */
120 siginfo.si_code = FPE_FLTINV;
121 break;
122 case 0x002: /* Denormalize */
123 case 0x010: /* Underflow */
124 siginfo.si_code = FPE_FLTUND;
125 break;
126 case 0x004: /* Zero Divide */
127 siginfo.si_code = FPE_FLTDIV;
128 break;
129 case 0x008: /* Overflow */
130 siginfo.si_code = FPE_FLTOVF;
131 break;
132 case 0x020: /* Precision */
133 siginfo.si_code = FPE_FLTRES;
134 break;
135 }
136
137 break;
138 }
139
140 case 17: /* Alignment check */
141 siginfo.si_signo = SIGSEGV;
142 siginfo.si_code = BUS_ADRALN;
143 break;
144
145 case 19: /* SSE Numeric error */
146 siginfo.si_signo = SIGFPE;
147 siginfo.si_code = 0;
148 break;
149
150 default:
151 return -1;
152 }
153 force_sig_info(siginfo.si_signo, &siginfo, current);
154 return 0;
155 }
156