diff options
Diffstat (limited to 'arch/x86/kernel/entry_64.S')
-rw-r--r-- | arch/x86/kernel/entry_64.S | 81 |
1 files changed, 22 insertions, 59 deletions
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index df088bb03fb3..c0226ab54106 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -828,9 +828,15 @@ ENTRY(native_iret) | |||
828 | jnz native_irq_return_ldt | 828 | jnz native_irq_return_ldt |
829 | #endif | 829 | #endif |
830 | 830 | ||
831 | .global native_irq_return_iret | ||
831 | native_irq_return_iret: | 832 | native_irq_return_iret: |
833 | /* | ||
834 | * This may fault. Non-paranoid faults on return to userspace are | ||
835 | * handled by fixup_bad_iret. These include #SS, #GP, and #NP. | ||
836 | * Double-faults due to espfix64 are handled in do_double_fault. | ||
837 | * Other faults here are fatal. | ||
838 | */ | ||
832 | iretq | 839 | iretq |
833 | _ASM_EXTABLE(native_irq_return_iret, bad_iret) | ||
834 | 840 | ||
835 | #ifdef CONFIG_X86_ESPFIX64 | 841 | #ifdef CONFIG_X86_ESPFIX64 |
836 | native_irq_return_ldt: | 842 | native_irq_return_ldt: |
@@ -858,25 +864,6 @@ native_irq_return_ldt: | |||
858 | jmp native_irq_return_iret | 864 | jmp native_irq_return_iret |
859 | #endif | 865 | #endif |
860 | 866 | ||
861 | .section .fixup,"ax" | ||
862 | bad_iret: | ||
863 | /* | ||
864 | * The iret traps when the %cs or %ss being restored is bogus. | ||
865 | * We've lost the original trap vector and error code. | ||
866 | * #GPF is the most likely one to get for an invalid selector. | ||
867 | * So pretend we completed the iret and took the #GPF in user mode. | ||
868 | * | ||
869 | * We are now running with the kernel GS after exception recovery. | ||
870 | * But error_entry expects us to have user GS to match the user %cs, | ||
871 | * so swap back. | ||
872 | */ | ||
873 | pushq $0 | ||
874 | |||
875 | SWAPGS | ||
876 | jmp general_protection | ||
877 | |||
878 | .previous | ||
879 | |||
880 | /* edi: workmask, edx: work */ | 867 | /* edi: workmask, edx: work */ |
881 | retint_careful: | 868 | retint_careful: |
882 | CFI_RESTORE_STATE | 869 | CFI_RESTORE_STATE |
@@ -922,37 +909,6 @@ ENTRY(retint_kernel) | |||
922 | CFI_ENDPROC | 909 | CFI_ENDPROC |
923 | END(common_interrupt) | 910 | END(common_interrupt) |
924 | 911 | ||
925 | /* | ||
926 | * If IRET takes a fault on the espfix stack, then we | ||
927 | * end up promoting it to a doublefault. In that case, | ||
928 | * modify the stack to make it look like we just entered | ||
929 | * the #GP handler from user space, similar to bad_iret. | ||
930 | */ | ||
931 | #ifdef CONFIG_X86_ESPFIX64 | ||
932 | ALIGN | ||
933 | __do_double_fault: | ||
934 | XCPT_FRAME 1 RDI+8 | ||
935 | movq RSP(%rdi),%rax /* Trap on the espfix stack? */ | ||
936 | sarq $PGDIR_SHIFT,%rax | ||
937 | cmpl $ESPFIX_PGD_ENTRY,%eax | ||
938 | jne do_double_fault /* No, just deliver the fault */ | ||
939 | cmpl $__KERNEL_CS,CS(%rdi) | ||
940 | jne do_double_fault | ||
941 | movq RIP(%rdi),%rax | ||
942 | cmpq $native_irq_return_iret,%rax | ||
943 | jne do_double_fault /* This shouldn't happen... */ | ||
944 | movq PER_CPU_VAR(kernel_stack),%rax | ||
945 | subq $(6*8-KERNEL_STACK_OFFSET),%rax /* Reset to original stack */ | ||
946 | movq %rax,RSP(%rdi) | ||
947 | movq $0,(%rax) /* Missing (lost) #GP error code */ | ||
948 | movq $general_protection,RIP(%rdi) | ||
949 | retq | ||
950 | CFI_ENDPROC | ||
951 | END(__do_double_fault) | ||
952 | #else | ||
953 | # define __do_double_fault do_double_fault | ||
954 | #endif | ||
955 | |||
956 | /* | 912 | /* |
957 | * APIC interrupts. | 913 | * APIC interrupts. |
958 | */ | 914 | */ |
@@ -1124,7 +1080,7 @@ idtentry overflow do_overflow has_error_code=0 | |||
1124 | idtentry bounds do_bounds has_error_code=0 | 1080 | idtentry bounds do_bounds has_error_code=0 |
1125 | idtentry invalid_op do_invalid_op has_error_code=0 | 1081 | idtentry invalid_op do_invalid_op has_error_code=0 |
1126 | idtentry device_not_available do_device_not_available has_error_code=0 | 1082 | idtentry device_not_available do_device_not_available has_error_code=0 |
1127 | idtentry double_fault __do_double_fault has_error_code=1 paranoid=1 | 1083 | idtentry double_fault do_double_fault has_error_code=1 paranoid=1 |
1128 | idtentry coprocessor_segment_overrun do_coprocessor_segment_overrun has_error_code=0 | 1084 | idtentry coprocessor_segment_overrun do_coprocessor_segment_overrun has_error_code=0 |
1129 | idtentry invalid_TSS do_invalid_TSS has_error_code=1 | 1085 | idtentry invalid_TSS do_invalid_TSS has_error_code=1 |
1130 | idtentry segment_not_present do_segment_not_present has_error_code=1 | 1086 | idtentry segment_not_present do_segment_not_present has_error_code=1 |
@@ -1289,7 +1245,7 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \ | |||
1289 | 1245 | ||
1290 | idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK | 1246 | idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK |
1291 | idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK | 1247 | idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK |
1292 | idtentry stack_segment do_stack_segment has_error_code=1 paranoid=1 | 1248 | idtentry stack_segment do_stack_segment has_error_code=1 |
1293 | #ifdef CONFIG_XEN | 1249 | #ifdef CONFIG_XEN |
1294 | idtentry xen_debug do_debug has_error_code=0 | 1250 | idtentry xen_debug do_debug has_error_code=0 |
1295 | idtentry xen_int3 do_int3 has_error_code=0 | 1251 | idtentry xen_int3 do_int3 has_error_code=0 |
@@ -1399,17 +1355,16 @@ error_sti: | |||
1399 | 1355 | ||
1400 | /* | 1356 | /* |
1401 | * There are two places in the kernel that can potentially fault with | 1357 | * There are two places in the kernel that can potentially fault with |
1402 | * usergs. Handle them here. The exception handlers after iret run with | 1358 | * usergs. Handle them here. B stepping K8s sometimes report a |
1403 | * kernel gs again, so don't set the user space flag. B stepping K8s | 1359 | * truncated RIP for IRET exceptions returning to compat mode. Check |
1404 | * sometimes report an truncated RIP for IRET exceptions returning to | 1360 | * for these here too. |
1405 | * compat mode. Check for these here too. | ||
1406 | */ | 1361 | */ |
1407 | error_kernelspace: | 1362 | error_kernelspace: |
1408 | CFI_REL_OFFSET rcx, RCX+8 | 1363 | CFI_REL_OFFSET rcx, RCX+8 |
1409 | incl %ebx | 1364 | incl %ebx |
1410 | leaq native_irq_return_iret(%rip),%rcx | 1365 | leaq native_irq_return_iret(%rip),%rcx |
1411 | cmpq %rcx,RIP+8(%rsp) | 1366 | cmpq %rcx,RIP+8(%rsp) |
1412 | je error_swapgs | 1367 | je error_bad_iret |
1413 | movl %ecx,%eax /* zero extend */ | 1368 | movl %ecx,%eax /* zero extend */ |
1414 | cmpq %rax,RIP+8(%rsp) | 1369 | cmpq %rax,RIP+8(%rsp) |
1415 | je bstep_iret | 1370 | je bstep_iret |
@@ -1420,7 +1375,15 @@ error_kernelspace: | |||
1420 | bstep_iret: | 1375 | bstep_iret: |
1421 | /* Fix truncated RIP */ | 1376 | /* Fix truncated RIP */ |
1422 | movq %rcx,RIP+8(%rsp) | 1377 | movq %rcx,RIP+8(%rsp) |
1423 | jmp error_swapgs | 1378 | /* fall through */ |
1379 | |||
1380 | error_bad_iret: | ||
1381 | SWAPGS | ||
1382 | mov %rsp,%rdi | ||
1383 | call fixup_bad_iret | ||
1384 | mov %rax,%rsp | ||
1385 | decl %ebx /* Return to usergs */ | ||
1386 | jmp error_sti | ||
1424 | CFI_ENDPROC | 1387 | CFI_ENDPROC |
1425 | END(error_entry) | 1388 | END(error_entry) |
1426 | 1389 | ||