/* * Low-level ftrace handling * * Copyright (C) 2009 Michal Simek * Copyright (C) 2009 PetaLogix * * 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 #define NOALIGN_ENTRY(name) .globl name; name: /* FIXME MS: I think that I don't need to save all regs */ #define SAVE_REGS \ addik r1, r1, -120; \ swi r2, r1, 4; \ swi r3, r1, 8; \ swi r4, r1, 12; \ swi r5, r1, 116; \ swi r6, r1, 16; \ swi r7, r1, 20; \ swi r8, r1, 24; \ swi r9, r1, 28; \ swi r10, r1, 32; \ swi r11, r1, 36; \ swi r12, r1, 40; \ swi r13, r1, 44; \ swi r14, r1, 48; \ swi r16, r1, 52; \ swi r17, r1, 56; \ swi r18, r1, 60; \ swi r19, r1, 64; \ swi r20, r1, 68; \ swi r21, r1, 72; \ swi r22, r1, 76; \ swi r23, r1, 80; \ swi r24, r1, 84; \ swi r25, r1, 88; \ swi r26, r1, 92; \ swi r27, r1, 96; \ swi r28, r1, 100; \ swi r29, r1, 104; \ swi r30, r1, 108; \ swi r31, r1, 112; #define RESTORE_REGS \ lwi r2, r1, 4; \ lwi r3, r1, 8; \ lwi r4, r1, 12; \ lwi r5, r1, 116; \ lwi r6, r1, 16; \ lwi r7, r1, 20; \ lwi r8, r1, 24; \ lwi r9, r1, 28; \ lwi r10, r1, 32; \ lwi r11, r1, 36; \ lwi r12, r1, 40; \ lwi r13, r1, 44; \ lwi r14, r1, 48; \ lwi r16, r1, 52; \ lwi r17, r1, 56; \ lwi r18, r1, 60; \ lwi r19, r1, 64; \ lwi r20, r1, 68; \ lwi r21, r1, 72; \ lwi r22, r1, 76; \ lwi r23, r1, 80; \ lwi r24, r1, 84; \ lwi r25, r1, 88; \ lwi r26, r1, 92; \ lwi r27, r1, 96; \ lwi r28, r1, 100; \ lwi r29, r1, 104; \ lwi r30, r1, 108; \ lwi r31, r1, 112; \ addik r1, r1, 120; ENTRY(ftrace_stub) rtsd r15, 8; nop; ENTRY(_mcount) #ifdef CONFIG_DYNAMIC_FTRACE ENTRY(ftrace_caller) /* MS: It is just barrier which is removed from C code */ rtsd r15, 8 nop #endif /* CONFIG_DYNAMIC_FTRACE */ SAVE_REGS swi r15, r1, 0; /* MS: HAVE_FUNCTION_TRACE_MCOUNT_TEST begin of checking */ lwi r5, r0, function_trace_stop; bneid r5, end; nop; /* MS: HAVE_FUNCTION_TRACE_MCOUNT_TEST end of checking */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER #ifndef CONFIG_DYNAMIC_FTRACE lwi r5, r0, ftrace_graph_return; addik r6, r0, ftrace_stub; /* asm implementation */ cmpu r5, r5, r6; /* ftrace_graph_return != ftrace_stub */ beqid r5, end_graph_tracer; nop; lwi r6, r0, ftrace_graph_entry; addik r5, r0, ftrace_graph_entry_stub; /* implemented in C */ cmpu r5, r5, r6; /* ftrace_graph_entry != ftrace_graph_entry_stub */ beqid r5, end_graph_tracer; nop; #else /* CONFIG_DYNAMIC_FTRACE */ NOALIGN_ENTRY(ftrace_call_graph) /* MS: jump over graph function - replaced from C code */ bri end_graph_tracer #endif /* CONFIG_DYNAMIC_FTRACE */ addik r5, r1, 120; /* MS: load parent addr */ addik r6, r15, 0; /* MS: load current function addr */ bralid r15, prepare_ftrace_return; nop; /* MS: graph was taken that's why - can jump over function trace */ brid end; nop; end_graph_tracer: #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ #ifndef CONFIG_DYNAMIC_FTRACE /* MS: test function trace if is taken or not */ lwi r20, r0, ftrace_trace_function; addik r6, r0, ftrace_stub; cmpu r5, r20, r6; /* ftrace_trace_function != ftrace_stub */ beqid r5, end; /* MS: not taken -> jump over */ nop; #else /* CONFIG_DYNAMIC_FTRACE */ NOALIGN_ENTRY(ftrace_call) /* instruction for setup imm FUNC_part1, addik r20, r0, FUNC_part2 */ nop nop #endif /* CONFIG_DYNAMIC_FTRACE */ /* static normal trace */ lwi r6, r1, 120; /* MS: load parent addr */ addik r5, r15, 0; /* MS: load current function addr */ /* MS: here is dependency on previous code */ brald r15, r20; /* MS: jump to ftrace handler */ nop; end: lwi r15, r1, 0; RESTORE_REGS rtsd r15, 8; /* MS: jump back */ nop; #ifdef CONFIG_FUNCTION_GRAPH_TRACER ENTRY(return_to_handler) nop; /* MS: just barrier for rtsd r15, 8 */ nop; SAVE_REGS swi r15, r1, 0; /* MS: find out returning address */ bralid r15, ftrace_return_to_handler; nop; /* MS: return value from ftrace_return_to_handler is my returning addr * must be before restore regs because I have to restore r3 content */ addik r15, r3, 0; RESTORE_REGS rtsd r15, 8; /* MS: jump back */ nop; #endif /* CONFIG_FUNCTION_TRACER */