aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2008-03-17 19:37:17 -0400
committerIngo Molnar <mingo@elte.hu>2008-04-24 17:57:31 -0400
commite2a81baf6604a2e08e10c7405b0349106f77c8af (patch)
tree3eaf386316be1f499d92fae213493ec3d6b5b576 /arch/x86
parentaa380c82b83252754a8c11bfc92359bd87cbf710 (diff)
xen: support sysenter/sysexit if hypervisor does
64-bit Xen supports sysenter for 32-bit guests, so support its use. (sysenter is faster than int $0x80 in 32-on-64.) sysexit is still not supported, so we fake it up using iret. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/entry_32.S18
-rw-r--r--arch/x86/xen/enlighten.c3
-rw-r--r--arch/x86/xen/setup.c21
-rw-r--r--arch/x86/xen/smp.c1
-rw-r--r--arch/x86/xen/xen-asm.S56
-rw-r--r--arch/x86/xen/xen-ops.h3
6 files changed, 99 insertions, 3 deletions
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 568c6ccd7ae..5d80d53eaff 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -1017,6 +1017,13 @@ ENTRY(kernel_thread_helper)
1017ENDPROC(kernel_thread_helper) 1017ENDPROC(kernel_thread_helper)
1018 1018
1019#ifdef CONFIG_XEN 1019#ifdef CONFIG_XEN
1020/* Xen doesn't set %esp to be precisely what the normal sysenter
1021 entrypoint expects, so fix it up before using the normal path. */
1022ENTRY(xen_sysenter_target)
1023 RING0_INT_FRAME
1024 addl $5*4, %esp /* remove xen-provided frame */
1025 jmp sysenter_past_esp
1026
1020ENTRY(xen_hypervisor_callback) 1027ENTRY(xen_hypervisor_callback)
1021 CFI_STARTPROC 1028 CFI_STARTPROC
1022 pushl $0 1029 pushl $0
@@ -1036,8 +1043,17 @@ ENTRY(xen_hypervisor_callback)
1036 jae 1f 1043 jae 1f
1037 1044
1038 call xen_iret_crit_fixup 1045 call xen_iret_crit_fixup
1046 jmp 2f
1047
10481: cmpl $xen_sysexit_start_crit,%eax
1049 jb 2f
1050 cmpl $xen_sysexit_end_crit,%eax
1051 jae 2f
1052
1053 jmp xen_sysexit_crit_fixup
1039 1054
10401: mov %esp, %eax 1055ENTRY(xen_do_upcall)
10562: mov %esp, %eax
1041 call xen_evtchn_do_upcall 1057 call xen_evtchn_do_upcall
1042 jmp ret_from_intr 1058 jmp ret_from_intr
1043 CFI_ENDPROC 1059 CFI_ENDPROC
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 36f36e6b087..943684566eb 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -155,7 +155,6 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
155 if (*ax == 1) 155 if (*ax == 1)
156 maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */ 156 maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */
157 (1 << X86_FEATURE_ACPI) | /* disable ACPI */ 157 (1 << X86_FEATURE_ACPI) | /* disable ACPI */
158 (1 << X86_FEATURE_SEP) | /* disable SEP */
159 (1 << X86_FEATURE_ACC)); /* thermal monitoring */ 158 (1 << X86_FEATURE_ACC)); /* thermal monitoring */
160 159
161 asm(XEN_EMULATE_PREFIX "cpuid" 160 asm(XEN_EMULATE_PREFIX "cpuid"
@@ -994,7 +993,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
994 .read_pmc = native_read_pmc, 993 .read_pmc = native_read_pmc,
995 994
996 .iret = xen_iret, 995 .iret = xen_iret,
997 .irq_enable_syscall_ret = NULL, /* never called */ 996 .irq_enable_syscall_ret = xen_sysexit,
998 997
999 .load_tr_desc = paravirt_nop, 998 .load_tr_desc = paravirt_nop,
1000 .set_ldt = xen_set_ldt, 999 .set_ldt = xen_set_ldt,
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index 2341492bf7a..82517e4a752 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -16,6 +16,7 @@
16#include <asm/xen/hypervisor.h> 16#include <asm/xen/hypervisor.h>
17#include <asm/xen/hypercall.h> 17#include <asm/xen/hypercall.h>
18 18
19#include <xen/interface/callback.h>
19#include <xen/interface/physdev.h> 20#include <xen/interface/physdev.h>
20#include <xen/features.h> 21#include <xen/features.h>
21 22
@@ -68,6 +69,24 @@ static void __init fiddle_vdso(void)
68 *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; 69 *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT;
69} 70}
70 71
72void xen_enable_sysenter(void)
73{
74 int cpu = smp_processor_id();
75 extern void xen_sysenter_target(void);
76 /* Mask events on entry, even though they get enabled immediately */
77 static struct callback_register sysenter = {
78 .type = CALLBACKTYPE_sysenter,
79 .address = { __KERNEL_CS, (unsigned long)xen_sysenter_target },
80 .flags = CALLBACKF_mask_events,
81 };
82
83 if (!boot_cpu_has(X86_FEATURE_SEP) ||
84 HYPERVISOR_callback_op(CALLBACKOP_register, &sysenter) != 0) {
85 clear_cpu_cap(&cpu_data(cpu), X86_FEATURE_SEP);
86 clear_cpu_cap(&boot_cpu_data, X86_FEATURE_SEP);
87 }
88}
89
71void __init xen_arch_setup(void) 90void __init xen_arch_setup(void)
72{ 91{
73 struct physdev_set_iopl set_iopl; 92 struct physdev_set_iopl set_iopl;
@@ -82,6 +101,8 @@ void __init xen_arch_setup(void)
82 HYPERVISOR_set_callbacks(__KERNEL_CS, (unsigned long)xen_hypervisor_callback, 101 HYPERVISOR_set_callbacks(__KERNEL_CS, (unsigned long)xen_hypervisor_callback,
83 __KERNEL_CS, (unsigned long)xen_failsafe_callback); 102 __KERNEL_CS, (unsigned long)xen_failsafe_callback);
84 103
104 xen_enable_sysenter();
105
85 set_iopl.iopl = 1; 106 set_iopl.iopl = 1;
86 rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); 107 rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
87 if (rc != 0) 108 if (rc != 0)
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index e340ff92f6b..d61e4f8b07c 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -72,6 +72,7 @@ static __cpuinit void cpu_bringup_and_idle(void)
72 int cpu = smp_processor_id(); 72 int cpu = smp_processor_id();
73 73
74 cpu_init(); 74 cpu_init();
75 xen_enable_sysenter();
75 76
76 preempt_disable(); 77 preempt_disable();
77 per_cpu(cpu_state, cpu) = CPU_ONLINE; 78 per_cpu(cpu_state, cpu) = CPU_ONLINE;
diff --git a/arch/x86/xen/xen-asm.S b/arch/x86/xen/xen-asm.S
index 99223cc323b..1ac08082a4b 100644
--- a/arch/x86/xen/xen-asm.S
+++ b/arch/x86/xen/xen-asm.S
@@ -280,6 +280,62 @@ ENTRY(xen_iret_crit_fixup)
2802: ret 2802: ret
281 281
282 282
283ENTRY(xen_sysexit)
284 /* Store vcpu_info pointer for easy access. Do it this
285 way to avoid having to reload %fs */
286#ifdef CONFIG_SMP
287 GET_THREAD_INFO(%eax)
288 movl TI_cpu(%eax),%eax
289 movl __per_cpu_offset(,%eax,4),%eax
290 mov per_cpu__xen_vcpu(%eax),%eax
291#else
292 movl per_cpu__xen_vcpu, %eax
293#endif
294
295 /* We can't actually use sysexit in a pv guest,
296 so fake it up with iret */
297 pushl $__USER_DS /* user stack segment */
298 pushl %ecx /* user esp */
299 pushl PT_EFLAGS+2*4(%esp) /* user eflags */
300 pushl $__USER_CS /* user code segment */
301 pushl %edx /* user eip */
302
303xen_sysexit_start_crit:
304 /* Unmask events... */
305 movb $0, XEN_vcpu_info_mask(%eax)
306 /* ...and test for pending.
307 There's a preempt window here, but it doesn't
308 matter because we're within the critical section. */
309 testb $0xff, XEN_vcpu_info_pending(%eax)
310
311 /* If there's something pending, mask events again so we
312 can directly inject it back into the kernel. */
313 jnz 1f
314
315 movl PT_EAX+5*4(%esp),%eax
3162: iret
3171: movb $1, XEN_vcpu_info_mask(%eax)
318xen_sysexit_end_crit:
319 addl $5*4, %esp /* remove iret frame */
320 /* no need to re-save regs, but need to restore kernel %fs */
321 mov $__KERNEL_PERCPU, %eax
322 mov %eax, %fs
323 jmp xen_do_upcall
324.section __ex_table,"a"
325 .align 4
326 .long 2b,iret_exc
327.previous
328
329 .globl xen_sysexit_start_crit, xen_sysexit_end_crit
330/*
331 sysexit fixup is easy, since the old frame is still sitting there
332 on the stack. We just need to remove the new recursive
333 interrupt and return.
334 */
335ENTRY(xen_sysexit_crit_fixup)
336 addl $PT_OLDESP+5*4, %esp /* remove frame+iret */
337 jmp xen_do_upcall
338
283/* 339/*
284 Force an event check by making a hypercall, 340 Force an event check by making a hypercall,
285 but preserve regs before making the call. 341 but preserve regs before making the call.
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 956a491ea99..01d4ff2ce40 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -19,6 +19,7 @@ extern struct shared_info *HYPERVISOR_shared_info;
19char * __init xen_memory_setup(void); 19char * __init xen_memory_setup(void);
20void __init xen_arch_setup(void); 20void __init xen_arch_setup(void);
21void __init xen_init_IRQ(void); 21void __init xen_init_IRQ(void);
22void xen_enable_sysenter(void);
22 23
23void xen_setup_timer(int cpu); 24void xen_setup_timer(int cpu);
24void xen_setup_cpu_clockevents(void); 25void xen_setup_cpu_clockevents(void);
@@ -64,4 +65,6 @@ DECL_ASM(unsigned long, xen_save_fl_direct, void);
64DECL_ASM(void, xen_restore_fl_direct, unsigned long); 65DECL_ASM(void, xen_restore_fl_direct, unsigned long);
65 66
66void xen_iret(void); 67void xen_iret(void);
68void xen_sysexit(void);
69
67#endif /* XEN_OPS_H */ 70#endif /* XEN_OPS_H */