.. | .. |
---|
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) |
---|