| .. | .. |
|---|
| 4 | 4 | * |
|---|
| 5 | 5 | * Copyright 2000-2002 Andi Kleen, SuSE Labs. |
|---|
| 6 | 6 | */ |
|---|
| 7 | | -#include "calling.h" |
|---|
| 8 | 7 | #include <asm/asm-offsets.h> |
|---|
| 9 | 8 | #include <asm/current.h> |
|---|
| 10 | 9 | #include <asm/errno.h> |
|---|
| .. | .. |
|---|
| 14 | 13 | #include <asm/irqflags.h> |
|---|
| 15 | 14 | #include <asm/asm.h> |
|---|
| 16 | 15 | #include <asm/smap.h> |
|---|
| 16 | +#include <asm/nospec-branch.h> |
|---|
| 17 | 17 | #include <linux/linkage.h> |
|---|
| 18 | 18 | #include <linux/err.h> |
|---|
| 19 | + |
|---|
| 20 | +#include "calling.h" |
|---|
| 19 | 21 | |
|---|
| 20 | 22 | .section .entry.text, "ax" |
|---|
| 21 | 23 | |
|---|
| .. | .. |
|---|
| 46 | 48 | * ebp user stack |
|---|
| 47 | 49 | * 0(%ebp) arg6 |
|---|
| 48 | 50 | */ |
|---|
| 49 | | -ENTRY(entry_SYSENTER_compat) |
|---|
| 51 | +SYM_CODE_START(entry_SYSENTER_compat) |
|---|
| 52 | + UNWIND_HINT_ENTRY |
|---|
| 50 | 53 | /* Interrupts are off on entry. */ |
|---|
| 51 | 54 | SWAPGS |
|---|
| 52 | 55 | |
|---|
| 53 | | - /* We are about to clobber %rsp anyway, clobbering here is OK */ |
|---|
| 54 | | - SWITCH_TO_KERNEL_CR3 scratch_reg=%rsp |
|---|
| 56 | + pushq %rax |
|---|
| 57 | + SWITCH_TO_KERNEL_CR3 scratch_reg=%rax |
|---|
| 58 | + popq %rax |
|---|
| 55 | 59 | |
|---|
| 56 | 60 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp |
|---|
| 61 | + |
|---|
| 62 | + /* Construct struct pt_regs on stack */ |
|---|
| 63 | + pushq $__USER32_DS /* pt_regs->ss */ |
|---|
| 64 | + pushq $0 /* pt_regs->sp = 0 (placeholder) */ |
|---|
| 65 | + |
|---|
| 66 | + /* |
|---|
| 67 | + * Push flags. This is nasty. First, interrupts are currently |
|---|
| 68 | + * off, but we need pt_regs->flags to have IF set. Second, if TS |
|---|
| 69 | + * was set in usermode, it's still set, and we're singlestepping |
|---|
| 70 | + * through this code. do_SYSENTER_32() will fix up IF. |
|---|
| 71 | + */ |
|---|
| 72 | + pushfq /* pt_regs->flags (except IF = 0) */ |
|---|
| 73 | + pushq $__USER32_CS /* pt_regs->cs */ |
|---|
| 74 | + pushq $0 /* pt_regs->ip = 0 (placeholder) */ |
|---|
| 75 | +SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL) |
|---|
| 57 | 76 | |
|---|
| 58 | 77 | /* |
|---|
| 59 | 78 | * User tracing code (ptrace or signal handlers) might assume that |
|---|
| .. | .. |
|---|
| 64 | 83 | */ |
|---|
| 65 | 84 | movl %eax, %eax |
|---|
| 66 | 85 | |
|---|
| 67 | | - /* Construct struct pt_regs on stack */ |
|---|
| 68 | | - pushq $__USER32_DS /* pt_regs->ss */ |
|---|
| 69 | | - pushq %rbp /* pt_regs->sp (stashed in bp) */ |
|---|
| 70 | | - |
|---|
| 71 | | - /* |
|---|
| 72 | | - * Push flags. This is nasty. First, interrupts are currently |
|---|
| 73 | | - * off, but we need pt_regs->flags to have IF set. Second, even |
|---|
| 74 | | - * if TF was set when SYSENTER started, it's clear by now. We fix |
|---|
| 75 | | - * that later using TIF_SINGLESTEP. |
|---|
| 76 | | - */ |
|---|
| 77 | | - pushfq /* pt_regs->flags (except IF = 0) */ |
|---|
| 78 | | - orl $X86_EFLAGS_IF, (%rsp) /* Fix saved flags */ |
|---|
| 79 | | - pushq $__USER32_CS /* pt_regs->cs */ |
|---|
| 80 | | - pushq $0 /* pt_regs->ip = 0 (placeholder) */ |
|---|
| 81 | 86 | pushq %rax /* pt_regs->orig_ax */ |
|---|
| 82 | 87 | pushq %rdi /* pt_regs->di */ |
|---|
| 83 | 88 | pushq %rsi /* pt_regs->si */ |
|---|
| .. | .. |
|---|
| 104 | 109 | xorl %r14d, %r14d /* nospec r14 */ |
|---|
| 105 | 110 | pushq $0 /* pt_regs->r15 = 0 */ |
|---|
| 106 | 111 | xorl %r15d, %r15d /* nospec r15 */ |
|---|
| 112 | + |
|---|
| 113 | + UNWIND_HINT_REGS |
|---|
| 114 | + |
|---|
| 107 | 115 | cld |
|---|
| 116 | + |
|---|
| 117 | + IBRS_ENTER |
|---|
| 118 | + UNTRAIN_RET |
|---|
| 108 | 119 | |
|---|
| 109 | 120 | /* |
|---|
| 110 | 121 | * SYSENTER doesn't filter flags, so we need to clear NT and AC |
|---|
| .. | .. |
|---|
| 129 | 140 | jnz .Lsysenter_fix_flags |
|---|
| 130 | 141 | .Lsysenter_flags_fixed: |
|---|
| 131 | 142 | |
|---|
| 132 | | - /* |
|---|
| 133 | | - * User mode is traced as though IRQs are on, and SYSENTER |
|---|
| 134 | | - * turned them off. |
|---|
| 135 | | - */ |
|---|
| 136 | | - TRACE_IRQS_OFF |
|---|
| 137 | | - |
|---|
| 138 | 143 | movq %rsp, %rdi |
|---|
| 139 | | - call do_fast_syscall_32 |
|---|
| 144 | + call do_SYSENTER_32 |
|---|
| 140 | 145 | /* XEN PV guests always use IRET path */ |
|---|
| 141 | | - ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \ |
|---|
| 142 | | - "jmp .Lsyscall_32_done", X86_FEATURE_XENPV |
|---|
| 146 | + ALTERNATIVE "testl %eax, %eax; jz swapgs_restore_regs_and_return_to_usermode", \ |
|---|
| 147 | + "jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV |
|---|
| 143 | 148 | jmp sysret32_from_system_call |
|---|
| 144 | 149 | |
|---|
| 145 | 150 | .Lsysenter_fix_flags: |
|---|
| 146 | 151 | pushq $X86_EFLAGS_FIXED |
|---|
| 147 | 152 | popfq |
|---|
| 148 | 153 | jmp .Lsysenter_flags_fixed |
|---|
| 149 | | -GLOBAL(__end_entry_SYSENTER_compat) |
|---|
| 150 | | -ENDPROC(entry_SYSENTER_compat) |
|---|
| 154 | +SYM_INNER_LABEL(__end_entry_SYSENTER_compat, SYM_L_GLOBAL) |
|---|
| 155 | +SYM_CODE_END(entry_SYSENTER_compat) |
|---|
| 151 | 156 | |
|---|
| 152 | 157 | /* |
|---|
| 153 | 158 | * 32-bit SYSCALL entry. |
|---|
| .. | .. |
|---|
| 196 | 201 | * esp user stack |
|---|
| 197 | 202 | * 0(%esp) arg6 |
|---|
| 198 | 203 | */ |
|---|
| 199 | | -ENTRY(entry_SYSCALL_compat) |
|---|
| 204 | +SYM_CODE_START(entry_SYSCALL_compat) |
|---|
| 205 | + UNWIND_HINT_ENTRY |
|---|
| 200 | 206 | /* Interrupts are off on entry. */ |
|---|
| 201 | 207 | swapgs |
|---|
| 202 | 208 | |
|---|
| .. | .. |
|---|
| 209 | 215 | /* Switch to the kernel stack */ |
|---|
| 210 | 216 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp |
|---|
| 211 | 217 | |
|---|
| 218 | +SYM_INNER_LABEL(entry_SYSCALL_compat_safe_stack, SYM_L_GLOBAL) |
|---|
| 219 | + |
|---|
| 212 | 220 | /* Construct struct pt_regs on stack */ |
|---|
| 213 | 221 | pushq $__USER32_DS /* pt_regs->ss */ |
|---|
| 214 | 222 | pushq %r8 /* pt_regs->sp */ |
|---|
| 215 | 223 | pushq %r11 /* pt_regs->flags */ |
|---|
| 216 | 224 | pushq $__USER32_CS /* pt_regs->cs */ |
|---|
| 217 | 225 | pushq %rcx /* pt_regs->ip */ |
|---|
| 218 | | -GLOBAL(entry_SYSCALL_compat_after_hwframe) |
|---|
| 226 | +SYM_INNER_LABEL(entry_SYSCALL_compat_after_hwframe, SYM_L_GLOBAL) |
|---|
| 219 | 227 | movl %eax, %eax /* discard orig_ax high bits */ |
|---|
| 220 | 228 | pushq %rax /* pt_regs->orig_ax */ |
|---|
| 221 | 229 | pushq %rdi /* pt_regs->di */ |
|---|
| .. | .. |
|---|
| 247 | 255 | pushq $0 /* pt_regs->r15 = 0 */ |
|---|
| 248 | 256 | xorl %r15d, %r15d /* nospec r15 */ |
|---|
| 249 | 257 | |
|---|
| 250 | | - /* |
|---|
| 251 | | - * User mode is traced as though IRQs are on, and SYSENTER |
|---|
| 252 | | - * turned them off. |
|---|
| 253 | | - */ |
|---|
| 254 | | - TRACE_IRQS_OFF |
|---|
| 258 | + UNWIND_HINT_REGS |
|---|
| 259 | + |
|---|
| 260 | + IBRS_ENTER |
|---|
| 261 | + UNTRAIN_RET |
|---|
| 255 | 262 | |
|---|
| 256 | 263 | movq %rsp, %rdi |
|---|
| 257 | 264 | call do_fast_syscall_32 |
|---|
| 258 | 265 | /* XEN PV guests always use IRET path */ |
|---|
| 259 | | - ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \ |
|---|
| 260 | | - "jmp .Lsyscall_32_done", X86_FEATURE_XENPV |
|---|
| 266 | + ALTERNATIVE "testl %eax, %eax; jz swapgs_restore_regs_and_return_to_usermode", \ |
|---|
| 267 | + "jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV |
|---|
| 261 | 268 | |
|---|
| 262 | 269 | /* Opportunistic SYSRET */ |
|---|
| 263 | 270 | sysret32_from_system_call: |
|---|
| 264 | | - TRACE_IRQS_ON /* User mode traces as IRQs on. */ |
|---|
| 271 | + /* |
|---|
| 272 | + * We are not going to return to userspace from the trampoline |
|---|
| 273 | + * stack. So let's erase the thread stack right now. |
|---|
| 274 | + */ |
|---|
| 275 | + STACKLEAK_ERASE |
|---|
| 276 | + |
|---|
| 277 | + IBRS_EXIT |
|---|
| 278 | + |
|---|
| 265 | 279 | movq RBX(%rsp), %rbx /* pt_regs->rbx */ |
|---|
| 266 | 280 | movq RBP(%rsp), %rbp /* pt_regs->rbp */ |
|---|
| 267 | 281 | movq EFLAGS(%rsp), %r11 /* pt_regs->flags (in r11) */ |
|---|
| .. | .. |
|---|
| 306 | 320 | xorl %r10d, %r10d |
|---|
| 307 | 321 | swapgs |
|---|
| 308 | 322 | sysretl |
|---|
| 309 | | -END(entry_SYSCALL_compat) |
|---|
| 323 | +SYM_CODE_END(entry_SYSCALL_compat) |
|---|
| 310 | 324 | |
|---|
| 311 | 325 | /* |
|---|
| 312 | 326 | * 32-bit legacy system call entry. |
|---|
| .. | .. |
|---|
| 334 | 348 | * edi arg5 |
|---|
| 335 | 349 | * ebp arg6 |
|---|
| 336 | 350 | */ |
|---|
| 337 | | -ENTRY(entry_INT80_compat) |
|---|
| 351 | +SYM_CODE_START(entry_INT80_compat) |
|---|
| 352 | + UNWIND_HINT_ENTRY |
|---|
| 338 | 353 | /* |
|---|
| 339 | 354 | * Interrupts are off on entry. |
|---|
| 340 | 355 | */ |
|---|
| .. | .. |
|---|
| 356 | 371 | |
|---|
| 357 | 372 | /* Need to switch before accessing the thread stack. */ |
|---|
| 358 | 373 | SWITCH_TO_KERNEL_CR3 scratch_reg=%rdi |
|---|
| 374 | + |
|---|
| 359 | 375 | /* In the Xen PV case we already run on the thread stack. */ |
|---|
| 360 | | - ALTERNATIVE "movq %rsp, %rdi", "jmp .Lint80_keep_stack", X86_FEATURE_XENPV |
|---|
| 376 | + ALTERNATIVE "", "jmp .Lint80_keep_stack", X86_FEATURE_XENPV |
|---|
| 377 | + |
|---|
| 378 | + movq %rsp, %rdi |
|---|
| 361 | 379 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp |
|---|
| 362 | 380 | |
|---|
| 363 | 381 | pushq 6*8(%rdi) /* regs->ss */ |
|---|
| .. | .. |
|---|
| 396 | 414 | xorl %r14d, %r14d /* nospec r14 */ |
|---|
| 397 | 415 | pushq %r15 /* pt_regs->r15 */ |
|---|
| 398 | 416 | xorl %r15d, %r15d /* nospec r15 */ |
|---|
| 417 | + |
|---|
| 418 | + UNWIND_HINT_REGS |
|---|
| 419 | + |
|---|
| 399 | 420 | cld |
|---|
| 400 | 421 | |
|---|
| 401 | | - /* |
|---|
| 402 | | - * User mode is traced as though IRQs are on, and the interrupt |
|---|
| 403 | | - * gate turned them off. |
|---|
| 404 | | - */ |
|---|
| 405 | | - TRACE_IRQS_OFF |
|---|
| 422 | + IBRS_ENTER |
|---|
| 423 | + UNTRAIN_RET |
|---|
| 406 | 424 | |
|---|
| 407 | 425 | movq %rsp, %rdi |
|---|
| 408 | 426 | call do_int80_syscall_32 |
|---|
| 409 | | -.Lsyscall_32_done: |
|---|
| 410 | | - |
|---|
| 411 | | - /* Go back to user mode. */ |
|---|
| 412 | | - TRACE_IRQS_ON |
|---|
| 413 | 427 | jmp swapgs_restore_regs_and_return_to_usermode |
|---|
| 414 | | -END(entry_INT80_compat) |
|---|
| 428 | +SYM_CODE_END(entry_INT80_compat) |
|---|