diff options
| -rw-r--r-- | arch/x86/entry/entry_64.S | 32 | ||||
| -rw-r--r-- | arch/x86/entry/entry_64_compat.S | 3 |
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 | |||
| 322 | opportunistic_sysret_failed: | ||
| 323 | SWAPGS | ||
| 324 | jmp restore_regs_and_return_to_usermode | ||
| 325 | END(entry_SYSCALL_64) | 323 | END(entry_SYSCALL_64) |
| 326 | 324 | ||
| 327 | ENTRY(stub_ptregs_64) | 325 | ENTRY(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 | ||
| 428 | 1: | 425 | 1: |
| 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 | ||
| 616 | GLOBAL(restore_regs_and_return_to_usermode) | 612 | GLOBAL(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 |
| 622 | 1: | 618 | 1: |
| 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 | ||
| 341 | END(entry_INT80_compat) | 340 | END(entry_INT80_compat) |
| 342 | 341 | ||
| 343 | ENTRY(stub32_clone) | 342 | ENTRY(stub32_clone) |
