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>
This commit is contained in:

committed by
Ingo Molnar

parent
aa380c82b8
commit
e2a81baf66
@@ -280,6 +280,62 @@ ENTRY(xen_iret_crit_fixup)
|
||||
2: ret
|
||||
|
||||
|
||||
ENTRY(xen_sysexit)
|
||||
/* Store vcpu_info pointer for easy access. Do it this
|
||||
way to avoid having to reload %fs */
|
||||
#ifdef CONFIG_SMP
|
||||
GET_THREAD_INFO(%eax)
|
||||
movl TI_cpu(%eax),%eax
|
||||
movl __per_cpu_offset(,%eax,4),%eax
|
||||
mov per_cpu__xen_vcpu(%eax),%eax
|
||||
#else
|
||||
movl per_cpu__xen_vcpu, %eax
|
||||
#endif
|
||||
|
||||
/* We can't actually use sysexit in a pv guest,
|
||||
so fake it up with iret */
|
||||
pushl $__USER_DS /* user stack segment */
|
||||
pushl %ecx /* user esp */
|
||||
pushl PT_EFLAGS+2*4(%esp) /* user eflags */
|
||||
pushl $__USER_CS /* user code segment */
|
||||
pushl %edx /* user eip */
|
||||
|
||||
xen_sysexit_start_crit:
|
||||
/* Unmask events... */
|
||||
movb $0, XEN_vcpu_info_mask(%eax)
|
||||
/* ...and test for pending.
|
||||
There's a preempt window here, but it doesn't
|
||||
matter because we're within the critical section. */
|
||||
testb $0xff, XEN_vcpu_info_pending(%eax)
|
||||
|
||||
/* If there's something pending, mask events again so we
|
||||
can directly inject it back into the kernel. */
|
||||
jnz 1f
|
||||
|
||||
movl PT_EAX+5*4(%esp),%eax
|
||||
2: iret
|
||||
1: movb $1, XEN_vcpu_info_mask(%eax)
|
||||
xen_sysexit_end_crit:
|
||||
addl $5*4, %esp /* remove iret frame */
|
||||
/* no need to re-save regs, but need to restore kernel %fs */
|
||||
mov $__KERNEL_PERCPU, %eax
|
||||
mov %eax, %fs
|
||||
jmp xen_do_upcall
|
||||
.section __ex_table,"a"
|
||||
.align 4
|
||||
.long 2b,iret_exc
|
||||
.previous
|
||||
|
||||
.globl xen_sysexit_start_crit, xen_sysexit_end_crit
|
||||
/*
|
||||
sysexit fixup is easy, since the old frame is still sitting there
|
||||
on the stack. We just need to remove the new recursive
|
||||
interrupt and return.
|
||||
*/
|
||||
ENTRY(xen_sysexit_crit_fixup)
|
||||
addl $PT_OLDESP+5*4, %esp /* remove frame+iret */
|
||||
jmp xen_do_upcall
|
||||
|
||||
/*
|
||||
Force an event check by making a hypercall,
|
||||
but preserve regs before making the call.
|
||||
|
Reference in New Issue
Block a user