direct-io.hg

view xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/traps.c @ 372:93721e4cec72

bitkeeper revision 1.174.1.1 (3e9da471qg3yz_feoqPtr18G7aJ8UA)

ptrace.h, traps.c:
Fix ring privilege checking in Xenolinux (OS runs in ring 1, not ring 0).
author kaf24@scramble.cl.cam.ac.uk
date Wed Apr 16 18:44:01 2003 +0000 (2003-04-16)
parents 2eb189eacf01
children c3eb2a837ee5
line source
1 /*
2 * linux/arch/i386/traps.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * Pentium III FXSR, SSE support
7 * Gareth Hughes <gareth@valinux.com>, May 2000
8 */
10 /*
11 * 'Traps.c' handles hardware traps and faults after we have saved some
12 * state in 'asm.s'.
13 */
14 #include <linux/config.h>
15 #include <linux/sched.h>
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/errno.h>
19 #include <linux/ptrace.h>
20 #include <linux/timer.h>
21 #include <linux/mm.h>
22 #include <linux/init.h>
23 #include <linux/delay.h>
24 #include <linux/spinlock.h>
25 #include <linux/interrupt.h>
26 #include <linux/highmem.h>
28 #include <asm/system.h>
29 #include <asm/uaccess.h>
30 #include <asm/io.h>
31 #include <asm/atomic.h>
32 #include <asm/debugreg.h>
33 #include <asm/desc.h>
34 #include <asm/i387.h>
36 #include <asm/smp.h>
37 #include <asm/pgalloc.h>
39 #include <asm/hypervisor.h>
41 #include <linux/irq.h>
42 #include <linux/module.h>
44 asmlinkage int system_call(void);
45 asmlinkage void lcall7(void);
46 asmlinkage void lcall27(void);
48 asmlinkage void divide_error(void);
49 asmlinkage void debug(void);
50 asmlinkage void int3(void);
51 asmlinkage void overflow(void);
52 asmlinkage void bounds(void);
53 asmlinkage void invalid_op(void);
54 asmlinkage void device_not_available(void);
55 asmlinkage void double_fault(void);
56 asmlinkage void coprocessor_segment_overrun(void);
57 asmlinkage void invalid_TSS(void);
58 asmlinkage void segment_not_present(void);
59 asmlinkage void stack_segment(void);
60 asmlinkage void general_protection(void);
61 asmlinkage void page_fault(void);
62 asmlinkage void coprocessor_error(void);
63 asmlinkage void simd_coprocessor_error(void);
64 asmlinkage void alignment_check(void);
65 asmlinkage void spurious_interrupt_bug(void);
66 asmlinkage void machine_check(void);
68 int kstack_depth_to_print = 24;
71 /*
72 * If the address is either in the .text section of the
73 * kernel, or in the vmalloc'ed module regions, it *may*
74 * be the address of a calling routine
75 */
77 #ifdef CONFIG_MODULES
79 extern struct module *module_list;
80 extern struct module kernel_module;
82 static inline int kernel_text_address(unsigned long addr)
83 {
84 int retval = 0;
85 struct module *mod;
87 if (addr >= (unsigned long) &_stext &&
88 addr <= (unsigned long) &_etext)
89 return 1;
91 for (mod = module_list; mod != &kernel_module; mod = mod->next) {
92 /* mod_bound tests for addr being inside the vmalloc'ed
93 * module area. Of course it'd be better to test only
94 * for the .text subset... */
95 if (mod_bound(addr, 0, mod)) {
96 retval = 1;
97 break;
98 }
99 }
101 return retval;
102 }
104 #else
106 static inline int kernel_text_address(unsigned long addr)
107 {
108 return (addr >= (unsigned long) &_stext &&
109 addr <= (unsigned long) &_etext);
110 }
112 #endif
114 void show_trace(unsigned long * stack)
115 {
116 int i;
117 unsigned long addr;
119 if (!stack)
120 stack = (unsigned long*)&stack;
122 printk("Call Trace: ");
123 i = 1;
124 while (((long) stack & (THREAD_SIZE-1)) != 0) {
125 addr = *stack++;
126 if (kernel_text_address(addr)) {
127 if (i && ((i % 6) == 0))
128 printk("\n ");
129 printk("[<%08lx>] ", addr);
130 i++;
131 }
132 }
133 printk("\n");
134 }
136 void show_trace_task(struct task_struct *tsk)
137 {
138 unsigned long esp = tsk->thread.esp;
140 /* User space on another CPU? */
141 if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
142 return;
143 show_trace((unsigned long *)esp);
144 }
146 void show_stack(unsigned long * esp)
147 {
148 unsigned long *stack;
149 int i;
151 // debugging aid: "show_stack(NULL);" prints the
152 // back trace for this cpu.
154 if(esp==NULL)
155 esp=(unsigned long*)&esp;
157 stack = esp;
158 for(i=0; i < kstack_depth_to_print; i++) {
159 if (((long) stack & (THREAD_SIZE-1)) == 0)
160 break;
161 if (i && ((i % 8) == 0))
162 printk("\n ");
163 printk("%08lx ", *stack++);
164 }
165 printk("\n");
166 show_trace(esp);
167 }
169 void show_registers(struct pt_regs *regs)
170 {
171 int i;
172 int in_kernel = 1;
173 unsigned long esp;
174 unsigned short ss;
176 esp = (unsigned long) (&regs->esp);
177 ss = __KERNEL_DS;
178 if (regs->xcs & 2) {
179 in_kernel = 0;
180 esp = regs->esp;
181 ss = regs->xss & 0xffff;
182 }
183 printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx\n",
184 smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags);
185 printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
186 regs->eax, regs->ebx, regs->ecx, regs->edx);
187 printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
188 regs->esi, regs->edi, regs->ebp, esp);
189 printk("ds: %04x es: %04x ss: %04x\n",
190 regs->xds & 0xffff, regs->xes & 0xffff, ss);
191 printk("Process %s (pid: %d, stackpage=%08lx)",
192 current->comm, current->pid, 4096+(unsigned long)current);
193 /*
194 * When in-kernel, we also print out the stack and code at the
195 * time of the fault..
196 */
197 if (in_kernel) {
199 printk("\nStack: ");
200 show_stack((unsigned long*)esp);
202 #if 0
203 printk("\nCode: ");
204 if(regs->eip < PAGE_OFFSET)
205 goto bad;
207 for(i=0;i<20;i++)
208 {
209 unsigned char c;
210 if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
211 bad:
212 printk(" Bad EIP value.");
213 break;
214 }
215 printk("%02x ", c);
216 }
217 #endif
218 }
219 printk("\n");
220 }
222 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
224 void die(const char * str, struct pt_regs * regs, long err)
225 {
226 console_verbose();
227 spin_lock_irq(&die_lock);
228 bust_spinlocks(1);
229 printk("%s: %04lx\n", str, err & 0xffff);
230 show_registers(regs);
231 bust_spinlocks(0);
232 spin_unlock_irq(&die_lock);
233 do_exit(SIGSEGV);
234 }
236 static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
237 {
238 if (!(2 & regs->xcs))
239 die(str, regs, err);
240 }
243 static void inline do_trap(int trapnr, int signr, char *str,
244 struct pt_regs * regs, long error_code,
245 siginfo_t *info)
246 {
247 if (!(regs->xcs & 2))
248 goto kernel_trap;
250 /*trap_signal:*/ {
251 struct task_struct *tsk = current;
252 tsk->thread.error_code = error_code;
253 tsk->thread.trap_no = trapnr;
254 if (info)
255 force_sig_info(signr, info, tsk);
256 else
257 force_sig(signr, tsk);
258 return;
259 }
261 kernel_trap: {
262 unsigned long fixup = search_exception_table(regs->eip);
263 if (fixup)
264 regs->eip = fixup;
265 else
266 die(str, regs, error_code);
267 return;
268 }
269 }
271 #define DO_ERROR(trapnr, signr, str, name) \
272 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
273 { \
274 do_trap(trapnr, signr, str, regs, error_code, NULL); \
275 }
277 #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
278 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
279 { \
280 siginfo_t info; \
281 info.si_signo = signr; \
282 info.si_errno = 0; \
283 info.si_code = sicode; \
284 info.si_addr = (void *)siaddr; \
285 do_trap(trapnr, signr, str, regs, error_code, &info); \
286 }
288 DO_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip)
289 DO_ERROR( 3, SIGTRAP, "int3", int3)
290 DO_ERROR( 4, SIGSEGV, "overflow", overflow)
291 DO_ERROR( 5, SIGSEGV, "bounds", bounds)
292 DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
293 DO_ERROR( 7, SIGSEGV, "device not available", device_not_available)
294 DO_ERROR( 8, SIGSEGV, "double fault", double_fault)
295 DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
296 DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
297 DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
298 DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
299 DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
300 DO_ERROR(18, SIGBUS, "machine check", machine_check)
302 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
303 {
304 if (!(regs->xcs & 2))
305 goto gp_in_kernel;
307 current->thread.error_code = error_code;
308 current->thread.trap_no = 13;
309 force_sig(SIGSEGV, current);
310 return;
312 gp_in_kernel:
313 {
314 unsigned long fixup;
315 fixup = search_exception_table(regs->eip);
316 if (fixup) {
317 regs->eip = fixup;
318 return;
319 }
320 die("general protection fault", regs, error_code);
321 }
322 }
325 asmlinkage void do_debug(struct pt_regs * regs, long error_code)
326 {
327 unsigned int condition;
328 struct task_struct *tsk = current;
329 siginfo_t info;
331 condition = HYPERVISOR_get_debugreg(6);
333 /* Mask out spurious debug traps due to lazy DR7 setting */
334 if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
335 if (!tsk->thread.debugreg[7])
336 goto clear_dr7;
337 }
339 /* Save debug status register where ptrace can see it */
340 tsk->thread.debugreg[6] = condition;
342 /* Mask out spurious TF errors due to lazy TF clearing */
343 if (condition & DR_STEP) {
344 /*
345 * The TF error should be masked out only if the current
346 * process is not traced and if the TRAP flag has been set
347 * previously by a tracing process (condition detected by
348 * the PT_DTRACE flag); remember that the i386 TRAP flag
349 * can be modified by the process itself in user mode,
350 * allowing programs to debug themselves without the ptrace()
351 * interface.
352 */
353 if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
354 goto clear_TF;
355 }
357 /* Ok, finally something we can handle */
358 tsk->thread.trap_no = 1;
359 tsk->thread.error_code = error_code;
360 info.si_signo = SIGTRAP;
361 info.si_errno = 0;
362 info.si_code = TRAP_BRKPT;
364 /* If this is a kernel mode trap, save the user PC on entry to
365 * the kernel, that's what the debugger can make sense of.
366 */
367 info.si_addr = ((regs->xcs & 2) == 0) ? (void *)tsk->thread.eip :
368 (void *)regs->eip;
369 force_sig_info(SIGTRAP, &info, tsk);
371 /* Disable additional traps. They'll be re-enabled when
372 * the signal is delivered.
373 */
374 clear_dr7:
375 HYPERVISOR_set_debugreg(7, 0);
376 return;
378 clear_TF:
379 regs->eflags &= ~TF_MASK;
380 return;
381 }
384 /*
385 * Note that we play around with the 'TS' bit in an attempt to get
386 * the correct behaviour even in the presence of the asynchronous
387 * IRQ13 behaviour
388 */
389 void math_error(void *eip)
390 {
391 struct task_struct * task;
392 siginfo_t info;
393 unsigned short cwd, swd;
395 /*
396 * Save the info for the exception handler and clear the error.
397 */
398 task = current;
399 save_init_fpu(task);
400 task->thread.trap_no = 16;
401 task->thread.error_code = 0;
402 info.si_signo = SIGFPE;
403 info.si_errno = 0;
404 info.si_code = __SI_FAULT;
405 info.si_addr = eip;
406 /*
407 * (~cwd & swd) will mask out exceptions that are not set to unmasked
408 * status. 0x3f is the exception bits in these regs, 0x200 is the
409 * C1 reg you need in case of a stack fault, 0x040 is the stack
410 * fault bit. We should only be taking one exception at a time,
411 * so if this combination doesn't produce any single exception,
412 * then we have a bad program that isn't syncronizing its FPU usage
413 * and it will suffer the consequences since we won't be able to
414 * fully reproduce the context of the exception
415 */
416 cwd = get_fpu_cwd(task);
417 swd = get_fpu_swd(task);
418 switch (((~cwd) & swd & 0x3f) | (swd & 0x240)) {
419 case 0x000:
420 default:
421 break;
422 case 0x001: /* Invalid Op */
423 case 0x040: /* Stack Fault */
424 case 0x240: /* Stack Fault | Direction */
425 info.si_code = FPE_FLTINV;
426 break;
427 case 0x002: /* Denormalize */
428 case 0x010: /* Underflow */
429 info.si_code = FPE_FLTUND;
430 break;
431 case 0x004: /* Zero Divide */
432 info.si_code = FPE_FLTDIV;
433 break;
434 case 0x008: /* Overflow */
435 info.si_code = FPE_FLTOVF;
436 break;
437 case 0x020: /* Precision */
438 info.si_code = FPE_FLTRES;
439 break;
440 }
441 force_sig_info(SIGFPE, &info, task);
442 }
444 asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
445 {
446 ignore_irq13 = 1;
447 math_error((void *)regs->eip);
448 }
450 void simd_math_error(void *eip)
451 {
452 struct task_struct * task;
453 siginfo_t info;
454 unsigned short mxcsr;
456 /*
457 * Save the info for the exception handler and clear the error.
458 */
459 task = current;
460 save_init_fpu(task);
461 task->thread.trap_no = 19;
462 task->thread.error_code = 0;
463 info.si_signo = SIGFPE;
464 info.si_errno = 0;
465 info.si_code = __SI_FAULT;
466 info.si_addr = eip;
467 /*
468 * The SIMD FPU exceptions are handled a little differently, as there
469 * is only a single status/control register. Thus, to determine which
470 * unmasked exception was caught we must mask the exception mask bits
471 * at 0x1f80, and then use these to mask the exception bits at 0x3f.
472 */
473 mxcsr = get_fpu_mxcsr(task);
474 switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
475 case 0x000:
476 default:
477 break;
478 case 0x001: /* Invalid Op */
479 info.si_code = FPE_FLTINV;
480 break;
481 case 0x002: /* Denormalize */
482 case 0x010: /* Underflow */
483 info.si_code = FPE_FLTUND;
484 break;
485 case 0x004: /* Zero Divide */
486 info.si_code = FPE_FLTDIV;
487 break;
488 case 0x008: /* Overflow */
489 info.si_code = FPE_FLTOVF;
490 break;
491 case 0x020: /* Precision */
492 info.si_code = FPE_FLTRES;
493 break;
494 }
495 force_sig_info(SIGFPE, &info, task);
496 }
498 asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs,
499 long error_code)
500 {
501 if (cpu_has_xmm) {
502 /* Handle SIMD FPU exceptions on PIII+ processors. */
503 ignore_irq13 = 1;
504 simd_math_error((void *)regs->eip);
505 } else {
506 die_if_kernel("cache flush denied", regs, error_code);
507 current->thread.trap_no = 19;
508 current->thread.error_code = error_code;
509 force_sig(SIGSEGV, current);
510 }
511 }
513 asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
514 long error_code)
515 {
516 }
518 /*
519 * 'math_state_restore()' saves the current math information in the
520 * old math state array, and gets the new ones from the current task
521 *
522 * Careful.. There are problems with IBM-designed IRQ13 behaviour.
523 * Don't touch unless you *really* know how it works.
524 */
525 asmlinkage void math_state_restore(struct pt_regs regs)
526 {
527 if (current->used_math) {
528 restore_fpu(current);
529 } else {
530 init_fpu();
531 }
532 current->flags |= PF_USEDFPU; /* So we fnsave on switch_to() */
533 }
536 #define _set_gate(gate_addr,type,dpl,addr) \
537 do { \
538 int __d0, __d1; \
539 __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
540 "movw %4,%%dx\n\t" \
541 "movl %%eax,%0\n\t" \
542 "movl %%edx,%1" \
543 :"=m" (*((long *) (gate_addr))), \
544 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
545 :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
546 "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
547 } while (0)
549 static void __init set_call_gate(void *a, void *addr)
550 {
551 _set_gate(a,12,3,addr);
552 }
555 static trap_info_t trap_table[] = {
556 { 0, 0, __KERNEL_CS, (unsigned long)divide_error },
557 { 1, 0, __KERNEL_CS, (unsigned long)debug },
558 { 3, 3, __KERNEL_CS, (unsigned long)int3 },
559 { 4, 3, __KERNEL_CS, (unsigned long)overflow },
560 { 5, 3, __KERNEL_CS, (unsigned long)bounds },
561 { 6, 0, __KERNEL_CS, (unsigned long)invalid_op },
562 { 7, 0, __KERNEL_CS, (unsigned long)device_not_available },
563 { 8, 0, __KERNEL_CS, (unsigned long)double_fault },
564 { 9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun },
565 { 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS },
566 { 11, 0, __KERNEL_CS, (unsigned long)segment_not_present },
567 { 12, 0, __KERNEL_CS, (unsigned long)stack_segment },
568 { 13, 0, __KERNEL_CS, (unsigned long)general_protection },
569 { 14, 0, __KERNEL_CS, (unsigned long)page_fault },
570 { 15, 0, __KERNEL_CS, (unsigned long)spurious_interrupt_bug },
571 { 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error },
572 { 17, 0, __KERNEL_CS, (unsigned long)alignment_check },
573 { 18, 0, __KERNEL_CS, (unsigned long)machine_check },
574 { 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error },
575 { SYSCALL_VECTOR,
576 3, __KERNEL_CS, (unsigned long)system_call },
577 { 0, 0, 0, 0 }
578 };
582 void __init trap_init(void)
583 {
584 HYPERVISOR_set_trap_table(trap_table);
585 HYPERVISOR_set_fast_trap(SYSCALL_VECTOR);
587 /*
588 * The default LDT is a single-entry callgate to lcall7 for iBCS and a
589 * callgate to lcall27 for Solaris/x86 binaries.
590 */
591 clear_page(&default_ldt[0]);
592 set_call_gate(&default_ldt[0],lcall7);
593 set_call_gate(&default_ldt[4],lcall27);
594 __make_page_readonly(&default_ldt[0]);
596 cpu_init();
597 }