diff options
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/microcode/core.c | 10 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c | 49 | ||||
-rw-r--r-- | arch/x86/kernel/dumpstack_64.c | 1 | ||||
-rw-r--r-- | arch/x86/kernel/entry_64.S | 81 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/traps.c | 71 |
7 files changed, 134 insertions, 82 deletions
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 4b4f78c9ba19..cfa9b5b2c27a 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -146,6 +146,8 @@ EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); | |||
146 | 146 | ||
147 | static int __init x86_xsave_setup(char *s) | 147 | static int __init x86_xsave_setup(char *s) |
148 | { | 148 | { |
149 | if (strlen(s)) | ||
150 | return 0; | ||
149 | setup_clear_cpu_cap(X86_FEATURE_XSAVE); | 151 | setup_clear_cpu_cap(X86_FEATURE_XSAVE); |
150 | setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); | 152 | setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT); |
151 | setup_clear_cpu_cap(X86_FEATURE_XSAVES); | 153 | setup_clear_cpu_cap(X86_FEATURE_XSAVES); |
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index dd9d6190b08d..08fe6e8a726e 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c | |||
@@ -465,6 +465,16 @@ static void mc_bp_resume(void) | |||
465 | 465 | ||
466 | if (uci->valid && uci->mc) | 466 | if (uci->valid && uci->mc) |
467 | microcode_ops->apply_microcode(cpu); | 467 | microcode_ops->apply_microcode(cpu); |
468 | #ifdef CONFIG_X86_64 | ||
469 | else if (!uci->mc) | ||
470 | /* | ||
471 | * We might resume and not have applied late microcode but still | ||
472 | * have a newer patch stashed from the early loader. We don't | ||
473 | * have it in uci->mc so we have to load it the same way we're | ||
474 | * applying patches early on the APs. | ||
475 | */ | ||
476 | load_ucode_ap(); | ||
477 | #endif | ||
468 | } | 478 | } |
469 | 479 | ||
470 | static struct syscore_ops mc_syscore_ops = { | 480 | static struct syscore_ops mc_syscore_ops = { |
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c index adf138eac85c..f9ed429d6e4f 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c | |||
@@ -486,14 +486,17 @@ static struct attribute_group snbep_uncore_qpi_format_group = { | |||
486 | .attrs = snbep_uncore_qpi_formats_attr, | 486 | .attrs = snbep_uncore_qpi_formats_attr, |
487 | }; | 487 | }; |
488 | 488 | ||
489 | #define SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \ | 489 | #define __SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \ |
490 | .init_box = snbep_uncore_msr_init_box, \ | ||
491 | .disable_box = snbep_uncore_msr_disable_box, \ | 490 | .disable_box = snbep_uncore_msr_disable_box, \ |
492 | .enable_box = snbep_uncore_msr_enable_box, \ | 491 | .enable_box = snbep_uncore_msr_enable_box, \ |
493 | .disable_event = snbep_uncore_msr_disable_event, \ | 492 | .disable_event = snbep_uncore_msr_disable_event, \ |
494 | .enable_event = snbep_uncore_msr_enable_event, \ | 493 | .enable_event = snbep_uncore_msr_enable_event, \ |
495 | .read_counter = uncore_msr_read_counter | 494 | .read_counter = uncore_msr_read_counter |
496 | 495 | ||
496 | #define SNBEP_UNCORE_MSR_OPS_COMMON_INIT() \ | ||
497 | __SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), \ | ||
498 | .init_box = snbep_uncore_msr_init_box \ | ||
499 | |||
497 | static struct intel_uncore_ops snbep_uncore_msr_ops = { | 500 | static struct intel_uncore_ops snbep_uncore_msr_ops = { |
498 | SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), | 501 | SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), |
499 | }; | 502 | }; |
@@ -1919,6 +1922,30 @@ static struct intel_uncore_type hswep_uncore_cbox = { | |||
1919 | .format_group = &hswep_uncore_cbox_format_group, | 1922 | .format_group = &hswep_uncore_cbox_format_group, |
1920 | }; | 1923 | }; |
1921 | 1924 | ||
1925 | /* | ||
1926 | * Write SBOX Initialization register bit by bit to avoid spurious #GPs | ||
1927 | */ | ||
1928 | static void hswep_uncore_sbox_msr_init_box(struct intel_uncore_box *box) | ||
1929 | { | ||
1930 | unsigned msr = uncore_msr_box_ctl(box); | ||
1931 | |||
1932 | if (msr) { | ||
1933 | u64 init = SNBEP_PMON_BOX_CTL_INT; | ||
1934 | u64 flags = 0; | ||
1935 | int i; | ||
1936 | |||
1937 | for_each_set_bit(i, (unsigned long *)&init, 64) { | ||
1938 | flags |= (1ULL << i); | ||
1939 | wrmsrl(msr, flags); | ||
1940 | } | ||
1941 | } | ||
1942 | } | ||
1943 | |||
1944 | static struct intel_uncore_ops hswep_uncore_sbox_msr_ops = { | ||
1945 | __SNBEP_UNCORE_MSR_OPS_COMMON_INIT(), | ||
1946 | .init_box = hswep_uncore_sbox_msr_init_box | ||
1947 | }; | ||
1948 | |||
1922 | static struct attribute *hswep_uncore_sbox_formats_attr[] = { | 1949 | static struct attribute *hswep_uncore_sbox_formats_attr[] = { |
1923 | &format_attr_event.attr, | 1950 | &format_attr_event.attr, |
1924 | &format_attr_umask.attr, | 1951 | &format_attr_umask.attr, |
@@ -1944,7 +1971,7 @@ static struct intel_uncore_type hswep_uncore_sbox = { | |||
1944 | .event_mask = HSWEP_S_MSR_PMON_RAW_EVENT_MASK, | 1971 | .event_mask = HSWEP_S_MSR_PMON_RAW_EVENT_MASK, |
1945 | .box_ctl = HSWEP_S0_MSR_PMON_BOX_CTL, | 1972 | .box_ctl = HSWEP_S0_MSR_PMON_BOX_CTL, |
1946 | .msr_offset = HSWEP_SBOX_MSR_OFFSET, | 1973 | .msr_offset = HSWEP_SBOX_MSR_OFFSET, |
1947 | .ops = &snbep_uncore_msr_ops, | 1974 | .ops = &hswep_uncore_sbox_msr_ops, |
1948 | .format_group = &hswep_uncore_sbox_format_group, | 1975 | .format_group = &hswep_uncore_sbox_format_group, |
1949 | }; | 1976 | }; |
1950 | 1977 | ||
@@ -2025,13 +2052,27 @@ static struct intel_uncore_type hswep_uncore_imc = { | |||
2025 | SNBEP_UNCORE_PCI_COMMON_INIT(), | 2052 | SNBEP_UNCORE_PCI_COMMON_INIT(), |
2026 | }; | 2053 | }; |
2027 | 2054 | ||
2055 | static unsigned hswep_uncore_irp_ctrs[] = {0xa0, 0xa8, 0xb0, 0xb8}; | ||
2056 | |||
2057 | static u64 hswep_uncore_irp_read_counter(struct intel_uncore_box *box, struct perf_event *event) | ||
2058 | { | ||
2059 | struct pci_dev *pdev = box->pci_dev; | ||
2060 | struct hw_perf_event *hwc = &event->hw; | ||
2061 | u64 count = 0; | ||
2062 | |||
2063 | pci_read_config_dword(pdev, hswep_uncore_irp_ctrs[hwc->idx], (u32 *)&count); | ||
2064 | pci_read_config_dword(pdev, hswep_uncore_irp_ctrs[hwc->idx] + 4, (u32 *)&count + 1); | ||
2065 | |||
2066 | return count; | ||
2067 | } | ||
2068 | |||
2028 | static struct intel_uncore_ops hswep_uncore_irp_ops = { | 2069 | static struct intel_uncore_ops hswep_uncore_irp_ops = { |
2029 | .init_box = snbep_uncore_pci_init_box, | 2070 | .init_box = snbep_uncore_pci_init_box, |
2030 | .disable_box = snbep_uncore_pci_disable_box, | 2071 | .disable_box = snbep_uncore_pci_disable_box, |
2031 | .enable_box = snbep_uncore_pci_enable_box, | 2072 | .enable_box = snbep_uncore_pci_enable_box, |
2032 | .disable_event = ivbep_uncore_irp_disable_event, | 2073 | .disable_event = ivbep_uncore_irp_disable_event, |
2033 | .enable_event = ivbep_uncore_irp_enable_event, | 2074 | .enable_event = ivbep_uncore_irp_enable_event, |
2034 | .read_counter = ivbep_uncore_irp_read_counter, | 2075 | .read_counter = hswep_uncore_irp_read_counter, |
2035 | }; | 2076 | }; |
2036 | 2077 | ||
2037 | static struct intel_uncore_type hswep_uncore_irp = { | 2078 | static struct intel_uncore_type hswep_uncore_irp = { |
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 1abcb50b48ae..ff86f19b5758 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c | |||
@@ -24,7 +24,6 @@ static char x86_stack_ids[][8] = { | |||
24 | [ DEBUG_STACK-1 ] = "#DB", | 24 | [ DEBUG_STACK-1 ] = "#DB", |
25 | [ NMI_STACK-1 ] = "NMI", | 25 | [ NMI_STACK-1 ] = "NMI", |
26 | [ DOUBLEFAULT_STACK-1 ] = "#DF", | 26 | [ DOUBLEFAULT_STACK-1 ] = "#DF", |
27 | [ STACKFAULT_STACK-1 ] = "#SS", | ||
28 | [ MCE_STACK-1 ] = "#MC", | 27 | [ MCE_STACK-1 ] = "#MC", |
29 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | 28 | #if DEBUG_STKSZ > EXCEPTION_STKSZ |
30 | [ N_EXCEPTION_STACKS ... | 29 | [ N_EXCEPTION_STACKS ... |
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 | ||
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 749b0e423419..e510618b2e91 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
@@ -1484,7 +1484,7 @@ unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch) | |||
1484 | */ | 1484 | */ |
1485 | if (work & _TIF_NOHZ) { | 1485 | if (work & _TIF_NOHZ) { |
1486 | user_exit(); | 1486 | user_exit(); |
1487 | work &= ~TIF_NOHZ; | 1487 | work &= ~_TIF_NOHZ; |
1488 | } | 1488 | } |
1489 | 1489 | ||
1490 | #ifdef CONFIG_SECCOMP | 1490 | #ifdef CONFIG_SECCOMP |
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 0d0e922fafc1..de801f22128a 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c | |||
@@ -233,32 +233,40 @@ DO_ERROR(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op) | |||
233 | DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun) | 233 | DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun) |
234 | DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS) | 234 | DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS) |
235 | DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present) | 235 | DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present) |
236 | #ifdef CONFIG_X86_32 | ||
237 | DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment) | 236 | DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment) |
238 | #endif | ||
239 | DO_ERROR(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check) | 237 | DO_ERROR(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check) |
240 | 238 | ||
241 | #ifdef CONFIG_X86_64 | 239 | #ifdef CONFIG_X86_64 |
242 | /* Runs on IST stack */ | 240 | /* Runs on IST stack */ |
243 | dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) | ||
244 | { | ||
245 | enum ctx_state prev_state; | ||
246 | |||
247 | prev_state = exception_enter(); | ||
248 | if (notify_die(DIE_TRAP, "stack segment", regs, error_code, | ||
249 | X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) { | ||
250 | preempt_conditional_sti(regs); | ||
251 | do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL); | ||
252 | preempt_conditional_cli(regs); | ||
253 | } | ||
254 | exception_exit(prev_state); | ||
255 | } | ||
256 | |||
257 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) | 241 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) |
258 | { | 242 | { |
259 | static const char str[] = "double fault"; | 243 | static const char str[] = "double fault"; |
260 | struct task_struct *tsk = current; | 244 | struct task_struct *tsk = current; |
261 | 245 | ||
246 | #ifdef CONFIG_X86_ESPFIX64 | ||
247 | extern unsigned char native_irq_return_iret[]; | ||
248 | |||
249 | /* | ||
250 | * If IRET takes a non-IST fault on the espfix64 stack, then we | ||
251 | * end up promoting it to a doublefault. In that case, modify | ||
252 | * the stack to make it look like we just entered the #GP | ||
253 | * handler from user space, similar to bad_iret. | ||
254 | */ | ||
255 | if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY && | ||
256 | regs->cs == __KERNEL_CS && | ||
257 | regs->ip == (unsigned long)native_irq_return_iret) | ||
258 | { | ||
259 | struct pt_regs *normal_regs = task_pt_regs(current); | ||
260 | |||
261 | /* Fake a #GP(0) from userspace. */ | ||
262 | memmove(&normal_regs->ip, (void *)regs->sp, 5*8); | ||
263 | normal_regs->orig_ax = 0; /* Missing (lost) #GP error code */ | ||
264 | regs->ip = (unsigned long)general_protection; | ||
265 | regs->sp = (unsigned long)&normal_regs->orig_ax; | ||
266 | return; | ||
267 | } | ||
268 | #endif | ||
269 | |||
262 | exception_enter(); | 270 | exception_enter(); |
263 | /* Return not checked because double check cannot be ignored */ | 271 | /* Return not checked because double check cannot be ignored */ |
264 | notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV); | 272 | notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV); |
@@ -399,6 +407,35 @@ asmlinkage __visible struct pt_regs *sync_regs(struct pt_regs *eregs) | |||
399 | return regs; | 407 | return regs; |
400 | } | 408 | } |
401 | NOKPROBE_SYMBOL(sync_regs); | 409 | NOKPROBE_SYMBOL(sync_regs); |
410 | |||
411 | struct bad_iret_stack { | ||
412 | void *error_entry_ret; | ||
413 | struct pt_regs regs; | ||
414 | }; | ||
415 | |||
416 | asmlinkage __visible | ||
417 | struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s) | ||
418 | { | ||
419 | /* | ||
420 | * This is called from entry_64.S early in handling a fault | ||
421 | * caused by a bad iret to user mode. To handle the fault | ||
422 | * correctly, we want move our stack frame to task_pt_regs | ||
423 | * and we want to pretend that the exception came from the | ||
424 | * iret target. | ||
425 | */ | ||
426 | struct bad_iret_stack *new_stack = | ||
427 | container_of(task_pt_regs(current), | ||
428 | struct bad_iret_stack, regs); | ||
429 | |||
430 | /* Copy the IRET target to the new stack. */ | ||
431 | memmove(&new_stack->regs.ip, (void *)s->regs.sp, 5*8); | ||
432 | |||
433 | /* Copy the remainder of the stack from the current stack. */ | ||
434 | memmove(new_stack, s, offsetof(struct bad_iret_stack, regs.ip)); | ||
435 | |||
436 | BUG_ON(!user_mode_vm(&new_stack->regs)); | ||
437 | return new_stack; | ||
438 | } | ||
402 | #endif | 439 | #endif |
403 | 440 | ||
404 | /* | 441 | /* |
@@ -778,7 +815,7 @@ void __init trap_init(void) | |||
778 | set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun); | 815 | set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun); |
779 | set_intr_gate(X86_TRAP_TS, invalid_TSS); | 816 | set_intr_gate(X86_TRAP_TS, invalid_TSS); |
780 | set_intr_gate(X86_TRAP_NP, segment_not_present); | 817 | set_intr_gate(X86_TRAP_NP, segment_not_present); |
781 | set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK); | 818 | set_intr_gate(X86_TRAP_SS, stack_segment); |
782 | set_intr_gate(X86_TRAP_GP, general_protection); | 819 | set_intr_gate(X86_TRAP_GP, general_protection); |
783 | set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug); | 820 | set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug); |
784 | set_intr_gate(X86_TRAP_MF, coprocessor_error); | 821 | set_intr_gate(X86_TRAP_MF, coprocessor_error); |