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, &regs->cr_ipsr, &regs->ar_fpsr, &isr, &regs->pr,
287     			       &regs->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