debuggers.hg
annotate xen/arch/x86/traps.c @ 3635:ed902e5c4b49
bitkeeper revision 1.1159.212.62 (41fff40aESe4aWS82z_rLHeonXpxuQ)
More x86/64 stuff.
Signed-off-by: keir.fraser@cl.cam.ac.uk
More x86/64 stuff.
Signed-off-by: keir.fraser@cl.cam.ac.uk
author | kaf24@scramble.cl.cam.ac.uk |
---|---|
date | Tue Feb 01 21:26:34 2005 +0000 (2005-02-01) |
parents | 578b6c14e635 |
children | 9a9c5a491401 e6af5d8f8b39 fd1dd0663b09 |
rev | line source |
---|---|
kaf24@1490 | 1 /****************************************************************************** |
kaf24@3635 | 2 * arch/x86/traps.c |
kaf24@1490 | 3 * |
kaf24@2114 | 4 * Modifications to Linux original are copyright (c) 2002-2004, K A Fraser |
kaf24@1490 | 5 * |
kaf24@1490 | 6 * This program is free software; you can redistribute it and/or modify |
kaf24@1490 | 7 * it under the terms of the GNU General Public License as published by |
kaf24@1490 | 8 * the Free Software Foundation; either version 2 of the License, or |
kaf24@1490 | 9 * (at your option) any later version. |
kaf24@1490 | 10 * |
kaf24@1490 | 11 * This program is distributed in the hope that it will be useful, |
kaf24@1490 | 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
kaf24@1490 | 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
kaf24@1490 | 14 * GNU General Public License for more details. |
kaf24@1490 | 15 * |
kaf24@1490 | 16 * You should have received a copy of the GNU General Public License |
kaf24@1490 | 17 * along with this program; if not, write to the Free Software |
kaf24@1490 | 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
kaf24@1490 | 19 */ |
kaf24@1490 | 20 |
kaf24@1490 | 21 /* |
kaf24@1490 | 22 * Copyright (C) 1991, 1992 Linus Torvalds |
kaf24@1490 | 23 * |
kaf24@1490 | 24 * Pentium III FXSR, SSE support |
kaf24@1490 | 25 * Gareth Hughes <gareth@valinux.com>, May 2000 |
kaf24@1490 | 26 */ |
kaf24@1490 | 27 |
kaf24@1490 | 28 #include <xen/config.h> |
kaf24@1490 | 29 #include <xen/init.h> |
kaf24@1490 | 30 #include <xen/sched.h> |
kaf24@1490 | 31 #include <xen/lib.h> |
kaf24@1490 | 32 #include <xen/errno.h> |
kaf24@1490 | 33 #include <xen/mm.h> |
kaf24@2079 | 34 #include <xen/console.h> |
ach61@2843 | 35 #include <asm/regs.h> |
kaf24@1490 | 36 #include <xen/delay.h> |
kaf24@2085 | 37 #include <xen/event.h> |
kaf24@1490 | 38 #include <xen/spinlock.h> |
kaf24@1490 | 39 #include <xen/irq.h> |
kaf24@1490 | 40 #include <xen/perfc.h> |
kaf24@2085 | 41 #include <xen/softirq.h> |
kaf24@1787 | 42 #include <asm/shadow.h> |
kaf24@1490 | 43 #include <asm/domain_page.h> |
kaf24@1490 | 44 #include <asm/system.h> |
kaf24@1490 | 45 #include <asm/io.h> |
kaf24@1490 | 46 #include <asm/atomic.h> |
kaf24@1490 | 47 #include <asm/desc.h> |
kaf24@1490 | 48 #include <asm/debugreg.h> |
kaf24@1490 | 49 #include <asm/smp.h> |
kaf24@1490 | 50 #include <asm/flushtlb.h> |
kaf24@1490 | 51 #include <asm/uaccess.h> |
kaf24@1490 | 52 #include <asm/i387.h> |
kaf24@3009 | 53 #include <asm/debugger.h> |
kaf24@3375 | 54 #include <asm/msr.h> |
kaf24@1490 | 55 |
kaf24@3372 | 56 /* |
kaf24@3372 | 57 * opt_nmi: one of 'ignore', 'dom0', or 'fatal'. |
kaf24@3372 | 58 * fatal: Xen prints diagnostic message and then hangs. |
kaf24@3372 | 59 * dom0: The NMI is virtualised to DOM0. |
kaf24@3372 | 60 * ignore: The NMI error is cleared and ignored. |
kaf24@3372 | 61 */ |
kaf24@3372 | 62 #ifdef NDEBUG |
kaf24@3372 | 63 char opt_nmi[10] = "dom0"; |
kaf24@3372 | 64 #else |
kaf24@3372 | 65 char opt_nmi[10] = "fatal"; |
kaf24@3372 | 66 #endif |
kaf24@3372 | 67 string_param("nmi", opt_nmi); |
kaf24@3372 | 68 |
kaf24@3207 | 69 #define GUEST_FAULT(_r) (likely(VM86_MODE(_r) || !RING_0(_r))) |
kaf24@3207 | 70 |
kaf24@1490 | 71 #define DOUBLEFAULT_STACK_SIZE 1024 |
kaf24@1490 | 72 static struct tss_struct doublefault_tss; |
kaf24@1490 | 73 static unsigned char doublefault_stack[DOUBLEFAULT_STACK_SIZE]; |
kaf24@1490 | 74 |
kaf24@1594 | 75 asmlinkage int hypercall(void); |
kaf24@1490 | 76 |
kaf24@1490 | 77 /* Master table, and the one used by CPU0. */ |
kaf24@3635 | 78 idt_entry_t idt_table[IDT_ENTRIES] = { {0, 0}, }; |
kaf24@1490 | 79 /* All other CPUs have their own copy. */ |
kaf24@3635 | 80 idt_entry_t *idt_tables[NR_CPUS] = { 0 }; |
kaf24@1490 | 81 |
kaf24@1490 | 82 asmlinkage void divide_error(void); |
kaf24@1490 | 83 asmlinkage void debug(void); |
kaf24@1490 | 84 asmlinkage void nmi(void); |
kaf24@1490 | 85 asmlinkage void int3(void); |
kaf24@1490 | 86 asmlinkage void overflow(void); |
kaf24@1490 | 87 asmlinkage void bounds(void); |
kaf24@1490 | 88 asmlinkage void invalid_op(void); |
kaf24@1490 | 89 asmlinkage void device_not_available(void); |
kaf24@1490 | 90 asmlinkage void coprocessor_segment_overrun(void); |
kaf24@1490 | 91 asmlinkage void invalid_TSS(void); |
kaf24@1490 | 92 asmlinkage void segment_not_present(void); |
kaf24@1490 | 93 asmlinkage void stack_segment(void); |
kaf24@1490 | 94 asmlinkage void general_protection(void); |
kaf24@1490 | 95 asmlinkage void page_fault(void); |
kaf24@1490 | 96 asmlinkage void coprocessor_error(void); |
kaf24@1490 | 97 asmlinkage void simd_coprocessor_error(void); |
kaf24@1490 | 98 asmlinkage void alignment_check(void); |
kaf24@1490 | 99 asmlinkage void spurious_interrupt_bug(void); |
kaf24@1490 | 100 asmlinkage void machine_check(void); |
kaf24@1490 | 101 |
kaf24@1490 | 102 int kstack_depth_to_print = 8*20; |
kaf24@1490 | 103 |
kaf24@1490 | 104 static inline int kernel_text_address(unsigned long addr) |
kaf24@1490 | 105 { |
kaf24@1490 | 106 if (addr >= (unsigned long) &_stext && |
kaf24@1490 | 107 addr <= (unsigned long) &_etext) |
kaf24@1490 | 108 return 1; |
kaf24@1490 | 109 return 0; |
kaf24@1490 | 110 |
kaf24@1490 | 111 } |
kaf24@1490 | 112 |
kaf24@3635 | 113 void show_guest_stack(void) |
iap10@2479 | 114 { |
iap10@2479 | 115 int i; |
iap10@2479 | 116 execution_context_t *ec = get_execution_context(); |
iap10@2479 | 117 unsigned long *stack = (unsigned long *)ec->esp; |
iap10@2479 | 118 printk("Guest EIP is %lx\n",ec->eip); |
iap10@2479 | 119 |
iap10@2479 | 120 for ( i = 0; i < kstack_depth_to_print; i++ ) |
iap10@2479 | 121 { |
iap10@2479 | 122 if ( ((long)stack & (STACK_SIZE-1)) == 0 ) |
iap10@2479 | 123 break; |
iap10@2479 | 124 if ( i && ((i % 8) == 0) ) |
iap10@2479 | 125 printk("\n "); |
iap10@2479 | 126 printk("%08lx ", *stack++); |
iap10@2479 | 127 } |
iap10@2479 | 128 printk("\n"); |
iap10@2479 | 129 |
iap10@2479 | 130 } |
iap10@2479 | 131 |
iap10@2509 | 132 void show_trace(unsigned long *esp) |
iap10@2509 | 133 { |
iap10@2509 | 134 unsigned long *stack, addr; |
iap10@2509 | 135 int i; |
iap10@2509 | 136 |
iap10@2509 | 137 printk("Call Trace from ESP=%p: ", esp); |
iap10@2509 | 138 stack = esp; |
iap10@2509 | 139 i = 0; |
iap10@2509 | 140 while (((long) stack & (STACK_SIZE-1)) != 0) { |
iap10@2509 | 141 addr = *stack++; |
iap10@2509 | 142 if (kernel_text_address(addr)) { |
iap10@2509 | 143 if (i && ((i % 6) == 0)) |
iap10@2509 | 144 printk("\n "); |
iap10@2509 | 145 printk("[<%08lx>] ", addr); |
iap10@2509 | 146 i++; |
iap10@2509 | 147 } |
iap10@2509 | 148 } |
iap10@2509 | 149 printk("\n"); |
iap10@2509 | 150 } |
iap10@2509 | 151 |
kaf24@1490 | 152 void show_stack(unsigned long *esp) |
kaf24@1490 | 153 { |
iap10@2509 | 154 unsigned long *stack; |
kaf24@1490 | 155 int i; |
kaf24@1490 | 156 |
kaf24@1490 | 157 printk("Stack trace from ESP=%p:\n", esp); |
kaf24@1490 | 158 |
kaf24@1490 | 159 stack = esp; |
kaf24@1490 | 160 for ( i = 0; i < kstack_depth_to_print; i++ ) |
kaf24@1490 | 161 { |
kaf24@1490 | 162 if ( ((long)stack & (STACK_SIZE-1)) == 0 ) |
kaf24@1490 | 163 break; |
kaf24@1490 | 164 if ( i && ((i % 8) == 0) ) |
kaf24@1490 | 165 printk("\n "); |
kaf24@1490 | 166 if ( kernel_text_address(*stack) ) |
kaf24@1490 | 167 printk("[%08lx] ", *stack++); |
kaf24@1490 | 168 else |
kaf24@1490 | 169 printk("%08lx ", *stack++); |
kaf24@1490 | 170 } |
kaf24@1490 | 171 printk("\n"); |
kaf24@1490 | 172 |
iap10@2509 | 173 show_trace( esp ); |
kaf24@1490 | 174 } |
kaf24@1490 | 175 |
ach61@2843 | 176 void show_registers(struct xen_regs *regs) |
kaf24@1490 | 177 { |
kaf24@1490 | 178 unsigned long esp; |
kaf24@2954 | 179 unsigned short ss, ds, es, fs, gs; |
kaf24@1490 | 180 |
kaf24@3207 | 181 if ( GUEST_FAULT(regs) ) |
kaf24@1490 | 182 { |
kaf24@1490 | 183 esp = regs->esp; |
kaf24@2956 | 184 ss = regs->ss & 0xffff; |
kaf24@2956 | 185 ds = regs->ds & 0xffff; |
kaf24@2956 | 186 es = regs->es & 0xffff; |
kaf24@2956 | 187 fs = regs->fs & 0xffff; |
kaf24@2956 | 188 gs = regs->gs & 0xffff; |
kaf24@2954 | 189 } |
kaf24@2954 | 190 else |
kaf24@2954 | 191 { |
kaf24@2954 | 192 esp = (unsigned long)(®s->esp); |
kaf24@2954 | 193 ss = __HYPERVISOR_DS; |
kaf24@2954 | 194 ds = __HYPERVISOR_DS; |
kaf24@2954 | 195 es = __HYPERVISOR_DS; |
kaf24@2954 | 196 fs = __HYPERVISOR_DS; |
kaf24@2954 | 197 gs = __HYPERVISOR_DS; |
kaf24@1490 | 198 } |
kaf24@1490 | 199 |
kaf24@3635 | 200 printk("CPU: %d\nEIP: %04lx:[<%08lx>] \nEFLAGS: %08lx\n", |
kaf24@2956 | 201 smp_processor_id(), 0xffff & regs->cs, regs->eip, regs->eflags); |
kaf24@3635 | 202 printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", |
kaf24@1490 | 203 regs->eax, regs->ebx, regs->ecx, regs->edx); |
kaf24@3635 | 204 printk("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", |
kaf24@1490 | 205 regs->esi, regs->edi, regs->ebp, esp); |
kaf24@1490 | 206 printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n", |
kaf24@2954 | 207 ds, es, fs, gs, ss); |
kaf24@1490 | 208 |
kaf24@3127 | 209 show_stack((unsigned long *)®s->esp); |
kaf24@1490 | 210 } |
kaf24@1490 | 211 |
kaf24@3079 | 212 /* |
kaf24@3079 | 213 * This is called for faults at very unexpected times (e.g., when interrupts |
kaf24@3079 | 214 * are disabled). In such situations we can't do much that is safe. We try to |
kaf24@3079 | 215 * print out some tracing and then we just spin. |
kaf24@3079 | 216 */ |
kaf24@3127 | 217 asmlinkage void fatal_trap(int trapnr, struct xen_regs *regs) |
kaf24@1490 | 218 { |
kaf24@3079 | 219 int cpu = smp_processor_id(); |
kaf24@3127 | 220 unsigned long cr2; |
kaf24@3079 | 221 static char *trapstr[] = { |
kaf24@3079 | 222 "divide error", "debug", "nmi", "bkpt", "overflow", "bounds", |
kaf24@3079 | 223 "invalid operation", "device not available", "double fault", |
kaf24@3079 | 224 "coprocessor segment", "invalid tss", "segment not found", |
kaf24@3079 | 225 "stack error", "general protection fault", "page fault", |
kaf24@3079 | 226 "spurious interrupt", "coprocessor error", "alignment check", |
kaf24@3079 | 227 "machine check", "simd error" |
kaf24@3079 | 228 }; |
kaf24@3079 | 229 |
kaf24@1490 | 230 show_registers(regs); |
kaf24@3127 | 231 |
kaf24@3127 | 232 if ( trapnr == TRAP_page_fault ) |
kaf24@3127 | 233 { |
kaf24@3127 | 234 __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (cr2) : ); |
kaf24@3127 | 235 printk("Faulting linear address might be %08lx\n", cr2); |
kaf24@3127 | 236 } |
kaf24@3127 | 237 |
kaf24@3079 | 238 printk("************************************\n"); |
kaf24@3127 | 239 printk("CPU%d FATAL TRAP %d (%s), ERROR_CODE %04x%s.\n", |
kaf24@3127 | 240 cpu, trapnr, trapstr[trapnr], regs->error_code, |
kaf24@3079 | 241 (regs->eflags & X86_EFLAGS_IF) ? "" : ", IN INTERRUPT CONTEXT"); |
kaf24@3079 | 242 printk("System shutting down -- need manual reset.\n"); |
kaf24@3079 | 243 printk("************************************\n"); |
kaf24@3079 | 244 |
kaf24@3079 | 245 /* Lock up the console to prevent spurious output from other CPUs. */ |
kaf24@3079 | 246 console_force_lock(); |
kaf24@3079 | 247 |
kaf24@3079 | 248 /* Wait for manual reset. */ |
kaf24@3079 | 249 for ( ; ; ) |
kaf24@3079 | 250 __asm__ __volatile__ ( "hlt" ); |
kaf24@1490 | 251 } |
kaf24@1490 | 252 |
kaf24@3090 | 253 static inline int do_trap(int trapnr, char *str, |
kaf24@3127 | 254 struct xen_regs *regs, |
kaf24@3127 | 255 int use_error_code) |
kaf24@1490 | 256 { |
cl349@2957 | 257 struct exec_domain *ed = current; |
cl349@3085 | 258 struct trap_bounce *tb = &ed->thread.trap_bounce; |
kaf24@1490 | 259 trap_info_t *ti; |
kaf24@1490 | 260 unsigned long fixup; |
kaf24@1490 | 261 |
kaf24@3127 | 262 DEBUGGER_trap_entry(trapnr, regs); |
kaf24@3009 | 263 |
kaf24@3207 | 264 if ( !GUEST_FAULT(regs) ) |
kaf24@1628 | 265 goto xen_fault; |
kaf24@1490 | 266 |
kaf24@1490 | 267 ti = current->thread.traps + trapnr; |
kaf24@3127 | 268 tb->flags = TBF_EXCEPTION; |
kaf24@3127 | 269 tb->cs = ti->cs; |
kaf24@3127 | 270 tb->eip = ti->address; |
kaf24@3127 | 271 if ( use_error_code ) |
kaf24@3127 | 272 { |
kaf24@3127 | 273 tb->flags |= TBF_EXCEPTION_ERRCODE; |
kaf24@3127 | 274 tb->error_code = regs->error_code; |
kaf24@3127 | 275 } |
kaf24@1490 | 276 if ( TI_GET_IF(ti) ) |
cl349@2959 | 277 ed->vcpu_info->evtchn_upcall_mask = 1; |
kaf24@3090 | 278 return 0; |
kaf24@1490 | 279 |
kaf24@1628 | 280 xen_fault: |
kaf24@1490 | 281 |
kaf24@1490 | 282 if ( likely((fixup = search_exception_table(regs->eip)) != 0) ) |
kaf24@1490 | 283 { |
kaf24@3635 | 284 DPRINTK("Trap %d: %08lx -> %08lx\n", trapnr, regs->eip, fixup); |
kaf24@1490 | 285 regs->eip = fixup; |
kaf24@3090 | 286 return 0; |
kaf24@1490 | 287 } |
kaf24@1490 | 288 |
kaf24@3127 | 289 DEBUGGER_trap_fatal(trapnr, regs); |
cl349@2995 | 290 |
kaf24@1490 | 291 show_registers(regs); |
kaf24@1490 | 292 panic("CPU%d FATAL TRAP: vector = %d (%s)\n" |
kaf24@3127 | 293 "[error_code=%04x]\n", |
kaf24@3127 | 294 smp_processor_id(), trapnr, str, regs->error_code); |
kaf24@3090 | 295 return 0; |
kaf24@1490 | 296 } |
kaf24@1490 | 297 |
kaf24@1490 | 298 #define DO_ERROR_NOCODE(trapnr, str, name) \ |
kaf24@3127 | 299 asmlinkage int do_##name(struct xen_regs *regs) \ |
kaf24@1490 | 300 { \ |
kaf24@3127 | 301 return do_trap(trapnr, str, regs, 0); \ |
kaf24@1490 | 302 } |
kaf24@1490 | 303 |
kaf24@1490 | 304 #define DO_ERROR(trapnr, str, name) \ |
kaf24@3127 | 305 asmlinkage int do_##name(struct xen_regs *regs) \ |
kaf24@1490 | 306 { \ |
kaf24@3127 | 307 return do_trap(trapnr, str, regs, 1); \ |
kaf24@1490 | 308 } |
kaf24@1490 | 309 |
kaf24@1490 | 310 DO_ERROR_NOCODE( 0, "divide error", divide_error) |
kaf24@2114 | 311 DO_ERROR_NOCODE( 4, "overflow", overflow) |
kaf24@2114 | 312 DO_ERROR_NOCODE( 5, "bounds", bounds) |
kaf24@2114 | 313 DO_ERROR_NOCODE( 6, "invalid operand", invalid_op) |
kaf24@2114 | 314 DO_ERROR_NOCODE( 9, "coprocessor segment overrun", coprocessor_segment_overrun) |
kaf24@2114 | 315 DO_ERROR(10, "invalid TSS", invalid_TSS) |
kaf24@2114 | 316 DO_ERROR(11, "segment not present", segment_not_present) |
kaf24@2114 | 317 DO_ERROR(12, "stack segment", stack_segment) |
kaf24@2114 | 318 DO_ERROR_NOCODE(16, "fpu error", coprocessor_error) |
kaf24@2114 | 319 DO_ERROR(17, "alignment check", alignment_check) |
kaf24@2114 | 320 DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error) |
kaf24@1490 | 321 |
kaf24@3127 | 322 asmlinkage int do_int3(struct xen_regs *regs) |
kaf24@1490 | 323 { |
cl349@2957 | 324 struct exec_domain *ed = current; |
cl349@3085 | 325 struct trap_bounce *tb = &ed->thread.trap_bounce; |
kaf24@1490 | 326 trap_info_t *ti; |
kaf24@1490 | 327 |
kaf24@3127 | 328 DEBUGGER_trap_entry(TRAP_int3, regs); |
kaf24@1490 | 329 |
kaf24@3207 | 330 if ( !GUEST_FAULT(regs) ) |
kaf24@1490 | 331 { |
kaf24@3127 | 332 DEBUGGER_trap_fatal(TRAP_int3, regs); |
kaf24@3009 | 333 show_registers(regs); |
kaf24@3127 | 334 panic("CPU%d FATAL TRAP: vector = 3 (Int3)\n", smp_processor_id()); |
kaf24@1490 | 335 } |
kaf24@1490 | 336 |
kaf24@1490 | 337 ti = current->thread.traps + 3; |
kaf24@3127 | 338 tb->flags = TBF_EXCEPTION; |
kaf24@3127 | 339 tb->cs = ti->cs; |
kaf24@3127 | 340 tb->eip = ti->address; |
kaf24@1490 | 341 if ( TI_GET_IF(ti) ) |
cl349@2959 | 342 ed->vcpu_info->evtchn_upcall_mask = 1; |
kaf24@3090 | 343 |
kaf24@3090 | 344 return 0; |
kaf24@1490 | 345 } |
kaf24@1490 | 346 |
kaf24@1490 | 347 asmlinkage void do_double_fault(void) |
kaf24@1490 | 348 { |
kaf24@1490 | 349 struct tss_struct *tss = &doublefault_tss; |
kaf24@1490 | 350 unsigned int cpu = ((tss->back_link>>3)-__FIRST_TSS_ENTRY)>>1; |
kaf24@1490 | 351 |
kaf24@1490 | 352 /* Disable the NMI watchdog. It's useless now. */ |
kaf24@1490 | 353 watchdog_on = 0; |
kaf24@1490 | 354 |
kaf24@1490 | 355 /* Find information saved during fault and dump it to the console. */ |
kaf24@1490 | 356 tss = &init_tss[cpu]; |
kaf24@1518 | 357 printk("CPU: %d\nEIP: %04x:[<%08x>] \nEFLAGS: %08x\n", |
kaf24@1490 | 358 cpu, tss->cs, tss->eip, tss->eflags); |
kaf24@1518 | 359 printk("CR3: %08x\n", tss->__cr3); |
kaf24@1518 | 360 printk("eax: %08x ebx: %08x ecx: %08x edx: %08x\n", |
kaf24@1490 | 361 tss->eax, tss->ebx, tss->ecx, tss->edx); |
kaf24@1518 | 362 printk("esi: %08x edi: %08x ebp: %08x esp: %08x\n", |
kaf24@1490 | 363 tss->esi, tss->edi, tss->ebp, tss->esp); |
kaf24@1490 | 364 printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n", |
kaf24@1490 | 365 tss->ds, tss->es, tss->fs, tss->gs, tss->ss); |
kaf24@1490 | 366 printk("************************************\n"); |
kaf24@1490 | 367 printk("CPU%d DOUBLE FAULT -- system shutdown\n", cpu); |
kaf24@1490 | 368 printk("System needs manual reset.\n"); |
kaf24@1490 | 369 printk("************************************\n"); |
kaf24@1490 | 370 |
kaf24@1490 | 371 /* Lock up the console to prevent spurious output from other CPUs. */ |
kaf24@2079 | 372 console_force_lock(); |
kaf24@1490 | 373 |
kaf24@1490 | 374 /* Wait for manual reset. */ |
kaf24@3079 | 375 for ( ; ; ) |
kaf24@3079 | 376 __asm__ __volatile__ ( "hlt" ); |
kaf24@3079 | 377 } |
kaf24@3079 | 378 |
kaf24@3127 | 379 asmlinkage void do_machine_check(struct xen_regs *regs) |
kaf24@3079 | 380 { |
kaf24@3127 | 381 fatal_trap(TRAP_machine_check, regs); |
kaf24@1490 | 382 } |
kaf24@1490 | 383 |
kaf24@3462 | 384 void propagate_page_fault(unsigned long addr, u16 error_code) |
kaf24@3462 | 385 { |
kaf24@3462 | 386 trap_info_t *ti; |
kaf24@3443 | 387 struct exec_domain *ed = current; |
kaf24@3443 | 388 struct trap_bounce *tb = &ed->thread.trap_bounce; |
kaf24@3462 | 389 |
kaf24@3443 | 390 ti = ed->thread.traps + 14; |
kaf24@3462 | 391 tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE | TBF_EXCEPTION_CR2; |
kaf24@3462 | 392 tb->cr2 = addr; |
kaf24@3462 | 393 tb->error_code = error_code; |
kaf24@3462 | 394 tb->cs = ti->cs; |
kaf24@3462 | 395 tb->eip = ti->address; |
kaf24@3462 | 396 if ( TI_GET_IF(ti) ) |
kaf24@3443 | 397 ed->vcpu_info->evtchn_upcall_mask = 1; |
kaf24@3443 | 398 |
kaf24@3443 | 399 ed->mm.guest_cr2 = addr; |
kaf24@3462 | 400 } |
kaf24@3462 | 401 |
kaf24@3127 | 402 asmlinkage int do_page_fault(struct xen_regs *regs) |
kaf24@1490 | 403 { |
kaf24@1490 | 404 unsigned long off, addr, fixup; |
cl349@2957 | 405 struct exec_domain *ed = current; |
cl349@2957 | 406 struct domain *d = ed->domain; |
kaf24@1490 | 407 extern int map_ldt_shadow_page(unsigned int); |
cl349@2957 | 408 int cpu = ed->processor; |
cl349@3036 | 409 int ret; |
kaf24@1490 | 410 |
kaf24@1490 | 411 __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (addr) : ); |
kaf24@1490 | 412 |
kaf24@3127 | 413 DEBUGGER_trap_entry(TRAP_page_fault, regs); |
kaf24@3009 | 414 |
kaf24@1490 | 415 perfc_incrc(page_faults); |
kaf24@1490 | 416 |
iap10@2458 | 417 if ( likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) ) |
kaf24@2111 | 418 { |
cl349@3186 | 419 LOCK_BIGLOCK(d); |
kaf24@2663 | 420 if ( unlikely(ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].l1va) && |
kaf24@2663 | 421 unlikely((addr >> L2_PAGETABLE_SHIFT) == |
kaf24@2663 | 422 ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].l2_idx) ) |
kaf24@2375 | 423 { |
cl349@2512 | 424 ptwr_flush(PTWR_PT_ACTIVE); |
cl349@3036 | 425 UNLOCK_BIGLOCK(d); |
kaf24@3090 | 426 return EXCRET_fault_fixed; |
kaf24@2375 | 427 } |
cl349@1860 | 428 |
kaf24@2375 | 429 if ( (addr < PAGE_OFFSET) && |
kaf24@3127 | 430 ((regs->error_code & 3) == 3) && /* write-protection fault */ |
kaf24@2375 | 431 ptwr_do_page_fault(addr) ) |
kaf24@3090 | 432 { |
cl349@3112 | 433 if ( unlikely(ed->mm.shadow_mode) ) |
kaf24@3127 | 434 (void)shadow_fault(addr, regs->error_code); |
cl349@3186 | 435 UNLOCK_BIGLOCK(d); |
kaf24@3090 | 436 return EXCRET_fault_fixed; |
kaf24@3090 | 437 } |
cl349@3186 | 438 UNLOCK_BIGLOCK(d); |
kaf24@2375 | 439 } |
cl349@1860 | 440 |
cl349@2957 | 441 if ( unlikely(ed->mm.shadow_mode) && |
kaf24@3127 | 442 (addr < PAGE_OFFSET) && shadow_fault(addr, regs->error_code) ) |
kaf24@3090 | 443 return EXCRET_fault_fixed; |
kaf24@1490 | 444 |
cl349@3036 | 445 if ( unlikely(addr >= LDT_VIRT_START(ed)) && |
cl349@3036 | 446 (addr < (LDT_VIRT_START(ed) + (ed->mm.ldt_ents*LDT_ENTRY_SIZE))) ) |
iap10@2611 | 447 { |
iap10@2611 | 448 /* |
iap10@2611 | 449 * Copy a mapping from the guest's LDT, if it is valid. Otherwise we |
iap10@2611 | 450 * send the fault up to the guest OS to be handled. |
iap10@2611 | 451 */ |
cl349@3036 | 452 LOCK_BIGLOCK(d); |
cl349@3036 | 453 off = addr - LDT_VIRT_START(ed); |
cl349@2957 | 454 addr = ed->mm.ldt_base + off; |
cl349@3036 | 455 ret = map_ldt_shadow_page(off >> PAGE_SHIFT); |
cl349@3036 | 456 UNLOCK_BIGLOCK(d); |
cl349@3036 | 457 if ( likely(ret) ) |
kaf24@3090 | 458 return EXCRET_fault_fixed; /* successfully copied the mapping */ |
iap10@2611 | 459 } |
iap10@2611 | 460 |
kaf24@3207 | 461 if ( !GUEST_FAULT(regs) ) |
kaf24@1628 | 462 goto xen_fault; |
kaf24@1490 | 463 |
kaf24@3462 | 464 propagate_page_fault(addr, regs->error_code); |
kaf24@3090 | 465 return 0; |
kaf24@1490 | 466 |
kaf24@1628 | 467 xen_fault: |
kaf24@1490 | 468 |
kaf24@1490 | 469 if ( likely((fixup = search_exception_table(regs->eip)) != 0) ) |
kaf24@1490 | 470 { |
kaf24@1490 | 471 perfc_incrc(copy_user_faults); |
cl349@2957 | 472 if ( !ed->mm.shadow_mode ) |
kaf24@3635 | 473 DPRINTK("Page fault: %08lx -> %08lx\n", regs->eip, fixup); |
kaf24@1490 | 474 regs->eip = fixup; |
kaf24@3090 | 475 return 0; |
kaf24@1490 | 476 } |
kaf24@1490 | 477 |
kaf24@3127 | 478 DEBUGGER_trap_fatal(TRAP_page_fault, regs); |
cl349@2995 | 479 |
kaf24@1490 | 480 if ( addr >= PAGE_OFFSET ) |
kaf24@1490 | 481 { |
kaf24@1490 | 482 unsigned long page; |
kaf24@1490 | 483 page = l2_pgentry_val(idle_pg_table[addr >> L2_PAGETABLE_SHIFT]); |
kaf24@1490 | 484 printk("*pde = %08lx\n", page); |
kaf24@1490 | 485 if ( page & _PAGE_PRESENT ) |
kaf24@1490 | 486 { |
kaf24@1490 | 487 page &= PAGE_MASK; |
kaf24@1490 | 488 page = ((unsigned long *) __va(page))[(addr&0x3ff000)>>PAGE_SHIFT]; |
kaf24@1490 | 489 printk(" *pte = %08lx\n", page); |
kaf24@1490 | 490 } |
kaf24@1490 | 491 #ifdef MEMORY_GUARD |
kaf24@3127 | 492 if ( !(regs->error_code & 1) ) |
kaf24@1490 | 493 printk(" -- POSSIBLY AN ACCESS TO FREED MEMORY? --\n"); |
kaf24@1490 | 494 #endif |
kaf24@1490 | 495 } |
kaf24@1490 | 496 |
kaf24@1490 | 497 show_registers(regs); |
kaf24@1490 | 498 panic("CPU%d FATAL PAGE FAULT\n" |
kaf24@3127 | 499 "[error_code=%04x]\n" |
kaf24@1490 | 500 "Faulting linear address might be %08lx\n", |
kaf24@3127 | 501 smp_processor_id(), regs->error_code, addr); |
kaf24@3090 | 502 return 0; |
kaf24@1490 | 503 } |
kaf24@1490 | 504 |
kaf24@3349 | 505 static int emulate_privileged_op(struct xen_regs *regs) |
kaf24@3349 | 506 { |
kaf24@3443 | 507 extern long do_fpu_taskswitch(void); |
kaf24@3443 | 508 extern void *decode_reg(struct xen_regs *regs, u8 b); |
kaf24@3349 | 509 |
kaf24@3443 | 510 struct exec_domain *ed = current; |
kaf24@3443 | 511 unsigned long *reg, eip = regs->eip; |
kaf24@3443 | 512 u8 opcode; |
kaf24@3443 | 513 |
kaf24@3443 | 514 if ( get_user(opcode, (u8 *)eip) ) |
kaf24@3443 | 515 goto page_fault; |
kaf24@3443 | 516 eip += 1; |
kaf24@3443 | 517 if ( (opcode & 0xff) != 0x0f ) |
kaf24@3443 | 518 goto fail; |
kaf24@3349 | 519 |
kaf24@3443 | 520 if ( get_user(opcode, (u8 *)eip) ) |
kaf24@3443 | 521 goto page_fault; |
kaf24@3443 | 522 eip += 1; |
kaf24@3443 | 523 |
kaf24@3443 | 524 switch ( opcode ) |
kaf24@3349 | 525 { |
kaf24@3443 | 526 case 0x06: /* CLTS */ |
kaf24@3443 | 527 (void)do_fpu_taskswitch(); |
kaf24@3443 | 528 break; |
kaf24@3443 | 529 |
kaf24@3349 | 530 case 0x09: /* WBINVD */ |
kaf24@3443 | 531 if ( !IS_CAPABLE_PHYSDEV(ed->domain) ) |
kaf24@3349 | 532 { |
kaf24@3349 | 533 DPRINTK("Non-physdev domain attempted WBINVD.\n"); |
kaf24@3443 | 534 goto fail; |
kaf24@3349 | 535 } |
kaf24@3349 | 536 wbinvd(); |
kaf24@3443 | 537 break; |
kaf24@3443 | 538 |
kaf24@3443 | 539 case 0x20: /* MOV CR?,<reg> */ |
kaf24@3443 | 540 if ( get_user(opcode, (u8 *)eip) ) |
kaf24@3443 | 541 goto page_fault; |
kaf24@3443 | 542 eip += 1; |
kaf24@3443 | 543 if ( (opcode & 0xc0) != 0xc0 ) |
kaf24@3443 | 544 goto fail; |
kaf24@3443 | 545 reg = decode_reg(regs, opcode); |
kaf24@3443 | 546 switch ( (opcode >> 3) & 7 ) |
kaf24@3443 | 547 { |
kaf24@3443 | 548 case 0: /* Read CR0 */ |
kaf24@3443 | 549 *reg = |
kaf24@3443 | 550 (read_cr0() & ~X86_CR0_TS) | |
kaf24@3443 | 551 (test_bit(EDF_GUEST_STTS, &ed->ed_flags) ? X86_CR0_TS : 0); |
kaf24@3443 | 552 break; |
kaf24@3443 | 553 |
kaf24@3443 | 554 case 2: /* Read CR2 */ |
kaf24@3443 | 555 *reg = ed->mm.guest_cr2; |
kaf24@3443 | 556 break; |
kaf24@3443 | 557 |
kaf24@3443 | 558 case 3: /* Read CR3 */ |
kaf24@3443 | 559 *reg = pagetable_val(ed->mm.pagetable); |
kaf24@3443 | 560 break; |
kaf24@3443 | 561 |
kaf24@3443 | 562 default: |
kaf24@3443 | 563 goto fail; |
kaf24@3443 | 564 } |
kaf24@3443 | 565 break; |
kaf24@3443 | 566 |
kaf24@3443 | 567 case 0x22: /* MOV <reg>,CR? */ |
kaf24@3443 | 568 if ( get_user(opcode, (u8 *)eip) ) |
kaf24@3443 | 569 goto page_fault; |
kaf24@3443 | 570 eip += 1; |
kaf24@3443 | 571 if ( (opcode & 0xc0) != 0xc0 ) |
kaf24@3443 | 572 goto fail; |
kaf24@3443 | 573 reg = decode_reg(regs, opcode); |
kaf24@3443 | 574 switch ( (opcode >> 3) & 7 ) |
kaf24@3443 | 575 { |
kaf24@3443 | 576 case 0: /* Write CR0 */ |
kaf24@3443 | 577 if ( *reg & X86_CR0_TS ) /* XXX ignore all but TS bit */ |
kaf24@3443 | 578 (void)do_fpu_taskswitch; |
kaf24@3443 | 579 break; |
kaf24@3443 | 580 |
kaf24@3443 | 581 case 2: /* Write CR2 */ |
kaf24@3443 | 582 ed->mm.guest_cr2 = *reg; |
kaf24@3443 | 583 break; |
kaf24@3443 | 584 |
kaf24@3443 | 585 case 3: /* Write CR3 */ |
kaf24@3443 | 586 LOCK_BIGLOCK(ed->domain); |
kaf24@3443 | 587 (void)new_guest_cr3(*reg); |
kaf24@3443 | 588 UNLOCK_BIGLOCK(ed->domain); |
kaf24@3443 | 589 break; |
kaf24@3443 | 590 |
kaf24@3443 | 591 default: |
kaf24@3443 | 592 goto fail; |
kaf24@3443 | 593 } |
kaf24@3443 | 594 break; |
kaf24@3443 | 595 |
kaf24@3349 | 596 case 0x30: /* WRMSR */ |
kaf24@3443 | 597 if ( !IS_PRIV(ed->domain) ) |
kaf24@3349 | 598 { |
kaf24@3349 | 599 DPRINTK("Non-priv domain attempted WRMSR.\n"); |
kaf24@3443 | 600 goto fail; |
kaf24@3349 | 601 } |
kaf24@3349 | 602 wrmsr(regs->ecx, regs->eax, regs->edx); |
kaf24@3443 | 603 break; |
kaf24@3349 | 604 |
kaf24@3349 | 605 case 0x32: /* RDMSR */ |
kaf24@3443 | 606 if ( !IS_PRIV(ed->domain) ) |
kaf24@3349 | 607 { |
kaf24@3349 | 608 DPRINTK("Non-priv domain attempted RDMSR.\n"); |
kaf24@3443 | 609 goto fail; |
kaf24@3349 | 610 } |
kaf24@3349 | 611 rdmsr(regs->ecx, regs->eax, regs->edx); |
kaf24@3443 | 612 break; |
kaf24@3443 | 613 |
kaf24@3443 | 614 default: |
kaf24@3443 | 615 goto fail; |
kaf24@3349 | 616 } |
kaf24@3349 | 617 |
kaf24@3443 | 618 regs->eip = eip; |
kaf24@3443 | 619 return EXCRET_fault_fixed; |
kaf24@3443 | 620 |
kaf24@3443 | 621 fail: |
kaf24@3349 | 622 return 0; |
kaf24@3443 | 623 |
kaf24@3443 | 624 page_fault: |
kaf24@3443 | 625 propagate_page_fault(eip, 0); |
kaf24@3443 | 626 return EXCRET_fault_fixed; |
kaf24@3349 | 627 } |
kaf24@3349 | 628 |
kaf24@3127 | 629 asmlinkage int do_general_protection(struct xen_regs *regs) |
kaf24@1490 | 630 { |
cl349@2957 | 631 struct exec_domain *ed = current; |
cl349@2957 | 632 struct domain *d = ed->domain; |
cl349@3086 | 633 struct trap_bounce *tb = &ed->thread.trap_bounce; |
kaf24@1490 | 634 trap_info_t *ti; |
kaf24@1490 | 635 unsigned long fixup; |
kaf24@1490 | 636 |
kaf24@3127 | 637 DEBUGGER_trap_entry(TRAP_gp_fault, regs); |
kaf24@3009 | 638 |
kaf24@3207 | 639 if ( regs->error_code & 1 ) |
kaf24@3207 | 640 goto hardware_gp; |
kaf24@3207 | 641 |
kaf24@3207 | 642 if ( !GUEST_FAULT(regs) ) |
kaf24@1490 | 643 goto gp_in_kernel; |
kaf24@1490 | 644 |
kaf24@1490 | 645 /* |
kaf24@1490 | 646 * Cunning trick to allow arbitrary "INT n" handling. |
kaf24@1490 | 647 * |
kaf24@1490 | 648 * We set DPL == 0 on all vectors in the IDT. This prevents any INT <n> |
kaf24@1490 | 649 * instruction from trapping to the appropriate vector, when that might not |
kaf24@1490 | 650 * be expected by Xen or the guest OS. For example, that entry might be for |
kaf24@1490 | 651 * a fault handler (unlike traps, faults don't increment EIP), or might |
kaf24@1490 | 652 * expect an error code on the stack (which a software trap never |
kaf24@1490 | 653 * provides), or might be a hardware interrupt handler that doesn't like |
kaf24@1490 | 654 * being called spuriously. |
kaf24@1490 | 655 * |
kaf24@1490 | 656 * Instead, a GPF occurs with the faulting IDT vector in the error code. |
kaf24@1490 | 657 * Bit 1 is set to indicate that an IDT entry caused the fault. Bit 0 is |
kaf24@1490 | 658 * clear to indicate that it's a software fault, not hardware. |
kaf24@1490 | 659 * |
kaf24@1490 | 660 * NOTE: Vectors 3 and 4 are dealt with from their own handler. This is |
kaf24@1490 | 661 * okay because they can only be triggered by an explicit DPL-checked |
kaf24@1490 | 662 * instruction. The DPL specified by the guest OS for these vectors is NOT |
kaf24@1490 | 663 * CHECKED!! |
kaf24@1490 | 664 */ |
kaf24@3127 | 665 if ( (regs->error_code & 3) == 2 ) |
kaf24@1490 | 666 { |
kaf24@1490 | 667 /* This fault must be due to <INT n> instruction. */ |
kaf24@3127 | 668 ti = current->thread.traps + (regs->error_code>>3); |
kaf24@3207 | 669 if ( TI_GET_DPL(ti) >= (VM86_MODE(regs) ? 3 : (regs->cs & 3)) ) |
kaf24@1490 | 670 { |
kaf24@3127 | 671 tb->flags = TBF_EXCEPTION; |
kaf24@1490 | 672 regs->eip += 2; |
kaf24@1490 | 673 goto finish_propagation; |
kaf24@1490 | 674 } |
kaf24@1490 | 675 } |
kaf24@1854 | 676 |
kaf24@3349 | 677 /* Emulate some simple privileged instructions when exec'ed in ring 1. */ |
kaf24@3349 | 678 if ( (regs->error_code == 0) && |
kaf24@3349 | 679 RING_1(regs) && |
kaf24@3349 | 680 emulate_privileged_op(regs) ) |
kaf24@3349 | 681 return 0; |
kaf24@3349 | 682 |
kaf24@1854 | 683 #if defined(__i386__) |
kaf24@2111 | 684 if ( VM_ASSIST(d, VMASST_TYPE_4gb_segments) && |
kaf24@3127 | 685 (regs->error_code == 0) && |
kaf24@2111 | 686 gpf_emulate_4gb(regs) ) |
kaf24@3090 | 687 return 0; |
kaf24@1854 | 688 #endif |
kaf24@3009 | 689 |
kaf24@1490 | 690 /* Pass on GPF as is. */ |
kaf24@1490 | 691 ti = current->thread.traps + 13; |
kaf24@3127 | 692 tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE; |
kaf24@3127 | 693 tb->error_code = regs->error_code; |
kaf24@1490 | 694 finish_propagation: |
kaf24@3081 | 695 tb->cs = ti->cs; |
kaf24@3081 | 696 tb->eip = ti->address; |
kaf24@1490 | 697 if ( TI_GET_IF(ti) ) |
cl349@2959 | 698 ed->vcpu_info->evtchn_upcall_mask = 1; |
kaf24@3090 | 699 return 0; |
kaf24@1490 | 700 |
kaf24@1490 | 701 gp_in_kernel: |
kaf24@1490 | 702 |
kaf24@1490 | 703 if ( likely((fixup = search_exception_table(regs->eip)) != 0) ) |
kaf24@1490 | 704 { |
kaf24@3635 | 705 DPRINTK("GPF (%04x): %08lx -> %08lx\n", |
kaf24@3127 | 706 regs->error_code, regs->eip, fixup); |
kaf24@1490 | 707 regs->eip = fixup; |
kaf24@3090 | 708 return 0; |
kaf24@1490 | 709 } |
kaf24@1490 | 710 |
kaf24@3127 | 711 DEBUGGER_trap_fatal(TRAP_gp_fault, regs); |
cl349@2995 | 712 |
kaf24@3207 | 713 hardware_gp: |
kaf24@3079 | 714 show_registers(regs); |
kaf24@3127 | 715 panic("CPU%d GENERAL PROTECTION FAULT\n[error_code=%04x]\n", |
kaf24@3127 | 716 smp_processor_id(), regs->error_code); |
kaf24@3090 | 717 return 0; |
kaf24@1490 | 718 } |
kaf24@1490 | 719 |
ach61@2843 | 720 asmlinkage void mem_parity_error(struct xen_regs *regs) |
kaf24@1490 | 721 { |
kaf24@2079 | 722 console_force_unlock(); |
kaf24@3079 | 723 printk("\n\nNMI - MEMORY ERROR\n"); |
kaf24@3127 | 724 fatal_trap(TRAP_nmi, regs); |
kaf24@1490 | 725 } |
kaf24@1490 | 726 |
ach61@2843 | 727 asmlinkage void io_check_error(struct xen_regs *regs) |
kaf24@1490 | 728 { |
kaf24@2079 | 729 console_force_unlock(); |
kaf24@2079 | 730 |
kaf24@3079 | 731 printk("\n\nNMI - I/O ERROR\n"); |
kaf24@3127 | 732 fatal_trap(TRAP_nmi, regs); |
kaf24@1490 | 733 } |
kaf24@1490 | 734 |
ach61@2843 | 735 static void unknown_nmi_error(unsigned char reason, struct xen_regs * regs) |
kaf24@1490 | 736 { |
kaf24@1490 | 737 printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); |
kaf24@1490 | 738 printk("Dazed and confused, but trying to continue\n"); |
kaf24@1490 | 739 printk("Do you have a strange power saving mode enabled?\n"); |
kaf24@1490 | 740 } |
kaf24@1490 | 741 |
ach61@2843 | 742 asmlinkage void do_nmi(struct xen_regs * regs, unsigned long reason) |
kaf24@1490 | 743 { |
kaf24@1490 | 744 ++nmi_count(smp_processor_id()); |
kaf24@1490 | 745 |
kaf24@1490 | 746 #if CONFIG_X86_LOCAL_APIC |
kaf24@1490 | 747 if ( nmi_watchdog ) |
kaf24@1490 | 748 nmi_watchdog_tick(regs); |
kaf24@1490 | 749 else |
kaf24@1490 | 750 #endif |
kaf24@1490 | 751 unknown_nmi_error((unsigned char)(reason&0xff), regs); |
kaf24@1490 | 752 } |
kaf24@1490 | 753 |
kaf24@2085 | 754 unsigned long nmi_softirq_reason; |
kaf24@2085 | 755 static void nmi_softirq(void) |
kaf24@2085 | 756 { |
kaf24@2844 | 757 if ( dom0 == NULL ) |
kaf24@2085 | 758 return; |
kaf24@2085 | 759 |
kaf24@2085 | 760 if ( test_and_clear_bit(0, &nmi_softirq_reason) ) |
cl349@2957 | 761 send_guest_virq(dom0->exec_domain[0], VIRQ_PARITY_ERR); |
kaf24@2085 | 762 |
kaf24@2085 | 763 if ( test_and_clear_bit(1, &nmi_softirq_reason) ) |
cl349@2957 | 764 send_guest_virq(dom0->exec_domain[0], VIRQ_IO_ERR); |
kaf24@2085 | 765 } |
kaf24@2085 | 766 |
kaf24@3127 | 767 asmlinkage int math_state_restore(struct xen_regs *regs) |
kaf24@1490 | 768 { |
kaf24@1490 | 769 /* Prevent recursion. */ |
kaf24@1490 | 770 clts(); |
kaf24@1490 | 771 |
cl349@2957 | 772 if ( !test_bit(EDF_USEDFPU, ¤t->ed_flags) ) |
kaf24@1490 | 773 { |
cl349@2957 | 774 if ( test_bit(EDF_DONEFPUINIT, ¤t->ed_flags) ) |
kaf24@1490 | 775 restore_fpu(current); |
kaf24@1490 | 776 else |
kaf24@1490 | 777 init_fpu(); |
cl349@2957 | 778 set_bit(EDF_USEDFPU, ¤t->ed_flags); /* so we fnsave on switch_to() */ |
kaf24@1490 | 779 } |
kaf24@1490 | 780 |
cl349@2957 | 781 if ( test_and_clear_bit(EDF_GUEST_STTS, ¤t->ed_flags) ) |
kaf24@1490 | 782 { |
kaf24@3081 | 783 struct trap_bounce *tb = ¤t->thread.trap_bounce; |
kaf24@3127 | 784 tb->flags = TBF_EXCEPTION; |
kaf24@3081 | 785 tb->cs = current->thread.traps[7].cs; |
kaf24@3081 | 786 tb->eip = current->thread.traps[7].address; |
kaf24@1490 | 787 } |
kaf24@3090 | 788 |
kaf24@3090 | 789 return EXCRET_fault_fixed; |
kaf24@1490 | 790 } |
kaf24@1490 | 791 |
kaf24@3127 | 792 asmlinkage int do_debug(struct xen_regs *regs) |
kaf24@1490 | 793 { |
kaf24@1490 | 794 unsigned int condition; |
cl349@3085 | 795 struct exec_domain *d = current; |
kaf24@3081 | 796 struct trap_bounce *tb = &d->thread.trap_bounce; |
kaf24@1490 | 797 |
kaf24@3127 | 798 DEBUGGER_trap_entry(TRAP_debug, regs); |
kaf24@1490 | 799 |
kaf24@1490 | 800 __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); |
kaf24@1490 | 801 |
kaf24@1490 | 802 /* Mask out spurious debug traps due to lazy DR7 setting */ |
kaf24@1490 | 803 if ( (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) && |
kaf24@3081 | 804 (d->thread.debugreg[7] == 0) ) |
kaf24@1490 | 805 { |
kaf24@1490 | 806 __asm__("movl %0,%%db7" : : "r" (0)); |
kaf24@3090 | 807 goto out; |
kaf24@1490 | 808 } |
kaf24@1490 | 809 |
kaf24@3207 | 810 if ( !GUEST_FAULT(regs) ) |
kaf24@1490 | 811 { |
kaf24@1490 | 812 /* Clear TF just for absolute sanity. */ |
kaf24@1490 | 813 regs->eflags &= ~EF_TF; |
kaf24@1490 | 814 /* |
kaf24@1628 | 815 * We ignore watchpoints when they trigger within Xen. This may happen |
kaf24@1628 | 816 * when a buffer is passed to us which previously had a watchpoint set |
kaf24@1628 | 817 * on it. No need to bump EIP; the only faulting trap is an instruction |
kaf24@1628 | 818 * breakpoint, which can't happen to us. |
kaf24@1490 | 819 */ |
kaf24@3090 | 820 goto out; |
kaf24@1490 | 821 } |
kaf24@1490 | 822 |
kaf24@1490 | 823 /* Save debug status register where guest OS can peek at it */ |
kaf24@3081 | 824 d->thread.debugreg[6] = condition; |
kaf24@1490 | 825 |
kaf24@3127 | 826 tb->flags = TBF_EXCEPTION; |
kaf24@3081 | 827 tb->cs = d->thread.traps[1].cs; |
kaf24@3081 | 828 tb->eip = d->thread.traps[1].address; |
kaf24@3090 | 829 |
kaf24@3090 | 830 out: |
kaf24@3090 | 831 return EXCRET_not_a_fault; |
kaf24@1490 | 832 } |
kaf24@1490 | 833 |
kaf24@3127 | 834 asmlinkage int do_spurious_interrupt_bug(struct xen_regs *regs) |
kaf24@3090 | 835 { |
kaf24@3090 | 836 return EXCRET_not_a_fault; |
kaf24@3090 | 837 } |
kaf24@1490 | 838 |
kaf24@1490 | 839 #define _set_gate(gate_addr,type,dpl,addr) \ |
kaf24@1490 | 840 do { \ |
kaf24@1490 | 841 int __d0, __d1; \ |
kaf24@1490 | 842 __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ |
kaf24@1490 | 843 "movw %4,%%dx\n\t" \ |
kaf24@1490 | 844 "movl %%eax,%0\n\t" \ |
kaf24@1490 | 845 "movl %%edx,%1" \ |
kaf24@1490 | 846 :"=m" (*((long *) (gate_addr))), \ |
kaf24@1490 | 847 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ |
kaf24@1490 | 848 :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ |
kaf24@1490 | 849 "3" ((char *) (addr)),"2" (__HYPERVISOR_CS << 16)); \ |
kaf24@1490 | 850 } while (0) |
kaf24@1490 | 851 |
kaf24@1490 | 852 void set_intr_gate(unsigned int n, void *addr) |
kaf24@1490 | 853 { |
kaf24@1490 | 854 _set_gate(idt_table+n,14,0,addr); |
kaf24@1490 | 855 } |
kaf24@1490 | 856 |
kaf24@1490 | 857 static void __init set_system_gate(unsigned int n, void *addr) |
kaf24@1490 | 858 { |
kaf24@1490 | 859 _set_gate(idt_table+n,14,3,addr); |
kaf24@1490 | 860 } |
kaf24@1490 | 861 |
kaf24@1490 | 862 static void set_task_gate(unsigned int n, unsigned int sel) |
kaf24@1490 | 863 { |
kaf24@1490 | 864 idt_table[n].a = sel << 16; |
kaf24@1490 | 865 idt_table[n].b = 0x8500; |
kaf24@1490 | 866 } |
kaf24@1490 | 867 |
kaf24@1490 | 868 #define _set_seg_desc(gate_addr,type,dpl,base,limit) {\ |
kaf24@1490 | 869 *((gate_addr)+1) = ((base) & 0xff000000) | \ |
kaf24@1490 | 870 (((base) & 0x00ff0000)>>16) | \ |
kaf24@1490 | 871 ((limit) & 0xf0000) | \ |
kaf24@1490 | 872 ((dpl)<<13) | \ |
kaf24@1490 | 873 (0x00408000) | \ |
kaf24@1490 | 874 ((type)<<8); \ |
kaf24@1490 | 875 *(gate_addr) = (((base) & 0x0000ffff)<<16) | \ |
kaf24@1490 | 876 ((limit) & 0x0ffff); } |
kaf24@1490 | 877 |
kaf24@1490 | 878 #define _set_tssldt_desc(n,addr,limit,type) \ |
kaf24@1490 | 879 __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \ |
kaf24@1490 | 880 "movw %%ax,2(%2)\n\t" \ |
kaf24@1490 | 881 "rorl $16,%%eax\n\t" \ |
kaf24@1490 | 882 "movb %%al,4(%2)\n\t" \ |
kaf24@1490 | 883 "movb %4,5(%2)\n\t" \ |
kaf24@1490 | 884 "movb $0,6(%2)\n\t" \ |
kaf24@1490 | 885 "movb %%ah,7(%2)\n\t" \ |
kaf24@1490 | 886 "rorl $16,%%eax" \ |
kaf24@1490 | 887 : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type)) |
kaf24@1490 | 888 |
kaf24@1490 | 889 void set_tss_desc(unsigned int n, void *addr) |
kaf24@1490 | 890 { |
kaf24@3113 | 891 _set_tssldt_desc( |
kaf24@3113 | 892 gdt_table + __TSS(n), |
kaf24@3113 | 893 (int)addr, |
kaf24@3113 | 894 offsetof(struct tss_struct, __cacheline_filler) - 1, |
kaf24@3113 | 895 0x89); |
kaf24@1490 | 896 } |
kaf24@1490 | 897 |
kaf24@1490 | 898 void __init trap_init(void) |
kaf24@1490 | 899 { |
kaf24@1490 | 900 /* |
kaf24@1490 | 901 * Make a separate task for double faults. This will get us debug output if |
kaf24@1490 | 902 * we blow the kernel stack. |
kaf24@1490 | 903 */ |
kaf24@1490 | 904 struct tss_struct *tss = &doublefault_tss; |
kaf24@1490 | 905 memset(tss, 0, sizeof(*tss)); |
kaf24@1490 | 906 tss->ds = __HYPERVISOR_DS; |
kaf24@1490 | 907 tss->es = __HYPERVISOR_DS; |
kaf24@1490 | 908 tss->ss = __HYPERVISOR_DS; |
kaf24@1490 | 909 tss->esp = (unsigned long) |
kaf24@1490 | 910 &doublefault_stack[DOUBLEFAULT_STACK_SIZE]; |
kaf24@1490 | 911 tss->__cr3 = __pa(idle_pg_table); |
kaf24@1490 | 912 tss->cs = __HYPERVISOR_CS; |
kaf24@1490 | 913 tss->eip = (unsigned long)do_double_fault; |
kaf24@1490 | 914 tss->eflags = 2; |
kaf24@3088 | 915 tss->bitmap = IOBMP_INVALID_OFFSET; |
kaf24@1490 | 916 _set_tssldt_desc(gdt_table+__DOUBLEFAULT_TSS_ENTRY, |
kaf24@1490 | 917 (int)tss, 235, 0x89); |
kaf24@1490 | 918 |
kaf24@1490 | 919 /* |
kaf24@1490 | 920 * Note that interrupt gates are always used, rather than trap gates. We |
kaf24@1490 | 921 * must have interrupts disabled until DS/ES/FS/GS are saved because the |
kaf24@1490 | 922 * first activation must have the "bad" value(s) for these registers and |
kaf24@1490 | 923 * we may lose them if another activation is installed before they are |
kaf24@1490 | 924 * saved. The page-fault handler also needs interrupts disabled until %cr2 |
kaf24@1490 | 925 * has been read and saved on the stack. |
kaf24@1490 | 926 */ |
kaf24@3079 | 927 set_intr_gate(TRAP_divide_error,÷_error); |
kaf24@3079 | 928 set_intr_gate(TRAP_debug,&debug); |
kaf24@3079 | 929 set_intr_gate(TRAP_nmi,&nmi); |
kaf24@3079 | 930 set_system_gate(TRAP_int3,&int3); /* usable from all privileges */ |
kaf24@3079 | 931 set_system_gate(TRAP_overflow,&overflow); /* usable from all privileges */ |
kaf24@3079 | 932 set_intr_gate(TRAP_bounds,&bounds); |
kaf24@3079 | 933 set_intr_gate(TRAP_invalid_op,&invalid_op); |
kaf24@3079 | 934 set_intr_gate(TRAP_no_device,&device_not_available); |
kaf24@3079 | 935 set_task_gate(TRAP_double_fault,__DOUBLEFAULT_TSS_ENTRY<<3); |
kaf24@3079 | 936 set_intr_gate(TRAP_copro_seg,&coprocessor_segment_overrun); |
kaf24@3079 | 937 set_intr_gate(TRAP_invalid_tss,&invalid_TSS); |
kaf24@3079 | 938 set_intr_gate(TRAP_no_segment,&segment_not_present); |
kaf24@3079 | 939 set_intr_gate(TRAP_stack_error,&stack_segment); |
kaf24@3079 | 940 set_intr_gate(TRAP_gp_fault,&general_protection); |
kaf24@3079 | 941 set_intr_gate(TRAP_page_fault,&page_fault); |
kaf24@3079 | 942 set_intr_gate(TRAP_spurious_int,&spurious_interrupt_bug); |
kaf24@3079 | 943 set_intr_gate(TRAP_copro_error,&coprocessor_error); |
kaf24@3079 | 944 set_intr_gate(TRAP_alignment_check,&alignment_check); |
kaf24@3079 | 945 set_intr_gate(TRAP_machine_check,&machine_check); |
kaf24@3079 | 946 set_intr_gate(TRAP_simd_error,&simd_coprocessor_error); |
kaf24@3633 | 947 set_intr_gate(TRAP_deferred_nmi,&nmi); |
kaf24@1490 | 948 |
kaf24@1628 | 949 /* Only ring 1 can access Xen services. */ |
kaf24@1594 | 950 _set_gate(idt_table+HYPERCALL_VECTOR,14,1,&hypercall); |
kaf24@1490 | 951 |
kaf24@1490 | 952 /* CPU0 uses the master IDT. */ |
kaf24@1490 | 953 idt_tables[0] = idt_table; |
kaf24@1490 | 954 |
kaf24@1490 | 955 /* |
kaf24@1490 | 956 * Should be a barrier for any external CPU state. |
kaf24@1490 | 957 */ |
kaf24@1490 | 958 { |
kaf24@1490 | 959 extern void cpu_init(void); |
kaf24@1490 | 960 cpu_init(); |
kaf24@1490 | 961 } |
kaf24@2085 | 962 |
kaf24@2085 | 963 open_softirq(NMI_SOFTIRQ, nmi_softirq); |
kaf24@1490 | 964 } |
kaf24@1490 | 965 |
kaf24@1490 | 966 |
kaf24@1490 | 967 long do_set_trap_table(trap_info_t *traps) |
kaf24@1490 | 968 { |
kaf24@1490 | 969 trap_info_t cur; |
kaf24@1490 | 970 trap_info_t *dst = current->thread.traps; |
kaf24@1490 | 971 |
cl349@3036 | 972 LOCK_BIGLOCK(current->domain); |
cl349@3036 | 973 |
kaf24@1490 | 974 for ( ; ; ) |
kaf24@1490 | 975 { |
kaf24@3177 | 976 if ( hypercall_preempt_check() ) |
kaf24@3177 | 977 { |
cl349@3191 | 978 UNLOCK_BIGLOCK(current->domain); |
kaf24@3187 | 979 return hypercall_create_continuation( |
kaf24@3177 | 980 __HYPERVISOR_set_trap_table, 1, traps); |
kaf24@3177 | 981 } |
kaf24@3129 | 982 |
kaf24@1490 | 983 if ( copy_from_user(&cur, traps, sizeof(cur)) ) return -EFAULT; |
kaf24@1490 | 984 |
kaf24@1490 | 985 if ( cur.address == 0 ) break; |
kaf24@1490 | 986 |
kaf24@1490 | 987 if ( !VALID_CODESEL(cur.cs) ) return -EPERM; |
kaf24@1490 | 988 |
kaf24@1490 | 989 memcpy(dst+cur.vector, &cur, sizeof(cur)); |
kaf24@1490 | 990 traps++; |
kaf24@1490 | 991 } |
kaf24@1490 | 992 |
cl349@3036 | 993 UNLOCK_BIGLOCK(current->domain); |
cl349@3036 | 994 |
kaf24@1490 | 995 return 0; |
kaf24@1490 | 996 } |
kaf24@1490 | 997 |
kaf24@1490 | 998 |
kaf24@1490 | 999 long do_set_callbacks(unsigned long event_selector, |
kaf24@1490 | 1000 unsigned long event_address, |
kaf24@1490 | 1001 unsigned long failsafe_selector, |
kaf24@1490 | 1002 unsigned long failsafe_address) |
kaf24@1490 | 1003 { |
cl349@3085 | 1004 struct exec_domain *d = current; |
kaf24@1490 | 1005 |
kaf24@1490 | 1006 if ( !VALID_CODESEL(event_selector) || !VALID_CODESEL(failsafe_selector) ) |
kaf24@1490 | 1007 return -EPERM; |
kaf24@1490 | 1008 |
kaf24@3081 | 1009 d->thread.event_selector = event_selector; |
kaf24@3081 | 1010 d->thread.event_address = event_address; |
kaf24@3081 | 1011 d->thread.failsafe_selector = failsafe_selector; |
kaf24@3081 | 1012 d->thread.failsafe_address = failsafe_address; |
kaf24@1490 | 1013 |
kaf24@1490 | 1014 return 0; |
kaf24@1490 | 1015 } |
kaf24@1490 | 1016 |
kaf24@1490 | 1017 |
cl349@2957 | 1018 long set_fast_trap(struct exec_domain *p, int idx) |
kaf24@1490 | 1019 { |
kaf24@1490 | 1020 trap_info_t *ti; |
kaf24@1490 | 1021 |
kaf24@1490 | 1022 /* Index 0 is special: it disables fast traps. */ |
kaf24@1490 | 1023 if ( idx == 0 ) |
kaf24@1490 | 1024 { |
kaf24@1490 | 1025 if ( p == current ) |
kaf24@1490 | 1026 CLEAR_FAST_TRAP(&p->thread); |
kaf24@1490 | 1027 SET_DEFAULT_FAST_TRAP(&p->thread); |
kaf24@1490 | 1028 return 0; |
kaf24@1490 | 1029 } |
kaf24@1490 | 1030 |
kaf24@1490 | 1031 /* |
kaf24@1490 | 1032 * We only fast-trap vectors 0x20-0x2f, and vector 0x80. |
kaf24@1490 | 1033 * The former range is used by Windows and MS-DOS. |
kaf24@1490 | 1034 * Vector 0x80 is used by Linux and the BSD variants. |
kaf24@1490 | 1035 */ |
kaf24@1490 | 1036 if ( (idx != 0x80) && ((idx < 0x20) || (idx > 0x2f)) ) |
kaf24@1490 | 1037 return -1; |
kaf24@1490 | 1038 |
kaf24@1490 | 1039 ti = p->thread.traps + idx; |
kaf24@1490 | 1040 |
kaf24@1490 | 1041 /* |
kaf24@1490 | 1042 * We can't virtualise interrupt gates, as there's no way to get |
kaf24@1490 | 1043 * the CPU to automatically clear the events_mask variable. |
kaf24@1490 | 1044 */ |
kaf24@1490 | 1045 if ( TI_GET_IF(ti) ) |
kaf24@1490 | 1046 return -1; |
kaf24@1490 | 1047 |
kaf24@1490 | 1048 if ( p == current ) |
kaf24@1490 | 1049 CLEAR_FAST_TRAP(&p->thread); |
kaf24@1490 | 1050 |
kaf24@1490 | 1051 p->thread.fast_trap_idx = idx; |
kaf24@1490 | 1052 p->thread.fast_trap_desc.a = (ti->cs << 16) | (ti->address & 0xffff); |
kaf24@1490 | 1053 p->thread.fast_trap_desc.b = |
kaf24@1490 | 1054 (ti->address & 0xffff0000) | 0x8f00 | (TI_GET_DPL(ti)&3)<<13; |
kaf24@1490 | 1055 |
kaf24@1490 | 1056 if ( p == current ) |
kaf24@1490 | 1057 SET_FAST_TRAP(&p->thread); |
kaf24@1490 | 1058 |
kaf24@1490 | 1059 return 0; |
kaf24@1490 | 1060 } |
kaf24@1490 | 1061 |
kaf24@1490 | 1062 |
kaf24@1490 | 1063 long do_set_fast_trap(int idx) |
kaf24@1490 | 1064 { |
kaf24@1490 | 1065 return set_fast_trap(current, idx); |
kaf24@1490 | 1066 } |
kaf24@1490 | 1067 |
kaf24@1490 | 1068 |
kaf24@1490 | 1069 long do_fpu_taskswitch(void) |
kaf24@1490 | 1070 { |
cl349@2957 | 1071 set_bit(EDF_GUEST_STTS, ¤t->ed_flags); |
kaf24@1490 | 1072 stts(); |
kaf24@1490 | 1073 return 0; |
kaf24@1490 | 1074 } |
kaf24@1490 | 1075 |
kaf24@1490 | 1076 |
cl349@2957 | 1077 long set_debugreg(struct exec_domain *p, int reg, unsigned long value) |
kaf24@1490 | 1078 { |
kaf24@1490 | 1079 int i; |
kaf24@1490 | 1080 |
kaf24@1490 | 1081 switch ( reg ) |
kaf24@1490 | 1082 { |
kaf24@1490 | 1083 case 0: |
kaf24@1490 | 1084 if ( value > (PAGE_OFFSET-4) ) return -EPERM; |
kaf24@1490 | 1085 if ( p == current ) |
kaf24@1490 | 1086 __asm__ ( "movl %0, %%db0" : : "r" (value) ); |
kaf24@1490 | 1087 break; |
kaf24@1490 | 1088 case 1: |
kaf24@1490 | 1089 if ( value > (PAGE_OFFSET-4) ) return -EPERM; |
kaf24@1490 | 1090 if ( p == current ) |
kaf24@1490 | 1091 __asm__ ( "movl %0, %%db1" : : "r" (value) ); |
kaf24@1490 | 1092 break; |
kaf24@1490 | 1093 case 2: |
kaf24@1490 | 1094 if ( value > (PAGE_OFFSET-4) ) return -EPERM; |
kaf24@1490 | 1095 if ( p == current ) |
kaf24@1490 | 1096 __asm__ ( "movl %0, %%db2" : : "r" (value) ); |
kaf24@1490 | 1097 break; |
kaf24@1490 | 1098 case 3: |
kaf24@1490 | 1099 if ( value > (PAGE_OFFSET-4) ) return -EPERM; |
kaf24@1490 | 1100 if ( p == current ) |
kaf24@1490 | 1101 __asm__ ( "movl %0, %%db3" : : "r" (value) ); |
kaf24@1490 | 1102 break; |
kaf24@1490 | 1103 case 6: |
kaf24@1490 | 1104 /* |
kaf24@1490 | 1105 * DR6: Bits 4-11,16-31 reserved (set to 1). |
kaf24@1490 | 1106 * Bit 12 reserved (set to 0). |
kaf24@1490 | 1107 */ |
kaf24@1490 | 1108 value &= 0xffffefff; /* reserved bits => 0 */ |
kaf24@1490 | 1109 value |= 0xffff0ff0; /* reserved bits => 1 */ |
kaf24@1490 | 1110 if ( p == current ) |
kaf24@1490 | 1111 __asm__ ( "movl %0, %%db6" : : "r" (value) ); |
kaf24@1490 | 1112 break; |
kaf24@1490 | 1113 case 7: |
kaf24@1490 | 1114 /* |
kaf24@1490 | 1115 * DR7: Bit 10 reserved (set to 1). |
kaf24@1490 | 1116 * Bits 11-12,14-15 reserved (set to 0). |
kaf24@1490 | 1117 * Privileged bits: |
kaf24@1490 | 1118 * GD (bit 13): must be 0. |
kaf24@1490 | 1119 * R/Wn (bits 16-17,20-21,24-25,28-29): mustn't be 10. |
kaf24@1490 | 1120 * LENn (bits 18-19,22-23,26-27,30-31): mustn't be 10. |
kaf24@1490 | 1121 */ |
kaf24@1490 | 1122 /* DR7 == 0 => debugging disabled for this domain. */ |
kaf24@1490 | 1123 if ( value != 0 ) |
kaf24@1490 | 1124 { |
kaf24@1490 | 1125 value &= 0xffff27ff; /* reserved bits => 0 */ |
kaf24@1490 | 1126 value |= 0x00000400; /* reserved bits => 1 */ |
kaf24@1490 | 1127 if ( (value & (1<<13)) != 0 ) return -EPERM; |
kaf24@1490 | 1128 for ( i = 0; i < 16; i += 2 ) |
kaf24@1490 | 1129 if ( ((value >> (i+16)) & 3) == 2 ) return -EPERM; |
kaf24@1490 | 1130 } |
kaf24@1490 | 1131 if ( p == current ) |
kaf24@1490 | 1132 __asm__ ( "movl %0, %%db7" : : "r" (value) ); |
kaf24@1490 | 1133 break; |
kaf24@1490 | 1134 default: |
kaf24@1490 | 1135 return -EINVAL; |
kaf24@1490 | 1136 } |
kaf24@1490 | 1137 |
kaf24@1490 | 1138 p->thread.debugreg[reg] = value; |
kaf24@1490 | 1139 return 0; |
kaf24@1490 | 1140 } |
kaf24@1490 | 1141 |
kaf24@1490 | 1142 long do_set_debugreg(int reg, unsigned long value) |
kaf24@1490 | 1143 { |
kaf24@1490 | 1144 return set_debugreg(current, reg, value); |
kaf24@1490 | 1145 } |
kaf24@1490 | 1146 |
kaf24@1490 | 1147 unsigned long do_get_debugreg(int reg) |
kaf24@1490 | 1148 { |
kaf24@1490 | 1149 if ( (reg < 0) || (reg > 7) ) return -EINVAL; |
kaf24@1490 | 1150 return current->thread.debugreg[reg]; |
kaf24@1490 | 1151 } |