aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/entry/entry_64.S32
-rw-r--r--arch/x86/entry/entry_64_compat.S3
2 files changed, 15 insertions, 20 deletions
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index 3eeb1694210c..d6ffdc9afcbb 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -249,12 +249,14 @@ return_from_SYSCALL_64:
249 249
250 /* 250 /*
251 * Try to use SYSRET instead of IRET if we're returning to 251 * Try to use SYSRET instead of IRET if we're returning to
252 * a completely clean 64-bit userspace context. 252 * a completely clean 64-bit userspace context. If we're not,
253 * go to the slow exit path.
253 */ 254 */
254 movq RCX(%rsp), %rcx 255 movq RCX(%rsp), %rcx
255 movq RIP(%rsp), %r11 256 movq RIP(%rsp), %r11
256 cmpq %rcx, %r11 /* RCX == RIP */ 257
257 jne opportunistic_sysret_failed 258 cmpq %rcx, %r11 /* SYSRET requires RCX == RIP */
259 jne swapgs_restore_regs_and_return_to_usermode
258 260
259 /* 261 /*
260 * On Intel CPUs, SYSRET with non-canonical RCX/RIP will #GP 262 * On Intel CPUs, SYSRET with non-canonical RCX/RIP will #GP
@@ -272,14 +274,14 @@ return_from_SYSCALL_64:
272 274
273 /* If this changed %rcx, it was not canonical */ 275 /* If this changed %rcx, it was not canonical */
274 cmpq %rcx, %r11 276 cmpq %rcx, %r11
275 jne opportunistic_sysret_failed 277 jne swapgs_restore_regs_and_return_to_usermode
276 278
277 cmpq $__USER_CS, CS(%rsp) /* CS must match SYSRET */ 279 cmpq $__USER_CS, CS(%rsp) /* CS must match SYSRET */
278 jne opportunistic_sysret_failed 280 jne swapgs_restore_regs_and_return_to_usermode
279 281
280 movq R11(%rsp), %r11 282 movq R11(%rsp), %r11
281 cmpq %r11, EFLAGS(%rsp) /* R11 == RFLAGS */ 283 cmpq %r11, EFLAGS(%rsp) /* R11 == RFLAGS */
282 jne opportunistic_sysret_failed 284 jne swapgs_restore_regs_and_return_to_usermode
283 285
284 /* 286 /*
285 * SYSCALL clears RF when it saves RFLAGS in R11 and SYSRET cannot 287 * SYSCALL clears RF when it saves RFLAGS in R11 and SYSRET cannot
@@ -300,12 +302,12 @@ return_from_SYSCALL_64:
300 * would never get past 'stuck_here'. 302 * would never get past 'stuck_here'.
301 */ 303 */
302 testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11 304 testq $(X86_EFLAGS_RF|X86_EFLAGS_TF), %r11
303 jnz opportunistic_sysret_failed 305 jnz swapgs_restore_regs_and_return_to_usermode
304 306
305 /* nothing to check for RSP */ 307 /* nothing to check for RSP */
306 308
307 cmpq $__USER_DS, SS(%rsp) /* SS must match SYSRET */ 309 cmpq $__USER_DS, SS(%rsp) /* SS must match SYSRET */
308 jne opportunistic_sysret_failed 310 jne swapgs_restore_regs_and_return_to_usermode
309 311
310 /* 312 /*
311 * We win! This label is here just for ease of understanding 313 * We win! This label is here just for ease of understanding
@@ -318,10 +320,6 @@ syscall_return_via_sysret:
318 movq RSP(%rsp), %rsp 320 movq RSP(%rsp), %rsp
319 UNWIND_HINT_EMPTY 321 UNWIND_HINT_EMPTY
320 USERGS_SYSRET64 322 USERGS_SYSRET64
321
322opportunistic_sysret_failed:
323 SWAPGS
324 jmp restore_regs_and_return_to_usermode
325END(entry_SYSCALL_64) 323END(entry_SYSCALL_64)
326 324
327ENTRY(stub_ptregs_64) 325ENTRY(stub_ptregs_64)
@@ -422,8 +420,7 @@ ENTRY(ret_from_fork)
422 movq %rsp, %rdi 420 movq %rsp, %rdi
423 call syscall_return_slowpath /* returns with IRQs disabled */ 421 call syscall_return_slowpath /* returns with IRQs disabled */
424 TRACE_IRQS_ON /* user mode is traced as IRQS on */ 422 TRACE_IRQS_ON /* user mode is traced as IRQS on */
425 SWAPGS 423 jmp swapgs_restore_regs_and_return_to_usermode
426 jmp restore_regs_and_return_to_usermode
427 424
4281: 4251:
429 /* kernel thread */ 426 /* kernel thread */
@@ -611,9 +608,8 @@ GLOBAL(retint_user)
611 mov %rsp,%rdi 608 mov %rsp,%rdi
612 call prepare_exit_to_usermode 609 call prepare_exit_to_usermode
613 TRACE_IRQS_IRETQ 610 TRACE_IRQS_IRETQ
614 SWAPGS
615 611
616GLOBAL(restore_regs_and_return_to_usermode) 612GLOBAL(swapgs_restore_regs_and_return_to_usermode)
617#ifdef CONFIG_DEBUG_ENTRY 613#ifdef CONFIG_DEBUG_ENTRY
618 /* Assert that pt_regs indicates user mode. */ 614 /* Assert that pt_regs indicates user mode. */
619 testl $3, CS(%rsp) 615 testl $3, CS(%rsp)
@@ -621,6 +617,7 @@ GLOBAL(restore_regs_and_return_to_usermode)
621 ud2 617 ud2
6221: 6181:
623#endif 619#endif
620 SWAPGS
624 RESTORE_EXTRA_REGS 621 RESTORE_EXTRA_REGS
625 RESTORE_C_REGS 622 RESTORE_C_REGS
626 REMOVE_PT_GPREGS_FROM_STACK 8 623 REMOVE_PT_GPREGS_FROM_STACK 8
@@ -1342,8 +1339,7 @@ ENTRY(nmi)
1342 * Return back to user mode. We must *not* do the normal exit 1339 * Return back to user mode. We must *not* do the normal exit
1343 * work, because we don't want to enable interrupts. 1340 * work, because we don't want to enable interrupts.
1344 */ 1341 */
1345 SWAPGS 1342 jmp swapgs_restore_regs_and_return_to_usermode
1346 jmp restore_regs_and_return_to_usermode
1347 1343
1348.Lnmi_from_kernel: 1344.Lnmi_from_kernel:
1349 /* 1345 /*
diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S
index 9ca014a99968..932b96ce1b06 100644
--- a/arch/x86/entry/entry_64_compat.S
+++ b/arch/x86/entry/entry_64_compat.S
@@ -336,8 +336,7 @@ ENTRY(entry_INT80_compat)
336 336
337 /* Go back to user mode. */ 337 /* Go back to user mode. */
338 TRACE_IRQS_ON 338 TRACE_IRQS_ON
339 SWAPGS 339 jmp swapgs_restore_regs_and_return_to_usermode
340 jmp restore_regs_and_return_to_usermode
341END(entry_INT80_compat) 340END(entry_INT80_compat)
342 341
343ENTRY(stub32_clone) 342ENTRY(stub32_clone)