| /* | |
| * arch/sh/lib/mcount.S | |
| * | |
| * Copyright (C) 2008, 2009 Paul Mundt | |
| * Copyright (C) 2008, 2009 Matt Fleming | |
| * | |
| * This file is subject to the terms and conditions of the GNU General Public | |
| * License. See the file "COPYING" in the main directory of this archive | |
| * for more details. | |
| */ | |
| #include <asm/ftrace.h> | |
| #include <asm/thread_info.h> | |
| #include <asm/asm-offsets.h> | |
| #define MCOUNT_ENTER() \ | |
| mov.l r4, @-r15; \ | |
| mov.l r5, @-r15; \ | |
| mov.l r6, @-r15; \ | |
| mov.l r7, @-r15; \ | |
| sts.l pr, @-r15; \ | |
| \ | |
| mov.l @(20,r15),r4; \ | |
| sts pr, r5 | |
| #define MCOUNT_LEAVE() \ | |
| lds.l @r15+, pr; \ | |
| mov.l @r15+, r7; \ | |
| mov.l @r15+, r6; \ | |
| mov.l @r15+, r5; \ | |
| 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 __bss_stop) 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 > __bss_stop 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 < __bss_stop, 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 | |
| .globl mcount | |
| .type mcount,@function | |
| _mcount: | |
| mcount: | |
| STACK_CHECK() | |
| #ifndef CONFIG_FUNCTION_TRACER | |
| rts | |
| nop | |
| #else | |
| MCOUNT_ENTER() | |
| #ifdef CONFIG_DYNAMIC_FTRACE | |
| .globl mcount_call | |
| mcount_call: | |
| mov.l .Lftrace_stub, r6 | |
| #else | |
| mov.l .Lftrace_trace_function, r6 | |
| mov.l ftrace_stub, r7 | |
| cmp/eq r6, r7 | |
| bt skip_trace | |
| mov.l @r6, r6 | |
| #endif | |
| jsr @r6 | |
| nop | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| mov.l .Lftrace_graph_return, r6 | |
| mov.l .Lftrace_stub, r7 | |
| cmp/eq r6, r7 | |
| bt 1f | |
| mov.l .Lftrace_graph_caller, r0 | |
| jmp @r0 | |
| nop | |
| 1: | |
| mov.l .Lftrace_graph_entry, r6 | |
| mov.l .Lftrace_graph_entry_stub, r7 | |
| cmp/eq r6, r7 | |
| bt skip_trace | |
| mov.l .Lftrace_graph_caller, r0 | |
| jmp @r0 | |
| nop | |
| .align 2 | |
| .Lftrace_graph_return: | |
| .long ftrace_graph_return | |
| .Lftrace_graph_entry: | |
| .long ftrace_graph_entry | |
| .Lftrace_graph_entry_stub: | |
| .long ftrace_graph_entry_stub | |
| .Lftrace_graph_caller: | |
| .long ftrace_graph_caller | |
| #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | |
| .globl skip_trace | |
| skip_trace: | |
| MCOUNT_LEAVE() | |
| .align 2 | |
| .Lftrace_trace_function: | |
| .long ftrace_trace_function | |
| #ifdef CONFIG_DYNAMIC_FTRACE | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| /* | |
| * NOTE: Do not move either ftrace_graph_call or ftrace_caller | |
| * as this will affect the calculation of GRAPH_INSN_OFFSET. | |
| */ | |
| .globl ftrace_graph_call | |
| ftrace_graph_call: | |
| mov.l .Lskip_trace, r0 | |
| jmp @r0 | |
| nop | |
| .align 2 | |
| .Lskip_trace: | |
| .long skip_trace | |
| #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | |
| .globl ftrace_caller | |
| ftrace_caller: | |
| MCOUNT_ENTER() | |
| .globl ftrace_call | |
| ftrace_call: | |
| mov.l .Lftrace_stub, r6 | |
| jsr @r6 | |
| nop | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| bra ftrace_graph_call | |
| nop | |
| #else | |
| MCOUNT_LEAVE() | |
| #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | |
| #endif /* CONFIG_DYNAMIC_FTRACE */ | |
| .align 2 | |
| /* | |
| * NOTE: From here on the locations of the .Lftrace_stub label and | |
| * ftrace_stub itself are fixed. Adding additional data here will skew | |
| * the displacement for the memory table and break the block replacement. | |
| * Place new labels either after the ftrace_stub body, or before | |
| * ftrace_caller. You have been warned. | |
| */ | |
| .Lftrace_stub: | |
| .long ftrace_stub | |
| .globl ftrace_stub | |
| ftrace_stub: | |
| rts | |
| nop | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| .globl ftrace_graph_caller | |
| ftrace_graph_caller: | |
| mov.l 2f, r1 | |
| jmp @r1 | |
| nop | |
| 1: | |
| /* | |
| * MCOUNT_ENTER() pushed 5 registers onto the stack, so | |
| * the stack address containing our return address is | |
| * r15 + 20. | |
| */ | |
| mov #20, r0 | |
| add r15, r0 | |
| mov r0, r4 | |
| mov.l .Lprepare_ftrace_return, r0 | |
| jsr @r0 | |
| nop | |
| MCOUNT_LEAVE() | |
| .align 2 | |
| 2: .long skip_trace | |
| .Lprepare_ftrace_return: | |
| .long prepare_ftrace_return | |
| .globl return_to_handler | |
| return_to_handler: | |
| /* | |
| * Save the return values. | |
| */ | |
| mov.l r0, @-r15 | |
| mov.l r1, @-r15 | |
| mov #0, r4 | |
| mov.l .Lftrace_return_to_handler, r0 | |
| jsr @r0 | |
| nop | |
| /* | |
| * The return value from ftrace_return_handler has the real | |
| * address that we should return to. | |
| */ | |
| lds r0, pr | |
| mov.l @r15+, r1 | |
| rts | |
| mov.l @r15+, r0 | |
| .align 2 | |
| .Lftrace_return_to_handler: | |
| .long ftrace_return_to_handler | |
| #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | |
| #endif /* CONFIG_FUNCTION_TRACER */ | |
| #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 | |
| .L_init_thread_union: | |
| .long init_thread_union | |
| .L_ebss: | |
| .long __bss_stop | |
| .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 */ |