ia64/xen-unstable

view xen-2.4.16/arch/i386/traps.c @ 86:4a10fe9b20ec

bitkeeper revision 1.15 (3e24a984iRiWWcgfKCxu2p5q3YbxXw)

Many files:
First half of support for per-domain GDTs and LDTs
author kaf24@labyrinth.cl.cam.ac.uk
date Wed Jan 15 00:21:24 2003 +0000 (2003-01-15)
parents c3e6a52cd801
children 88c1cf85fc8f 2f78322be16a
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 #include <xeno/config.h>
11 #include <xeno/init.h>
12 #include <xeno/interrupt.h>
13 #include <xeno/sched.h>
14 #include <xeno/lib.h>
15 #include <xeno/errno.h>
16 #include <asm/ptrace.h>
17 #include <xeno/delay.h>
18 #include <xeno/spinlock.h>
19 #include <xeno/irq.h>
21 #include <asm/system.h>
22 #include <asm/io.h>
23 #include <asm/atomic.h>
24 #include <asm/desc.h>
25 #include <asm/debugreg.h>
26 #include <asm/smp.h>
27 #include <asm/pgalloc.h>
28 #include <asm/uaccess.h>
29 #include <asm/i387.h>
31 #define GTBF_TRAP 1
32 #define GTBF_TRAP_NOCODE 2
33 #define GTBF_TRAP_CR2 4
34 struct guest_trap_bounce {
35 unsigned long error_code; /* 0 */
36 unsigned long cr2; /* 4 */
37 unsigned short flags; /* 8 */
38 unsigned short cs; /* 10 */
39 unsigned long eip; /* 12 */
40 } guest_trap_bounce[NR_CPUS] = { { 0 } };
42 asmlinkage int hypervisor_call(void);
43 asmlinkage void lcall7(void);
44 asmlinkage void lcall27(void);
46 /*
47 * The IDT has to be page-aligned to simplify the Pentium
48 * F0 0F bug workaround.. We have a special link segment
49 * for this.
50 */
51 struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };
53 asmlinkage void divide_error(void);
54 asmlinkage void debug(void);
55 asmlinkage void nmi(void);
56 asmlinkage void int3(void);
57 asmlinkage void overflow(void);
58 asmlinkage void bounds(void);
59 asmlinkage void invalid_op(void);
60 asmlinkage void device_not_available(void);
61 asmlinkage void double_fault(void);
62 asmlinkage void coprocessor_segment_overrun(void);
63 asmlinkage void invalid_TSS(void);
64 asmlinkage void segment_not_present(void);
65 asmlinkage void stack_segment(void);
66 asmlinkage void general_protection(void);
67 asmlinkage void page_fault(void);
68 asmlinkage void coprocessor_error(void);
69 asmlinkage void simd_coprocessor_error(void);
70 asmlinkage void alignment_check(void);
71 asmlinkage void spurious_interrupt_bug(void);
72 asmlinkage void machine_check(void);
74 int kstack_depth_to_print = 24;
76 static inline int kernel_text_address(unsigned long addr)
77 {
78 return ( 1 );
79 }
81 void show_trace(unsigned long * stack)
82 {
83 int i;
84 unsigned long addr;
86 if (!stack)
87 stack = (unsigned long*)&stack;
89 printk("Call Trace: ");
90 i = 1;
91 while (((long) stack & (THREAD_SIZE-1)) != 0) {
92 addr = *stack++;
93 if (kernel_text_address(addr)) {
94 if (i && ((i % 6) == 0))
95 printk("\n ");
96 printk("[<%08lx>] ", addr);
97 i++;
98 }
99 }
100 printk("\n");
101 }
103 void show_trace_task(struct task_struct *tsk)
104 {
105 unsigned long esp = tsk->thread.esp;
107 /* User space on another CPU? */
108 if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1))
109 return;
110 show_trace((unsigned long *)esp);
111 }
113 void show_stack(unsigned long * esp)
114 {
115 unsigned long *stack;
116 int i;
118 // debugging aid: "show_stack(NULL);" prints the
119 // back trace for this cpu.
121 if(esp==NULL)
122 esp=(unsigned long*)&esp;
124 stack = esp;
125 for(i=0; i < kstack_depth_to_print; i++) {
126 if (((long) stack & (THREAD_SIZE-1)) == 0)
127 break;
128 if (i && ((i % 8) == 0))
129 printk("\n ");
130 printk("%08lx ", *stack++);
131 }
132 printk("\n");
133 show_trace(esp);
134 }
136 void show_registers(struct pt_regs *regs)
137 {
138 unsigned long esp;
139 unsigned short ss;
141 esp = (unsigned long) (&regs->esp);
142 ss = __HYPERVISOR_DS;
143 if ( regs->xcs & 3 )
144 {
145 esp = regs->esp;
146 ss = regs->xss & 0xffff;
147 }
149 printk("CPU: %d\nEIP: %04x:[<%08lx>] \nEFLAGS: %08lx\n",
150 smp_processor_id(), 0xffff & regs->xcs, regs->eip, regs->eflags);
151 printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
152 regs->eax, regs->ebx, regs->ecx, regs->edx);
153 printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
154 regs->esi, regs->edi, regs->ebp, esp);
155 printk("ds: %04x es: %04x ss: %04x\n",
156 regs->xds & 0xffff, regs->xes & 0xffff, ss);
157 }
160 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
162 void die(const char * str, struct pt_regs * regs, long err)
163 {
164 spin_lock_irq(&die_lock);
165 printk("%s: %04lx,%04lx\n", str, err >> 16, err & 0xffff);
166 show_registers(regs);
167 spin_unlock_irq(&die_lock);
168 panic("HYPERVISOR DEATH!!\n");
169 }
171 static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
172 {
173 if (!(3 & regs->xcs)) die(str, regs, err);
174 }
176 static void inline do_trap(int trapnr, char *str,
177 struct pt_regs * regs,
178 long error_code, int use_error_code)
179 {
180 struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
181 trap_info_t *ti;
182 unsigned long addr, fixup;
184 if (!(regs->xcs & 3))
185 goto fault_in_hypervisor;
187 ti = current->thread.traps + trapnr;
188 if ( trapnr == 14 )
189 {
190 /* page fault pushes %cr2 */
191 gtb->flags = GTBF_TRAP_CR2;
192 __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (gtb->cr2) : );
193 }
194 else
195 {
196 gtb->flags = use_error_code ? GTBF_TRAP : GTBF_TRAP_NOCODE;
197 }
198 gtb->error_code = error_code;
199 gtb->cs = ti->cs;
200 gtb->eip = ti->address;
201 return;
203 fault_in_hypervisor:
205 if ( (fixup = search_exception_table(regs->eip)) != 0 )
206 {
207 regs->eip = fixup;
208 return;
209 }
211 __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (addr) : );
213 if ( (trapnr == 14) && (addr >= PAGE_OFFSET) )
214 {
215 unsigned long page;
216 unsigned long *pde;
217 pde = (unsigned long *)idle_pg_table[smp_processor_id()];
218 page = pde[addr >> L2_PAGETABLE_SHIFT];
219 printk("*pde = %08lx\n", page);
220 if ( page & _PAGE_PRESENT )
221 {
222 page &= PAGE_MASK;
223 page = ((unsigned long *) __va(page))[(addr&0x3ff000)>>PAGE_SHIFT];
224 printk(" *pte = %08lx\n", page);
225 }
226 }
228 show_registers(regs);
229 panic("CPU%d FATAL TRAP: vector = %d (%s)\n"
230 "[error_code=%08x]\n"
231 "Faulting linear address might be %08lx\n",
232 smp_processor_id(), trapnr, str,
233 error_code, addr);
234 }
236 #define DO_ERROR_NOCODE(trapnr, str, name) \
237 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
238 { \
239 do_trap(trapnr, str, regs, error_code, 0); \
240 }
242 #define DO_ERROR(trapnr, str, name) \
243 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
244 { \
245 do_trap(trapnr, str, regs, error_code, 1); \
246 }
248 DO_ERROR_NOCODE( 0, "divide error", divide_error)
249 DO_ERROR_NOCODE( 3, "int3", int3)
250 DO_ERROR_NOCODE( 4, "overflow", overflow)
251 DO_ERROR_NOCODE( 5, "bounds", bounds)
252 DO_ERROR_NOCODE( 6, "invalid operand", invalid_op)
253 DO_ERROR_NOCODE( 7, "device not available", device_not_available)
254 DO_ERROR( 8, "double fault", double_fault)
255 DO_ERROR_NOCODE( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
256 DO_ERROR(10, "invalid TSS", invalid_TSS)
257 DO_ERROR(11, "segment not present", segment_not_present)
258 DO_ERROR(12, "stack segment", stack_segment)
259 DO_ERROR(14, "page fault", page_fault)
260 /* Vector 15 reserved by Intel */
261 DO_ERROR_NOCODE(16, "fpu error", coprocessor_error)
262 DO_ERROR(17, "alignment check", alignment_check)
263 DO_ERROR_NOCODE(18, "machine check", machine_check)
264 DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error)
266 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
267 {
268 struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
269 trap_info_t *ti;
270 unsigned long fixup;
272 /* Bad shit if error in ring 0, or result of an interrupt. */
273 if (!(regs->xcs & 3) || (error_code & 1))
274 goto gp_in_kernel;
276 /*
277 * Cunning trick to allow arbitrary "INT n" handling.
278 *
279 * We set DPL == 0 on all vectors in the IDT. This prevents any INT <n>
280 * instruction from trapping to the appropriate vector, when that might not
281 * be expected by Xen or the guest OS. For example, that entry might be for
282 * a fault handler (unlike traps, faults don't increment EIP), or might
283 * expect an error code on the stack (which a software trap never
284 * provides), or might be a hardware interrupt handler that doesn't like
285 * being called spuriously.
286 *
287 * Instead, a GPF occurs with the faulting IDT vector in the error code.
288 * Bit 1 is set to indicate that an IDT entry caused the fault.
289 * Bit 0 is clear to indicate that it's a software fault, not hardware.
290 *
291 * NOTE: Vectors 3 and 4 are dealt with from their own handler. This is okay
292 * because they can only be triggered by an explicit DPL-checked instruction.
293 * The DPL specified by the guest OS for these vectors is NOT CHECKED!!
294 */
295 if ( (error_code & 3) == 2 )
296 {
297 /* This fault must be due to <INT n> instruction. */
298 ti = current->thread.traps + (error_code>>3);
299 if ( ti->dpl >= (regs->xcs & 3) )
300 {
301 gtb->flags = GTBF_TRAP_NOCODE;
302 gtb->cs = ti->cs;
303 gtb->eip = ti->address;
304 regs->eip += 2;
305 return;
306 }
307 }
309 /* Pass on GPF as is. */
310 ti = current->thread.traps + 13;
311 gtb->flags = GTBF_TRAP;
312 gtb->error_code = error_code;
313 gtb->cs = ti->cs;
314 gtb->eip = ti->address;
315 return;
317 gp_in_kernel:
318 if ( (fixup = search_exception_table(regs->eip)) != 0 )
319 {
320 regs->eip = fixup;
321 return;
322 }
324 die("general protection fault", regs, error_code);
325 }
327 static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
328 {
329 printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
330 printk("You probably have a hardware problem with your RAM chips\n");
332 /* Clear and disable the memory parity error line. */
333 reason = (reason & 0xf) | 4;
334 outb(reason, 0x61);
335 }
337 static void io_check_error(unsigned char reason, struct pt_regs * regs)
338 {
339 unsigned long i;
341 printk("NMI: IOCK error (debug interrupt?)\n");
342 show_registers(regs);
344 /* Re-enable the IOCK line, wait for a few seconds */
345 reason = (reason & 0xf) | 8;
346 outb(reason, 0x61);
347 i = 2000;
348 while (--i) udelay(1000);
349 reason &= ~8;
350 outb(reason, 0x61);
351 }
353 static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
354 {
355 printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
356 printk("Dazed and confused, but trying to continue\n");
357 printk("Do you have a strange power saving mode enabled?\n");
358 }
360 asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
361 {
362 unsigned char reason = inb(0x61);
364 if (!(reason & 0xc0)) {
365 unknown_nmi_error(reason, regs);
366 return;
367 }
368 if (reason & 0x80)
369 mem_parity_error(reason, regs);
370 if (reason & 0x40)
371 io_check_error(reason, regs);
372 /*
373 * Reassert NMI in case it became active meanwhile
374 * as it's edge-triggered.
375 */
376 outb(0x8f, 0x70);
377 inb(0x71); /* dummy */
378 outb(0x0f, 0x70);
379 inb(0x71); /* dummy */
380 }
382 asmlinkage void math_state_restore(struct pt_regs *regs, long error_code)
383 {
384 /* Prevent recursion. */
385 clts();
387 if ( !(current->flags & PF_USEDFPU) )
388 {
389 if ( current->flags & PF_DONEFPUINIT )
390 restore_fpu(current);
391 else
392 init_fpu();
393 current->flags |= PF_USEDFPU; /* So we fnsave on switch_to() */
394 }
396 if ( current->flags & PF_GUEST_STTS )
397 {
398 struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
399 gtb->flags = GTBF_TRAP_NOCODE;
400 gtb->cs = current->thread.traps[7].cs;
401 gtb->eip = current->thread.traps[7].address;
402 current->flags &= ~PF_GUEST_STTS;
403 }
404 }
407 asmlinkage void do_debug(struct pt_regs * regs, long error_code)
408 {
409 unsigned int condition;
410 struct task_struct *tsk = current;
411 struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
413 __asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
415 /* Mask out spurious debug traps due to lazy DR7 setting */
416 if ( (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) &&
417 (tsk->thread.debugreg[7] == 0) )
418 {
419 __asm__("movl %0,%%db7" : : "r" (0));
420 return;
421 }
423 if ( (regs->xcs & 3) == 0 )
424 {
425 /* Clear TF just for absolute sanity. */
426 regs->eflags &= ~EF_TF;
427 /*
428 * Basically, we ignore watchpoints when they trigger in
429 * the hypervisor. This may happen when a buffer is passed
430 * to us which previously had a watchpoint set on it.
431 * No need to bump EIP; the only faulting trap is an
432 * instruction breakpoint, which can't happen to us.
433 */
434 return;
435 }
437 /* Save debug status register where guest OS can peek at it */
438 tsk->thread.debugreg[6] = condition;
440 gtb->flags = GTBF_TRAP_NOCODE;
441 gtb->cs = tsk->thread.traps[1].cs;
442 gtb->eip = tsk->thread.traps[1].address;
443 }
446 asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
447 long error_code)
448 { /* nothing */ }
451 #define _set_gate(gate_addr,type,dpl,addr) \
452 do { \
453 int __d0, __d1; \
454 __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
455 "movw %4,%%dx\n\t" \
456 "movl %%eax,%0\n\t" \
457 "movl %%edx,%1" \
458 :"=m" (*((long *) (gate_addr))), \
459 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
460 :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
461 "3" ((char *) (addr)),"2" (__HYPERVISOR_CS << 16)); \
462 } while (0)
465 /*
466 * This needs to use 'idt_table' rather than 'idt', and
467 * thus use the _nonmapped_ version of the IDT, as the
468 * Pentium F0 0F bugfix can have resulted in the mapped
469 * IDT being write-protected.
470 */
471 void set_intr_gate(unsigned int n, void *addr)
472 {
473 _set_gate(idt_table+n,14,0,addr);
474 }
476 static void __init set_trap_gate(unsigned int n, void *addr)
477 {
478 _set_gate(idt_table+n,15,0,addr);
479 }
481 static void __init set_system_gate(unsigned int n, void *addr)
482 {
483 _set_gate(idt_table+n,15,3,addr);
484 }
486 static void __init set_call_gate(void *a, void *addr)
487 {
488 _set_gate(a,12,3,addr);
489 }
491 #define _set_seg_desc(gate_addr,type,dpl,base,limit) {\
492 *((gate_addr)+1) = ((base) & 0xff000000) | \
493 (((base) & 0x00ff0000)>>16) | \
494 ((limit) & 0xf0000) | \
495 ((dpl)<<13) | \
496 (0x00408000) | \
497 ((type)<<8); \
498 *(gate_addr) = (((base) & 0x0000ffff)<<16) | \
499 ((limit) & 0x0ffff); }
501 #define _set_tssldt_desc(n,addr,limit,type) \
502 __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
503 "movw %%ax,2(%2)\n\t" \
504 "rorl $16,%%eax\n\t" \
505 "movb %%al,4(%2)\n\t" \
506 "movb %4,5(%2)\n\t" \
507 "movb $0,6(%2)\n\t" \
508 "movb %%ah,7(%2)\n\t" \
509 "rorl $16,%%eax" \
510 : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type))
512 void set_tss_desc(unsigned int n, void *addr)
513 {
514 _set_tssldt_desc(gdt_table+__TSS(n), (int)addr, 235, 0x89);
515 }
517 void __init trap_init(void)
518 {
519 set_trap_gate(0,&divide_error);
520 set_trap_gate(1,&debug);
521 set_intr_gate(2,&nmi);
522 set_system_gate(3,&int3); /* usable from all privilege levels */
523 set_system_gate(4,&overflow); /* usable from all privilege levels */
524 set_trap_gate(5,&bounds);
525 set_trap_gate(6,&invalid_op);
526 set_trap_gate(7,&device_not_available);
527 set_trap_gate(8,&double_fault);
528 set_trap_gate(9,&coprocessor_segment_overrun);
529 set_trap_gate(10,&invalid_TSS);
530 set_trap_gate(11,&segment_not_present);
531 set_trap_gate(12,&stack_segment);
532 set_trap_gate(13,&general_protection);
533 set_intr_gate(14,&page_fault);
534 set_trap_gate(15,&spurious_interrupt_bug);
535 set_trap_gate(16,&coprocessor_error);
536 set_trap_gate(17,&alignment_check);
537 set_trap_gate(18,&machine_check);
538 set_trap_gate(19,&simd_coprocessor_error);
540 /* Only ring 1 can access monitor services. */
541 _set_gate(idt_table+HYPERVISOR_CALL_VECTOR,15,1,&hypervisor_call);
543 /*
544 * Should be a barrier for any external CPU state.
545 */
546 {
547 extern void cpu_init(void);
548 cpu_init();
549 }
550 }
553 long do_set_trap_table(trap_info_t *traps)
554 {
555 trap_info_t cur;
556 trap_info_t *dst = current->thread.traps;
558 memset(dst, 0, sizeof(*dst) * 256);
560 for ( ; ; )
561 {
562 if ( copy_from_user(&cur, traps, sizeof(cur)) ) return -EFAULT;
563 if ( (cur.cs & 3) == 0 ) return -EPERM;
564 if ( cur.address == 0 ) break;
565 memcpy(dst+cur.vector, &cur, sizeof(cur));
566 traps++;
567 }
569 return(0);
570 }
573 long do_fpu_taskswitch(void)
574 {
575 current->flags |= PF_GUEST_STTS;
576 stts();
577 return 0;
578 }
581 long do_set_debugreg(int reg, unsigned long value)
582 {
583 int i;
585 switch ( reg )
586 {
587 case 0:
588 if ( value > (PAGE_OFFSET-4) ) return -EPERM;
589 __asm__ ( "movl %0, %%db0" : : "r" (value) );
590 break;
591 case 1:
592 if ( value > (PAGE_OFFSET-4) ) return -EPERM;
593 __asm__ ( "movl %0, %%db1" : : "r" (value) );
594 break;
595 case 2:
596 if ( value > (PAGE_OFFSET-4) ) return -EPERM;
597 __asm__ ( "movl %0, %%db2" : : "r" (value) );
598 break;
599 case 3:
600 if ( value > (PAGE_OFFSET-4) ) return -EPERM;
601 __asm__ ( "movl %0, %%db3" : : "r" (value) );
602 break;
603 case 6:
604 /*
605 * DR6: Bits 4-11,16-31 reserved (set to 1).
606 * Bit 12 reserved (set to 0).
607 */
608 value &= 0xffffefff; /* reserved bits => 0 */
609 value |= 0xffff0ff0; /* reserved bits => 1 */
610 __asm__ ( "movl %0, %%db6" : : "r" (value) );
611 break;
612 case 7:
613 /*
614 * DR7: Bit 10 reserved (set to 1).
615 * Bits 11-12,14-15 reserved (set to 0).
616 * Privileged bits:
617 * GD (bit 13): must be 0.
618 * R/Wn (bits 16-17,20-21,24-25,28-29): mustn't be 10.
619 * LENn (bits 18-19,22-23,26-27,30-31): mustn't be 10.
620 */
621 /* DR7 == 0 => debugging disabled for this domain. */
622 if ( value != 0 )
623 {
624 value &= 0xffff27ff; /* reserved bits => 0 */
625 value |= 0x00000400; /* reserved bits => 1 */
626 if ( (value & (1<<13)) != 0 ) return -EPERM;
627 for ( i = 0; i < 16; i += 2 )
628 if ( ((value >> (i+16)) & 3) == 2 ) return -EPERM;
629 }
630 __asm__ ( "movl %0, %%db7" : : "r" (value) );
631 break;
632 default:
633 return -EINVAL;
634 }
636 current->thread.debugreg[reg] = value;
637 return 0;
638 }
640 unsigned long do_get_debugreg(int reg)
641 {
642 if ( (reg < 0) || (reg > 7) ) return -EINVAL;
643 return current->thread.debugreg[reg];
644 }