/* * Copyright 2012 Tilera Corporation. All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT. See the GNU General Public License for * more details. * * TILE-Gx specific __mcount support */ #include <linux/linkage.h> #include <asm/ftrace.h> #define REGSIZE 8 .text .global __mcount .macro MCOUNT_SAVE_REGS addli sp, sp, -REGSIZE { st sp, lr addli r29, sp, - (12 * REGSIZE) } { addli sp, sp, - (13 * REGSIZE) st r29, sp } addli r29, r29, REGSIZE { st r29, r0; addli r29, r29, REGSIZE } { st r29, r1; addli r29, r29, REGSIZE } { st r29, r2; addli r29, r29, REGSIZE } { st r29, r3; addli r29, r29, REGSIZE } { st r29, r4; addli r29, r29, REGSIZE } { st r29, r5; addli r29, r29, REGSIZE } { st r29, r6; addli r29, r29, REGSIZE } { st r29, r7; addli r29, r29, REGSIZE } { st r29, r8; addli r29, r29, REGSIZE } { st r29, r9; addli r29, r29, REGSIZE } { st r29, r10; addli r29, r29, REGSIZE } .endm .macro MCOUNT_RESTORE_REGS addli r29, sp, (2 * REGSIZE) { ld r0, r29; addli r29, r29, REGSIZE } { ld r1, r29; addli r29, r29, REGSIZE } { ld r2, r29; addli r29, r29, REGSIZE } { ld r3, r29; addli r29, r29, REGSIZE } { ld r4, r29; addli r29, r29, REGSIZE } { ld r5, r29; addli r29, r29, REGSIZE } { ld r6, r29; addli r29, r29, REGSIZE } { ld r7, r29; addli r29, r29, REGSIZE } { ld r8, r29; addli r29, r29, REGSIZE } { ld r9, r29; addli r29, r29, REGSIZE } { ld r10, r29; addli lr, sp, (13 * REGSIZE) } { ld lr, lr; addli sp, sp, (14 * REGSIZE) } .endm .macro RETURN_BACK { move r12, lr; move lr, r10 } jrp r12 .endm #ifdef CONFIG_DYNAMIC_FTRACE .align 64 STD_ENTRY(__mcount) __mcount: j ftrace_stub STD_ENDPROC(__mcount) .align 64 STD_ENTRY(ftrace_caller) MCOUNT_SAVE_REGS /* arg1: self return address */ /* arg2: parent's return address */ /* arg3: ftrace_ops */ /* arg4: regs (but make it NULL) */ { move r0, lr; moveli r2, hw2_last(function_trace_op) } { move r1, r10; shl16insli r2, r2, hw1(function_trace_op) } { movei r3, 0; shl16insli r2, r2, hw0(function_trace_op) } ld r2,r2 .global ftrace_call ftrace_call: /* * a placeholder for the call to a real tracing function, i.e. * ftrace_trace_function() */ nop #ifdef CONFIG_FUNCTION_GRAPH_TRACER .global ftrace_graph_call ftrace_graph_call: /* * a placeholder for the call to a real tracing function, i.e. * ftrace_graph_caller() */ nop #endif MCOUNT_RESTORE_REGS .global ftrace_stub ftrace_stub: RETURN_BACK STD_ENDPROC(ftrace_caller) #else /* ! CONFIG_DYNAMIC_FTRACE */ .align 64 STD_ENTRY(__mcount) { moveli r11, hw2_last(ftrace_trace_function) moveli r13, hw2_last(ftrace_stub) } { shl16insli r11, r11, hw1(ftrace_trace_function) shl16insli r13, r13, hw1(ftrace_stub) } { shl16insli r11, r11, hw0(ftrace_trace_function) shl16insli r13, r13, hw0(ftrace_stub) } ld r11, r11 sub r14, r13, r11 bnez r14, static_trace #ifdef CONFIG_FUNCTION_GRAPH_TRACER moveli r15, hw2_last(ftrace_graph_return) shl16insli r15, r15, hw1(ftrace_graph_return) shl16insli r15, r15, hw0(ftrace_graph_return) ld r15, r15 sub r15, r15, r13 bnez r15, ftrace_graph_caller { moveli r16, hw2_last(ftrace_graph_entry) moveli r17, hw2_last(ftrace_graph_entry_stub) } { shl16insli r16, r16, hw1(ftrace_graph_entry) shl16insli r17, r17, hw1(ftrace_graph_entry_stub) } { shl16insli r16, r16, hw0(ftrace_graph_entry) shl16insli r17, r17, hw0(ftrace_graph_entry_stub) } ld r16, r16 sub r17, r16, r17 bnez r17, ftrace_graph_caller #endif RETURN_BACK static_trace: MCOUNT_SAVE_REGS /* arg1: self return address */ /* arg2: parent's return address */ { move r0, lr; move r1, r10 } /* call ftrace_trace_function() */ jalr r11 MCOUNT_RESTORE_REGS .global ftrace_stub ftrace_stub: RETURN_BACK STD_ENDPROC(__mcount) #endif /* ! CONFIG_DYNAMIC_FTRACE */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER STD_ENTRY(ftrace_graph_caller) ftrace_graph_caller: #ifndef CONFIG_DYNAMIC_FTRACE MCOUNT_SAVE_REGS #endif /* arg1: Get the location of the parent's return address */ addi r0, sp, 12 * REGSIZE /* arg2: Get self return address */ move r1, lr jal prepare_ftrace_return MCOUNT_RESTORE_REGS RETURN_BACK STD_ENDPROC(ftrace_graph_caller) .global return_to_handler return_to_handler: MCOUNT_SAVE_REGS jal ftrace_return_to_handler /* restore the real parent address */ move r11, r0 MCOUNT_RESTORE_REGS jr r11 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */