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.
Unified · Split
| @@ -20,7 +20,6 @@ · 19 unmodified lines | ||
| 20 | 20 | #define THREAD_SIZE_ORDER 1 |
| 21 | 21 | #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) |
| 22 | 22 | |
| 23 | −#define STACKFAULT_STACK 0 | |
| 24 | 23 | #define DOUBLEFAULT_STACK 1 |
| 25 | 24 | #define NMI_STACK 0 |
| 26 | 25 | #define DEBUG_STACK 0 |
| @@ -14,12 +14,11 @@ · 13 unmodified lines | ||
| 14 | 14 | #define IRQ_STACK_ORDER 2 |
| 15 | 15 | #define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER) |
| 16 | 16 | |
| 17 | −#define STACKFAULT_STACK 1 | |
| 18 | −#define DOUBLEFAULT_STACK 2 | |
| 19 | −#define NMI_STACK 3 | |
| 20 | −#define DEBUG_STACK 4 | |
| 21 | −#define MCE_STACK 5 | |
| 22 | −#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */ | |
| 17 | +#define DOUBLEFAULT_STACK 1 | |
| 18 | +#define NMI_STACK 2 | |
| 19 | +#define DEBUG_STACK 3 | |
| 20 | +#define MCE_STACK 4 | |
| 21 | +#define N_EXCEPTION_STACKS 4 /* hw limit: 7 */ | |
| 23 | 22 | |
| 24 | 23 | #define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT) |
| 25 | 24 | #define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1)) |
| @@ -39,6 +39,7 @@ asmlinkage void simd_coprocessor_error(void); · 38 unmodified lines | ||
| 39 | 39 | |
| 40 | 40 | #ifdef CONFIG_TRACING |
| 41 | 41 | asmlinkage void trace_page_fault(void); |
| 42 | +#define trace_stack_segment stack_segment | |
| 42 | 43 | #define trace_divide_error divide_error |
| 43 | 44 | #define trace_bounds bounds |
| 44 | 45 | #define trace_invalid_op invalid_op |
| @@ -24,7 +24,6 @@ static char x86_stack_ids[][8] = { · 23 unmodified lines | ||
| 24 | 24 | [ DEBUG_STACK-1 ] = "#DB", |
| 25 | 25 | [ NMI_STACK-1 ] = "NMI", |
| 26 | 26 | [ DOUBLEFAULT_STACK-1 ] = "#DF", |
| 27 | − [ STACKFAULT_STACK-1 ] = "#SS", | |
| 28 | 27 | [ MCE_STACK-1 ] = "#MC", |
| 29 | 28 | #if DEBUG_STKSZ > EXCEPTION_STKSZ |
| 30 | 29 | [ N_EXCEPTION_STACKS ... |
| @@ -1259,7 +1259,7 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \ · 1258 unmodified lines | ||
| 1259 | 1259 | |
| 1260 | 1260 | idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK |
| 1261 | 1261 | idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK |
| 1262 | −idtentry stack_segment do_stack_segment has_error_code=1 paranoid=1 | |
| 1262 | +idtentry stack_segment do_stack_segment has_error_code=1 | |
| 1263 | 1263 | #ifdef CONFIG_XEN |
| 1264 | 1264 | idtentry xen_debug do_debug has_error_code=0 |
| 1265 | 1265 | idtentry xen_int3 do_int3 has_error_code=0 |
| @@ -233,27 +233,11 @@ DO_ERROR(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op) · 232 unmodified lines | ||
| 233 | 233 | DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun) |
| 234 | 234 | DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS) |
| 235 | 235 | DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present) |
| 236 | −#ifdef CONFIG_X86_32 | |
| 237 | 236 | DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment) |
| 238 | −#endif | |
| 239 | 237 | DO_ERROR(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check) |
| 240 | 238 | |
| 241 | 239 | #ifdef CONFIG_X86_64 |
| 242 | 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 | 241 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) |
| 258 | 242 | { |
| 259 | 243 | static const char str[] = "double fault"; |
| @@ -802,7 +786,7 @@ void __init trap_init(void) · 542 unmodified lines | ||
| 802 | 786 | set_intr_gate(X86_TRAP_OLD_MF, coprocessor_segment_overrun); |
| 803 | 787 | set_intr_gate(X86_TRAP_TS, invalid_TSS); |
| 804 | 788 | set_intr_gate(X86_TRAP_NP, segment_not_present); |
| 805 | − set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK); | |
| 789 | + set_intr_gate(X86_TRAP_SS, stack_segment); | |
| 806 | 790 | set_intr_gate(X86_TRAP_GP, general_protection); |
| 807 | 791 | set_intr_gate(X86_TRAP_SPURIOUS, spurious_interrupt_bug); |
| 808 | 792 | set_intr_gate(X86_TRAP_MF, coprocessor_error); |