xen-vtx-unstable

annotate xen/arch/x86/traps.c @ 6776:e7c7196fa329

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:46:49 2005 +0000 (2005-09-13)
parents 4d899a738d59 813c37b68376
children 72e4e2aab342
rev   line source
kaf24@1452 1 /******************************************************************************
kaf24@3597 2 * arch/x86/traps.c
kaf24@1452 3 *
kaf24@2076 4 * Modifications to Linux original are copyright (c) 2002-2004, K A Fraser
kaf24@1452 5 *
kaf24@1452 6 * This program is free software; you can redistribute it and/or modify
kaf24@1452 7 * it under the terms of the GNU General Public License as published by
kaf24@1452 8 * the Free Software Foundation; either version 2 of the License, or
kaf24@1452 9 * (at your option) any later version.
kaf24@1452 10 *
kaf24@1452 11 * This program is distributed in the hope that it will be useful,
kaf24@1452 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
kaf24@1452 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
kaf24@1452 14 * GNU General Public License for more details.
kaf24@1452 15 *
kaf24@1452 16 * You should have received a copy of the GNU General Public License
kaf24@1452 17 * along with this program; if not, write to the Free Software
kaf24@1452 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
kaf24@1452 19 */
kaf24@1452 20
kaf24@1452 21 /*
kaf24@1452 22 * Copyright (C) 1991, 1992 Linus Torvalds
kaf24@1452 23 *
kaf24@1452 24 * Pentium III FXSR, SSE support
kaf24@1452 25 * Gareth Hughes <gareth@valinux.com>, May 2000
kaf24@1452 26 */
kaf24@1452 27
kaf24@1452 28 #include <xen/config.h>
kaf24@1452 29 #include <xen/init.h>
kaf24@1452 30 #include <xen/sched.h>
kaf24@1452 31 #include <xen/lib.h>
kaf24@1452 32 #include <xen/errno.h>
kaf24@1452 33 #include <xen/mm.h>
kaf24@2041 34 #include <xen/console.h>
ach61@2805 35 #include <asm/regs.h>
kaf24@1452 36 #include <xen/delay.h>
kaf24@2047 37 #include <xen/event.h>
kaf24@1452 38 #include <xen/spinlock.h>
kaf24@1452 39 #include <xen/irq.h>
kaf24@1452 40 #include <xen/perfc.h>
kaf24@2047 41 #include <xen/softirq.h>
kaf24@5356 42 #include <xen/domain_page.h>
kaf24@5824 43 #include <xen/symbols.h>
kaf24@1749 44 #include <asm/shadow.h>
kaf24@1452 45 #include <asm/system.h>
kaf24@1452 46 #include <asm/io.h>
kaf24@1452 47 #include <asm/atomic.h>
kaf24@1452 48 #include <asm/desc.h>
kaf24@1452 49 #include <asm/debugreg.h>
kaf24@1452 50 #include <asm/smp.h>
kaf24@1452 51 #include <asm/flushtlb.h>
kaf24@1452 52 #include <asm/uaccess.h>
kaf24@1452 53 #include <asm/i387.h>
kaf24@2971 54 #include <asm/debugger.h>
kaf24@3337 55 #include <asm/msr.h>
kaf24@4047 56 #include <asm/x86_emulate.h>
kaf24@1452 57
kaf24@3334 58 /*
kaf24@3334 59 * opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
kaf24@3334 60 * fatal: Xen prints diagnostic message and then hangs.
kaf24@3334 61 * dom0: The NMI is virtualised to DOM0.
kaf24@3334 62 * ignore: The NMI error is cleared and ignored.
kaf24@3334 63 */
kaf24@3334 64 #ifdef NDEBUG
kaf24@3334 65 char opt_nmi[10] = "dom0";
kaf24@3334 66 #else
kaf24@3334 67 char opt_nmi[10] = "fatal";
kaf24@3334 68 #endif
kaf24@3334 69 string_param("nmi", opt_nmi);
kaf24@3334 70
kaf24@3774 71 /* Master table, used by all CPUs on x86/64, and by CPU0 on x86/32.*/
kaf24@3847 72 idt_entry_t idt_table[IDT_ENTRIES];
kaf24@1452 73
kaf24@4972 74 #define DECLARE_TRAP_HANDLER(_name) \
kaf24@4972 75 asmlinkage void _name(void); \
kaf24@4972 76 asmlinkage int do_ ## _name(struct cpu_user_regs *regs)
kaf24@1452 77
kaf24@1452 78 asmlinkage void nmi(void);
kaf24@4972 79 DECLARE_TRAP_HANDLER(divide_error);
kaf24@4972 80 DECLARE_TRAP_HANDLER(debug);
kaf24@4972 81 DECLARE_TRAP_HANDLER(int3);
kaf24@4972 82 DECLARE_TRAP_HANDLER(overflow);
kaf24@4972 83 DECLARE_TRAP_HANDLER(bounds);
kaf24@4972 84 DECLARE_TRAP_HANDLER(invalid_op);
kaf24@4972 85 DECLARE_TRAP_HANDLER(device_not_available);
kaf24@4972 86 DECLARE_TRAP_HANDLER(coprocessor_segment_overrun);
kaf24@4972 87 DECLARE_TRAP_HANDLER(invalid_TSS);
kaf24@4972 88 DECLARE_TRAP_HANDLER(segment_not_present);
kaf24@4972 89 DECLARE_TRAP_HANDLER(stack_segment);
kaf24@4972 90 DECLARE_TRAP_HANDLER(general_protection);
kaf24@4972 91 DECLARE_TRAP_HANDLER(page_fault);
kaf24@4972 92 DECLARE_TRAP_HANDLER(coprocessor_error);
kaf24@4972 93 DECLARE_TRAP_HANDLER(simd_coprocessor_error);
kaf24@4972 94 DECLARE_TRAP_HANDLER(alignment_check);
kaf24@4972 95 DECLARE_TRAP_HANDLER(spurious_interrupt_bug);
kaf24@4972 96 DECLARE_TRAP_HANDLER(machine_check);
kaf24@1452 97
kaf24@5696 98 long do_set_debugreg(int reg, unsigned long value);
kaf24@5696 99 unsigned long do_get_debugreg(int reg);
kaf24@5696 100
kaf24@4923 101 static int debug_stack_lines = 20;
kaf24@4923 102 integer_param("debug_stack_lines", debug_stack_lines);
kaf24@6573 103
kaf24@6573 104 #ifdef CONFIG_X86_32
kaf24@6573 105 #define stack_words_per_line 8
kaf24@6573 106 #define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)&regs->esp)
kaf24@6573 107 #else
kaf24@6573 108 #define stack_words_per_line 4
kaf24@6756 109 #define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)regs->rsp)
kaf24@6573 110 #endif
kaf24@1452 111
kaf24@5824 112 int is_kernel_text(unsigned long addr)
kaf24@1452 113 {
kaf24@5146 114 extern char _stext, _etext;
kaf24@1452 115 if (addr >= (unsigned long) &_stext &&
kaf24@1452 116 addr <= (unsigned long) &_etext)
kaf24@1452 117 return 1;
kaf24@1452 118 return 0;
kaf24@1452 119
kaf24@1452 120 }
kaf24@1452 121
kaf24@5824 122 unsigned long kernel_text_end(void)
kaf24@5824 123 {
kaf24@5824 124 extern char _etext;
kaf24@5824 125 return (unsigned long) &_etext;
kaf24@5824 126 }
kaf24@5824 127
kaf24@6573 128 static void show_guest_stack(struct cpu_user_regs *regs)
iap10@2441 129 {
iap10@2441 130 int i;
kaf24@4923 131 unsigned long *stack = (unsigned long *)regs->esp, addr;
iap10@2441 132
kaf24@4923 133 printk("Guest stack trace from "__OP"sp=%p:\n ", stack);
kaf24@4923 134
kaf24@6477 135 for ( i = 0; i < (debug_stack_lines*stack_words_per_line); i++ )
iap10@2441 136 {
kaf24@6573 137 if ( ((long)stack & (STACK_SIZE-BYTES_PER_LONG)) == 0 )
iap10@2441 138 break;
kaf24@4923 139 if ( get_user(addr, stack) )
kaf24@4923 140 {
kaf24@4923 141 if ( i != 0 )
kaf24@4923 142 printk("\n ");
kaf24@4923 143 printk("Fault while accessing guest memory.");
kaf24@4923 144 i = 1;
kaf24@4923 145 break;
kaf24@4923 146 }
kaf24@6477 147 if ( (i != 0) && ((i % stack_words_per_line) == 0) )
kaf24@4923 148 printk("\n ");
kaf24@4923 149 printk("%p ", _p(addr));
kaf24@4923 150 stack++;
iap10@2441 151 }
kaf24@4923 152 if ( i == 0 )
kaf24@4923 153 printk("Stack empty.");
iap10@2441 154 printk("\n");
iap10@2441 155 }
iap10@2441 156
kaf24@6573 157 #ifdef NDEBUG
kaf24@6573 158
kaf24@6573 159 static void show_trace(struct cpu_user_regs *regs)
iap10@2471 160 {
kaf24@6573 161 unsigned long *stack = ESP_BEFORE_EXCEPTION(regs), addr;
kaf24@6573 162
kaf24@6573 163 printk("Xen call trace:\n ");
kaf24@4923 164
kaf24@6573 165 printk("[<%p>]", _p(regs->eip));
kaf24@6573 166 print_symbol(" %s\n ", regs->eip);
iap10@2471 167
kaf24@6573 168 while ( ((long)stack & (STACK_SIZE-BYTES_PER_LONG)) != 0 )
kaf24@4923 169 {
iap10@2471 170 addr = *stack++;
kaf24@5824 171 if ( is_kernel_text(addr) )
kaf24@4923 172 {
kaf24@5824 173 printk("[<%p>]", _p(addr));
kaf24@6232 174 print_symbol(" %s\n ", addr);
iap10@2471 175 }
iap10@2471 176 }
kaf24@6573 177
iap10@2471 178 printk("\n");
iap10@2471 179 }
iap10@2471 180
kaf24@6573 181 #else
kaf24@6573 182
kaf24@6573 183 static void show_trace(struct cpu_user_regs *regs)
kaf24@1452 184 {
kaf24@6573 185 unsigned long *frame, next, addr, low, high;
kaf24@6573 186
kaf24@6573 187 printk("Xen call trace:\n ");
kaf24@6573 188
kaf24@6573 189 printk("[<%p>]", _p(regs->eip));
kaf24@6573 190 print_symbol(" %s\n ", regs->eip);
kaf24@6573 191
kaf24@6573 192 /* Bounds for range of valid frame pointer. */
kaf24@6573 193 low = (unsigned long)(ESP_BEFORE_EXCEPTION(regs) - 2);
kaf24@6573 194 high = (low & ~(STACK_SIZE - 1)) + (STACK_SIZE - sizeof(struct cpu_info));
kaf24@6573 195
kaf24@6573 196 /* The initial frame pointer. */
kaf24@6573 197 next = regs->ebp;
kaf24@6573 198
kaf24@6573 199 for ( ; ; )
kaf24@6573 200 {
kaf24@6573 201 /* Valid frame pointer? */
kaf24@6573 202 if ( (next < low) || (next > high) )
kaf24@6573 203 {
kaf24@6573 204 /*
kaf24@6573 205 * Exception stack frames have a different layout, denoted by an
kaf24@6573 206 * inverted frame pointer.
kaf24@6573 207 */
kaf24@6573 208 next = ~next;
kaf24@6573 209 if ( (next < low) || (next > high) )
kaf24@6573 210 break;
kaf24@6573 211 frame = (unsigned long *)next;
kaf24@6573 212 next = frame[0];
kaf24@6573 213 addr = frame[(offsetof(struct cpu_user_regs, eip) -
kaf24@6573 214 offsetof(struct cpu_user_regs, ebp))
kaf24@6573 215 / BYTES_PER_LONG];
kaf24@6573 216 }
kaf24@6573 217 else
kaf24@6573 218 {
kaf24@6573 219 /* Ordinary stack frame. */
kaf24@6573 220 frame = (unsigned long *)next;
kaf24@6573 221 next = frame[0];
kaf24@6573 222 addr = frame[1];
kaf24@6573 223 }
kaf24@6573 224
kaf24@6573 225 printk("[<%p>]", _p(addr));
kaf24@6573 226 print_symbol(" %s\n ", addr);
kaf24@6573 227
kaf24@6573 228 low = (unsigned long)&frame[2];
kaf24@6573 229 }
kaf24@6573 230
kaf24@6573 231 printk("\n");
kaf24@6573 232 }
kaf24@6573 233
kaf24@6573 234 #endif
kaf24@6573 235
kaf24@6573 236 void show_stack(struct cpu_user_regs *regs)
kaf24@6573 237 {
kaf24@6573 238 unsigned long *stack = ESP_BEFORE_EXCEPTION(regs), addr;
kaf24@1452 239 int i;
kaf24@1452 240
kaf24@6756 241 if ( GUEST_CONTEXT(current, regs) )
kaf24@6573 242 return show_guest_stack(regs);
kaf24@6573 243
kaf24@4923 244 printk("Xen stack trace from "__OP"sp=%p:\n ", stack);
kaf24@1452 245
kaf24@6477 246 for ( i = 0; i < (debug_stack_lines*stack_words_per_line); i++ )
kaf24@1452 247 {
kaf24@6573 248 if ( ((long)stack & (STACK_SIZE-BYTES_PER_LONG)) == 0 )
kaf24@1452 249 break;
kaf24@6477 250 if ( (i != 0) && ((i % stack_words_per_line) == 0) )
kaf24@4923 251 printk("\n ");
kaf24@4923 252 addr = *stack++;
kaf24@5824 253 printk("%p ", _p(addr));
kaf24@1452 254 }
kaf24@4923 255 if ( i == 0 )
kaf24@4923 256 printk("Stack empty.");
kaf24@1452 257 printk("\n");
kaf24@1452 258
kaf24@6573 259 show_trace(regs);
kaf24@1452 260 }
kaf24@1452 261
kaf24@3041 262 /*
kaf24@3041 263 * This is called for faults at very unexpected times (e.g., when interrupts
kaf24@3041 264 * are disabled). In such situations we can't do much that is safe. We try to
kaf24@3041 265 * print out some tracing and then we just spin.
kaf24@3041 266 */
kaf24@4683 267 asmlinkage void fatal_trap(int trapnr, struct cpu_user_regs *regs)
kaf24@1452 268 {
kaf24@3041 269 int cpu = smp_processor_id();
kaf24@3089 270 unsigned long cr2;
kaf24@3041 271 static char *trapstr[] = {
kaf24@3041 272 "divide error", "debug", "nmi", "bkpt", "overflow", "bounds",
kaf24@3041 273 "invalid operation", "device not available", "double fault",
kaf24@3041 274 "coprocessor segment", "invalid tss", "segment not found",
kaf24@3041 275 "stack error", "general protection fault", "page fault",
kaf24@3041 276 "spurious interrupt", "coprocessor error", "alignment check",
kaf24@3041 277 "machine check", "simd error"
kaf24@3041 278 };
kaf24@3041 279
kaf24@4926 280 watchdog_disable();
kaf24@5321 281 console_start_sync();
kaf24@3849 282
kaf24@1452 283 show_registers(regs);
kaf24@3089 284
kaf24@3089 285 if ( trapnr == TRAP_page_fault )
kaf24@3089 286 {
kaf24@3602 287 __asm__ __volatile__ ("mov %%cr2,%0" : "=r" (cr2) : );
kaf24@4817 288 printk("Faulting linear address: %p\n", _p(cr2));
kaf24@4817 289 show_page_walk(cr2);
kaf24@3089 290 }
kaf24@3089 291
kaf24@3041 292 printk("************************************\n");
kaf24@3089 293 printk("CPU%d FATAL TRAP %d (%s), ERROR_CODE %04x%s.\n",
kaf24@3089 294 cpu, trapnr, trapstr[trapnr], regs->error_code,
kaf24@3041 295 (regs->eflags & X86_EFLAGS_IF) ? "" : ", IN INTERRUPT CONTEXT");
kaf24@3041 296 printk("System shutting down -- need manual reset.\n");
kaf24@3041 297 printk("************************************\n");
kaf24@3041 298
sos22@3792 299 (void)debugger_trap_fatal(trapnr, regs);
sos22@3771 300
kaf24@3041 301 /* Lock up the console to prevent spurious output from other CPUs. */
kaf24@3041 302 console_force_lock();
kaf24@3041 303
kaf24@3041 304 /* Wait for manual reset. */
kaf24@3041 305 for ( ; ; )
kaf24@3041 306 __asm__ __volatile__ ( "hlt" );
kaf24@1452 307 }
kaf24@1452 308
kaf24@3052 309 static inline int do_trap(int trapnr, char *str,
kaf24@4683 310 struct cpu_user_regs *regs,
kaf24@3089 311 int use_error_code)
kaf24@1452 312 {
kaf24@5289 313 struct vcpu *v = current;
kaf24@5289 314 struct trap_bounce *tb = &v->arch.trap_bounce;
kaf24@1452 315 trap_info_t *ti;
kaf24@1452 316 unsigned long fixup;
kaf24@1452 317
kaf24@3089 318 DEBUGGER_trap_entry(trapnr, regs);
kaf24@2971 319
kaf24@3754 320 if ( !GUEST_MODE(regs) )
kaf24@1590 321 goto xen_fault;
kaf24@1452 322
kaf24@4689 323 ti = &current->arch.guest_context.trap_ctxt[trapnr];
kaf24@3089 324 tb->flags = TBF_EXCEPTION;
kaf24@3089 325 tb->cs = ti->cs;
kaf24@3089 326 tb->eip = ti->address;
kaf24@3089 327 if ( use_error_code )
kaf24@3089 328 {
kaf24@3089 329 tb->flags |= TBF_EXCEPTION_ERRCODE;
kaf24@3089 330 tb->error_code = regs->error_code;
kaf24@3089 331 }
kaf24@1452 332 if ( TI_GET_IF(ti) )
kaf24@4949 333 tb->flags |= TBF_INTERRUPT;
kaf24@3052 334 return 0;
kaf24@1452 335
kaf24@1590 336 xen_fault:
kaf24@1452 337
kaf24@1452 338 if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
kaf24@1452 339 {
kaf24@4654 340 DPRINTK("Trap %d: %p -> %p\n", trapnr, _p(regs->eip), _p(fixup));
kaf24@1452 341 regs->eip = fixup;
kaf24@3052 342 return 0;
kaf24@1452 343 }
kaf24@1452 344
kaf24@3089 345 DEBUGGER_trap_fatal(trapnr, regs);
cl349@2957 346
kaf24@1452 347 show_registers(regs);
kaf24@1452 348 panic("CPU%d FATAL TRAP: vector = %d (%s)\n"
kaf24@3089 349 "[error_code=%04x]\n",
kaf24@3089 350 smp_processor_id(), trapnr, str, regs->error_code);
kaf24@3052 351 return 0;
kaf24@1452 352 }
kaf24@1452 353
kaf24@1452 354 #define DO_ERROR_NOCODE(trapnr, str, name) \
kaf24@4683 355 asmlinkage int do_##name(struct cpu_user_regs *regs) \
kaf24@1452 356 { \
kaf24@3089 357 return do_trap(trapnr, str, regs, 0); \
kaf24@1452 358 }
kaf24@1452 359
kaf24@1452 360 #define DO_ERROR(trapnr, str, name) \
kaf24@4683 361 asmlinkage int do_##name(struct cpu_user_regs *regs) \
kaf24@1452 362 { \
kaf24@3089 363 return do_trap(trapnr, str, regs, 1); \
kaf24@1452 364 }
kaf24@1452 365
kaf24@1452 366 DO_ERROR_NOCODE( 0, "divide error", divide_error)
kaf24@2076 367 DO_ERROR_NOCODE( 4, "overflow", overflow)
kaf24@2076 368 DO_ERROR_NOCODE( 5, "bounds", bounds)
kaf24@2076 369 DO_ERROR_NOCODE( 6, "invalid operand", invalid_op)
kaf24@2076 370 DO_ERROR_NOCODE( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
kaf24@2076 371 DO_ERROR(10, "invalid TSS", invalid_TSS)
kaf24@2076 372 DO_ERROR(11, "segment not present", segment_not_present)
kaf24@2076 373 DO_ERROR(12, "stack segment", stack_segment)
kaf24@2076 374 DO_ERROR_NOCODE(16, "fpu error", coprocessor_error)
kaf24@2076 375 DO_ERROR(17, "alignment check", alignment_check)
kaf24@2076 376 DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error)
kaf24@1452 377
kaf24@4683 378 asmlinkage int do_int3(struct cpu_user_regs *regs)
kaf24@1452 379 {
kaf24@5289 380 struct vcpu *v = current;
kaf24@5289 381 struct trap_bounce *tb = &v->arch.trap_bounce;
kaf24@1452 382 trap_info_t *ti;
kaf24@1452 383
kaf24@3089 384 DEBUGGER_trap_entry(TRAP_int3, regs);
kaf24@1452 385
kaf24@3754 386 if ( !GUEST_MODE(regs) )
kaf24@1452 387 {
kaf24@3089 388 DEBUGGER_trap_fatal(TRAP_int3, regs);
kaf24@2971 389 show_registers(regs);
kaf24@3089 390 panic("CPU%d FATAL TRAP: vector = 3 (Int3)\n", smp_processor_id());
kmacy@4118 391 }
kaf24@1452 392
kaf24@4689 393 ti = &current->arch.guest_context.trap_ctxt[TRAP_int3];
kaf24@3089 394 tb->flags = TBF_EXCEPTION;
kaf24@3089 395 tb->cs = ti->cs;
kaf24@3089 396 tb->eip = ti->address;
kaf24@1452 397 if ( TI_GET_IF(ti) )
kaf24@4949 398 tb->flags |= TBF_INTERRUPT;
kaf24@3052 399
kaf24@3052 400 return 0;
kaf24@1452 401 }
kaf24@1452 402
kaf24@4972 403 asmlinkage int do_machine_check(struct cpu_user_regs *regs)
kaf24@3041 404 {
kaf24@3089 405 fatal_trap(TRAP_machine_check, regs);
kaf24@4972 406 return 0;
kaf24@1452 407 }
kaf24@1452 408
kaf24@3424 409 void propagate_page_fault(unsigned long addr, u16 error_code)
kaf24@3424 410 {
kaf24@3424 411 trap_info_t *ti;
kaf24@5289 412 struct vcpu *v = current;
kaf24@5289 413 struct trap_bounce *tb = &v->arch.trap_bounce;
kaf24@3424 414
kaf24@5289 415 ti = &v->arch.guest_context.trap_ctxt[TRAP_page_fault];
kaf24@3424 416 tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE | TBF_EXCEPTION_CR2;
kaf24@3424 417 tb->cr2 = addr;
kaf24@3424 418 tb->error_code = error_code;
kaf24@3424 419 tb->cs = ti->cs;
kaf24@3424 420 tb->eip = ti->address;
kaf24@3424 421 if ( TI_GET_IF(ti) )
kaf24@4949 422 tb->flags |= TBF_INTERRUPT;
kaf24@3405 423
kaf24@5576 424 v->arch.guest_context.ctrlreg[2] = addr;
kaf24@3424 425 }
kaf24@3424 426
kaf24@4972 427 static int handle_perdomain_mapping_fault(
kaf24@4972 428 unsigned long offset, struct cpu_user_regs *regs)
kaf24@1452 429 {
kaf24@1452 430 extern int map_ldt_shadow_page(unsigned int);
kaf24@4972 431
kaf24@5289 432 struct vcpu *v = current;
kaf24@5289 433 struct domain *d = v->domain;
kaf24@4972 434 int ret;
kaf24@4972 435
kaf24@4972 436 /* Which vcpu's area did we fault in, and is it in the ldt sub-area? */
kaf24@4972 437 unsigned int is_ldt_area = (offset >> (PDPT_VCPU_VA_SHIFT-1)) & 1;
kaf24@4972 438 unsigned int vcpu_area = (offset >> PDPT_VCPU_VA_SHIFT);
kaf24@4972 439
kaf24@4972 440 /* Should never fault in another vcpu's area. */
kaf24@4972 441 BUG_ON(vcpu_area != current->vcpu_id);
kaf24@4972 442
kaf24@4972 443 /* Byte offset within the gdt/ldt sub-area. */
kaf24@4972 444 offset &= (1UL << (PDPT_VCPU_VA_SHIFT-1)) - 1UL;
kaf24@4972 445
kaf24@4972 446 if ( likely(is_ldt_area) )
kaf24@4972 447 {
kaf24@4972 448 /* LDT fault: Copy a mapping from the guest's LDT, if it is valid. */
kaf24@4972 449 LOCK_BIGLOCK(d);
kaf24@4972 450 ret = map_ldt_shadow_page(offset >> PAGE_SHIFT);
kaf24@4972 451 UNLOCK_BIGLOCK(d);
kaf24@1452 452
kaf24@4972 453 if ( unlikely(ret == 0) )
kaf24@4972 454 {
kaf24@4972 455 /* In hypervisor mode? Leave it to the #PF handler to fix up. */
kaf24@4972 456 if ( !GUEST_MODE(regs) )
kaf24@4972 457 return 0;
kaf24@4972 458 /* In guest mode? Propagate #PF to guest, with adjusted %cr2. */
kaf24@4972 459 propagate_page_fault(
kaf24@5289 460 v->arch.guest_context.ldt_base + offset, regs->error_code);
kaf24@4972 461 }
kaf24@4972 462 }
kaf24@4972 463 else
kaf24@4972 464 {
kaf24@4972 465 /* GDT fault: handle the fault as #GP(selector). */
kaf24@4972 466 regs->error_code = (u16)offset & ~7;
kaf24@4972 467 (void)do_general_protection(regs);
kaf24@4972 468 }
kaf24@4972 469
kaf24@4972 470 return EXCRET_fault_fixed;
kaf24@4972 471 }
kaf24@4972 472
kaf24@6702 473 #ifdef HYPERVISOR_VIRT_END
kaf24@6702 474 #define IN_HYPERVISOR_RANGE(va) \
kaf24@6702 475 (((va) >= HYPERVISOR_VIRT_START) && ((va) < HYPERVISOR_VIRT_END))
kaf24@6702 476 #else
kaf24@6702 477 #define IN_HYPERVISOR_RANGE(va) \
kaf24@6702 478 (((va) >= HYPERVISOR_VIRT_START))
kaf24@6702 479 #endif
kaf24@6702 480
kaf24@6702 481 static int fixup_page_fault(unsigned long addr, struct cpu_user_regs *regs)
kaf24@1452 482 {
kaf24@6702 483 struct vcpu *v = current;
kaf24@5289 484 struct domain *d = v->domain;
kaf24@1452 485
kaf24@6702 486 if ( unlikely(IN_HYPERVISOR_RANGE(addr)) )
kaf24@6702 487 {
kaf24@6702 488 if ( shadow_mode_external(d) && GUEST_CONTEXT(v, regs) )
kaf24@6702 489 return shadow_fault(addr, regs);
kaf24@6702 490 if ( (addr >= PERDOMAIN_VIRT_START) && (addr < PERDOMAIN_VIRT_END) )
kaf24@6702 491 return handle_perdomain_mapping_fault(
kaf24@6702 492 addr - PERDOMAIN_VIRT_START, regs);
kaf24@6702 493 }
kaf24@6702 494 else if ( unlikely(shadow_mode_enabled(d)) )
kaf24@6702 495 {
kaf24@6702 496 return shadow_fault(addr, regs);
kaf24@6702 497 }
kaf24@6702 498 else if ( likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) )
kaf24@2073 499 {
cl349@3148 500 LOCK_BIGLOCK(d);
kaf24@4455 501 if ( unlikely(d->arch.ptwr[PTWR_PT_ACTIVE].l1va) &&
kaf24@6039 502 unlikely(l2_linear_offset(addr) ==
kaf24@4455 503 d->arch.ptwr[PTWR_PT_ACTIVE].l2_idx) )
kaf24@2337 504 {
kaf24@4455 505 ptwr_flush(d, PTWR_PT_ACTIVE);
cl349@2998 506 UNLOCK_BIGLOCK(d);
kaf24@3052 507 return EXCRET_fault_fixed;
kaf24@2337 508 }
cl349@1822 509
kaf24@6702 510 if ( KERNEL_MODE(v, regs) &&
kaf24@6702 511 /* Protection violation on write? No reserved-bit violation? */
kaf24@6702 512 ((regs->error_code & 0xb) == 0x3) &&
iap10@6135 513 ptwr_do_page_fault(d, addr, regs) )
kaf24@3052 514 {
cl349@3148 515 UNLOCK_BIGLOCK(d);
kaf24@3052 516 return EXCRET_fault_fixed;
kaf24@3052 517 }
cl349@3148 518 UNLOCK_BIGLOCK(d);
kaf24@2337 519 }
cl349@1822 520
kaf24@6702 521 return 0;
kaf24@6702 522 }
kaf24@6702 523
kaf24@6702 524 /*
kaf24@6702 525 * #PF error code:
kaf24@6702 526 * Bit 0: Protection violation (=1) ; Page not present (=0)
kaf24@6702 527 * Bit 1: Write access
kaf24@6702 528 * Bit 2: Supervisor mode
kaf24@6702 529 * Bit 3: Reserved bit violation
kaf24@6702 530 * Bit 4: Instruction fetch
kaf24@6702 531 */
kaf24@6702 532 asmlinkage int do_page_fault(struct cpu_user_regs *regs)
kaf24@6702 533 {
kaf24@6702 534 unsigned long addr, fixup;
kaf24@6702 535 int rc;
kaf24@6702 536
kaf24@6702 537 __asm__ __volatile__ ("mov %%cr2,%0" : "=r" (addr) : );
kaf24@6702 538
kaf24@6702 539 DEBUGGER_trap_entry(TRAP_page_fault, regs);
kaf24@6702 540
kaf24@6702 541 perfc_incrc(page_faults);
kaf24@1452 542
kaf24@6702 543 if ( unlikely((rc = fixup_page_fault(addr, regs)) != 0) )
kaf24@6702 544 return rc;
iap10@2573 545
kaf24@6702 546 if ( unlikely(!GUEST_MODE(regs)) )
kaf24@6702 547 {
kaf24@6702 548 if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
kaf24@6702 549 {
kaf24@6702 550 perfc_incrc(copy_user_faults);
kaf24@6702 551 regs->eip = fixup;
kaf24@6702 552 return 0;
kaf24@6702 553 }
kaf24@6702 554
kaf24@6702 555 DEBUGGER_trap_fatal(TRAP_page_fault, regs);
kaf24@6702 556
kaf24@6702 557 show_registers(regs);
kaf24@6702 558 show_page_walk(addr);
kaf24@6702 559 panic("CPU%d FATAL PAGE FAULT\n"
kaf24@6702 560 "[error_code=%04x]\n"
kaf24@6702 561 "Faulting linear address: %p\n",
kaf24@6702 562 smp_processor_id(), regs->error_code, addr);
kaf24@6702 563 }
kaf24@1452 564
kaf24@3424 565 propagate_page_fault(addr, regs->error_code);
kaf24@6039 566 return 0;
kaf24@1452 567 }
kaf24@1452 568
kaf24@3917 569 long do_fpu_taskswitch(int set)
kaf24@3917 570 {
kaf24@5289 571 struct vcpu *v = current;
kaf24@3917 572
kaf24@3917 573 if ( set )
kaf24@3917 574 {
kaf24@5576 575 v->arch.guest_context.ctrlreg[0] |= X86_CR0_TS;
kaf24@3917 576 stts();
kaf24@3917 577 }
kaf24@3917 578 else
kaf24@3917 579 {
kaf24@5576 580 v->arch.guest_context.ctrlreg[0] &= ~X86_CR0_TS;
kaf24@5289 581 if ( test_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags) )
kaf24@3917 582 clts();
kaf24@3917 583 }
kaf24@3917 584
kaf24@3917 585 return 0;
kaf24@3917 586 }
kaf24@3917 587
kaf24@4275 588 /* Has the guest requested sufficient permission for this I/O access? */
kaf24@4275 589 static inline int guest_io_okay(
kaf24@4275 590 unsigned int port, unsigned int bytes,
kaf24@5289 591 struct vcpu *v, struct cpu_user_regs *regs)
kaf24@4275 592 {
kaf24@4275 593 u16 x;
kaf24@4276 594 #if defined(__x86_64__)
kaf24@4276 595 /* If in user mode, switch to kernel mode just to read I/O bitmap. */
kaf24@5289 596 extern void toggle_guest_mode(struct vcpu *);
kaf24@5289 597 int user_mode = !(v->arch.flags & TF_kernel_mode);
kaf24@5289 598 #define TOGGLE_MODE() if ( user_mode ) toggle_guest_mode(v)
kaf24@4276 599 #elif defined(__i386__)
kaf24@4276 600 #define TOGGLE_MODE() ((void)0)
kaf24@4276 601 #endif
kaf24@4276 602
kaf24@5289 603 if ( v->arch.iopl >= (KERNEL_MODE(v, regs) ? 1 : 3) )
kaf24@4275 604 return 1;
kaf24@4276 605
kaf24@5289 606 if ( v->arch.iobmp_limit > (port + bytes) )
kaf24@4276 607 {
kaf24@4276 608 TOGGLE_MODE();
kaf24@5289 609 __get_user(x, (u16 *)(v->arch.iobmp+(port>>3)));
kaf24@4276 610 TOGGLE_MODE();
kaf24@4276 611 if ( (x & (((1<<bytes)-1) << (port&7))) == 0 )
kaf24@4276 612 return 1;
kaf24@4276 613 }
kaf24@4276 614
kaf24@4275 615 return 0;
kaf24@4275 616 }
kaf24@4275 617
kaf24@4275 618 /* Has the administrator granted sufficient permission for this I/O access? */
kaf24@4275 619 static inline int admin_io_okay(
kaf24@4103 620 unsigned int port, unsigned int bytes,
kaf24@5289 621 struct vcpu *v, struct cpu_user_regs *regs)
kaf24@4103 622 {
kaf24@5289 623 struct domain *d = v->domain;
kaf24@4275 624 u16 x;
kaf24@4276 625
kaf24@4275 626 if ( d->arch.iobmp_mask != NULL )
kaf24@4275 627 {
kaf24@4275 628 x = *(u16 *)(d->arch.iobmp_mask + (port >> 3));
kaf24@4275 629 if ( (x & (((1<<bytes)-1) << (port&7))) == 0 )
kaf24@4275 630 return 1;
kaf24@4275 631 }
kaf24@4276 632
kaf24@4275 633 return 0;
kaf24@4103 634 }
kaf24@4103 635
kaf24@4275 636 /* Check admin limits. Silently fail the access if it is disallowed. */
kaf24@4275 637 #define inb_user(_p, _d, _r) (admin_io_okay(_p, 1, _d, _r) ? inb(_p) : ~0)
kaf24@4275 638 #define inw_user(_p, _d, _r) (admin_io_okay(_p, 2, _d, _r) ? inw(_p) : ~0)
kaf24@4275 639 #define inl_user(_p, _d, _r) (admin_io_okay(_p, 4, _d, _r) ? inl(_p) : ~0)
kaf24@4275 640 #define outb_user(_v, _p, _d, _r) \
kaf24@4275 641 (admin_io_okay(_p, 1, _d, _r) ? outb(_v, _p) : ((void)0))
kaf24@4275 642 #define outw_user(_v, _p, _d, _r) \
kaf24@4275 643 (admin_io_okay(_p, 2, _d, _r) ? outw(_v, _p) : ((void)0))
kaf24@4275 644 #define outl_user(_v, _p, _d, _r) \
kaf24@4275 645 (admin_io_okay(_p, 4, _d, _r) ? outl(_v, _p) : ((void)0))
kaf24@4275 646
kaf24@4862 647 /* Propagate a fault back to the guest kernel. */
kaf24@4862 648 #define USER_READ_FAULT 4 /* user mode, read fault */
kaf24@4862 649 #define USER_WRITE_FAULT 6 /* user mode, write fault */
kaf24@4862 650 #define PAGE_FAULT(_faultaddr, _errcode) \
kaf24@4862 651 ({ propagate_page_fault(_faultaddr, _errcode); \
kaf24@4862 652 return EXCRET_fault_fixed; \
kaf24@4862 653 })
kaf24@4862 654
kaf24@4862 655 /* Isntruction fetch with error handling. */
kaf24@4103 656 #define insn_fetch(_type, _size, _ptr) \
kaf24@4103 657 ({ unsigned long _x; \
kaf24@4103 658 if ( get_user(_x, (_type *)eip) ) \
kaf24@4862 659 PAGE_FAULT(eip, USER_READ_FAULT); \
kaf24@4103 660 eip += _size; (_type)_x; })
kaf24@4103 661
kaf24@4683 662 static int emulate_privileged_op(struct cpu_user_regs *regs)
kaf24@1452 663 {
kaf24@5289 664 struct vcpu *v = current;
kaf24@5696 665 unsigned long *reg, eip = regs->eip, res;
kaf24@5696 666 u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0;
kaf24@4103 667 unsigned int port, i, op_bytes = 4, data;
kaf24@4103 668
kaf24@4103 669 /* Legacy prefixes. */
kaf24@4103 670 for ( i = 0; i < 8; i++ )
kaf24@4103 671 {
kaf24@4103 672 switch ( opcode = insn_fetch(u8, 1, eip) )
kaf24@4103 673 {
kaf24@4103 674 case 0x66: /* operand-size override */
kaf24@4103 675 op_bytes ^= 6; /* switch between 2/4 bytes */
kaf24@4103 676 break;
kaf24@4103 677 case 0x67: /* address-size override */
kaf24@4103 678 case 0x2e: /* CS override */
kaf24@4103 679 case 0x3e: /* DS override */
kaf24@4103 680 case 0x26: /* ES override */
kaf24@4103 681 case 0x64: /* FS override */
kaf24@4103 682 case 0x65: /* GS override */
kaf24@4103 683 case 0x36: /* SS override */
kaf24@4103 684 case 0xf0: /* LOCK */
kaf24@4103 685 case 0xf2: /* REPNE/REPNZ */
kaf24@4103 686 break;
kaf24@4103 687 case 0xf3: /* REP/REPE/REPZ */
kaf24@4103 688 rep_prefix = 1;
kaf24@4103 689 break;
kaf24@4103 690 default:
kaf24@4103 691 goto done_prefixes;
kaf24@4103 692 }
kaf24@4103 693 }
kaf24@4103 694 done_prefixes:
kaf24@4103 695
kaf24@4103 696 #ifdef __x86_64__
kaf24@4103 697 /* REX prefix. */
kaf24@4103 698 if ( (opcode & 0xf0) == 0x40 )
kaf24@4103 699 {
kaf24@4103 700 modrm_reg = (opcode & 4) << 1; /* REX.R */
kaf24@5696 701 modrm_rm = (opcode & 1) << 3; /* REX.B */
kaf24@5696 702
kaf24@5696 703 /* REX.W and REX.X do not need to be decoded. */
kaf24@4103 704 opcode = insn_fetch(u8, 1, eip);
kaf24@4103 705 }
kaf24@4103 706 #endif
kaf24@4103 707
kaf24@4103 708 /* Input/Output String instructions. */
kaf24@4103 709 if ( (opcode >= 0x6c) && (opcode <= 0x6f) )
kaf24@4103 710 {
kaf24@4103 711 if ( rep_prefix && (regs->ecx == 0) )
kaf24@4103 712 goto done;
kaf24@4103 713
kaf24@4103 714 continue_io_string:
kaf24@4103 715 switch ( opcode )
kaf24@4103 716 {
kaf24@4103 717 case 0x6c: /* INSB */
kaf24@4103 718 op_bytes = 1;
kaf24@4103 719 case 0x6d: /* INSW/INSL */
kaf24@5289 720 if ( !guest_io_okay((u16)regs->edx, op_bytes, v, regs) )
kaf24@4103 721 goto fail;
kaf24@4103 722 switch ( op_bytes )
kaf24@4103 723 {
kaf24@4103 724 case 1:
kaf24@5289 725 data = (u8)inb_user((u16)regs->edx, v, regs);
kaf24@4103 726 if ( put_user((u8)data, (u8 *)regs->edi) )
kaf24@4862 727 PAGE_FAULT(regs->edi, USER_WRITE_FAULT);
kaf24@4103 728 break;
kaf24@4103 729 case 2:
kaf24@5289 730 data = (u16)inw_user((u16)regs->edx, v, regs);
kaf24@4103 731 if ( put_user((u16)data, (u16 *)regs->edi) )
kaf24@4862 732 PAGE_FAULT(regs->edi, USER_WRITE_FAULT);
kaf24@4103 733 break;
kaf24@4103 734 case 4:
kaf24@5289 735 data = (u32)inl_user((u16)regs->edx, v, regs);
kaf24@4103 736 if ( put_user((u32)data, (u32 *)regs->edi) )
kaf24@4862 737 PAGE_FAULT(regs->edi, USER_WRITE_FAULT);
kaf24@4103 738 break;
kaf24@4103 739 }
kaf24@4103 740 regs->edi += (regs->eflags & EF_DF) ? -op_bytes : op_bytes;
kaf24@4103 741 break;
kaf24@3405 742
kaf24@4103 743 case 0x6e: /* OUTSB */
kaf24@4103 744 op_bytes = 1;
kaf24@4103 745 case 0x6f: /* OUTSW/OUTSL */
kaf24@5289 746 if ( !guest_io_okay((u16)regs->edx, op_bytes, v, regs) )
kaf24@4103 747 goto fail;
kaf24@4103 748 switch ( op_bytes )
kaf24@4103 749 {
kaf24@4103 750 case 1:
kaf24@4103 751 if ( get_user(data, (u8 *)regs->esi) )
kaf24@4862 752 PAGE_FAULT(regs->esi, USER_READ_FAULT);
kaf24@5289 753 outb_user((u8)data, (u16)regs->edx, v, regs);
kaf24@4103 754 break;
kaf24@4103 755 case 2:
kaf24@4103 756 if ( get_user(data, (u16 *)regs->esi) )
kaf24@4862 757 PAGE_FAULT(regs->esi, USER_READ_FAULT);
kaf24@5289 758 outw_user((u16)data, (u16)regs->edx, v, regs);
kaf24@4103 759 break;
kaf24@4103 760 case 4:
kaf24@4103 761 if ( get_user(data, (u32 *)regs->esi) )
kaf24@4862 762 PAGE_FAULT(regs->esi, USER_READ_FAULT);
kaf24@5289 763 outl_user((u32)data, (u16)regs->edx, v, regs);
kaf24@4103 764 break;
kaf24@4103 765 }
kaf24@4103 766 regs->esi += (regs->eflags & EF_DF) ? -op_bytes : op_bytes;
kaf24@4103 767 break;
kaf24@4103 768 }
kaf24@4103 769
kaf24@4103 770 if ( rep_prefix && (--regs->ecx != 0) )
kaf24@4103 771 {
kaf24@4103 772 if ( !hypercall_preempt_check() )
kaf24@4103 773 goto continue_io_string;
kaf24@4103 774 eip = regs->eip;
kaf24@4103 775 }
kaf24@4103 776
kaf24@4103 777 goto done;
kaf24@4103 778 }
kaf24@4103 779
kaf24@4103 780 /* I/O Port and Interrupt Flag instructions. */
kaf24@4103 781 switch ( opcode )
kaf24@4103 782 {
kaf24@4103 783 case 0xe4: /* IN imm8,%al */
kaf24@4103 784 op_bytes = 1;
kaf24@4103 785 case 0xe5: /* IN imm8,%eax */
kaf24@4103 786 port = insn_fetch(u8, 1, eip);
kaf24@4103 787 exec_in:
kaf24@5289 788 if ( !guest_io_okay(port, op_bytes, v, regs) )
kaf24@4103 789 goto fail;
kaf24@4103 790 switch ( op_bytes )
kaf24@4103 791 {
kaf24@4103 792 case 1:
kaf24@4103 793 regs->eax &= ~0xffUL;
kaf24@5289 794 regs->eax |= (u8)inb_user(port, v, regs);
kaf24@4103 795 break;
kaf24@4103 796 case 2:
kaf24@4103 797 regs->eax &= ~0xffffUL;
kaf24@5289 798 regs->eax |= (u16)inw_user(port, v, regs);
kaf24@4103 799 break;
kaf24@4103 800 case 4:
kaf24@5289 801 regs->eax = (u32)inl_user(port, v, regs);
kaf24@4103 802 break;
kaf24@4103 803 }
kaf24@4103 804 goto done;
kaf24@4103 805
kaf24@4103 806 case 0xec: /* IN %dx,%al */
kaf24@4103 807 op_bytes = 1;
kaf24@4103 808 case 0xed: /* IN %dx,%eax */
kaf24@4103 809 port = (u16)regs->edx;
kaf24@4103 810 goto exec_in;
kaf24@4103 811
kaf24@4103 812 case 0xe6: /* OUT %al,imm8 */
kaf24@4103 813 op_bytes = 1;
kaf24@4103 814 case 0xe7: /* OUT %eax,imm8 */
kaf24@4103 815 port = insn_fetch(u8, 1, eip);
kaf24@4103 816 exec_out:
kaf24@5289 817 if ( !guest_io_okay(port, op_bytes, v, regs) )
kaf24@4103 818 goto fail;
kaf24@4103 819 switch ( op_bytes )
kaf24@4103 820 {
kaf24@4103 821 case 1:
kaf24@5289 822 outb_user((u8)regs->eax, port, v, regs);
kaf24@4103 823 break;
kaf24@4103 824 case 2:
kaf24@5289 825 outw_user((u16)regs->eax, port, v, regs);
kaf24@4103 826 break;
kaf24@4103 827 case 4:
kaf24@5289 828 outl_user((u32)regs->eax, port, v, regs);
kaf24@4103 829 break;
kaf24@4103 830 }
kaf24@4103 831 goto done;
kaf24@4103 832
kaf24@4103 833 case 0xee: /* OUT %al,%dx */
kaf24@4103 834 op_bytes = 1;
kaf24@4103 835 case 0xef: /* OUT %eax,%dx */
kaf24@4103 836 port = (u16)regs->edx;
kaf24@4103 837 goto exec_out;
kaf24@4103 838
kaf24@4103 839 case 0xfa: /* CLI */
kaf24@4103 840 case 0xfb: /* STI */
kaf24@5289 841 if ( v->arch.iopl < (KERNEL_MODE(v, regs) ? 1 : 3) )
kaf24@4103 842 goto fail;
kaf24@4103 843 /*
kaf24@4103 844 * This is just too dangerous to allow, in my opinion. Consider if the
kaf24@4103 845 * caller then tries to reenable interrupts using POPF: we can't trap
kaf24@4103 846 * that and we'll end up with hard-to-debug lockups. Fast & loose will
kaf24@4103 847 * do for us. :-)
kaf24@4103 848 */
kaf24@5289 849 /*v->vcpu_info->evtchn_upcall_mask = (opcode == 0xfa);*/
kaf24@4103 850 goto done;
kaf24@4103 851
kaf24@4103 852 case 0x0f: /* Two-byte opcode */
kaf24@4103 853 break;
kaf24@4103 854
kaf24@4103 855 default:
kaf24@4103 856 goto fail;
kaf24@4103 857 }
kaf24@4103 858
kaf24@4103 859 /* Remaining instructions only emulated from guest kernel. */
kaf24@5289 860 if ( !KERNEL_MODE(v, regs) )
kaf24@3405 861 goto fail;
kaf24@3311 862
kaf24@4103 863 /* Privileged (ring 0) instructions. */
kaf24@4103 864 opcode = insn_fetch(u8, 1, eip);
kaf24@3405 865 switch ( opcode )
kaf24@3311 866 {
kaf24@3405 867 case 0x06: /* CLTS */
kaf24@3917 868 (void)do_fpu_taskswitch(0);
kaf24@3405 869 break;
kaf24@3405 870
kaf24@3311 871 case 0x09: /* WBINVD */
kaf24@3861 872 /* Ignore the instruction if unprivileged. */
kaf24@5289 873 if ( !IS_CAPABLE_PHYSDEV(v->domain) )
kaf24@3311 874 DPRINTK("Non-physdev domain attempted WBINVD.\n");
kaf24@3861 875 else
kaf24@3861 876 wbinvd();
kaf24@3405 877 break;
kaf24@3405 878
kaf24@3405 879 case 0x20: /* MOV CR?,<reg> */
kaf24@4103 880 opcode = insn_fetch(u8, 1, eip);
kaf24@5696 881 modrm_reg |= (opcode >> 3) & 7;
kaf24@5696 882 modrm_rm |= (opcode >> 0) & 7;
kaf24@5696 883 reg = decode_register(modrm_rm, regs, 0);
kaf24@5696 884 switch ( modrm_reg )
kaf24@3405 885 {
kaf24@3405 886 case 0: /* Read CR0 */
kaf24@5576 887 *reg = v->arch.guest_context.ctrlreg[0];
kaf24@3405 888 break;
kaf24@3405 889
kaf24@3405 890 case 2: /* Read CR2 */
kaf24@5576 891 *reg = v->arch.guest_context.ctrlreg[2];
kaf24@3405 892 break;
kaf24@3405 893
kaf24@3405 894 case 3: /* Read CR3 */
kaf24@5289 895 *reg = pagetable_get_paddr(v->arch.guest_table);
kaf24@3405 896 break;
kaf24@3405 897
kaf24@3405 898 default:
kaf24@3405 899 goto fail;
kaf24@3405 900 }
kaf24@3405 901 break;
kaf24@3405 902
kaf24@5696 903 case 0x21: /* MOV DR?,<reg> */
kaf24@5696 904 opcode = insn_fetch(u8, 1, eip);
kaf24@5696 905 modrm_reg |= (opcode >> 3) & 7;
kaf24@5696 906 modrm_rm |= (opcode >> 0) & 7;
kaf24@5696 907 reg = decode_register(modrm_rm, regs, 0);
kaf24@5696 908 if ( (res = do_get_debugreg(modrm_reg)) > (unsigned long)-256 )
kaf24@5696 909 goto fail;
kaf24@5696 910 *reg = res;
kaf24@5696 911 break;
kaf24@5696 912
kaf24@3405 913 case 0x22: /* MOV <reg>,CR? */
kaf24@4103 914 opcode = insn_fetch(u8, 1, eip);
kaf24@5696 915 modrm_reg |= (opcode >> 3) & 7;
kaf24@5696 916 modrm_rm |= (opcode >> 0) & 7;
kaf24@5696 917 reg = decode_register(modrm_rm, regs, 0);
kaf24@5696 918 switch ( modrm_reg )
kaf24@3405 919 {
kaf24@3405 920 case 0: /* Write CR0 */
kaf24@3917 921 (void)do_fpu_taskswitch(!!(*reg & X86_CR0_TS));
kaf24@3405 922 break;
kaf24@3405 923
kaf24@3405 924 case 2: /* Write CR2 */
kaf24@5576 925 v->arch.guest_context.ctrlreg[2] = *reg;
kaf24@3405 926 break;
kaf24@3405 927
kaf24@3405 928 case 3: /* Write CR3 */
kaf24@5289 929 LOCK_BIGLOCK(v->domain);
kaf24@3405 930 (void)new_guest_cr3(*reg);
kaf24@5289 931 UNLOCK_BIGLOCK(v->domain);
kaf24@3405 932 break;
kaf24@3405 933
kaf24@5723 934 default:
kaf24@5723 935 goto fail;
kaf24@5723 936 }
kaf24@5723 937 break;
kaf24@5723 938
kaf24@5696 939 case 0x23: /* MOV <reg>,DR? */
kaf24@5696 940 opcode = insn_fetch(u8, 1, eip);
kaf24@5696 941 modrm_reg |= (opcode >> 3) & 7;
kaf24@5696 942 modrm_rm |= (opcode >> 0) & 7;
kaf24@5696 943 reg = decode_register(modrm_rm, regs, 0);
kaf24@5696 944 if ( do_set_debugreg(modrm_reg, *reg) != 0 )
kaf24@5696 945 goto fail;
kaf24@5696 946 break;
kaf24@5696 947
kaf24@3311 948 case 0x30: /* WRMSR */
kaf24@3861 949 /* Ignore the instruction if unprivileged. */
kaf24@5289 950 if ( !IS_PRIV(v->domain) )
kaf24@3861 951 DPRINTK("Non-priv domain attempted WRMSR(%p,%08lx,%08lx).\n",
kaf24@4654 952 _p(regs->ecx), (long)regs->eax, (long)regs->edx);
kaf24@3861 953 else if ( wrmsr_user(regs->ecx, regs->eax, regs->edx) )
kaf24@3405 954 goto fail;
kaf24@3405 955 break;
kaf24@3311 956
kaf24@3311 957 case 0x32: /* RDMSR */
kaf24@5289 958 if ( !IS_PRIV(v->domain) )
kaf24@3861 959 DPRINTK("Non-priv domain attempted RDMSR(%p,%08lx,%08lx).\n",
kaf24@4654 960 _p(regs->ecx), (long)regs->eax, (long)regs->edx);
kaf24@3861 961 /* Everyone can read the MSR space. */
kaf24@3861 962 if ( rdmsr_user(regs->ecx, regs->eax, regs->edx) )
kaf24@3405 963 goto fail;
kaf24@3405 964 break;
kaf24@3405 965
kaf24@3405 966 default:
kaf24@3405 967 goto fail;
kaf24@3311 968 }
kaf24@3311 969
kaf24@4103 970 done:
kaf24@3405 971 regs->eip = eip;
kaf24@3405 972 return EXCRET_fault_fixed;
kaf24@3405 973
kaf24@3405 974 fail:
kaf24@3311 975 return 0;
kaf24@3311 976 }
kaf24@3311 977
kaf24@4683 978 asmlinkage int do_general_protection(struct cpu_user_regs *regs)
kaf24@1452 979 {
kaf24@5289 980 struct vcpu *v = current;
kaf24@5289 981 struct trap_bounce *tb = &v->arch.trap_bounce;
kaf24@1452 982 trap_info_t *ti;
kaf24@1452 983 unsigned long fixup;
kaf24@1452 984
kaf24@3089 985 DEBUGGER_trap_entry(TRAP_gp_fault, regs);
kaf24@3650 986
kaf24@3169 987 if ( regs->error_code & 1 )
kaf24@3169 988 goto hardware_gp;
kaf24@3169 989
kaf24@3754 990 if ( !GUEST_MODE(regs) )
kaf24@1452 991 goto gp_in_kernel;
kaf24@1452 992
kaf24@1452 993 /*
kaf24@1452 994 * Cunning trick to allow arbitrary "INT n" handling.
kaf24@1452 995 *
kaf24@1452 996 * We set DPL == 0 on all vectors in the IDT. This prevents any INT <n>
kaf24@1452 997 * instruction from trapping to the appropriate vector, when that might not
kaf24@1452 998 * be expected by Xen or the guest OS. For example, that entry might be for
kaf24@1452 999 * a fault handler (unlike traps, faults don't increment EIP), or might
kaf24@1452 1000 * expect an error code on the stack (which a software trap never
kaf24@1452 1001 * provides), or might be a hardware interrupt handler that doesn't like
kaf24@1452 1002 * being called spuriously.
kaf24@1452 1003 *
kaf24@1452 1004 * Instead, a GPF occurs with the faulting IDT vector in the error code.
kaf24@1452 1005 * Bit 1 is set to indicate that an IDT entry caused the fault. Bit 0 is
kaf24@1452 1006 * clear to indicate that it's a software fault, not hardware.
kaf24@1452 1007 *
kaf24@1452 1008 * NOTE: Vectors 3 and 4 are dealt with from their own handler. This is
kaf24@1452 1009 * okay because they can only be triggered by an explicit DPL-checked
kaf24@1452 1010 * instruction. The DPL specified by the guest OS for these vectors is NOT
kaf24@1452 1011 * CHECKED!!
kaf24@1452 1012 */
kaf24@3089 1013 if ( (regs->error_code & 3) == 2 )
kaf24@1452 1014 {
kaf24@1452 1015 /* This fault must be due to <INT n> instruction. */
kaf24@4689 1016 ti = &current->arch.guest_context.trap_ctxt[regs->error_code>>3];
kaf24@5289 1017 if ( PERMIT_SOFTINT(TI_GET_DPL(ti), v, regs) )
kaf24@1452 1018 {
kaf24@3089 1019 tb->flags = TBF_EXCEPTION;
kaf24@1452 1020 regs->eip += 2;
kaf24@1452 1021 goto finish_propagation;
kaf24@1452 1022 }
kaf24@1452 1023 }
kaf24@1816 1024
kaf24@4103 1025 /* Emulate some simple privileged and I/O instructions. */
kaf24@3311 1026 if ( (regs->error_code == 0) &&
kaf24@3311 1027 emulate_privileged_op(regs) )
kaf24@3311 1028 return 0;
kaf24@3311 1029
kaf24@1816 1030 #if defined(__i386__)
kaf24@5289 1031 if ( VM_ASSIST(v->domain, VMASST_TYPE_4gb_segments) &&
kaf24@3089 1032 (regs->error_code == 0) &&
kaf24@2073 1033 gpf_emulate_4gb(regs) )
kaf24@3052 1034 return 0;
kaf24@1816 1035 #endif
kaf24@2971 1036
kaf24@1452 1037 /* Pass on GPF as is. */
kaf24@4689 1038 ti = &current->arch.guest_context.trap_ctxt[TRAP_gp_fault];
kaf24@3089 1039 tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
kaf24@3089 1040 tb->error_code = regs->error_code;
kaf24@1452 1041 finish_propagation:
kaf24@3043 1042 tb->cs = ti->cs;
kaf24@3043 1043 tb->eip = ti->address;
kaf24@1452 1044 if ( TI_GET_IF(ti) )
kaf24@4949 1045 tb->flags |= TBF_INTERRUPT;
kaf24@3052 1046 return 0;
kaf24@1452 1047
kaf24@1452 1048 gp_in_kernel:
kaf24@1452 1049
kaf24@1452 1050 if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
kaf24@1452 1051 {
kaf24@3621 1052 DPRINTK("GPF (%04x): %p -> %p\n",
kaf24@4654 1053 regs->error_code, _p(regs->eip), _p(fixup));
kaf24@1452 1054 regs->eip = fixup;
kaf24@3052 1055 return 0;
kaf24@1452 1056 }
kaf24@1452 1057
kaf24@3089 1058 DEBUGGER_trap_fatal(TRAP_gp_fault, regs);
cl349@2957 1059
kaf24@3169 1060 hardware_gp:
kaf24@3041 1061 show_registers(regs);
kaf24@3089 1062 panic("CPU%d GENERAL PROTECTION FAULT\n[error_code=%04x]\n",
kaf24@3089 1063 smp_processor_id(), regs->error_code);
kaf24@3052 1064 return 0;
kaf24@1452 1065 }
kaf24@1452 1066
kaf24@3695 1067 unsigned long nmi_softirq_reason;
kaf24@3695 1068 static void nmi_softirq(void)
kaf24@1452 1069 {
kaf24@3695 1070 if ( dom0 == NULL )
kaf24@3695 1071 return;
kaf24@3695 1072
kaf24@3695 1073 if ( test_and_clear_bit(0, &nmi_softirq_reason) )
kaf24@5289 1074 send_guest_virq(dom0->vcpu[0], VIRQ_PARITY_ERR);
kaf24@3695 1075
kaf24@3695 1076 if ( test_and_clear_bit(1, &nmi_softirq_reason) )
kaf24@5289 1077 send_guest_virq(dom0->vcpu[0], VIRQ_IO_ERR);
kaf24@1452 1078 }
kaf24@1452 1079
kaf24@4683 1080 asmlinkage void mem_parity_error(struct cpu_user_regs *regs)
kaf24@1452 1081 {
kaf24@3695 1082 /* Clear and disable the parity-error line. */
kaf24@3695 1083 outb((inb(0x61)&15)|4,0x61);
kaf24@3695 1084
kaf24@3695 1085 switch ( opt_nmi[0] )
kaf24@3695 1086 {
kaf24@3695 1087 case 'd': /* 'dom0' */
kaf24@3695 1088 set_bit(0, &nmi_softirq_reason);
kaf24@3695 1089 raise_softirq(NMI_SOFTIRQ);
kaf24@3695 1090 case 'i': /* 'ignore' */
kaf24@3695 1091 break;
kaf24@3695 1092 default: /* 'fatal' */
kaf24@3695 1093 console_force_unlock();
kaf24@3695 1094 printk("\n\nNMI - MEMORY ERROR\n");
kaf24@3695 1095 fatal_trap(TRAP_nmi, regs);
kaf24@3695 1096 }
kaf24@1452 1097 }
kaf24@2041 1098
kaf24@4683 1099 asmlinkage void io_check_error(struct cpu_user_regs *regs)
kaf24@1452 1100 {
kaf24@3695 1101 /* Clear and disable the I/O-error line. */
kaf24@3695 1102 outb((inb(0x61)&15)|8,0x61);
kaf24@2041 1103
kaf24@3695 1104 switch ( opt_nmi[0] )
kaf24@3695 1105 {
kaf24@3695 1106 case 'd': /* 'dom0' */
kaf24@3695 1107 set_bit(0, &nmi_softirq_reason);
kaf24@3695 1108 raise_softirq(NMI_SOFTIRQ);
kaf24@3695 1109 case 'i': /* 'ignore' */
kaf24@3695 1110 break;
kaf24@3695 1111 default: /* 'fatal' */
kaf24@3695 1112 console_force_unlock();
kaf24@3695 1113 printk("\n\nNMI - I/O ERROR\n");
kaf24@3695 1114 fatal_trap(TRAP_nmi, regs);
kaf24@3695 1115 }
kaf24@1452 1116 }
kaf24@1452 1117
kaf24@3669 1118 static void unknown_nmi_error(unsigned char reason)
kaf24@1452 1119 {
kaf24@1452 1120 printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
kaf24@1452 1121 printk("Dazed and confused, but trying to continue\n");
kaf24@1452 1122 printk("Do you have a strange power saving mode enabled?\n");
kaf24@1452 1123 }
kaf24@1452 1124
kaf24@4683 1125 asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason)
kaf24@1452 1126 {
kaf24@1452 1127 ++nmi_count(smp_processor_id());
kaf24@1452 1128
kaf24@1452 1129 if ( nmi_watchdog )
kaf24@1452 1130 nmi_watchdog_tick(regs);
kaf24@3695 1131
kaf24@3695 1132 if ( reason & 0x80 )
kaf24@3695 1133 mem_parity_error(regs);
kaf24@3695 1134 else if ( reason & 0x40 )
kaf24@3695 1135 io_check_error(regs);
kaf24@3695 1136 else if ( !nmi_watchdog )
kaf24@3669 1137 unknown_nmi_error((unsigned char)(reason&0xff));
kaf24@1452 1138 }
kaf24@1452 1139
kaf24@4683 1140 asmlinkage int math_state_restore(struct cpu_user_regs *regs)
kaf24@1452 1141 {
kaf24@1452 1142 /* Prevent recursion. */
kaf24@1452 1143 clts();
kaf24@1452 1144
cl349@4856 1145 setup_fpu(current);
kaf24@1452 1146
kaf24@5576 1147 if ( current->arch.guest_context.ctrlreg[0] & X86_CR0_TS )
kaf24@1452 1148 {
kaf24@3677 1149 struct trap_bounce *tb = &current->arch.trap_bounce;
kaf24@4689 1150 tb->flags = TBF_EXCEPTION;
kaf24@4689 1151 tb->cs = current->arch.guest_context.trap_ctxt[7].cs;
kaf24@4689 1152 tb->eip = current->arch.guest_context.trap_ctxt[7].address;
kaf24@5576 1153 current->arch.guest_context.ctrlreg[0] &= ~X86_CR0_TS;
kaf24@1452 1154 }
kaf24@3052 1155
kaf24@3052 1156 return EXCRET_fault_fixed;
kaf24@1452 1157 }
kaf24@1452 1158
kaf24@4683 1159 asmlinkage int do_debug(struct cpu_user_regs *regs)
kaf24@1452 1160 {
kaf24@3602 1161 unsigned long condition;
kaf24@5289 1162 struct vcpu *v = current;
kaf24@5289 1163 struct trap_bounce *tb = &v->arch.trap_bounce;
kaf24@1452 1164
kaf24@3602 1165 __asm__ __volatile__("mov %%db6,%0" : "=r" (condition));
kaf24@1452 1166
kaf24@1452 1167 /* Mask out spurious debug traps due to lazy DR7 setting */
kaf24@1452 1168 if ( (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) &&
kaf24@5289 1169 (v->arch.guest_context.debugreg[7] == 0) )
kaf24@1452 1170 {
kaf24@3602 1171 __asm__("mov %0,%%db7" : : "r" (0UL));
kaf24@3052 1172 goto out;
kaf24@1452 1173 }
kaf24@1452 1174
cl349@4339 1175 DEBUGGER_trap_entry(TRAP_debug, regs);
cl349@4339 1176
kaf24@3754 1177 if ( !GUEST_MODE(regs) )
kaf24@1452 1178 {
kaf24@1452 1179 /* Clear TF just for absolute sanity. */
kaf24@1452 1180 regs->eflags &= ~EF_TF;
kaf24@1452 1181 /*
kaf24@1590 1182 * We ignore watchpoints when they trigger within Xen. This may happen
kaf24@1590 1183 * when a buffer is passed to us which previously had a watchpoint set
kaf24@1590 1184 * on it. No need to bump EIP; the only faulting trap is an instruction
kaf24@1590 1185 * breakpoint, which can't happen to us.
kaf24@1452 1186 */
kaf24@3052 1187 goto out;
kmacy@4118 1188 }
kaf24@1452 1189
kaf24@1452 1190 /* Save debug status register where guest OS can peek at it */
kaf24@5289 1191 v->arch.guest_context.debugreg[6] = condition;
kaf24@1452 1192
kaf24@3089 1193 tb->flags = TBF_EXCEPTION;
kaf24@5289 1194 tb->cs = v->arch.guest_context.trap_ctxt[TRAP_debug].cs;
kaf24@5289 1195 tb->eip = v->arch.guest_context.trap_ctxt[TRAP_debug].address;
kaf24@3052 1196
kaf24@3052 1197 out:
kaf24@3052 1198 return EXCRET_not_a_fault;
kaf24@1452 1199 }
kaf24@1452 1200
kaf24@4683 1201 asmlinkage int do_spurious_interrupt_bug(struct cpu_user_regs *regs)
kaf24@3052 1202 {
kaf24@3052 1203 return EXCRET_not_a_fault;
kaf24@3052 1204 }
kaf24@1452 1205
kaf24@1452 1206 void set_intr_gate(unsigned int n, void *addr)
kaf24@3669 1207 {
kaf24@3847 1208 #ifdef __i386__
kaf24@3847 1209 int i;
kaf24@3847 1210 /* Keep secondary tables in sync with IRQ updates. */
kaf24@3847 1211 for ( i = 1; i < NR_CPUS; i++ )
kaf24@3847 1212 if ( idt_tables[i] != NULL )
kaf24@3847 1213 _set_gate(&idt_tables[i][n], 14, 0, addr);
kaf24@3847 1214 #endif
kaf24@3847 1215 _set_gate(&idt_table[n], 14, 0, addr);
kaf24@3669 1216 }
kaf24@3669 1217
kaf24@3602 1218 void set_system_gate(unsigned int n, void *addr)
kaf24@1452 1219 {
kaf24@1452 1220 _set_gate(idt_table+n,14,3,addr);
kaf24@1452 1221 }
kaf24@1452 1222
kaf24@3602 1223 void set_task_gate(unsigned int n, unsigned int sel)
kaf24@1452 1224 {
kaf24@1452 1225 idt_table[n].a = sel << 16;
kaf24@1452 1226 idt_table[n].b = 0x8500;
kaf24@1452 1227 }
kaf24@1452 1228
kaf24@1452 1229 void set_tss_desc(unsigned int n, void *addr)
kaf24@1452 1230 {
kaf24@3075 1231 _set_tssldt_desc(
kaf24@4972 1232 gdt_table + __TSS(n) - FIRST_RESERVED_GDT_ENTRY,
kaf24@3623 1233 (unsigned long)addr,
kaf24@3075 1234 offsetof(struct tss_struct, __cacheline_filler) - 1,
kaf24@3623 1235 9);
kaf24@1452 1236 }
kaf24@1452 1237
kaf24@1452 1238 void __init trap_init(void)
kaf24@1452 1239 {
kaf24@3695 1240 extern void percpu_traps_init(void);
kaf24@1452 1241
kaf24@1452 1242 /*
kaf24@1452 1243 * Note that interrupt gates are always used, rather than trap gates. We
kaf24@1452 1244 * must have interrupts disabled until DS/ES/FS/GS are saved because the
kaf24@1452 1245 * first activation must have the "bad" value(s) for these registers and
kaf24@1452 1246 * we may lose them if another activation is installed before they are
kaf24@1452 1247 * saved. The page-fault handler also needs interrupts disabled until %cr2
kaf24@1452 1248 * has been read and saved on the stack.
kaf24@1452 1249 */
kaf24@3041 1250 set_intr_gate(TRAP_divide_error,&divide_error);
kaf24@3041 1251 set_intr_gate(TRAP_debug,&debug);
kaf24@3041 1252 set_intr_gate(TRAP_nmi,&nmi);
kaf24@3041 1253 set_system_gate(TRAP_int3,&int3); /* usable from all privileges */
kaf24@3041 1254 set_system_gate(TRAP_overflow,&overflow); /* usable from all privileges */
kaf24@3041 1255 set_intr_gate(TRAP_bounds,&bounds);
kaf24@3041 1256 set_intr_gate(TRAP_invalid_op,&invalid_op);
kaf24@3041 1257 set_intr_gate(TRAP_no_device,&device_not_available);
kaf24@3041 1258 set_intr_gate(TRAP_copro_seg,&coprocessor_segment_overrun);
kaf24@3041 1259 set_intr_gate(TRAP_invalid_tss,&invalid_TSS);
kaf24@3041 1260 set_intr_gate(TRAP_no_segment,&segment_not_present);
kaf24@3041 1261 set_intr_gate(TRAP_stack_error,&stack_segment);
kaf24@3041 1262 set_intr_gate(TRAP_gp_fault,&general_protection);
kaf24@3041 1263 set_intr_gate(TRAP_page_fault,&page_fault);
kaf24@3041 1264 set_intr_gate(TRAP_spurious_int,&spurious_interrupt_bug);
kaf24@3041 1265 set_intr_gate(TRAP_copro_error,&coprocessor_error);
kaf24@3041 1266 set_intr_gate(TRAP_alignment_check,&alignment_check);
kaf24@3041 1267 set_intr_gate(TRAP_machine_check,&machine_check);
kaf24@3041 1268 set_intr_gate(TRAP_simd_error,&simd_coprocessor_error);
kaf24@1452 1269
kaf24@3695 1270 percpu_traps_init();
kaf24@3695 1271
kaf24@3695 1272 cpu_init();
kaf24@2047 1273
kaf24@2047 1274 open_softirq(NMI_SOFTIRQ, nmi_softirq);
kaf24@1452 1275 }
kaf24@1452 1276
kaf24@1452 1277
kaf24@1452 1278 long do_set_trap_table(trap_info_t *traps)
kaf24@1452 1279 {
kaf24@1452 1280 trap_info_t cur;
kaf24@4689 1281 trap_info_t *dst = current->arch.guest_context.trap_ctxt;
kaf24@4105 1282 long rc = 0;
kaf24@1452 1283
cl349@2998 1284 LOCK_BIGLOCK(current->domain);
kaf24@1452 1285
kaf24@1452 1286 for ( ; ; )
kaf24@1452 1287 {
kaf24@3139 1288 if ( hypercall_preempt_check() )
kaf24@3139 1289 {
kaf24@4105 1290 rc = hypercall1_create_continuation(
kaf24@3702 1291 __HYPERVISOR_set_trap_table, traps);
kaf24@4105 1292 break;
kaf24@3139 1293 }
kaf24@3091 1294
kaf24@4105 1295 if ( copy_from_user(&cur, traps, sizeof(cur)) )
kaf24@4105 1296 {
kaf24@4105 1297 rc = -EFAULT;
kaf24@4105 1298 break;
kaf24@4105 1299 }
kaf24@1452 1300
kaf24@4105 1301 if ( cur.address == 0 )
kaf24@4105 1302 break;
kaf24@1452 1303
kaf24@4105 1304 if ( !VALID_CODESEL(cur.cs) )
kaf24@4105 1305 {
kaf24@4105 1306 rc = -EPERM;
kaf24@4105 1307 break;
kaf24@4105 1308 }
kaf24@1452 1309
kaf24@4930 1310 memcpy(&dst[cur.vector], &cur, sizeof(cur));
kaf24@4930 1311
kaf24@4930 1312 if ( cur.vector == 0x80 )
kaf24@4930 1313 init_int80_direct_trap(current);
kaf24@4930 1314
kaf24@1452 1315 traps++;
kaf24@1452 1316 }
kaf24@1452 1317
cl349@2998 1318 UNLOCK_BIGLOCK(current->domain);
kaf24@1452 1319
kaf24@4105 1320 return rc;
kaf24@1452 1321 }
kaf24@1452 1322
kaf24@1452 1323
kaf24@5289 1324 long set_debugreg(struct vcpu *p, int reg, unsigned long value)
kaf24@1452 1325 {
kaf24@1452 1326 int i;
kaf24@1452 1327
kaf24@1452 1328 switch ( reg )
kaf24@1452 1329 {
kaf24@1452 1330 case 0:
kaf24@4573 1331 if ( !access_ok(value, sizeof(long)) )
kaf24@4572 1332 return -EPERM;
kaf24@1452 1333 if ( p == current )
kaf24@3602 1334 __asm__ ( "mov %0, %%db0" : : "r" (value) );
kaf24@1452 1335 break;
kaf24@1452 1336 case 1:
kaf24@4573 1337 if ( !access_ok(value, sizeof(long)) )
kaf24@4572 1338 return -EPERM;
kaf24@1452 1339 if ( p == current )
kaf24@3602 1340 __asm__ ( "mov %0, %%db1" : : "r" (value) );
kaf24@1452 1341 break;
kaf24@1452 1342 case 2:
kaf24@4573 1343 if ( !access_ok(value, sizeof(long)) )
kaf24@4572 1344 return -EPERM;
kaf24@1452 1345 if ( p == current )
kaf24@3602 1346 __asm__ ( "mov %0, %%db2" : : "r" (value) );
kaf24@1452 1347 break;
kaf24@1452 1348 case 3:
kaf24@4573 1349 if ( !access_ok(value, sizeof(long)) )
kaf24@4572 1350 return -EPERM;
kaf24@1452 1351 if ( p == current )
kaf24@3602 1352 __asm__ ( "mov %0, %%db3" : : "r" (value) );
kaf24@1452 1353 break;
kaf24@1452 1354 case 6:
kaf24@1452 1355 /*
kaf24@1452 1356 * DR6: Bits 4-11,16-31 reserved (set to 1).
kaf24@1452 1357 * Bit 12 reserved (set to 0).
kaf24@1452 1358 */
kaf24@1452 1359 value &= 0xffffefff; /* reserved bits => 0 */
kaf24@1452 1360 value |= 0xffff0ff0; /* reserved bits => 1 */
kaf24@1452 1361 if ( p == current )
kaf24@3602 1362 __asm__ ( "mov %0, %%db6" : : "r" (value) );
kaf24@1452 1363 break;
kaf24@1452 1364 case 7:
kaf24@1452 1365 /*
kaf24@1452 1366 * DR7: Bit 10 reserved (set to 1).
kaf24@1452 1367 * Bits 11-12,14-15 reserved (set to 0).
kaf24@1452 1368 * Privileged bits:
kaf24@1452 1369 * GD (bit 13): must be 0.
kaf24@1452 1370 * R/Wn (bits 16-17,20-21,24-25,28-29): mustn't be 10.
kaf24@1452 1371 * LENn (bits 18-19,22-23,26-27,30-31): mustn't be 10.
kaf24@1452 1372 */
kaf24@1452 1373 /* DR7 == 0 => debugging disabled for this domain. */
kaf24@1452 1374 if ( value != 0 )
kaf24@1452 1375 {
kaf24@1452 1376 value &= 0xffff27ff; /* reserved bits => 0 */
kaf24@1452 1377 value |= 0x00000400; /* reserved bits => 1 */
kaf24@1452 1378 if ( (value & (1<<13)) != 0 ) return -EPERM;
kaf24@1452 1379 for ( i = 0; i < 16; i += 2 )
kaf24@1452 1380 if ( ((value >> (i+16)) & 3) == 2 ) return -EPERM;
kaf24@1452 1381 }
kaf24@1452 1382 if ( p == current )
kaf24@3602 1383 __asm__ ( "mov %0, %%db7" : : "r" (value) );
kaf24@1452 1384 break;
kaf24@1452 1385 default:
kaf24@1452 1386 return -EINVAL;
kaf24@1452 1387 }
kaf24@1452 1388
kaf24@4689 1389 p->arch.guest_context.debugreg[reg] = value;
kaf24@1452 1390 return 0;
kaf24@1452 1391 }
kaf24@1452 1392
kaf24@1452 1393 long do_set_debugreg(int reg, unsigned long value)
kaf24@1452 1394 {
kaf24@1452 1395 return set_debugreg(current, reg, value);
kaf24@1452 1396 }
kaf24@1452 1397
kaf24@1452 1398 unsigned long do_get_debugreg(int reg)
kaf24@1452 1399 {
kaf24@1452 1400 if ( (reg < 0) || (reg > 7) ) return -EINVAL;
kaf24@4689 1401 return current->arch.guest_context.debugreg[reg];
kaf24@1452 1402 }
kaf24@1672 1403
kaf24@3914 1404 /*
kaf24@3914 1405 * Local variables:
kaf24@3914 1406 * mode: C
kaf24@3914 1407 * c-set-style: "BSD"
kaf24@3914 1408 * c-basic-offset: 4
kaf24@3914 1409 * tab-width: 4
kaf24@3914 1410 * indent-tabs-mode: nil
kaf24@3988 1411 * End:
kaf24@3914 1412 */