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