diff options
-rw-r--r-- | arch/parisc/Kconfig.debug | 11 | ||||
-rw-r--r-- | arch/parisc/include/asm/thread_info.h | 2 | ||||
-rw-r--r-- | arch/parisc/kernel/irq.c | 31 | ||||
-rw-r--r-- | arch/parisc/kernel/vmlinux.lds.S | 2 |
4 files changed, 42 insertions, 4 deletions
diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug index bc989e522a04..08a332f6ee87 100644 --- a/arch/parisc/Kconfig.debug +++ b/arch/parisc/Kconfig.debug | |||
@@ -13,3 +13,14 @@ config DEBUG_RODATA | |||
13 | If in doubt, say "N". | 13 | If in doubt, say "N". |
14 | 14 | ||
15 | endmenu | 15 | endmenu |
16 | |||
17 | config DEBUG_STACKOVERFLOW | ||
18 | bool "Check for stack overflows" | ||
19 | default y | ||
20 | depends on DEBUG_KERNEL | ||
21 | ---help--- | ||
22 | Say Y here if you want to check the overflows of kernel, IRQ | ||
23 | and exception stacks. This option will cause messages of the | ||
24 | stacks in detail when free stack space drops below a certain | ||
25 | limit. | ||
26 | If in doubt, say "N". | ||
diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h index 6182832e5b6c..540c88fa8f86 100644 --- a/arch/parisc/include/asm/thread_info.h +++ b/arch/parisc/include/asm/thread_info.h | |||
@@ -40,7 +40,7 @@ struct thread_info { | |||
40 | 40 | ||
41 | /* thread information allocation */ | 41 | /* thread information allocation */ |
42 | 42 | ||
43 | #define THREAD_SIZE_ORDER 2 | 43 | #define THREAD_SIZE_ORDER 2 /* PA-RISC requires at least 16k stack */ |
44 | /* Be sure to hunt all references to this down when you change the size of | 44 | /* Be sure to hunt all references to this down when you change the size of |
45 | * the kernel stack */ | 45 | * the kernel stack */ |
46 | #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) | 46 | #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) |
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 8094d3ed3b64..61e51ac85659 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c | |||
@@ -330,6 +330,34 @@ static inline int eirr_to_irq(unsigned long eirr) | |||
330 | return (BITS_PER_LONG - bit) + TIMER_IRQ; | 330 | return (BITS_PER_LONG - bit) + TIMER_IRQ; |
331 | } | 331 | } |
332 | 332 | ||
333 | int sysctl_panic_on_stackoverflow = 1; | ||
334 | |||
335 | static inline void stack_overflow_check(struct pt_regs *regs) | ||
336 | { | ||
337 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | ||
338 | #define STACK_MARGIN (256*6) | ||
339 | |||
340 | /* Our stack starts directly behind the thread_info struct. */ | ||
341 | unsigned long stack_start = (unsigned long) current_thread_info(); | ||
342 | unsigned long sp = regs->gr[30]; | ||
343 | |||
344 | /* if sr7 != 0, we interrupted a userspace process which we do not want | ||
345 | * to check for stack overflow. We will only check the kernel stack. */ | ||
346 | if (regs->sr[7]) | ||
347 | return; | ||
348 | |||
349 | if (likely((sp - stack_start) < (THREAD_SIZE - STACK_MARGIN))) | ||
350 | return; | ||
351 | |||
352 | pr_emerg("stackcheck: %s will most likely overflow kernel stack " | ||
353 | "(sp:%lx, stk bottom-top:%lx-%lx)\n", | ||
354 | current->comm, sp, stack_start, stack_start + THREAD_SIZE); | ||
355 | |||
356 | if (sysctl_panic_on_stackoverflow) | ||
357 | panic("low stack detected by irq handler - check messages\n"); | ||
358 | #endif | ||
359 | } | ||
360 | |||
333 | /* ONLY called from entry.S:intr_extint() */ | 361 | /* ONLY called from entry.S:intr_extint() */ |
334 | void do_cpu_irq_mask(struct pt_regs *regs) | 362 | void do_cpu_irq_mask(struct pt_regs *regs) |
335 | { | 363 | { |
@@ -364,6 +392,7 @@ void do_cpu_irq_mask(struct pt_regs *regs) | |||
364 | goto set_out; | 392 | goto set_out; |
365 | } | 393 | } |
366 | #endif | 394 | #endif |
395 | stack_overflow_check(regs); | ||
367 | generic_handle_irq(irq); | 396 | generic_handle_irq(irq); |
368 | 397 | ||
369 | out: | 398 | out: |
@@ -420,6 +449,4 @@ void __init init_IRQ(void) | |||
420 | cpu_eiem = EIEM_MASK(TIMER_IRQ); | 449 | cpu_eiem = EIEM_MASK(TIMER_IRQ); |
421 | #endif | 450 | #endif |
422 | set_eiem(cpu_eiem); /* EIEM : enable all external intr */ | 451 | set_eiem(cpu_eiem); /* EIEM : enable all external intr */ |
423 | |||
424 | } | 452 | } |
425 | |||
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 64a999882e4f..4bb095a2f6fc 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S | |||
@@ -95,7 +95,7 @@ SECTIONS | |||
95 | NOTES | 95 | NOTES |
96 | 96 | ||
97 | /* Data */ | 97 | /* Data */ |
98 | RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) | 98 | RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, PAGE_SIZE) |
99 | 99 | ||
100 | /* PA-RISC locks requires 16-byte alignment */ | 100 | /* PA-RISC locks requires 16-byte alignment */ |
101 | . = ALIGN(16); | 101 | . = ALIGN(16); |