| |
| |
| |
| |
| |
| |
| #include "calling.h" |
| #include <asm/asm-offsets.h> |
| #include <asm/current.h> |
| #include <asm/errno.h> |
| #include <asm/ia32_unistd.h> |
| #include <asm/thread_info.h> |
| #include <asm/segment.h> |
| #include <asm/irqflags.h> |
| #include <asm/asm.h> |
| #include <asm/smap.h> |
| #include <linux/linkage.h> |
| #include <linux/err.h> |
| |
| <------>.section .entry.text, "ax" |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| SYM_CODE_START(entry_SYSENTER_compat) |
| <------>UNWIND_HINT_EMPTY |
| <------> |
| <------>SWAPGS |
| |
| <------>pushq %rax |
| <------>SWITCH_TO_KERNEL_CR3 scratch_reg=%rax |
| <------>popq %rax |
| |
| <------>movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp |
| |
| <------> |
| <------>pushq $__USER32_DS |
| <------>pushq $0 |
| |
| <------> |
| <------> * Push flags. This is nasty. First, interrupts are currently |
| <------> * off, but we need pt_regs->flags to have IF set. Second, if TS |
| <------> * was set in usermode, it's still set, and we're singlestepping |
| <------> * through this code. do_SYSENTER_32() will fix up IF. |
| <------> */ |
| <------>pushfq |
| <------>pushq $__USER32_CS |
| <------>pushq $0 |
| SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL) |
| |
| <------> |
| <------> * User tracing code (ptrace or signal handlers) might assume that |
| <------> * the saved RAX contains a 32-bit number when we're invoking a 32-bit |
| <------> * syscall. Just in case the high bits are nonzero, zero-extend |
| <------> * the syscall number. (This could almost certainly be deleted |
| <------> * with no ill effects.) |
| <------> */ |
| <------>movl %eax, %eax |
| |
| <------>pushq %rax |
| <------>pushq %rdi |
| <------>pushq %rsi |
| <------>pushq %rdx |
| <------>pushq %rcx |
| <------>pushq $-ENOSYS |
| <------>pushq $0 |
| <------>xorl %r8d, %r8d |
| <------>pushq $0 |
| <------>xorl %r9d, %r9d |
| <------>pushq $0 |
| <------>xorl %r10d, %r10d |
| <------>pushq $0 |
| <------>xorl %r11d, %r11d |
| <------>pushq %rbx |
| <------>xorl %ebx, %ebx |
| <------>pushq %rbp |
| <------>xorl %ebp, %ebp |
| <------>pushq $0 |
| <------>xorl %r12d, %r12d |
| <------>pushq $0 |
| <------>xorl %r13d, %r13d |
| <------>pushq $0 |
| <------>xorl %r14d, %r14d |
| <------>pushq $0 |
| <------>xorl %r15d, %r15d |
| |
| <------>UNWIND_HINT_REGS |
| |
| <------>cld |
| |
| <------> |
| <------> * SYSENTER doesn't filter flags, so we need to clear NT and AC |
| <------> * ourselves. To save a few cycles, we can check whether |
| <------> * either was set instead of doing an unconditional popfq. |
| <------> * This needs to happen before enabling interrupts so that |
| <------> * we don't get preempted with NT set. |
| <------> * |
| <------> * If TF is set, we will single-step all the way to here -- do_debug |
| <------> * will ignore all the traps. (Yes, this is slow, but so is |
| <------> * single-stepping in general. This allows us to avoid having |
| <------> * a more complicated code to handle the case where a user program |
| <------> * forces us to single-step through the SYSENTER entry code.) |
| <------> * |
| <------> * NB.: .Lsysenter_fix_flags is a label with the code under it moved |
| <------> * out-of-line as an optimization: NT is unlikely to be set in the |
| <------> * majority of the cases and instead of polluting the I$ unnecessarily, |
| <------> * we're keeping that code behind a branch which will predict as |
| <------> * not-taken and therefore its instructions won't be fetched. |
| <------> */ |
| <------>testl $X86_EFLAGS_NT|X86_EFLAGS_AC|X86_EFLAGS_TF, EFLAGS(%rsp) |
| <------>jnz .Lsysenter_fix_flags |
| .Lsysenter_flags_fixed: |
| |
| <------>movq %rsp, %rdi |
| <------>call do_SYSENTER_32 |
| <------> |
| <------>ALTERNATIVE "testl %eax, %eax; jz swapgs_restore_regs_and_return_to_usermode", \ |
| <------><------> "jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV |
| <------>jmp sysret32_from_system_call |
| |
| .Lsysenter_fix_flags: |
| <------>pushq $X86_EFLAGS_FIXED |
| <------>popfq |
| <------>jmp .Lsysenter_flags_fixed |
| SYM_INNER_LABEL(__end_entry_SYSENTER_compat, SYM_L_GLOBAL) |
| SYM_CODE_END(entry_SYSENTER_compat) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| SYM_CODE_START(entry_SYSCALL_compat) |
| <------>UNWIND_HINT_EMPTY |
| <------> |
| <------>swapgs |
| |
| <------> |
| <------>movl %esp, %r8d |
| |
| <------> |
| <------>SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp |
| |
| <------> |
| <------>movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp |
| |
| SYM_INNER_LABEL(entry_SYSCALL_compat_safe_stack, SYM_L_GLOBAL) |
| |
| <------> |
| <------>pushq $__USER32_DS |
| <------>pushq %r8 |
| <------>pushq %r11 |
| <------>pushq $__USER32_CS |
| <------>pushq %rcx |
| SYM_INNER_LABEL(entry_SYSCALL_compat_after_hwframe, SYM_L_GLOBAL) |
| <------>movl %eax, %eax |
| <------>pushq %rax |
| <------>pushq %rdi |
| <------>pushq %rsi |
| <------>xorl %esi, %esi |
| <------>pushq %rdx |
| <------>xorl %edx, %edx |
| <------>pushq %rbp |
| <------>xorl %ecx, %ecx |
| <------>pushq $-ENOSYS |
| <------>pushq $0 |
| <------>xorl %r8d, %r8d |
| <------>pushq $0 |
| <------>xorl %r9d, %r9d |
| <------>pushq $0 |
| <------>xorl %r10d, %r10d |
| <------>pushq $0 |
| <------>xorl %r11d, %r11d |
| <------>pushq %rbx |
| <------>xorl %ebx, %ebx |
| <------>pushq %rbp |
| <------>xorl %ebp, %ebp |
| <------>pushq $0 |
| <------>xorl %r12d, %r12d |
| <------>pushq $0 |
| <------>xorl %r13d, %r13d |
| <------>pushq $0 |
| <------>xorl %r14d, %r14d |
| <------>pushq $0 |
| <------>xorl %r15d, %r15d |
| |
| <------>UNWIND_HINT_REGS |
| |
| <------>movq %rsp, %rdi |
| <------>call do_fast_syscall_32 |
| <------> |
| <------>ALTERNATIVE "testl %eax, %eax; jz swapgs_restore_regs_and_return_to_usermode", \ |
| <------><------> "jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV |
| |
| <------> |
| sysret32_from_system_call: |
| <------> |
| <------> * We are not going to return to userspace from the trampoline |
| <------> * stack. So let's erase the thread stack right now. |
| <------> */ |
| <------>STACKLEAK_ERASE |
| |
| <------>movq RBX(%rsp), %rbx |
| <------>movq RBP(%rsp), %rbp |
| <------>movq EFLAGS(%rsp), %r11 |
| <------>movq RIP(%rsp), %rcx |
| <------>addq $RAX, %rsp |
| <------>popq %rax |
| <------>popq %rdx |
| <------>popq %rdx |
| <------>popq %rsi |
| <------>popq %rdi |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| <------>movq RSP-ORIG_RAX(%rsp), %rsp |
| |
| <------> |
| <------> * The original userspace %rsp (RSP-ORIG_RAX(%rsp)) is stored |
| <------> * on the process stack which is not mapped to userspace and |
| <------> * not readable after we SWITCH_TO_USER_CR3. Delay the CR3 |
| <------> * switch until after after the last reference to the process |
| <------> * stack. |
| <------> * |
| <------> * %r8/%r9 are zeroed before the sysret, thus safe to clobber. |
| <------> */ |
| <------>SWITCH_TO_USER_CR3_NOSTACK scratch_reg=%r8 scratch_reg2=%r9 |
| |
| <------>xorl %r8d, %r8d |
| <------>xorl %r9d, %r9d |
| <------>xorl %r10d, %r10d |
| <------>swapgs |
| <------>sysretl |
| SYM_CODE_END(entry_SYSCALL_compat) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| SYM_CODE_START(entry_INT80_compat) |
| <------>UNWIND_HINT_EMPTY |
| <------> |
| <------> * Interrupts are off on entry. |
| <------> */ |
| <------>ASM_CLAC |
| <------>SWAPGS |
| |
| <------> |
| <------> * User tracing code (ptrace or signal handlers) might assume that |
| <------> * the saved RAX contains a 32-bit number when we're invoking a 32-bit |
| <------> * syscall. Just in case the high bits are nonzero, zero-extend |
| <------> * the syscall number. (This could almost certainly be deleted |
| <------> * with no ill effects.) |
| <------> */ |
| <------>movl %eax, %eax |
| |
| <------> |
| <------>pushq %rax |
| <------>pushq %rdi |
| |
| <------> |
| <------>SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi |
| |
| <------> |
| <------>ALTERNATIVE "", "jmp .Lint80_keep_stack", X86_FEATURE_XENPV |
| |
| <------>movq %rsp, %rdi |
| <------>movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp |
| |
| <------>pushq 6*8(%rdi) |
| <------>pushq 5*8(%rdi) |
| <------>pushq 4*8(%rdi) |
| <------>pushq 3*8(%rdi) |
| <------>pushq 2*8(%rdi) |
| <------>pushq 1*8(%rdi) |
| <------>pushq (%rdi) |
| .Lint80_keep_stack: |
| |
| <------>pushq %rsi |
| <------>xorl %esi, %esi |
| <------>pushq %rdx |
| <------>xorl %edx, %edx |
| <------>pushq %rcx |
| <------>xorl %ecx, %ecx |
| <------>pushq $-ENOSYS |
| <------>pushq %r8 |
| <------>xorl %r8d, %r8d |
| <------>pushq %r9 |
| <------>xorl %r9d, %r9d |
| <------>pushq %r10 |
| <------>xorl %r10d, %r10d |
| <------>pushq %r11 |
| <------>xorl %r11d, %r11d |
| <------>pushq %rbx |
| <------>xorl %ebx, %ebx |
| <------>pushq %rbp |
| <------>xorl %ebp, %ebp |
| <------>pushq %r12 |
| <------>xorl %r12d, %r12d |
| <------>pushq %r13 |
| <------>xorl %r13d, %r13d |
| <------>pushq %r14 |
| <------>xorl %r14d, %r14d |
| <------>pushq %r15 |
| <------>xorl %r15d, %r15d |
| |
| <------>UNWIND_HINT_REGS |
| |
| <------>cld |
| |
| <------>movq %rsp, %rdi |
| <------>call do_int80_syscall_32 |
| <------>jmp swapgs_restore_regs_and_return_to_usermode |
| SYM_CODE_END(entry_INT80_compat) |
| |