123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- /*
- * Asm versions of Xen pv-ops, suitable for either direct use or
- * inlining. The inline versions are the same as the direct-use
- * versions, with the pre- and post-amble chopped off.
- *
- * This code is encoded for size rather than absolute efficiency, with
- * a view to being able to inline as much as possible.
- *
- * We only bother with direct forms (ie, vcpu in pda) of the
- * operations here; the indirect forms are better handled in C, since
- * they're generally too large to inline anyway.
- */
- #include <asm/errno.h>
- #include <asm/percpu.h>
- #include <asm/processor-flags.h>
- #include <asm/segment.h>
- #include <xen/interface/xen.h>
- #include "xen-asm.h"
- ENTRY(xen_adjust_exception_frame)
- mov 8+0(%rsp), %rcx
- mov 8+8(%rsp), %r11
- ret $16
- hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32
- /*
- * Xen64 iret frame:
- *
- * ss
- * rsp
- * rflags
- * cs
- * rip <-- standard iret frame
- *
- * flags
- *
- * rcx }
- * r11 }<-- pushed by hypercall page
- * rsp->rax }
- */
- ENTRY(xen_iret)
- pushq $0
- 1: jmp hypercall_iret
- ENDPATCH(xen_iret)
- RELOC(xen_iret, 1b+1)
- /*
- * sysexit is not used for 64-bit processes, so it's only ever used to
- * return to 32-bit compat userspace.
- */
- ENTRY(xen_sysexit)
- pushq $__USER32_DS
- pushq %rcx
- pushq $X86_EFLAGS_IF
- pushq $__USER32_CS
- pushq %rdx
- pushq $0
- 1: jmp hypercall_iret
- ENDPATCH(xen_sysexit)
- RELOC(xen_sysexit, 1b+1)
- ENTRY(xen_sysret64)
- /*
- * We're already on the usermode stack at this point, but
- * still with the kernel gs, so we can easily switch back
- */
- movq %rsp, PER_CPU_VAR(old_rsp)
- movq PER_CPU_VAR(kernel_stack), %rsp
- pushq $__USER_DS
- pushq PER_CPU_VAR(old_rsp)
- pushq %r11
- pushq $__USER_CS
- pushq %rcx
- pushq $VGCF_in_syscall
- 1: jmp hypercall_iret
- ENDPATCH(xen_sysret64)
- RELOC(xen_sysret64, 1b+1)
- ENTRY(xen_sysret32)
- /*
- * We're already on the usermode stack at this point, but
- * still with the kernel gs, so we can easily switch back
- */
- movq %rsp, PER_CPU_VAR(old_rsp)
- movq PER_CPU_VAR(kernel_stack), %rsp
- pushq $__USER32_DS
- pushq PER_CPU_VAR(old_rsp)
- pushq %r11
- pushq $__USER32_CS
- pushq %rcx
- pushq $0
- 1: jmp hypercall_iret
- ENDPATCH(xen_sysret32)
- RELOC(xen_sysret32, 1b+1)
- /*
- * Xen handles syscall callbacks much like ordinary exceptions, which
- * means we have:
- * - kernel gs
- * - kernel rsp
- * - an iret-like stack frame on the stack (including rcx and r11):
- * ss
- * rsp
- * rflags
- * cs
- * rip
- * r11
- * rsp->rcx
- *
- * In all the entrypoints, we undo all that to make it look like a
- * CPU-generated syscall/sysenter and jump to the normal entrypoint.
- */
- .macro undo_xen_syscall
- mov 0*8(%rsp), %rcx
- mov 1*8(%rsp), %r11
- mov 5*8(%rsp), %rsp
- .endm
- /* Normal 64-bit system call target */
- ENTRY(xen_syscall_target)
- undo_xen_syscall
- jmp system_call_after_swapgs
- ENDPROC(xen_syscall_target)
- #ifdef CONFIG_IA32_EMULATION
- /* 32-bit compat syscall target */
- ENTRY(xen_syscall32_target)
- undo_xen_syscall
- jmp ia32_cstar_target
- ENDPROC(xen_syscall32_target)
- /* 32-bit compat sysenter target */
- ENTRY(xen_sysenter_target)
- undo_xen_syscall
- jmp ia32_sysenter_target
- ENDPROC(xen_sysenter_target)
- #else /* !CONFIG_IA32_EMULATION */
- ENTRY(xen_syscall32_target)
- ENTRY(xen_sysenter_target)
- lea 16(%rsp), %rsp /* strip %rcx, %r11 */
- mov $-ENOSYS, %rax
- pushq $0
- jmp hypercall_iret
- ENDPROC(xen_syscall32_target)
- ENDPROC(xen_sysenter_target)
- #endif /* CONFIG_IA32_EMULATION */
|