aboutsummaryrefslogtreecommitdiff
path: root/arch/x86
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/entry_32.S9
-rw-r--r--arch/x86/xen/xen-asm.S70
2 files changed, 15 insertions, 64 deletions
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 209c334bb92..2a609dc3271 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -1044,15 +1044,8 @@ ENTRY(xen_hypervisor_callback)
jmp xen_iret_crit_fixup
-1: cmpl $xen_sysexit_start_crit,%eax
- jb 2f
- cmpl $xen_sysexit_end_crit,%eax
- jae 2f
-
- jmp xen_sysexit_crit_fixup
-
ENTRY(xen_do_upcall)
-2: mov %esp, %eax
+1: mov %esp, %eax
call xen_evtchn_do_upcall
jmp ret_from_intr
CFI_ENDPROC
diff --git a/arch/x86/xen/xen-asm.S b/arch/x86/xen/xen-asm.S
index 53cae923e14..2497a30f41d 100644
--- a/arch/x86/xen/xen-asm.S
+++ b/arch/x86/xen/xen-asm.S
@@ -108,6 +108,20 @@ ENDPATCH(xen_restore_fl_direct)
RELOC(xen_restore_fl_direct, 2b+1)
/*
+ We can't use sysexit directly, because we're not running in ring0.
+ But we can easily fake it up using iret. Assuming xen_sysexit
+ is jumped to with a standard stack frame, we can just strip it
+ back to a standard iret frame and use iret.
+ */
+ENTRY(xen_sysexit)
+ movl PT_EAX(%esp), %eax /* Shouldn't be necessary? */
+ orl $X86_EFLAGS_IF, PT_EFLAGS(%esp)
+ lea PT_EIP(%esp), %esp
+
+ jmp xen_iret
+ENDPROC(xen_sysexit)
+
+/*
This is run where a normal iret would be run, with the same stack setup:
8: eflags
4: cs
@@ -276,62 +290,6 @@ ENTRY(xen_iret_crit_fixup)
2: jmp xen_do_upcall
-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.