| From 6f442be2fb22be02cafa606f1769fa1e6f894441 Mon Sep 17 00:00:00 2001 |
| From: Andy Lutomirski <luto@amacapital.net> |
| Date: Sat, 22 Nov 2014 18:00:32 -0800 |
| Subject: x86_64, traps: Stop using IST for #SS |
| |
| From: Andy Lutomirski <luto@amacapital.net> |
| |
| commit 6f442be2fb22be02cafa606f1769fa1e6f894441 upstream. |
| |
| On a 32-bit kernel, this has no effect, since there are no IST stacks. |
| |
| On a 64-bit kernel, #SS can only happen in user code, on a failed iret |
| to user space, a canonical violation on access via RSP or RBP, or a |
| genuine stack segment violation in 32-bit kernel code. The first two |
| cases don't need IST, and the latter two cases are unlikely fatal bugs, |
| and promoting them to double faults would be fine. |
| |
| This fixes a bug in which the espfix64 code mishandles a stack segment |
| violation. |
| |
| This saves 4k of memory per CPU and a tiny bit of code. |
| |
| Signed-off-by: Andy Lutomirski <luto@amacapital.net> |
| Reviewed-by: Thomas Gleixner <tglx@linutronix.de> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/include/asm/page_32_types.h | 1 - |
| arch/x86/include/asm/page_64_types.h | 11 +++++------ |
| arch/x86/include/asm/traps.h | 1 + |
| arch/x86/kernel/dumpstack_64.c | 1 - |
| arch/x86/kernel/entry_64.S | 2 +- |
| arch/x86/kernel/traps.c | 18 +----------------- |
| 6 files changed, 8 insertions(+), 26 deletions(-) |
| |
| --- a/arch/x86/include/asm/page_32_types.h |
| +++ b/arch/x86/include/asm/page_32_types.h |
| @@ -20,7 +20,6 @@ |
| #define THREAD_SIZE_ORDER 1 |
| #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) |
| |
| -#define STACKFAULT_STACK 0 |
| #define DOUBLEFAULT_STACK 1 |
| #define NMI_STACK 0 |
| #define DEBUG_STACK 0 |
| --- a/arch/x86/include/asm/page_64_types.h |
| +++ b/arch/x86/include/asm/page_64_types.h |
| @@ -14,12 +14,11 @@ |
| #define IRQ_STACK_ORDER 2 |
| #define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER) |
| |
| -#define STACKFAULT_STACK 1 |
| -#define DOUBLEFAULT_STACK 2 |
| -#define NMI_STACK 3 |
| -#define DEBUG_STACK 4 |
| -#define MCE_STACK 5 |
| -#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */ |
| +#define DOUBLEFAULT_STACK 1 |
| +#define NMI_STACK 2 |
| +#define DEBUG_STACK 3 |
| +#define MCE_STACK 4 |
| +#define N_EXCEPTION_STACKS 4 /* hw limit: 7 */ |
| |
| #define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT) |
| #define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1)) |
| --- a/arch/x86/include/asm/traps.h |
| +++ b/arch/x86/include/asm/traps.h |
| @@ -39,6 +39,7 @@ asmlinkage void simd_coprocessor_error(v |
| |
| #ifdef CONFIG_TRACING |
| asmlinkage void trace_page_fault(void); |
| +#define trace_stack_segment stack_segment |
| #define trace_divide_error divide_error |
| #define trace_bounds bounds |
| #define trace_invalid_op invalid_op |
| --- a/arch/x86/kernel/dumpstack_64.c |
| +++ b/arch/x86/kernel/dumpstack_64.c |
| @@ -24,7 +24,6 @@ static char x86_stack_ids[][8] = { |
| [ DEBUG_STACK-1 ] = "#DB", |
| [ NMI_STACK-1 ] = "NMI", |
| [ DOUBLEFAULT_STACK-1 ] = "#DF", |
| - [ STACKFAULT_STACK-1 ] = "#SS", |
| [ MCE_STACK-1 ] = "#MC", |
| #if DEBUG_STKSZ > EXCEPTION_STKSZ |
| [ N_EXCEPTION_STACKS ... |
| --- a/arch/x86/kernel/entry_64.S |
| +++ b/arch/x86/kernel/entry_64.S |
| @@ -1519,7 +1519,7 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTO |
| |
| paranoidzeroentry_ist debug do_debug DEBUG_STACK |
| paranoidzeroentry_ist int3 do_int3 DEBUG_STACK |
| -paranoiderrorentry stack_segment do_stack_segment |
| +errorentry stack_segment do_stack_segment |
| #ifdef CONFIG_XEN |
| zeroentry xen_debug do_debug |
| zeroentry xen_int3 do_int3 |
| --- a/arch/x86/kernel/traps.c |
| +++ b/arch/x86/kernel/traps.c |
| @@ -218,27 +218,11 @@ DO_ERROR_INFO(X86_TRAP_UD, SIGILL, |
| DO_ERROR (X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun ) |
| DO_ERROR (X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS ) |
| DO_ERROR (X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present ) |
| -#ifdef CONFIG_X86_32 |
| DO_ERROR (X86_TRAP_SS, SIGBUS, "stack segment", stack_segment ) |
| -#endif |
| DO_ERROR_INFO(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0 ) |
| |
| #ifdef CONFIG_X86_64 |
| /* Runs on IST stack */ |
| -dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) |
| -{ |
| - enum ctx_state prev_state; |
| - |
| - prev_state = exception_enter(); |
| - if (notify_die(DIE_TRAP, "stack segment", regs, error_code, |
| - X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) { |
| - preempt_conditional_sti(regs); |
| - do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL); |
| - preempt_conditional_cli(regs); |
| - } |
| - exception_exit(prev_state); |
| -} |
| - |
| dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) |
| { |
| static const char str[] = "double fault"; |
| @@ -772,7 +756,7 @@ void __init trap_init(void) |
| set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun); |
| set_intr_gate(X86_TRAP_TS, invalid_TSS); |
| set_intr_gate(X86_TRAP_NP, segment_not_present); |
| - set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK); |
| + set_intr_gate(X86_TRAP_SS, stack_segment); |
| set_intr_gate(X86_TRAP_GP, general_protection); |
| set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug); |
| set_intr_gate(X86_TRAP_MF, coprocessor_error); |