debuggers.hg

view xen/arch/x86/traps.c @ 3640:9a9c5a491401

bitkeeper revision 1.1159.235.1 (42000d3dwcPyT8aY4VIPYGCfCAJuQQ)

More x86/64. Status: traps.c now included in the build, but actual building
of IDT doesn't happen, and we need some sort of entry.S. More page-table
building required so that arch_init_memory() can work. And there is something
odd with MP-table parsing; I currently suspect that __init sections are
causing problems.
Signed-off-by: keir.fraser@cl.cam.ac.uk
author kaf24@viper.(none)
date Tue Feb 01 23:14:05 2005 +0000 (2005-02-01)
parents ed902e5c4b49
children e6af5d8f8b39
line source
1 /******************************************************************************
2 * arch/x86/traps.c
3 *
4 * Modifications to Linux original are copyright (c) 2002-2004, K A Fraser
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
21 /*
22 * Copyright (C) 1991, 1992 Linus Torvalds
23 *
24 * Pentium III FXSR, SSE support
25 * Gareth Hughes <gareth@valinux.com>, May 2000
26 */
28 #include <xen/config.h>
29 #include <xen/init.h>
30 #include <xen/sched.h>
31 #include <xen/lib.h>
32 #include <xen/errno.h>
33 #include <xen/mm.h>
34 #include <xen/console.h>
35 #include <asm/regs.h>
36 #include <xen/delay.h>
37 #include <xen/event.h>
38 #include <xen/spinlock.h>
39 #include <xen/irq.h>
40 #include <xen/perfc.h>
41 #include <xen/softirq.h>
42 #include <asm/shadow.h>
43 #include <asm/domain_page.h>
44 #include <asm/system.h>
45 #include <asm/io.h>
46 #include <asm/atomic.h>
47 #include <asm/desc.h>
48 #include <asm/debugreg.h>
49 #include <asm/smp.h>
50 #include <asm/flushtlb.h>
51 #include <asm/uaccess.h>
52 #include <asm/i387.h>
53 #include <asm/debugger.h>
54 #include <asm/msr.h>
56 /*
57 * opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
58 * fatal: Xen prints diagnostic message and then hangs.
59 * dom0: The NMI is virtualised to DOM0.
60 * ignore: The NMI error is cleared and ignored.
61 */
62 #ifdef NDEBUG
63 char opt_nmi[10] = "dom0";
64 #else
65 char opt_nmi[10] = "fatal";
66 #endif
67 string_param("nmi", opt_nmi);
69 asmlinkage int hypercall(void);
71 /* Master table, and the one used by CPU0. */
72 idt_entry_t idt_table[IDT_ENTRIES] = { {0, 0}, };
73 /* All other CPUs have their own copy. */
74 idt_entry_t *idt_tables[NR_CPUS] = { 0 };
76 asmlinkage void divide_error(void);
77 asmlinkage void debug(void);
78 asmlinkage void nmi(void);
79 asmlinkage void int3(void);
80 asmlinkage void overflow(void);
81 asmlinkage void bounds(void);
82 asmlinkage void invalid_op(void);
83 asmlinkage void device_not_available(void);
84 asmlinkage void coprocessor_segment_overrun(void);
85 asmlinkage void invalid_TSS(void);
86 asmlinkage void segment_not_present(void);
87 asmlinkage void stack_segment(void);
88 asmlinkage void general_protection(void);
89 asmlinkage void page_fault(void);
90 asmlinkage void coprocessor_error(void);
91 asmlinkage void simd_coprocessor_error(void);
92 asmlinkage void alignment_check(void);
93 asmlinkage void spurious_interrupt_bug(void);
94 asmlinkage void machine_check(void);
96 /*
97 * This is called for faults at very unexpected times (e.g., when interrupts
98 * are disabled). In such situations we can't do much that is safe. We try to
99 * print out some tracing and then we just spin.
100 */
101 asmlinkage void fatal_trap(int trapnr, struct xen_regs *regs)
102 {
103 int cpu = smp_processor_id();
104 unsigned long cr2;
105 static char *trapstr[] = {
106 "divide error", "debug", "nmi", "bkpt", "overflow", "bounds",
107 "invalid operation", "device not available", "double fault",
108 "coprocessor segment", "invalid tss", "segment not found",
109 "stack error", "general protection fault", "page fault",
110 "spurious interrupt", "coprocessor error", "alignment check",
111 "machine check", "simd error"
112 };
114 show_registers(regs);
116 if ( trapnr == TRAP_page_fault )
117 {
118 __asm__ __volatile__ ("mov %%cr2,%0" : "=r" (cr2) : );
119 printk("Faulting linear address might be %08lx\n", cr2);
120 }
122 printk("************************************\n");
123 printk("CPU%d FATAL TRAP %d (%s), ERROR_CODE %04x%s.\n",
124 cpu, trapnr, trapstr[trapnr], regs->error_code,
125 (regs->eflags & X86_EFLAGS_IF) ? "" : ", IN INTERRUPT CONTEXT");
126 printk("System shutting down -- need manual reset.\n");
127 printk("************************************\n");
129 /* Lock up the console to prevent spurious output from other CPUs. */
130 console_force_lock();
132 /* Wait for manual reset. */
133 for ( ; ; )
134 __asm__ __volatile__ ( "hlt" );
135 }
137 static inline int do_trap(int trapnr, char *str,
138 struct xen_regs *regs,
139 int use_error_code)
140 {
141 struct exec_domain *ed = current;
142 struct trap_bounce *tb = &ed->thread.trap_bounce;
143 trap_info_t *ti;
144 unsigned long fixup;
146 DEBUGGER_trap_entry(trapnr, regs);
148 if ( !GUEST_FAULT(regs) )
149 goto xen_fault;
151 ti = current->thread.traps + trapnr;
152 tb->flags = TBF_EXCEPTION;
153 tb->cs = ti->cs;
154 tb->eip = ti->address;
155 if ( use_error_code )
156 {
157 tb->flags |= TBF_EXCEPTION_ERRCODE;
158 tb->error_code = regs->error_code;
159 }
160 if ( TI_GET_IF(ti) )
161 ed->vcpu_info->evtchn_upcall_mask = 1;
162 return 0;
164 xen_fault:
166 if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
167 {
168 DPRINTK("Trap %d: %08lx -> %08lx\n", trapnr, regs->eip, fixup);
169 regs->eip = fixup;
170 return 0;
171 }
173 DEBUGGER_trap_fatal(trapnr, regs);
175 show_registers(regs);
176 panic("CPU%d FATAL TRAP: vector = %d (%s)\n"
177 "[error_code=%04x]\n",
178 smp_processor_id(), trapnr, str, regs->error_code);
179 return 0;
180 }
182 #define DO_ERROR_NOCODE(trapnr, str, name) \
183 asmlinkage int do_##name(struct xen_regs *regs) \
184 { \
185 return do_trap(trapnr, str, regs, 0); \
186 }
188 #define DO_ERROR(trapnr, str, name) \
189 asmlinkage int do_##name(struct xen_regs *regs) \
190 { \
191 return do_trap(trapnr, str, regs, 1); \
192 }
194 DO_ERROR_NOCODE( 0, "divide error", divide_error)
195 DO_ERROR_NOCODE( 4, "overflow", overflow)
196 DO_ERROR_NOCODE( 5, "bounds", bounds)
197 DO_ERROR_NOCODE( 6, "invalid operand", invalid_op)
198 DO_ERROR_NOCODE( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
199 DO_ERROR(10, "invalid TSS", invalid_TSS)
200 DO_ERROR(11, "segment not present", segment_not_present)
201 DO_ERROR(12, "stack segment", stack_segment)
202 DO_ERROR_NOCODE(16, "fpu error", coprocessor_error)
203 DO_ERROR(17, "alignment check", alignment_check)
204 DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error)
206 asmlinkage int do_int3(struct xen_regs *regs)
207 {
208 struct exec_domain *ed = current;
209 struct trap_bounce *tb = &ed->thread.trap_bounce;
210 trap_info_t *ti;
212 DEBUGGER_trap_entry(TRAP_int3, regs);
214 if ( !GUEST_FAULT(regs) )
215 {
216 DEBUGGER_trap_fatal(TRAP_int3, regs);
217 show_registers(regs);
218 panic("CPU%d FATAL TRAP: vector = 3 (Int3)\n", smp_processor_id());
219 }
221 ti = current->thread.traps + 3;
222 tb->flags = TBF_EXCEPTION;
223 tb->cs = ti->cs;
224 tb->eip = ti->address;
225 if ( TI_GET_IF(ti) )
226 ed->vcpu_info->evtchn_upcall_mask = 1;
228 return 0;
229 }
231 asmlinkage void do_machine_check(struct xen_regs *regs)
232 {
233 fatal_trap(TRAP_machine_check, regs);
234 }
236 void propagate_page_fault(unsigned long addr, u16 error_code)
237 {
238 trap_info_t *ti;
239 struct exec_domain *ed = current;
240 struct trap_bounce *tb = &ed->thread.trap_bounce;
242 ti = ed->thread.traps + 14;
243 tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE | TBF_EXCEPTION_CR2;
244 tb->cr2 = addr;
245 tb->error_code = error_code;
246 tb->cs = ti->cs;
247 tb->eip = ti->address;
248 if ( TI_GET_IF(ti) )
249 ed->vcpu_info->evtchn_upcall_mask = 1;
251 ed->mm.guest_cr2 = addr;
252 }
254 asmlinkage int do_page_fault(struct xen_regs *regs)
255 {
256 unsigned long off, addr, fixup;
257 struct exec_domain *ed = current;
258 struct domain *d = ed->domain;
259 extern int map_ldt_shadow_page(unsigned int);
260 int cpu = ed->processor;
261 int ret;
263 __asm__ __volatile__ ("mov %%cr2,%0" : "=r" (addr) : );
265 DEBUGGER_trap_entry(TRAP_page_fault, regs);
267 perfc_incrc(page_faults);
269 if ( likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) )
270 {
271 LOCK_BIGLOCK(d);
272 if ( unlikely(ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].l1va) &&
273 unlikely((addr >> L2_PAGETABLE_SHIFT) ==
274 ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].l2_idx) )
275 {
276 ptwr_flush(PTWR_PT_ACTIVE);
277 UNLOCK_BIGLOCK(d);
278 return EXCRET_fault_fixed;
279 }
281 if ( (addr < PAGE_OFFSET) &&
282 ((regs->error_code & 3) == 3) && /* write-protection fault */
283 ptwr_do_page_fault(addr) )
284 {
285 if ( unlikely(ed->mm.shadow_mode) )
286 (void)shadow_fault(addr, regs->error_code);
287 UNLOCK_BIGLOCK(d);
288 return EXCRET_fault_fixed;
289 }
290 UNLOCK_BIGLOCK(d);
291 }
293 if ( unlikely(ed->mm.shadow_mode) &&
294 (addr < PAGE_OFFSET) && shadow_fault(addr, regs->error_code) )
295 return EXCRET_fault_fixed;
297 if ( unlikely(addr >= LDT_VIRT_START(ed)) &&
298 (addr < (LDT_VIRT_START(ed) + (ed->mm.ldt_ents*LDT_ENTRY_SIZE))) )
299 {
300 /*
301 * Copy a mapping from the guest's LDT, if it is valid. Otherwise we
302 * send the fault up to the guest OS to be handled.
303 */
304 LOCK_BIGLOCK(d);
305 off = addr - LDT_VIRT_START(ed);
306 addr = ed->mm.ldt_base + off;
307 ret = map_ldt_shadow_page(off >> PAGE_SHIFT);
308 UNLOCK_BIGLOCK(d);
309 if ( likely(ret) )
310 return EXCRET_fault_fixed; /* successfully copied the mapping */
311 }
313 if ( !GUEST_FAULT(regs) )
314 goto xen_fault;
316 propagate_page_fault(addr, regs->error_code);
317 return 0;
319 xen_fault:
321 if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
322 {
323 perfc_incrc(copy_user_faults);
324 if ( !ed->mm.shadow_mode )
325 DPRINTK("Page fault: %08lx -> %08lx\n", regs->eip, fixup);
326 regs->eip = fixup;
327 return 0;
328 }
330 DEBUGGER_trap_fatal(TRAP_page_fault, regs);
332 #ifdef __i386__
333 if ( addr >= PAGE_OFFSET )
334 {
335 unsigned long page;
336 page = l2_pgentry_val(idle_pg_table[addr >> L2_PAGETABLE_SHIFT]);
337 printk("*pde = %08lx\n", page);
338 if ( page & _PAGE_PRESENT )
339 {
340 page &= PAGE_MASK;
341 page = ((unsigned long *) __va(page))[(addr&0x3ff000)>>PAGE_SHIFT];
342 printk(" *pte = %08lx\n", page);
343 }
344 #ifdef MEMORY_GUARD
345 if ( !(regs->error_code & 1) )
346 printk(" -- POSSIBLY AN ACCESS TO FREED MEMORY? --\n");
347 #endif
348 }
349 #endif /* __i386__ */
351 show_registers(regs);
352 panic("CPU%d FATAL PAGE FAULT\n"
353 "[error_code=%04x]\n"
354 "Faulting linear address might be %08lx\n",
355 smp_processor_id(), regs->error_code, addr);
356 return 0;
357 }
359 static int emulate_privileged_op(struct xen_regs *regs)
360 {
361 extern long do_fpu_taskswitch(void);
362 extern void *decode_reg(struct xen_regs *regs, u8 b);
364 struct exec_domain *ed = current;
365 unsigned long *reg, eip = regs->eip;
366 u8 opcode;
368 if ( get_user(opcode, (u8 *)eip) )
369 goto page_fault;
370 eip += 1;
371 if ( (opcode & 0xff) != 0x0f )
372 goto fail;
374 if ( get_user(opcode, (u8 *)eip) )
375 goto page_fault;
376 eip += 1;
378 switch ( opcode )
379 {
380 case 0x06: /* CLTS */
381 (void)do_fpu_taskswitch();
382 break;
384 case 0x09: /* WBINVD */
385 if ( !IS_CAPABLE_PHYSDEV(ed->domain) )
386 {
387 DPRINTK("Non-physdev domain attempted WBINVD.\n");
388 goto fail;
389 }
390 wbinvd();
391 break;
393 case 0x20: /* MOV CR?,<reg> */
394 if ( get_user(opcode, (u8 *)eip) )
395 goto page_fault;
396 eip += 1;
397 if ( (opcode & 0xc0) != 0xc0 )
398 goto fail;
399 reg = decode_reg(regs, opcode & 7);
400 switch ( (opcode >> 3) & 7 )
401 {
402 case 0: /* Read CR0 */
403 *reg =
404 (read_cr0() & ~X86_CR0_TS) |
405 (test_bit(EDF_GUEST_STTS, &ed->ed_flags) ? X86_CR0_TS : 0);
406 break;
408 case 2: /* Read CR2 */
409 *reg = ed->mm.guest_cr2;
410 break;
412 case 3: /* Read CR3 */
413 *reg = pagetable_val(ed->mm.pagetable);
414 break;
416 default:
417 goto fail;
418 }
419 break;
421 case 0x22: /* MOV <reg>,CR? */
422 if ( get_user(opcode, (u8 *)eip) )
423 goto page_fault;
424 eip += 1;
425 if ( (opcode & 0xc0) != 0xc0 )
426 goto fail;
427 reg = decode_reg(regs, opcode & 7);
428 switch ( (opcode >> 3) & 7 )
429 {
430 case 0: /* Write CR0 */
431 if ( *reg & X86_CR0_TS ) /* XXX ignore all but TS bit */
432 (void)do_fpu_taskswitch;
433 break;
435 case 2: /* Write CR2 */
436 ed->mm.guest_cr2 = *reg;
437 break;
439 case 3: /* Write CR3 */
440 LOCK_BIGLOCK(ed->domain);
441 (void)new_guest_cr3(*reg);
442 UNLOCK_BIGLOCK(ed->domain);
443 break;
445 default:
446 goto fail;
447 }
448 break;
450 case 0x30: /* WRMSR */
451 if ( !IS_PRIV(ed->domain) )
452 {
453 DPRINTK("Non-priv domain attempted WRMSR.\n");
454 goto fail;
455 }
456 wrmsr(regs->ecx, regs->eax, regs->edx);
457 break;
459 case 0x32: /* RDMSR */
460 if ( !IS_PRIV(ed->domain) )
461 {
462 DPRINTK("Non-priv domain attempted RDMSR.\n");
463 goto fail;
464 }
465 rdmsr(regs->ecx, regs->eax, regs->edx);
466 break;
468 default:
469 goto fail;
470 }
472 regs->eip = eip;
473 return EXCRET_fault_fixed;
475 fail:
476 return 0;
478 page_fault:
479 propagate_page_fault(eip, 0);
480 return EXCRET_fault_fixed;
481 }
483 asmlinkage int do_general_protection(struct xen_regs *regs)
484 {
485 struct exec_domain *ed = current;
486 struct trap_bounce *tb = &ed->thread.trap_bounce;
487 trap_info_t *ti;
488 unsigned long fixup;
490 DEBUGGER_trap_entry(TRAP_gp_fault, regs);
492 if ( regs->error_code & 1 )
493 goto hardware_gp;
495 if ( !GUEST_FAULT(regs) )
496 goto gp_in_kernel;
498 /*
499 * Cunning trick to allow arbitrary "INT n" handling.
500 *
501 * We set DPL == 0 on all vectors in the IDT. This prevents any INT <n>
502 * instruction from trapping to the appropriate vector, when that might not
503 * be expected by Xen or the guest OS. For example, that entry might be for
504 * a fault handler (unlike traps, faults don't increment EIP), or might
505 * expect an error code on the stack (which a software trap never
506 * provides), or might be a hardware interrupt handler that doesn't like
507 * being called spuriously.
508 *
509 * Instead, a GPF occurs with the faulting IDT vector in the error code.
510 * Bit 1 is set to indicate that an IDT entry caused the fault. Bit 0 is
511 * clear to indicate that it's a software fault, not hardware.
512 *
513 * NOTE: Vectors 3 and 4 are dealt with from their own handler. This is
514 * okay because they can only be triggered by an explicit DPL-checked
515 * instruction. The DPL specified by the guest OS for these vectors is NOT
516 * CHECKED!!
517 */
518 if ( (regs->error_code & 3) == 2 )
519 {
520 /* This fault must be due to <INT n> instruction. */
521 ti = current->thread.traps + (regs->error_code>>3);
522 if ( TI_GET_DPL(ti) >= (VM86_MODE(regs) ? 3 : (regs->cs & 3)) )
523 {
524 tb->flags = TBF_EXCEPTION;
525 regs->eip += 2;
526 goto finish_propagation;
527 }
528 }
530 /* Emulate some simple privileged instructions when exec'ed in ring 1. */
531 if ( (regs->error_code == 0) &&
532 RING_1(regs) &&
533 emulate_privileged_op(regs) )
534 return 0;
536 #if defined(__i386__)
537 if ( VM_ASSIST(ed->domain, VMASST_TYPE_4gb_segments) &&
538 (regs->error_code == 0) &&
539 gpf_emulate_4gb(regs) )
540 return 0;
541 #endif
543 /* Pass on GPF as is. */
544 ti = current->thread.traps + 13;
545 tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
546 tb->error_code = regs->error_code;
547 finish_propagation:
548 tb->cs = ti->cs;
549 tb->eip = ti->address;
550 if ( TI_GET_IF(ti) )
551 ed->vcpu_info->evtchn_upcall_mask = 1;
552 return 0;
554 gp_in_kernel:
556 if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
557 {
558 DPRINTK("GPF (%04x): %08lx -> %08lx\n",
559 regs->error_code, regs->eip, fixup);
560 regs->eip = fixup;
561 return 0;
562 }
564 DEBUGGER_trap_fatal(TRAP_gp_fault, regs);
566 hardware_gp:
567 show_registers(regs);
568 panic("CPU%d GENERAL PROTECTION FAULT\n[error_code=%04x]\n",
569 smp_processor_id(), regs->error_code);
570 return 0;
571 }
573 asmlinkage void mem_parity_error(struct xen_regs *regs)
574 {
575 console_force_unlock();
576 printk("\n\nNMI - MEMORY ERROR\n");
577 fatal_trap(TRAP_nmi, regs);
578 }
580 asmlinkage void io_check_error(struct xen_regs *regs)
581 {
582 console_force_unlock();
584 printk("\n\nNMI - I/O ERROR\n");
585 fatal_trap(TRAP_nmi, regs);
586 }
588 static void unknown_nmi_error(unsigned char reason, struct xen_regs * regs)
589 {
590 printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
591 printk("Dazed and confused, but trying to continue\n");
592 printk("Do you have a strange power saving mode enabled?\n");
593 }
595 asmlinkage void do_nmi(struct xen_regs * regs, unsigned long reason)
596 {
597 ++nmi_count(smp_processor_id());
599 #if CONFIG_X86_LOCAL_APIC
600 if ( nmi_watchdog )
601 nmi_watchdog_tick(regs);
602 else
603 #endif
604 unknown_nmi_error((unsigned char)(reason&0xff), regs);
605 }
607 unsigned long nmi_softirq_reason;
608 static void nmi_softirq(void)
609 {
610 if ( dom0 == NULL )
611 return;
613 if ( test_and_clear_bit(0, &nmi_softirq_reason) )
614 send_guest_virq(dom0->exec_domain[0], VIRQ_PARITY_ERR);
616 if ( test_and_clear_bit(1, &nmi_softirq_reason) )
617 send_guest_virq(dom0->exec_domain[0], VIRQ_IO_ERR);
618 }
620 asmlinkage int math_state_restore(struct xen_regs *regs)
621 {
622 /* Prevent recursion. */
623 clts();
625 if ( !test_bit(EDF_USEDFPU, &current->ed_flags) )
626 {
627 if ( test_bit(EDF_DONEFPUINIT, &current->ed_flags) )
628 restore_fpu(current);
629 else
630 init_fpu();
631 set_bit(EDF_USEDFPU, &current->ed_flags); /* so we fnsave on switch_to() */
632 }
634 if ( test_and_clear_bit(EDF_GUEST_STTS, &current->ed_flags) )
635 {
636 struct trap_bounce *tb = &current->thread.trap_bounce;
637 tb->flags = TBF_EXCEPTION;
638 tb->cs = current->thread.traps[7].cs;
639 tb->eip = current->thread.traps[7].address;
640 }
642 return EXCRET_fault_fixed;
643 }
645 asmlinkage int do_debug(struct xen_regs *regs)
646 {
647 unsigned long condition;
648 struct exec_domain *d = current;
649 struct trap_bounce *tb = &d->thread.trap_bounce;
651 DEBUGGER_trap_entry(TRAP_debug, regs);
653 __asm__ __volatile__("mov %%db6,%0" : "=r" (condition));
655 /* Mask out spurious debug traps due to lazy DR7 setting */
656 if ( (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) &&
657 (d->thread.debugreg[7] == 0) )
658 {
659 __asm__("mov %0,%%db7" : : "r" (0UL));
660 goto out;
661 }
663 if ( !GUEST_FAULT(regs) )
664 {
665 /* Clear TF just for absolute sanity. */
666 regs->eflags &= ~EF_TF;
667 /*
668 * We ignore watchpoints when they trigger within Xen. This may happen
669 * when a buffer is passed to us which previously had a watchpoint set
670 * on it. No need to bump EIP; the only faulting trap is an instruction
671 * breakpoint, which can't happen to us.
672 */
673 goto out;
674 }
676 /* Save debug status register where guest OS can peek at it */
677 d->thread.debugreg[6] = condition;
679 tb->flags = TBF_EXCEPTION;
680 tb->cs = d->thread.traps[1].cs;
681 tb->eip = d->thread.traps[1].address;
683 out:
684 return EXCRET_not_a_fault;
685 }
687 asmlinkage int do_spurious_interrupt_bug(struct xen_regs *regs)
688 {
689 return EXCRET_not_a_fault;
690 }
692 void set_intr_gate(unsigned int n, void *addr)
693 {
694 _set_gate(idt_table+n,14,0,addr);
695 }
697 void set_system_gate(unsigned int n, void *addr)
698 {
699 _set_gate(idt_table+n,14,3,addr);
700 }
702 void set_task_gate(unsigned int n, unsigned int sel)
703 {
704 idt_table[n].a = sel << 16;
705 idt_table[n].b = 0x8500;
706 }
708 #define _set_seg_desc(gate_addr,type,dpl,base,limit) {\
709 *((gate_addr)+1) = ((base) & 0xff000000) | \
710 (((base) & 0x00ff0000)>>16) | \
711 ((limit) & 0xf0000) | \
712 ((dpl)<<13) | \
713 (0x00408000) | \
714 ((type)<<8); \
715 *(gate_addr) = (((base) & 0x0000ffff)<<16) | \
716 ((limit) & 0x0ffff); }
718 void set_tss_desc(unsigned int n, void *addr)
719 {
720 _set_tssldt_desc(
721 gdt_table + __TSS(n),
722 (int)addr,
723 offsetof(struct tss_struct, __cacheline_filler) - 1,
724 0x89);
725 }
727 void __init trap_init(void)
728 {
729 extern void doublefault_init(void);
730 doublefault_init();
732 #ifdef __i386__
733 /*
734 * Note that interrupt gates are always used, rather than trap gates. We
735 * must have interrupts disabled until DS/ES/FS/GS are saved because the
736 * first activation must have the "bad" value(s) for these registers and
737 * we may lose them if another activation is installed before they are
738 * saved. The page-fault handler also needs interrupts disabled until %cr2
739 * has been read and saved on the stack.
740 */
741 set_intr_gate(TRAP_divide_error,&divide_error);
742 set_intr_gate(TRAP_debug,&debug);
743 set_intr_gate(TRAP_nmi,&nmi);
744 set_system_gate(TRAP_int3,&int3); /* usable from all privileges */
745 set_system_gate(TRAP_overflow,&overflow); /* usable from all privileges */
746 set_intr_gate(TRAP_bounds,&bounds);
747 set_intr_gate(TRAP_invalid_op,&invalid_op);
748 set_intr_gate(TRAP_no_device,&device_not_available);
749 set_task_gate(TRAP_double_fault,__DOUBLEFAULT_TSS_ENTRY<<3);
750 set_intr_gate(TRAP_copro_seg,&coprocessor_segment_overrun);
751 set_intr_gate(TRAP_invalid_tss,&invalid_TSS);
752 set_intr_gate(TRAP_no_segment,&segment_not_present);
753 set_intr_gate(TRAP_stack_error,&stack_segment);
754 set_intr_gate(TRAP_gp_fault,&general_protection);
755 set_intr_gate(TRAP_page_fault,&page_fault);
756 set_intr_gate(TRAP_spurious_int,&spurious_interrupt_bug);
757 set_intr_gate(TRAP_copro_error,&coprocessor_error);
758 set_intr_gate(TRAP_alignment_check,&alignment_check);
759 set_intr_gate(TRAP_machine_check,&machine_check);
760 set_intr_gate(TRAP_simd_error,&simd_coprocessor_error);
761 set_intr_gate(TRAP_deferred_nmi,&nmi);
763 /* Only ring 1 can access Xen services. */
764 _set_gate(idt_table+HYPERCALL_VECTOR,14,1,&hypercall);
765 #endif
767 /* CPU0 uses the master IDT. */
768 idt_tables[0] = idt_table;
770 /*
771 * Should be a barrier for any external CPU state.
772 */
773 {
774 extern void cpu_init(void);
775 cpu_init();
776 }
778 open_softirq(NMI_SOFTIRQ, nmi_softirq);
779 }
782 long do_set_trap_table(trap_info_t *traps)
783 {
784 trap_info_t cur;
785 trap_info_t *dst = current->thread.traps;
787 LOCK_BIGLOCK(current->domain);
789 for ( ; ; )
790 {
791 if ( hypercall_preempt_check() )
792 {
793 UNLOCK_BIGLOCK(current->domain);
794 return hypercall_create_continuation(
795 __HYPERVISOR_set_trap_table, 1, traps);
796 }
798 if ( copy_from_user(&cur, traps, sizeof(cur)) ) return -EFAULT;
800 if ( cur.address == 0 ) break;
802 if ( !VALID_CODESEL(cur.cs) ) return -EPERM;
804 memcpy(dst+cur.vector, &cur, sizeof(cur));
805 traps++;
806 }
808 UNLOCK_BIGLOCK(current->domain);
810 return 0;
811 }
814 long do_set_callbacks(unsigned long event_selector,
815 unsigned long event_address,
816 unsigned long failsafe_selector,
817 unsigned long failsafe_address)
818 {
819 struct exec_domain *d = current;
821 if ( !VALID_CODESEL(event_selector) || !VALID_CODESEL(failsafe_selector) )
822 return -EPERM;
824 d->thread.event_selector = event_selector;
825 d->thread.event_address = event_address;
826 d->thread.failsafe_selector = failsafe_selector;
827 d->thread.failsafe_address = failsafe_address;
829 return 0;
830 }
833 long do_fpu_taskswitch(void)
834 {
835 set_bit(EDF_GUEST_STTS, &current->ed_flags);
836 stts();
837 return 0;
838 }
841 long set_debugreg(struct exec_domain *p, int reg, unsigned long value)
842 {
843 int i;
845 switch ( reg )
846 {
847 case 0:
848 if ( value > (PAGE_OFFSET-4) ) return -EPERM;
849 if ( p == current )
850 __asm__ ( "mov %0, %%db0" : : "r" (value) );
851 break;
852 case 1:
853 if ( value > (PAGE_OFFSET-4) ) return -EPERM;
854 if ( p == current )
855 __asm__ ( "mov %0, %%db1" : : "r" (value) );
856 break;
857 case 2:
858 if ( value > (PAGE_OFFSET-4) ) return -EPERM;
859 if ( p == current )
860 __asm__ ( "mov %0, %%db2" : : "r" (value) );
861 break;
862 case 3:
863 if ( value > (PAGE_OFFSET-4) ) return -EPERM;
864 if ( p == current )
865 __asm__ ( "mov %0, %%db3" : : "r" (value) );
866 break;
867 case 6:
868 /*
869 * DR6: Bits 4-11,16-31 reserved (set to 1).
870 * Bit 12 reserved (set to 0).
871 */
872 value &= 0xffffefff; /* reserved bits => 0 */
873 value |= 0xffff0ff0; /* reserved bits => 1 */
874 if ( p == current )
875 __asm__ ( "mov %0, %%db6" : : "r" (value) );
876 break;
877 case 7:
878 /*
879 * DR7: Bit 10 reserved (set to 1).
880 * Bits 11-12,14-15 reserved (set to 0).
881 * Privileged bits:
882 * GD (bit 13): must be 0.
883 * R/Wn (bits 16-17,20-21,24-25,28-29): mustn't be 10.
884 * LENn (bits 18-19,22-23,26-27,30-31): mustn't be 10.
885 */
886 /* DR7 == 0 => debugging disabled for this domain. */
887 if ( value != 0 )
888 {
889 value &= 0xffff27ff; /* reserved bits => 0 */
890 value |= 0x00000400; /* reserved bits => 1 */
891 if ( (value & (1<<13)) != 0 ) return -EPERM;
892 for ( i = 0; i < 16; i += 2 )
893 if ( ((value >> (i+16)) & 3) == 2 ) return -EPERM;
894 }
895 if ( p == current )
896 __asm__ ( "mov %0, %%db7" : : "r" (value) );
897 break;
898 default:
899 return -EINVAL;
900 }
902 p->thread.debugreg[reg] = value;
903 return 0;
904 }
906 long do_set_debugreg(int reg, unsigned long value)
907 {
908 return set_debugreg(current, reg, value);
909 }
911 unsigned long do_get_debugreg(int reg)
912 {
913 if ( (reg < 0) || (reg > 7) ) return -EINVAL;
914 return current->thread.debugreg[reg];
915 }