• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
ia32_intercept(struct pt_regs * regs,unsigned long isr)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
ia32_exception(struct pt_regs * regs,unsigned long isr)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 }
157