sh: Provide diagnostic kernel stack checks
[deliverable/linux.git] / arch / sh / lib / mcount.S
index 71e87f9b4fdaca2037161bb1fb6941460e464414..8596483f7b4128b3ff0c25e372f45670d63fc910 100644 (file)
@@ -9,6 +9,8 @@
  * for more details.
  */
 #include <asm/ftrace.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
 
 #define MCOUNT_ENTER()         \
        mov.l   r4, @-r15;      \
        rts;                    \
         mov.l  @r15+, r4
 
+#ifdef CONFIG_STACK_DEBUG
+/*
+ * Perform diagnostic checks on the state of the kernel stack.
+ *
+ * Check for stack overflow. If there is less than 1KB free
+ * then it has overflowed.
+ *
+ * Make sure the stack pointer contains a valid address. Valid
+ * addresses for kernel stacks are anywhere after the bss
+ * (after _ebss) and anywhere in init_thread_union (init_stack).
+ */
+#define STACK_CHECK()                                  \
+       mov     #(THREAD_SIZE >> 10), r0;               \
+       shll8   r0;                                     \
+       shll2   r0;                                     \
+                                                       \
+       /* r1 = sp & (THREAD_SIZE - 1) */               \
+       mov     #-1, r1;                                \
+       add     r0, r1;                                 \
+       and     r15, r1;                                \
+                                                       \
+       mov     #TI_SIZE, r3;                           \
+       mov     #(STACK_WARN >> 8), r2;                 \
+       shll8   r2;                                     \
+       add     r3, r2;                                 \
+                                                       \
+       /* Is the stack overflowing? */                 \
+       cmp/hi  r2, r1;                                 \
+       bf      stack_panic;                            \
+                                                       \
+       /* If sp > _ebss then we're OK. */              \
+       mov.l   .L_ebss, r1;                            \
+       cmp/hi  r1, r15;                                \
+       bt      1f;                                     \
+                                                       \
+       /* If sp < init_stack, we're not OK. */         \
+       mov.l   .L_init_thread_union, r1;               \
+       cmp/hs  r1, r15;                                \
+       bf      stack_panic;                            \
+                                                       \
+       /* If sp > init_stack && sp < _ebss, not OK. */ \
+       add     r0, r1;                                 \
+       cmp/hs  r1, r15;                                \
+       bt      stack_panic;                            \
+1:
+#else
+#define STACK_CHECK()
+#endif /* CONFIG_STACK_DEBUG */
+
        .align 2
        .globl  _mcount
        .type   _mcount,@function
@@ -41,6 +92,8 @@ mcount:
        tst     r0, r0
        bf      ftrace_stub
 #endif
+       STACK_CHECK()
+
        MCOUNT_ENTER()
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -73,6 +126,8 @@ ftrace_caller:
        tst     r0, r0
        bf      ftrace_stub
 
+       STACK_CHECK()
+
        MCOUNT_ENTER()
 
        .globl ftrace_call
@@ -100,6 +155,36 @@ ftrace_stub:
        rts
         nop
 
+#ifdef CONFIG_STACK_DEBUG
+       .globl  stack_panic
+stack_panic:
+       mov.l   .Ldump_stack, r0
+       jsr     @r0
+        nop
+
+       mov.l   .Lpanic, r0
+       jsr     @r0
+        mov.l  .Lpanic_s, r4
+
+       rts
+        nop
+
        .align 2
 .Lfunction_trace_stop:
        .long   function_trace_stop
+.L_ebss:
+       .long   _ebss
+.L_init_thread_union:
+       .long   init_thread_union
+.Lpanic:
+       .long   panic
+.Lpanic_s:
+       .long   .Lpanic_str
+.Ldump_stack:
+       .long   dump_stack
+
+       .section        .rodata
+       .align 2
+.Lpanic_str:
+       .string "Stack error"
+#endif /* CONFIG_STACK_DEBUG */
This page took 0.02592 seconds and 5 git commands to generate.