.. | .. |
---|
18 | 18 | #include <linux/uaccess.h> |
---|
19 | 19 | #include <linux/smp.h> |
---|
20 | 20 | #include <linux/sched/task_stack.h> |
---|
| 21 | + |
---|
| 22 | +#include <asm/cpu_entry_area.h> |
---|
| 23 | +#include <asm/irq_stack.h> |
---|
21 | 24 | #include <asm/io_apic.h> |
---|
22 | 25 | #include <asm/apic.h> |
---|
23 | 26 | |
---|
24 | | -int sysctl_panic_on_stackoverflow; |
---|
| 27 | +DEFINE_PER_CPU_PAGE_ALIGNED(struct irq_stack, irq_stack_backing_store) __visible; |
---|
| 28 | +DECLARE_INIT_PER_CPU(irq_stack_backing_store); |
---|
25 | 29 | |
---|
| 30 | +#ifdef CONFIG_VMAP_STACK |
---|
26 | 31 | /* |
---|
27 | | - * Probabilistic stack overflow check: |
---|
28 | | - * |
---|
29 | | - * Regular device interrupts can enter on the following stacks: |
---|
30 | | - * |
---|
31 | | - * - User stack |
---|
32 | | - * |
---|
33 | | - * - Kernel task stack |
---|
34 | | - * |
---|
35 | | - * - Interrupt stack if a device driver reenables interrupts |
---|
36 | | - * which should only happen in really old drivers. |
---|
37 | | - * |
---|
38 | | - * - Debug IST stack |
---|
39 | | - * |
---|
40 | | - * All other contexts are invalid. |
---|
| 32 | + * VMAP the backing store with guard pages |
---|
41 | 33 | */ |
---|
42 | | -static inline void stack_overflow_check(struct pt_regs *regs) |
---|
| 34 | +static int map_irq_stack(unsigned int cpu) |
---|
43 | 35 | { |
---|
44 | | -#ifdef CONFIG_DEBUG_STACKOVERFLOW |
---|
45 | | -#define STACK_TOP_MARGIN 128 |
---|
46 | | - struct orig_ist *oist; |
---|
47 | | - u64 irq_stack_top, irq_stack_bottom; |
---|
48 | | - u64 estack_top, estack_bottom; |
---|
49 | | - u64 curbase = (u64)task_stack_page(current); |
---|
| 36 | + char *stack = (char *)per_cpu_ptr(&irq_stack_backing_store, cpu); |
---|
| 37 | + struct page *pages[IRQ_STACK_SIZE / PAGE_SIZE]; |
---|
| 38 | + void *va; |
---|
| 39 | + int i; |
---|
50 | 40 | |
---|
51 | | - if (user_mode(regs)) |
---|
52 | | - return; |
---|
| 41 | + for (i = 0; i < IRQ_STACK_SIZE / PAGE_SIZE; i++) { |
---|
| 42 | + phys_addr_t pa = per_cpu_ptr_to_phys(stack + (i << PAGE_SHIFT)); |
---|
53 | 43 | |
---|
54 | | - if (regs->sp >= curbase + sizeof(struct pt_regs) + STACK_TOP_MARGIN && |
---|
55 | | - regs->sp <= curbase + THREAD_SIZE) |
---|
56 | | - return; |
---|
| 44 | + pages[i] = pfn_to_page(pa >> PAGE_SHIFT); |
---|
| 45 | + } |
---|
57 | 46 | |
---|
58 | | - irq_stack_top = (u64)this_cpu_ptr(irq_stack_union.irq_stack) + |
---|
59 | | - STACK_TOP_MARGIN; |
---|
60 | | - irq_stack_bottom = (u64)__this_cpu_read(irq_stack_ptr); |
---|
61 | | - if (regs->sp >= irq_stack_top && regs->sp <= irq_stack_bottom) |
---|
62 | | - return; |
---|
| 47 | + va = vmap(pages, IRQ_STACK_SIZE / PAGE_SIZE, VM_MAP, PAGE_KERNEL); |
---|
| 48 | + if (!va) |
---|
| 49 | + return -ENOMEM; |
---|
63 | 50 | |
---|
64 | | - oist = this_cpu_ptr(&orig_ist); |
---|
65 | | - estack_bottom = (u64)oist->ist[DEBUG_STACK]; |
---|
66 | | - estack_top = estack_bottom - DEBUG_STKSZ + STACK_TOP_MARGIN; |
---|
67 | | - if (regs->sp >= estack_top && regs->sp <= estack_bottom) |
---|
68 | | - return; |
---|
| 51 | + per_cpu(hardirq_stack_ptr, cpu) = va + IRQ_STACK_SIZE; |
---|
| 52 | + return 0; |
---|
| 53 | +} |
---|
| 54 | +#else |
---|
| 55 | +/* |
---|
| 56 | + * If VMAP stacks are disabled due to KASAN, just use the per cpu |
---|
| 57 | + * backing store without guard pages. |
---|
| 58 | + */ |
---|
| 59 | +static int map_irq_stack(unsigned int cpu) |
---|
| 60 | +{ |
---|
| 61 | + void *va = per_cpu_ptr(&irq_stack_backing_store, cpu); |
---|
69 | 62 | |
---|
70 | | - WARN_ONCE(1, "do_IRQ(): %s has overflown the kernel stack (cur:%Lx,sp:%lx,irq stk top-bottom:%Lx-%Lx,exception stk top-bottom:%Lx-%Lx,ip:%pF)\n", |
---|
71 | | - current->comm, curbase, regs->sp, |
---|
72 | | - irq_stack_top, irq_stack_bottom, |
---|
73 | | - estack_top, estack_bottom, (void *)regs->ip); |
---|
74 | | - |
---|
75 | | - if (sysctl_panic_on_stackoverflow) |
---|
76 | | - panic("low stack detected by irq handler - check messages\n"); |
---|
| 63 | + per_cpu(hardirq_stack_ptr, cpu) = va + IRQ_STACK_SIZE; |
---|
| 64 | + return 0; |
---|
| 65 | +} |
---|
77 | 66 | #endif |
---|
| 67 | + |
---|
| 68 | +int irq_init_percpu_irqstack(unsigned int cpu) |
---|
| 69 | +{ |
---|
| 70 | + if (per_cpu(hardirq_stack_ptr, cpu)) |
---|
| 71 | + return 0; |
---|
| 72 | + return map_irq_stack(cpu); |
---|
78 | 73 | } |
---|
79 | 74 | |
---|
80 | | -bool handle_irq(struct irq_desc *desc, struct pt_regs *regs) |
---|
| 75 | +void do_softirq_own_stack(void) |
---|
81 | 76 | { |
---|
82 | | - stack_overflow_check(regs); |
---|
83 | | - |
---|
84 | | - if (IS_ERR_OR_NULL(desc)) |
---|
85 | | - return false; |
---|
86 | | - |
---|
87 | | - generic_handle_irq_desc(desc); |
---|
88 | | - return true; |
---|
| 77 | + run_on_irqstack_cond(__do_softirq, NULL); |
---|
89 | 78 | } |
---|