|  | /* | 
|  | * Low-level ftrace handling | 
|  | * | 
|  | * Copyright (C) 2009 Michal Simek <monstr@monstr.eu> | 
|  | * 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 <linux/linkage.h> | 
|  |  | 
|  | #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 */ |