diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ia64/kernel/traps.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ia64/kernel/traps.c')
-rw-r--r-- | arch/ia64/kernel/traps.c | 609 |
1 files changed, 609 insertions, 0 deletions
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c new file mode 100644 index 000000000000..e82ad78081b3 --- /dev/null +++ b/arch/ia64/kernel/traps.c | |||
@@ -0,0 +1,609 @@ | |||
1 | /* | ||
2 | * Architecture-specific trap handling. | ||
3 | * | ||
4 | * Copyright (C) 1998-2003 Hewlett-Packard Co | ||
5 | * David Mosberger-Tang <davidm@hpl.hp.com> | ||
6 | * | ||
7 | * 05/12/00 grao <goutham.rao@intel.com> : added isr in siginfo for SIGFPE | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/tty.h> | ||
15 | #include <linux/vt_kern.h> /* For unblank_screen() */ | ||
16 | #include <linux/module.h> /* for EXPORT_SYMBOL */ | ||
17 | #include <linux/hardirq.h> | ||
18 | |||
19 | #include <asm/fpswa.h> | ||
20 | #include <asm/ia32.h> | ||
21 | #include <asm/intrinsics.h> | ||
22 | #include <asm/processor.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | |||
25 | extern spinlock_t timerlist_lock; | ||
26 | |||
27 | fpswa_interface_t *fpswa_interface; | ||
28 | EXPORT_SYMBOL(fpswa_interface); | ||
29 | |||
30 | void __init | ||
31 | trap_init (void) | ||
32 | { | ||
33 | if (ia64_boot_param->fpswa) | ||
34 | /* FPSWA fixup: make the interface pointer a kernel virtual address: */ | ||
35 | fpswa_interface = __va(ia64_boot_param->fpswa); | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | * Unlock any spinlocks which will prevent us from getting the message out (timerlist_lock | ||
40 | * is acquired through the console unblank code) | ||
41 | */ | ||
42 | void | ||
43 | bust_spinlocks (int yes) | ||
44 | { | ||
45 | int loglevel_save = console_loglevel; | ||
46 | |||
47 | if (yes) { | ||
48 | oops_in_progress = 1; | ||
49 | return; | ||
50 | } | ||
51 | |||
52 | #ifdef CONFIG_VT | ||
53 | unblank_screen(); | ||
54 | #endif | ||
55 | oops_in_progress = 0; | ||
56 | /* | ||
57 | * OK, the message is on the console. Now we call printk() without | ||
58 | * oops_in_progress set so that printk will give klogd a poke. Hold onto | ||
59 | * your hats... | ||
60 | */ | ||
61 | console_loglevel = 15; /* NMI oopser may have shut the console up */ | ||
62 | printk(" "); | ||
63 | console_loglevel = loglevel_save; | ||
64 | } | ||
65 | |||
66 | void | ||
67 | die (const char *str, struct pt_regs *regs, long err) | ||
68 | { | ||
69 | static struct { | ||
70 | spinlock_t lock; | ||
71 | u32 lock_owner; | ||
72 | int lock_owner_depth; | ||
73 | } die = { | ||
74 | .lock = SPIN_LOCK_UNLOCKED, | ||
75 | .lock_owner = -1, | ||
76 | .lock_owner_depth = 0 | ||
77 | }; | ||
78 | static int die_counter; | ||
79 | |||
80 | if (die.lock_owner != smp_processor_id()) { | ||
81 | console_verbose(); | ||
82 | spin_lock_irq(&die.lock); | ||
83 | die.lock_owner = smp_processor_id(); | ||
84 | die.lock_owner_depth = 0; | ||
85 | bust_spinlocks(1); | ||
86 | } | ||
87 | |||
88 | if (++die.lock_owner_depth < 3) { | ||
89 | printk("%s[%d]: %s %ld [%d]\n", | ||
90 | current->comm, current->pid, str, err, ++die_counter); | ||
91 | show_regs(regs); | ||
92 | } else | ||
93 | printk(KERN_ERR "Recursive die() failure, output suppressed\n"); | ||
94 | |||
95 | bust_spinlocks(0); | ||
96 | die.lock_owner = -1; | ||
97 | spin_unlock_irq(&die.lock); | ||
98 | do_exit(SIGSEGV); | ||
99 | } | ||
100 | |||
101 | void | ||
102 | die_if_kernel (char *str, struct pt_regs *regs, long err) | ||
103 | { | ||
104 | if (!user_mode(regs)) | ||
105 | die(str, regs, err); | ||
106 | } | ||
107 | |||
108 | void | ||
109 | ia64_bad_break (unsigned long break_num, struct pt_regs *regs) | ||
110 | { | ||
111 | siginfo_t siginfo; | ||
112 | int sig, code; | ||
113 | |||
114 | /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ | ||
115 | siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); | ||
116 | siginfo.si_imm = break_num; | ||
117 | siginfo.si_flags = 0; /* clear __ISR_VALID */ | ||
118 | siginfo.si_isr = 0; | ||
119 | |||
120 | switch (break_num) { | ||
121 | case 0: /* unknown error (used by GCC for __builtin_abort()) */ | ||
122 | die_if_kernel("bugcheck!", regs, break_num); | ||
123 | sig = SIGILL; code = ILL_ILLOPC; | ||
124 | break; | ||
125 | |||
126 | case 1: /* integer divide by zero */ | ||
127 | sig = SIGFPE; code = FPE_INTDIV; | ||
128 | break; | ||
129 | |||
130 | case 2: /* integer overflow */ | ||
131 | sig = SIGFPE; code = FPE_INTOVF; | ||
132 | break; | ||
133 | |||
134 | case 3: /* range check/bounds check */ | ||
135 | sig = SIGFPE; code = FPE_FLTSUB; | ||
136 | break; | ||
137 | |||
138 | case 4: /* null pointer dereference */ | ||
139 | sig = SIGSEGV; code = SEGV_MAPERR; | ||
140 | break; | ||
141 | |||
142 | case 5: /* misaligned data */ | ||
143 | sig = SIGSEGV; code = BUS_ADRALN; | ||
144 | break; | ||
145 | |||
146 | case 6: /* decimal overflow */ | ||
147 | sig = SIGFPE; code = __FPE_DECOVF; | ||
148 | break; | ||
149 | |||
150 | case 7: /* decimal divide by zero */ | ||
151 | sig = SIGFPE; code = __FPE_DECDIV; | ||
152 | break; | ||
153 | |||
154 | case 8: /* packed decimal error */ | ||
155 | sig = SIGFPE; code = __FPE_DECERR; | ||
156 | break; | ||
157 | |||
158 | case 9: /* invalid ASCII digit */ | ||
159 | sig = SIGFPE; code = __FPE_INVASC; | ||
160 | break; | ||
161 | |||
162 | case 10: /* invalid decimal digit */ | ||
163 | sig = SIGFPE; code = __FPE_INVDEC; | ||
164 | break; | ||
165 | |||
166 | case 11: /* paragraph stack overflow */ | ||
167 | sig = SIGSEGV; code = __SEGV_PSTKOVF; | ||
168 | break; | ||
169 | |||
170 | case 0x3f000 ... 0x3ffff: /* bundle-update in progress */ | ||
171 | sig = SIGILL; code = __ILL_BNDMOD; | ||
172 | break; | ||
173 | |||
174 | default: | ||
175 | if (break_num < 0x40000 || break_num > 0x100000) | ||
176 | die_if_kernel("Bad break", regs, break_num); | ||
177 | |||
178 | if (break_num < 0x80000) { | ||
179 | sig = SIGILL; code = __ILL_BREAK; | ||
180 | } else { | ||
181 | sig = SIGTRAP; code = TRAP_BRKPT; | ||
182 | } | ||
183 | } | ||
184 | siginfo.si_signo = sig; | ||
185 | siginfo.si_errno = 0; | ||
186 | siginfo.si_code = code; | ||
187 | force_sig_info(sig, &siginfo, current); | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * disabled_fph_fault() is called when a user-level process attempts to access f32..f127 | ||
192 | * and it doesn't own the fp-high register partition. When this happens, we save the | ||
193 | * current fph partition in the task_struct of the fpu-owner (if necessary) and then load | ||
194 | * the fp-high partition of the current task (if necessary). Note that the kernel has | ||
195 | * access to fph by the time we get here, as the IVT's "Disabled FP-Register" handler takes | ||
196 | * care of clearing psr.dfh. | ||
197 | */ | ||
198 | static inline void | ||
199 | disabled_fph_fault (struct pt_regs *regs) | ||
200 | { | ||
201 | struct ia64_psr *psr = ia64_psr(regs); | ||
202 | |||
203 | /* first, grant user-level access to fph partition: */ | ||
204 | psr->dfh = 0; | ||
205 | #ifndef CONFIG_SMP | ||
206 | { | ||
207 | struct task_struct *fpu_owner | ||
208 | = (struct task_struct *)ia64_get_kr(IA64_KR_FPU_OWNER); | ||
209 | |||
210 | if (ia64_is_local_fpu_owner(current)) | ||
211 | return; | ||
212 | |||
213 | if (fpu_owner) | ||
214 | ia64_flush_fph(fpu_owner); | ||
215 | } | ||
216 | #endif /* !CONFIG_SMP */ | ||
217 | ia64_set_local_fpu_owner(current); | ||
218 | if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) { | ||
219 | __ia64_load_fpu(current->thread.fph); | ||
220 | psr->mfh = 0; | ||
221 | } else { | ||
222 | __ia64_init_fpu(); | ||
223 | /* | ||
224 | * Set mfh because the state in thread.fph does not match the state in | ||
225 | * the fph partition. | ||
226 | */ | ||
227 | psr->mfh = 1; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | static inline int | ||
232 | fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long *pr, long *ifs, | ||
233 | struct pt_regs *regs) | ||
234 | { | ||
235 | fp_state_t fp_state; | ||
236 | fpswa_ret_t ret; | ||
237 | |||
238 | if (!fpswa_interface) | ||
239 | return -1; | ||
240 | |||
241 | memset(&fp_state, 0, sizeof(fp_state_t)); | ||
242 | |||
243 | /* | ||
244 | * compute fp_state. only FP registers f6 - f11 are used by the | ||
245 | * kernel, so set those bits in the mask and set the low volatile | ||
246 | * pointer to point to these registers. | ||
247 | */ | ||
248 | fp_state.bitmask_low64 = 0xfc0; /* bit6..bit11 */ | ||
249 | |||
250 | fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) ®s->f6; | ||
251 | /* | ||
252 | * unsigned long (*EFI_FPSWA) ( | ||
253 | * unsigned long trap_type, | ||
254 | * void *Bundle, | ||
255 | * unsigned long *pipsr, | ||
256 | * unsigned long *pfsr, | ||
257 | * unsigned long *pisr, | ||
258 | * unsigned long *ppreds, | ||
259 | * unsigned long *pifs, | ||
260 | * void *fp_state); | ||
261 | */ | ||
262 | ret = (*fpswa_interface->fpswa)((unsigned long) fp_fault, bundle, | ||
263 | (unsigned long *) ipsr, (unsigned long *) fpsr, | ||
264 | (unsigned long *) isr, (unsigned long *) pr, | ||
265 | (unsigned long *) ifs, &fp_state); | ||
266 | |||
267 | return ret.status; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Handle floating-point assist faults and traps. | ||
272 | */ | ||
273 | static int | ||
274 | handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) | ||
275 | { | ||
276 | long exception, bundle[2]; | ||
277 | unsigned long fault_ip; | ||
278 | struct siginfo siginfo; | ||
279 | static int fpu_swa_count = 0; | ||
280 | static unsigned long last_time; | ||
281 | |||
282 | fault_ip = regs->cr_iip; | ||
283 | if (!fp_fault && (ia64_psr(regs)->ri == 0)) | ||
284 | fault_ip -= 16; | ||
285 | if (copy_from_user(bundle, (void __user *) fault_ip, sizeof(bundle))) | ||
286 | return -1; | ||
287 | |||
288 | if (jiffies - last_time > 5*HZ) | ||
289 | fpu_swa_count = 0; | ||
290 | if ((fpu_swa_count < 4) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) { | ||
291 | last_time = jiffies; | ||
292 | ++fpu_swa_count; | ||
293 | printk(KERN_WARNING | ||
294 | "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n", | ||
295 | current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr); | ||
296 | } | ||
297 | |||
298 | exception = fp_emulate(fp_fault, bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr, | ||
299 | ®s->cr_ifs, regs); | ||
300 | if (fp_fault) { | ||
301 | if (exception == 0) { | ||
302 | /* emulation was successful */ | ||
303 | ia64_increment_ip(regs); | ||
304 | } else if (exception == -1) { | ||
305 | printk(KERN_ERR "handle_fpu_swa: fp_emulate() returned -1\n"); | ||
306 | return -1; | ||
307 | } else { | ||
308 | /* is next instruction a trap? */ | ||
309 | if (exception & 2) { | ||
310 | ia64_increment_ip(regs); | ||
311 | } | ||
312 | siginfo.si_signo = SIGFPE; | ||
313 | siginfo.si_errno = 0; | ||
314 | siginfo.si_code = __SI_FAULT; /* default code */ | ||
315 | siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); | ||
316 | if (isr & 0x11) { | ||
317 | siginfo.si_code = FPE_FLTINV; | ||
318 | } else if (isr & 0x22) { | ||
319 | /* denormal operand gets the same si_code as underflow | ||
320 | * see arch/i386/kernel/traps.c:math_error() */ | ||
321 | siginfo.si_code = FPE_FLTUND; | ||
322 | } else if (isr & 0x44) { | ||
323 | siginfo.si_code = FPE_FLTDIV; | ||
324 | } | ||
325 | siginfo.si_isr = isr; | ||
326 | siginfo.si_flags = __ISR_VALID; | ||
327 | siginfo.si_imm = 0; | ||
328 | force_sig_info(SIGFPE, &siginfo, current); | ||
329 | } | ||
330 | } else { | ||
331 | if (exception == -1) { | ||
332 | printk(KERN_ERR "handle_fpu_swa: fp_emulate() returned -1\n"); | ||
333 | return -1; | ||
334 | } else if (exception != 0) { | ||
335 | /* raise exception */ | ||
336 | siginfo.si_signo = SIGFPE; | ||
337 | siginfo.si_errno = 0; | ||
338 | siginfo.si_code = __SI_FAULT; /* default code */ | ||
339 | siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); | ||
340 | if (isr & 0x880) { | ||
341 | siginfo.si_code = FPE_FLTOVF; | ||
342 | } else if (isr & 0x1100) { | ||
343 | siginfo.si_code = FPE_FLTUND; | ||
344 | } else if (isr & 0x2200) { | ||
345 | siginfo.si_code = FPE_FLTRES; | ||
346 | } | ||
347 | siginfo.si_isr = isr; | ||
348 | siginfo.si_flags = __ISR_VALID; | ||
349 | siginfo.si_imm = 0; | ||
350 | force_sig_info(SIGFPE, &siginfo, current); | ||
351 | } | ||
352 | } | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | struct illegal_op_return { | ||
357 | unsigned long fkt, arg1, arg2, arg3; | ||
358 | }; | ||
359 | |||
360 | struct illegal_op_return | ||
361 | ia64_illegal_op_fault (unsigned long ec, long arg1, long arg2, long arg3, | ||
362 | long arg4, long arg5, long arg6, long arg7, | ||
363 | struct pt_regs regs) | ||
364 | { | ||
365 | struct illegal_op_return rv; | ||
366 | struct siginfo si; | ||
367 | char buf[128]; | ||
368 | |||
369 | #ifdef CONFIG_IA64_BRL_EMU | ||
370 | { | ||
371 | extern struct illegal_op_return ia64_emulate_brl (struct pt_regs *, unsigned long); | ||
372 | |||
373 | rv = ia64_emulate_brl(®s, ec); | ||
374 | if (rv.fkt != (unsigned long) -1) | ||
375 | return rv; | ||
376 | } | ||
377 | #endif | ||
378 | |||
379 | sprintf(buf, "IA-64 Illegal operation fault"); | ||
380 | die_if_kernel(buf, ®s, 0); | ||
381 | |||
382 | memset(&si, 0, sizeof(si)); | ||
383 | si.si_signo = SIGILL; | ||
384 | si.si_code = ILL_ILLOPC; | ||
385 | si.si_addr = (void __user *) (regs.cr_iip + ia64_psr(®s)->ri); | ||
386 | force_sig_info(SIGILL, &si, current); | ||
387 | rv.fkt = 0; | ||
388 | return rv; | ||
389 | } | ||
390 | |||
391 | void | ||
392 | ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, | ||
393 | unsigned long iim, unsigned long itir, long arg5, long arg6, | ||
394 | long arg7, struct pt_regs regs) | ||
395 | { | ||
396 | unsigned long code, error = isr, iip; | ||
397 | struct siginfo siginfo; | ||
398 | char buf[128]; | ||
399 | int result, sig; | ||
400 | static const char *reason[] = { | ||
401 | "IA-64 Illegal Operation fault", | ||
402 | "IA-64 Privileged Operation fault", | ||
403 | "IA-64 Privileged Register fault", | ||
404 | "IA-64 Reserved Register/Field fault", | ||
405 | "Disabled Instruction Set Transition fault", | ||
406 | "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault", | ||
407 | "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", | ||
408 | "Unknown fault 13", "Unknown fault 14", "Unknown fault 15" | ||
409 | }; | ||
410 | |||
411 | if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) { | ||
412 | /* | ||
413 | * This fault was due to lfetch.fault, set "ed" bit in the psr to cancel | ||
414 | * the lfetch. | ||
415 | */ | ||
416 | ia64_psr(®s)->ed = 1; | ||
417 | return; | ||
418 | } | ||
419 | |||
420 | iip = regs.cr_iip + ia64_psr(®s)->ri; | ||
421 | |||
422 | switch (vector) { | ||
423 | case 24: /* General Exception */ | ||
424 | code = (isr >> 4) & 0xf; | ||
425 | sprintf(buf, "General Exception: %s%s", reason[code], | ||
426 | (code == 3) ? ((isr & (1UL << 37)) | ||
427 | ? " (RSE access)" : " (data access)") : ""); | ||
428 | if (code == 8) { | ||
429 | # ifdef CONFIG_IA64_PRINT_HAZARDS | ||
430 | printk("%s[%d]: possible hazard @ ip=%016lx (pr = %016lx)\n", | ||
431 | current->comm, current->pid, | ||
432 | regs.cr_iip + ia64_psr(®s)->ri, regs.pr); | ||
433 | # endif | ||
434 | return; | ||
435 | } | ||
436 | break; | ||
437 | |||
438 | case 25: /* Disabled FP-Register */ | ||
439 | if (isr & 2) { | ||
440 | disabled_fph_fault(®s); | ||
441 | return; | ||
442 | } | ||
443 | sprintf(buf, "Disabled FPL fault---not supposed to happen!"); | ||
444 | break; | ||
445 | |||
446 | case 26: /* NaT Consumption */ | ||
447 | if (user_mode(®s)) { | ||
448 | void __user *addr; | ||
449 | |||
450 | if (((isr >> 4) & 0xf) == 2) { | ||
451 | /* NaT page consumption */ | ||
452 | sig = SIGSEGV; | ||
453 | code = SEGV_ACCERR; | ||
454 | addr = (void __user *) ifa; | ||
455 | } else { | ||
456 | /* register NaT consumption */ | ||
457 | sig = SIGILL; | ||
458 | code = ILL_ILLOPN; | ||
459 | addr = (void __user *) (regs.cr_iip | ||
460 | + ia64_psr(®s)->ri); | ||
461 | } | ||
462 | siginfo.si_signo = sig; | ||
463 | siginfo.si_code = code; | ||
464 | siginfo.si_errno = 0; | ||
465 | siginfo.si_addr = addr; | ||
466 | siginfo.si_imm = vector; | ||
467 | siginfo.si_flags = __ISR_VALID; | ||
468 | siginfo.si_isr = isr; | ||
469 | force_sig_info(sig, &siginfo, current); | ||
470 | return; | ||
471 | } else if (ia64_done_with_exception(®s)) | ||
472 | return; | ||
473 | sprintf(buf, "NaT consumption"); | ||
474 | break; | ||
475 | |||
476 | case 31: /* Unsupported Data Reference */ | ||
477 | if (user_mode(®s)) { | ||
478 | siginfo.si_signo = SIGILL; | ||
479 | siginfo.si_code = ILL_ILLOPN; | ||
480 | siginfo.si_errno = 0; | ||
481 | siginfo.si_addr = (void __user *) iip; | ||
482 | siginfo.si_imm = vector; | ||
483 | siginfo.si_flags = __ISR_VALID; | ||
484 | siginfo.si_isr = isr; | ||
485 | force_sig_info(SIGILL, &siginfo, current); | ||
486 | return; | ||
487 | } | ||
488 | sprintf(buf, "Unsupported data reference"); | ||
489 | break; | ||
490 | |||
491 | case 29: /* Debug */ | ||
492 | case 35: /* Taken Branch Trap */ | ||
493 | case 36: /* Single Step Trap */ | ||
494 | if (fsys_mode(current, ®s)) { | ||
495 | extern char __kernel_syscall_via_break[]; | ||
496 | /* | ||
497 | * Got a trap in fsys-mode: Taken Branch Trap and Single Step trap | ||
498 | * need special handling; Debug trap is not supposed to happen. | ||
499 | */ | ||
500 | if (unlikely(vector == 29)) { | ||
501 | die("Got debug trap in fsys-mode---not supposed to happen!", | ||
502 | ®s, 0); | ||
503 | return; | ||
504 | } | ||
505 | /* re-do the system call via break 0x100000: */ | ||
506 | regs.cr_iip = (unsigned long) __kernel_syscall_via_break; | ||
507 | ia64_psr(®s)->ri = 0; | ||
508 | ia64_psr(®s)->cpl = 3; | ||
509 | return; | ||
510 | } | ||
511 | switch (vector) { | ||
512 | case 29: | ||
513 | siginfo.si_code = TRAP_HWBKPT; | ||
514 | #ifdef CONFIG_ITANIUM | ||
515 | /* | ||
516 | * Erratum 10 (IFA may contain incorrect address) now has | ||
517 | * "NoFix" status. There are no plans for fixing this. | ||
518 | */ | ||
519 | if (ia64_psr(®s)->is == 0) | ||
520 | ifa = regs.cr_iip; | ||
521 | #endif | ||
522 | break; | ||
523 | case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break; | ||
524 | case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break; | ||
525 | } | ||
526 | siginfo.si_signo = SIGTRAP; | ||
527 | siginfo.si_errno = 0; | ||
528 | siginfo.si_addr = (void __user *) ifa; | ||
529 | siginfo.si_imm = 0; | ||
530 | siginfo.si_flags = __ISR_VALID; | ||
531 | siginfo.si_isr = isr; | ||
532 | force_sig_info(SIGTRAP, &siginfo, current); | ||
533 | return; | ||
534 | |||
535 | case 32: /* fp fault */ | ||
536 | case 33: /* fp trap */ | ||
537 | result = handle_fpu_swa((vector == 32) ? 1 : 0, ®s, isr); | ||
538 | if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { | ||
539 | siginfo.si_signo = SIGFPE; | ||
540 | siginfo.si_errno = 0; | ||
541 | siginfo.si_code = FPE_FLTINV; | ||
542 | siginfo.si_addr = (void __user *) iip; | ||
543 | siginfo.si_flags = __ISR_VALID; | ||
544 | siginfo.si_isr = isr; | ||
545 | siginfo.si_imm = 0; | ||
546 | force_sig_info(SIGFPE, &siginfo, current); | ||
547 | } | ||
548 | return; | ||
549 | |||
550 | case 34: | ||
551 | if (isr & 0x2) { | ||
552 | /* Lower-Privilege Transfer Trap */ | ||
553 | /* | ||
554 | * Just clear PSR.lp and then return immediately: all the | ||
555 | * interesting work (e.g., signal delivery is done in the kernel | ||
556 | * exit path). | ||
557 | */ | ||
558 | ia64_psr(®s)->lp = 0; | ||
559 | return; | ||
560 | } else { | ||
561 | /* Unimplemented Instr. Address Trap */ | ||
562 | if (user_mode(®s)) { | ||
563 | siginfo.si_signo = SIGILL; | ||
564 | siginfo.si_code = ILL_BADIADDR; | ||
565 | siginfo.si_errno = 0; | ||
566 | siginfo.si_flags = 0; | ||
567 | siginfo.si_isr = 0; | ||
568 | siginfo.si_imm = 0; | ||
569 | siginfo.si_addr = (void __user *) iip; | ||
570 | force_sig_info(SIGILL, &siginfo, current); | ||
571 | return; | ||
572 | } | ||
573 | sprintf(buf, "Unimplemented Instruction Address fault"); | ||
574 | } | ||
575 | break; | ||
576 | |||
577 | case 45: | ||
578 | #ifdef CONFIG_IA32_SUPPORT | ||
579 | if (ia32_exception(®s, isr) == 0) | ||
580 | return; | ||
581 | #endif | ||
582 | printk(KERN_ERR "Unexpected IA-32 exception (Trap 45)\n"); | ||
583 | printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n", | ||
584 | iip, ifa, isr); | ||
585 | force_sig(SIGSEGV, current); | ||
586 | break; | ||
587 | |||
588 | case 46: | ||
589 | #ifdef CONFIG_IA32_SUPPORT | ||
590 | if (ia32_intercept(®s, isr) == 0) | ||
591 | return; | ||
592 | #endif | ||
593 | printk(KERN_ERR "Unexpected IA-32 intercept trap (Trap 46)\n"); | ||
594 | printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n", | ||
595 | iip, ifa, isr, iim); | ||
596 | force_sig(SIGSEGV, current); | ||
597 | return; | ||
598 | |||
599 | case 47: | ||
600 | sprintf(buf, "IA-32 Interruption Fault (int 0x%lx)", isr >> 16); | ||
601 | break; | ||
602 | |||
603 | default: | ||
604 | sprintf(buf, "Fault %lu", vector); | ||
605 | break; | ||
606 | } | ||
607 | die_if_kernel(buf, ®s, error); | ||
608 | force_sig(SIGILL, current); | ||
609 | } | ||