diff options
Diffstat (limited to 'arch/x86/xen/enlighten.c')
-rw-r--r-- | arch/x86/xen/enlighten.c | 65 |
1 files changed, 57 insertions, 8 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index f09e8c36ee80..0a1700a2be9c 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/start_kernel.h> | 21 | #include <linux/start_kernel.h> |
22 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
23 | #include <linux/kprobes.h> | ||
23 | #include <linux/bootmem.h> | 24 | #include <linux/bootmem.h> |
24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
25 | #include <linux/mm.h> | 26 | #include <linux/mm.h> |
@@ -44,6 +45,7 @@ | |||
44 | #include <asm/processor.h> | 45 | #include <asm/processor.h> |
45 | #include <asm/proto.h> | 46 | #include <asm/proto.h> |
46 | #include <asm/msr-index.h> | 47 | #include <asm/msr-index.h> |
48 | #include <asm/traps.h> | ||
47 | #include <asm/setup.h> | 49 | #include <asm/setup.h> |
48 | #include <asm/desc.h> | 50 | #include <asm/desc.h> |
49 | #include <asm/pgtable.h> | 51 | #include <asm/pgtable.h> |
@@ -240,10 +242,10 @@ static unsigned long xen_get_debugreg(int reg) | |||
240 | return HYPERVISOR_get_debugreg(reg); | 242 | return HYPERVISOR_get_debugreg(reg); |
241 | } | 243 | } |
242 | 244 | ||
243 | void xen_leave_lazy(void) | 245 | static void xen_end_context_switch(struct task_struct *next) |
244 | { | 246 | { |
245 | paravirt_leave_lazy(paravirt_get_lazy_mode()); | ||
246 | xen_mc_flush(); | 247 | xen_mc_flush(); |
248 | paravirt_end_context_switch(next); | ||
247 | } | 249 | } |
248 | 250 | ||
249 | static unsigned long xen_store_tr(void) | 251 | static unsigned long xen_store_tr(void) |
@@ -428,11 +430,44 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, | |||
428 | static int cvt_gate_to_trap(int vector, const gate_desc *val, | 430 | static int cvt_gate_to_trap(int vector, const gate_desc *val, |
429 | struct trap_info *info) | 431 | struct trap_info *info) |
430 | { | 432 | { |
433 | unsigned long addr; | ||
434 | |||
431 | if (val->type != GATE_TRAP && val->type != GATE_INTERRUPT) | 435 | if (val->type != GATE_TRAP && val->type != GATE_INTERRUPT) |
432 | return 0; | 436 | return 0; |
433 | 437 | ||
434 | info->vector = vector; | 438 | info->vector = vector; |
435 | info->address = gate_offset(*val); | 439 | |
440 | addr = gate_offset(*val); | ||
441 | #ifdef CONFIG_X86_64 | ||
442 | /* | ||
443 | * Look for known traps using IST, and substitute them | ||
444 | * appropriately. The debugger ones are the only ones we care | ||
445 | * about. Xen will handle faults like double_fault and | ||
446 | * machine_check, so we should never see them. Warn if | ||
447 | * there's an unexpected IST-using fault handler. | ||
448 | */ | ||
449 | if (addr == (unsigned long)debug) | ||
450 | addr = (unsigned long)xen_debug; | ||
451 | else if (addr == (unsigned long)int3) | ||
452 | addr = (unsigned long)xen_int3; | ||
453 | else if (addr == (unsigned long)stack_segment) | ||
454 | addr = (unsigned long)xen_stack_segment; | ||
455 | else if (addr == (unsigned long)double_fault || | ||
456 | addr == (unsigned long)nmi) { | ||
457 | /* Don't need to handle these */ | ||
458 | return 0; | ||
459 | #ifdef CONFIG_X86_MCE | ||
460 | } else if (addr == (unsigned long)machine_check) { | ||
461 | return 0; | ||
462 | #endif | ||
463 | } else { | ||
464 | /* Some other trap using IST? */ | ||
465 | if (WARN_ON(val->ist != 0)) | ||
466 | return 0; | ||
467 | } | ||
468 | #endif /* CONFIG_X86_64 */ | ||
469 | info->address = addr; | ||
470 | |||
436 | info->cs = gate_segment(*val); | 471 | info->cs = gate_segment(*val); |
437 | info->flags = val->dpl; | 472 | info->flags = val->dpl; |
438 | /* interrupt gates clear IF */ | 473 | /* interrupt gates clear IF */ |
@@ -623,10 +658,26 @@ static void xen_clts(void) | |||
623 | xen_mc_issue(PARAVIRT_LAZY_CPU); | 658 | xen_mc_issue(PARAVIRT_LAZY_CPU); |
624 | } | 659 | } |
625 | 660 | ||
661 | static DEFINE_PER_CPU(unsigned long, xen_cr0_value); | ||
662 | |||
663 | static unsigned long xen_read_cr0(void) | ||
664 | { | ||
665 | unsigned long cr0 = percpu_read(xen_cr0_value); | ||
666 | |||
667 | if (unlikely(cr0 == 0)) { | ||
668 | cr0 = native_read_cr0(); | ||
669 | percpu_write(xen_cr0_value, cr0); | ||
670 | } | ||
671 | |||
672 | return cr0; | ||
673 | } | ||
674 | |||
626 | static void xen_write_cr0(unsigned long cr0) | 675 | static void xen_write_cr0(unsigned long cr0) |
627 | { | 676 | { |
628 | struct multicall_space mcs; | 677 | struct multicall_space mcs; |
629 | 678 | ||
679 | percpu_write(xen_cr0_value, cr0); | ||
680 | |||
630 | /* Only pay attention to cr0.TS; everything else is | 681 | /* Only pay attention to cr0.TS; everything else is |
631 | ignored. */ | 682 | ignored. */ |
632 | mcs = xen_mc_entry(0); | 683 | mcs = xen_mc_entry(0); |
@@ -812,7 +863,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { | |||
812 | 863 | ||
813 | .clts = xen_clts, | 864 | .clts = xen_clts, |
814 | 865 | ||
815 | .read_cr0 = native_read_cr0, | 866 | .read_cr0 = xen_read_cr0, |
816 | .write_cr0 = xen_write_cr0, | 867 | .write_cr0 = xen_write_cr0, |
817 | 868 | ||
818 | .read_cr4 = native_read_cr4, | 869 | .read_cr4 = native_read_cr4, |
@@ -860,10 +911,8 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = { | |||
860 | /* Xen takes care of %gs when switching to usermode for us */ | 911 | /* Xen takes care of %gs when switching to usermode for us */ |
861 | .swapgs = paravirt_nop, | 912 | .swapgs = paravirt_nop, |
862 | 913 | ||
863 | .lazy_mode = { | 914 | .start_context_switch = paravirt_start_context_switch, |
864 | .enter = paravirt_enter_lazy_cpu, | 915 | .end_context_switch = xen_end_context_switch, |
865 | .leave = xen_leave_lazy, | ||
866 | }, | ||
867 | }; | 916 | }; |
868 | 917 | ||
869 | static const struct pv_apic_ops xen_apic_ops __initdata = { | 918 | static const struct pv_apic_ops xen_apic_ops __initdata = { |