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