File: /usr/src/linux/arch/ia64/kernel/traps.c
1 /*
2 * Architecture-specific trap handling.
3 *
4 * Copyright (C) 1998-2000 Hewlett-Packard Co
5 * Copyright (C) 1998-2000 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 /*
11 * The fpu_fault() handler needs to be able to access and update all
12 * floating point registers. Those saved in pt_regs can be accessed
13 * through that structure, but those not saved, will be accessed
14 * directly. To make this work, we need to ensure that the compiler
15 * does not end up using a preserved floating point register on its
16 * own. The following achieves this by declaring preserved registers
17 * that are not marked as "fixed" as global register variables.
18 */
19 register double f2 asm ("f2"); register double f3 asm ("f3");
20 register double f4 asm ("f4"); register double f5 asm ("f5");
21
22 register long f16 asm ("f16"); register long f17 asm ("f17");
23 register long f18 asm ("f18"); register long f19 asm ("f19");
24 register long f20 asm ("f20"); register long f21 asm ("f21");
25 register long f22 asm ("f22"); register long f23 asm ("f23");
26
27 register double f24 asm ("f24"); register double f25 asm ("f25");
28 register double f26 asm ("f26"); register double f27 asm ("f27");
29 register double f28 asm ("f28"); register double f29 asm ("f29");
30 register double f30 asm ("f30"); register double f31 asm ("f31");
31
32 #include <linux/config.h>
33 #include <linux/kernel.h>
34 #include <linux/init.h>
35 #include <linux/sched.h>
36
37 #include <asm/ia32.h>
38 #include <asm/processor.h>
39 #include <asm/uaccess.h>
40
41 #include <asm/fpswa.h>
42
43 static fpswa_interface_t *fpswa_interface;
44
45 void __init
46 trap_init (void)
47 {
48 printk("fpswa interface at %lx\n", ia64_boot_param->fpswa);
49 if (ia64_boot_param->fpswa)
50 /* FPSWA fixup: make the interface pointer a kernel virtual address: */
51 fpswa_interface = __va(ia64_boot_param->fpswa);
52 }
53
54 void
55 die_if_kernel (char *str, struct pt_regs *regs, long err)
56 {
57 if (user_mode(regs)) {
58 #if 0
59 /* XXX for debugging only */
60 printk ("!!die_if_kernel: %s(%d): %s %ld\n",
61 current->comm, current->pid, str, err);
62 show_regs(regs);
63 #endif
64 return;
65 }
66
67 printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
68
69 show_regs(regs);
70
71 if (current->thread.flags & IA64_KERNEL_DEATH) {
72 printk("die_if_kernel recursion detected.\n");
73 sti();
74 while (1);
75 }
76 current->thread.flags |= IA64_KERNEL_DEATH;
77 do_exit(SIGSEGV);
78 }
79
80 void
81 ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
82 {
83 siginfo_t siginfo;
84 int sig, code;
85
86 /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */
87 siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
88 siginfo.si_imm = break_num;
89
90 switch (break_num) {
91 case 0: /* unknown error */
92 sig = SIGILL; code = ILL_ILLOPC;
93 break;
94
95 case 1: /* integer divide by zero */
96 sig = SIGFPE; code = FPE_INTDIV;
97 break;
98
99 case 2: /* integer overflow */
100 sig = SIGFPE; code = FPE_INTOVF;
101 break;
102
103 case 3: /* range check/bounds check */
104 sig = SIGFPE; code = FPE_FLTSUB;
105 break;
106
107 case 4: /* null pointer dereference */
108 sig = SIGSEGV; code = SEGV_MAPERR;
109 break;
110
111 case 5: /* misaligned data */
112 sig = SIGSEGV; code = BUS_ADRALN;
113 break;
114
115 case 6: /* decimal overflow */
116 sig = SIGFPE; code = __FPE_DECOVF;
117 break;
118
119 case 7: /* decimal divide by zero */
120 sig = SIGFPE; code = __FPE_DECDIV;
121 break;
122
123 case 8: /* packed decimal error */
124 sig = SIGFPE; code = __FPE_DECERR;
125 break;
126
127 case 9: /* invalid ASCII digit */
128 sig = SIGFPE; code = __FPE_INVASC;
129 break;
130
131 case 10: /* invalid decimal digit */
132 sig = SIGFPE; code = __FPE_INVDEC;
133 break;
134
135 case 11: /* paragraph stack overflow */
136 sig = SIGSEGV; code = __SEGV_PSTKOVF;
137 break;
138
139 default:
140 if (break_num < 0x40000 || break_num > 0x100000)
141 die_if_kernel("Bad break", regs, break_num);
142
143 if (break_num < 0x80000) {
144 sig = SIGILL; code = __ILL_BREAK;
145 } else {
146 sig = SIGTRAP; code = TRAP_BRKPT;
147 }
148 }
149 siginfo.si_signo = sig;
150 siginfo.si_errno = 0;
151 siginfo.si_code = code;
152 force_sig_info(sig, &siginfo, current);
153 }
154
155 /*
156 * Unimplemented system calls. This is called only for stuff that
157 * we're supposed to implement but haven't done so yet. Everything
158 * else goes to sys_ni_syscall.
159 */
160 asmlinkage long
161 ia64_ni_syscall (unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3,
162 unsigned long arg4, unsigned long arg5, unsigned long arg6, unsigned long arg7,
163 unsigned long stack)
164 {
165 struct pt_regs *regs = (struct pt_regs *) &stack;
166
167 printk("<sc%ld(%lx,%lx,%lx,%lx)>\n", regs->r15, arg0, arg1, arg2, arg3);
168 return -ENOSYS;
169 }
170
171 /*
172 * disabled_fph_fault() is called when a user-level process attempts
173 * to access one of the registers f32..f127 when it doesn't own the
174 * fp-high register partition. When this happens, we save the current
175 * fph partition in the task_struct of the fpu-owner (if necessary)
176 * and then load the fp-high partition of the current task (if
177 * necessary). Note that the kernel has access to fph by the time we
178 * get here, as the IVT's "Diabled FP-Register" handler takes care of
179 * clearing psr.dfh.
180 */
181 static inline void
182 disabled_fph_fault (struct pt_regs *regs)
183 {
184 struct ia64_psr *psr = ia64_psr(regs);
185
186 /* first, grant user-level access to fph partition: */
187 psr->dfh = 0;
188 #ifndef CONFIG_SMP
189 {
190 struct task_struct *fpu_owner = ia64_get_fpu_owner();
191
192 if (fpu_owner == current)
193 return;
194
195 if (fpu_owner)
196 ia64_flush_fph(fpu_owner);
197
198 ia64_set_fpu_owner(current);
199 }
200 #endif /* !CONFIG_SMP */
201 if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) {
202 __ia64_load_fpu(current->thread.fph);
203 psr->mfh = 0;
204 } else {
205 __ia64_init_fpu();
206 /*
207 * Set mfh because the state in thread.fph does not match the state in
208 * the fph partition.
209 */
210 psr->mfh = 1;
211 }
212 }
213
214 static inline int
215 fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long *pr, long *ifs,
216 struct pt_regs *regs)
217 {
218 struct ia64_fpreg f6_11[6];
219 fp_state_t fp_state;
220 fpswa_ret_t ret;
221
222 if (!fpswa_interface)
223 return -1;
224
225 memset(&fp_state, 0, sizeof(fp_state_t));
226
227 /*
228 * compute fp_state. only FP registers f6 - f11 are used by the
229 * kernel, so set those bits in the mask and set the low volatile
230 * pointer to point to these registers.
231 */
232 fp_state.bitmask_low64 = 0xfc0; /* bit6..bit11 */
233 f6_11[0] = regs->f6; f6_11[1] = regs->f7;
234 f6_11[2] = regs->f8; f6_11[3] = regs->f9;
235 __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_11[4]));
236 __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_11[5]));
237 fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_11;
238 /*
239 * unsigned long (*EFI_FPSWA) (
240 * unsigned long trap_type,
241 * void *Bundle,
242 * unsigned long *pipsr,
243 * unsigned long *pfsr,
244 * unsigned long *pisr,
245 * unsigned long *ppreds,
246 * unsigned long *pifs,
247 * void *fp_state);
248 */
249 ret = (*fpswa_interface->fpswa)((unsigned long) fp_fault, bundle,
250 (unsigned long *) ipsr, (unsigned long *) fpsr,
251 (unsigned long *) isr, (unsigned long *) pr,
252 (unsigned long *) ifs, &fp_state);
253 regs->f6 = f6_11[0]; regs->f7 = f6_11[1];
254 regs->f8 = f6_11[2]; regs->f9 = f6_11[3];
255 __asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_11[4]));
256 __asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_11[5]));
257 return ret.status;
258 }
259
260 /*
261 * Handle floating-point assist faults and traps.
262 */
263 static int
264 handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
265 {
266 long exception, bundle[2];
267 unsigned long fault_ip;
268 struct siginfo siginfo;
269 static int fpu_swa_count = 0;
270 static unsigned long last_time;
271
272 fault_ip = regs->cr_iip;
273 if (!fp_fault && (ia64_psr(regs)->ri == 0))
274 fault_ip -= 16;
275 if (copy_from_user(bundle, (void *) fault_ip, sizeof(bundle)))
276 return -1;
277
278 if (jiffies - last_time > 5*HZ)
279 fpu_swa_count = 0;
280 if (++fpu_swa_count < 5) {
281 last_time = jiffies;
282 printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx\n",
283 current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri);
284 }
285
286 exception = fp_emulate(fp_fault, bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr,
287 ®s->cr_ifs, regs);
288 if (fp_fault) {
289 if (exception == 0) {
290 /* emulation was successful */
291 ia64_increment_ip(regs);
292 } else if (exception == -1) {
293 printk("handle_fpu_swa: fp_emulate() returned -1\n");
294 return -1;
295 } else {
296 /* is next instruction a trap? */
297 if (exception & 2) {
298 ia64_increment_ip(regs);
299 }
300 siginfo.si_signo = SIGFPE;
301 siginfo.si_errno = 0;
302 siginfo.si_code = __SI_FAULT; /* default code */
303 siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
304 if (isr & 0x11) {
305 siginfo.si_code = FPE_FLTINV;
306 } else if (isr & 0x44) {
307 siginfo.si_code = FPE_FLTDIV;
308 }
309 siginfo.si_isr = isr;
310 force_sig_info(SIGFPE, &siginfo, current);
311 }
312 } else {
313 if (exception == -1) {
314 printk("handle_fpu_swa: fp_emulate() returned -1\n");
315 return -1;
316 } else if (exception != 0) {
317 /* raise exception */
318 siginfo.si_signo = SIGFPE;
319 siginfo.si_errno = 0;
320 siginfo.si_code = __SI_FAULT; /* default code */
321 siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
322 if (isr & 0x880) {
323 siginfo.si_code = FPE_FLTOVF;
324 } else if (isr & 0x1100) {
325 siginfo.si_code = FPE_FLTUND;
326 } else if (isr & 0x2200) {
327 siginfo.si_code = FPE_FLTRES;
328 }
329 siginfo.si_isr = isr;
330 force_sig_info(SIGFPE, &siginfo, current);
331 }
332 }
333 return 0;
334 }
335
336 struct illegal_op_return {
337 unsigned long fkt, arg1, arg2, arg3;
338 };
339
340 struct illegal_op_return
341 ia64_illegal_op_fault (unsigned long ec, unsigned long arg1, unsigned long arg2,
342 unsigned long arg3, unsigned long arg4, unsigned long arg5,
343 unsigned long arg6, unsigned long arg7, unsigned long stack)
344 {
345 struct pt_regs *regs = (struct pt_regs *) &stack;
346 struct illegal_op_return rv;
347 struct siginfo si;
348 char buf[128];
349
350 #ifdef CONFIG_IA64_BRL_EMU
351 {
352 extern struct illegal_op_return ia64_emulate_brl (struct pt_regs *, unsigned long);
353
354 rv = ia64_emulate_brl(regs, ec);
355 if (rv.fkt != (unsigned long) -1)
356 return rv;
357 }
358 #endif
359
360 sprintf(buf, "IA-64 Illegal operation fault");
361 die_if_kernel(buf, regs, 0);
362
363 memset(&si, 0, sizeof(si));
364 si.si_signo = SIGILL;
365 si.si_code = ILL_ILLOPC;
366 si.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
367 force_sig_info(SIGILL, &si, current);
368 rv.fkt = 0;
369 return rv;
370 }
371
372 void
373 ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
374 unsigned long iim, unsigned long itir, unsigned long arg5,
375 unsigned long arg6, unsigned long arg7, unsigned long stack)
376 {
377 struct pt_regs *regs = (struct pt_regs *) &stack;
378 unsigned long code, error = isr;
379 struct siginfo siginfo;
380 char buf[128];
381 int result;
382 static const char *reason[] = {
383 "IA-64 Illegal Operation fault",
384 "IA-64 Privileged Operation fault",
385 "IA-64 Privileged Register fault",
386 "IA-64 Reserved Register/Field fault",
387 "Disabled Instruction Set Transition fault",
388 "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault",
389 "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12",
390 "Unknown fault 13", "Unknown fault 14", "Unknown fault 15"
391 };
392
393 #if 0
394 /* this is for minimal trust debugging; yeah this kind of stuff is useful at times... */
395
396 if (vector != 25) {
397 static unsigned long last_time;
398 static char count;
399 unsigned long n = vector;
400 char buf[32], *cp;
401
402 if (jiffies - last_time > 5*HZ)
403 count = 0;
404
405 if (count++ < 5) {
406 last_time = jiffies;
407 cp = buf + sizeof(buf);
408 *--cp = '\0';
409 while (n) {
410 *--cp = "0123456789abcdef"[n & 0xf];
411 n >>= 4;
412 }
413 printk("<0x%s>", cp);
414 }
415 }
416 #endif
417
418 switch (vector) {
419 case 24: /* General Exception */
420 code = (isr >> 4) & 0xf;
421 sprintf(buf, "General Exception: %s%s", reason[code],
422 (code == 3) ? ((isr & (1UL << 37))
423 ? " (RSE access)" : " (data access)") : "");
424 if (code == 8) {
425 # ifdef CONFIG_IA64_PRINT_HAZARDS
426 printk("%016lx:possible hazard, pr = %016lx\n", regs->cr_iip, regs->pr);
427 # endif
428 return;
429 }
430 break;
431
432 case 25: /* Disabled FP-Register */
433 if (isr & 2) {
434 disabled_fph_fault(regs);
435 return;
436 }
437 sprintf(buf, "Disabled FPL fault---not supposed to happen!");
438 break;
439
440 case 26: /* NaT Consumption */
441 case 31: /* Unsupported Data Reference */
442 if (user_mode(regs)) {
443 siginfo.si_signo = SIGILL;
444 siginfo.si_code = ILL_ILLOPN;
445 siginfo.si_errno = 0;
446 siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
447 siginfo.si_imm = vector;
448 force_sig_info(SIGILL, &siginfo, current);
449 return;
450 }
451 sprintf(buf, (vector == 26) ? "NaT consumption" : "Unsupported data reference");
452 break;
453
454 case 29: /* Debug */
455 case 35: /* Taken Branch Trap */
456 case 36: /* Single Step Trap */
457 switch (vector) {
458 case 29:
459 siginfo.si_code = TRAP_HWBKPT;
460 #ifdef CONFIG_ITANIUM
461 /*
462 * Erratum 10 (IFA may contain incorrect address) now has
463 * "NoFix" status. There are no plans for fixing this.
464 */
465 if (ia64_psr(regs)->is == 0)
466 ifa = regs->cr_iip;
467 #endif
468 siginfo.si_addr = (void *) ifa;
469 break;
470 case 35: siginfo.si_code = TRAP_BRANCH; break;
471 case 36: siginfo.si_code = TRAP_TRACE; break;
472 }
473 siginfo.si_signo = SIGTRAP;
474 siginfo.si_errno = 0;
475 force_sig_info(SIGTRAP, &siginfo, current);
476 return;
477
478 case 32: /* fp fault */
479 case 33: /* fp trap */
480 result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr);
481 if (result < 0) {
482 siginfo.si_signo = SIGFPE;
483 siginfo.si_errno = 0;
484 siginfo.si_code = FPE_FLTINV;
485 siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
486 force_sig(SIGFPE, current);
487 }
488 return;
489
490 case 34: /* Unimplemented Instruction Address Trap */
491 if (user_mode(regs)) {
492 siginfo.si_signo = SIGILL;
493 siginfo.si_code = ILL_BADIADDR;
494 siginfo.si_errno = 0;
495 siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
496 force_sig_info(SIGILL, &siginfo, current);
497 return;
498 }
499 sprintf(buf, "Unimplemented Instruction Address fault");
500 break;
501
502 case 45:
503 #ifdef CONFIG_IA32_SUPPORT
504 if (ia32_exception(regs, isr) == 0)
505 return;
506 #endif
507 printk("Unexpected IA-32 exception (Trap 45)\n");
508 printk(" iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n", regs->cr_iip, ifa, isr);
509 force_sig(SIGSEGV, current);
510 break;
511
512 case 46:
513 printk("Unexpected IA-32 intercept trap (Trap 46)\n");
514 printk(" iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n",
515 regs->cr_iip, ifa, isr, iim);
516 force_sig(SIGSEGV, current);
517 return;
518
519 case 47:
520 sprintf(buf, "IA-32 Interruption Fault (int 0x%lx)", isr >> 16);
521 break;
522
523 default:
524 sprintf(buf, "Fault %lu", vector);
525 break;
526 }
527 die_if_kernel(buf, regs, error);
528 force_sig(SIGILL, current);
529 }
530