1*4882a593Smuzhiyun/* 2*4882a593Smuzhiyun * Low-level ftrace handling 3*4882a593Smuzhiyun * 4*4882a593Smuzhiyun * Copyright (C) 2009 Michal Simek <monstr@monstr.eu> 5*4882a593Smuzhiyun * Copyright (C) 2009 PetaLogix 6*4882a593Smuzhiyun * 7*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General 8*4882a593Smuzhiyun * Public License. See the file COPYING in the main directory of this 9*4882a593Smuzhiyun * archive for more details. 10*4882a593Smuzhiyun */ 11*4882a593Smuzhiyun 12*4882a593Smuzhiyun#include <linux/linkage.h> 13*4882a593Smuzhiyun 14*4882a593Smuzhiyun#define NOALIGN_ENTRY(name) .globl name; name: 15*4882a593Smuzhiyun 16*4882a593Smuzhiyun/* FIXME MS: I think that I don't need to save all regs */ 17*4882a593Smuzhiyun#define SAVE_REGS \ 18*4882a593Smuzhiyun addik r1, r1, -120; \ 19*4882a593Smuzhiyun swi r2, r1, 4; \ 20*4882a593Smuzhiyun swi r3, r1, 8; \ 21*4882a593Smuzhiyun swi r4, r1, 12; \ 22*4882a593Smuzhiyun swi r5, r1, 116; \ 23*4882a593Smuzhiyun swi r6, r1, 16; \ 24*4882a593Smuzhiyun swi r7, r1, 20; \ 25*4882a593Smuzhiyun swi r8, r1, 24; \ 26*4882a593Smuzhiyun swi r9, r1, 28; \ 27*4882a593Smuzhiyun swi r10, r1, 32; \ 28*4882a593Smuzhiyun swi r11, r1, 36; \ 29*4882a593Smuzhiyun swi r12, r1, 40; \ 30*4882a593Smuzhiyun swi r13, r1, 44; \ 31*4882a593Smuzhiyun swi r14, r1, 48; \ 32*4882a593Smuzhiyun swi r16, r1, 52; \ 33*4882a593Smuzhiyun swi r17, r1, 56; \ 34*4882a593Smuzhiyun swi r18, r1, 60; \ 35*4882a593Smuzhiyun swi r19, r1, 64; \ 36*4882a593Smuzhiyun swi r20, r1, 68; \ 37*4882a593Smuzhiyun swi r21, r1, 72; \ 38*4882a593Smuzhiyun swi r22, r1, 76; \ 39*4882a593Smuzhiyun swi r23, r1, 80; \ 40*4882a593Smuzhiyun swi r24, r1, 84; \ 41*4882a593Smuzhiyun swi r25, r1, 88; \ 42*4882a593Smuzhiyun swi r26, r1, 92; \ 43*4882a593Smuzhiyun swi r27, r1, 96; \ 44*4882a593Smuzhiyun swi r28, r1, 100; \ 45*4882a593Smuzhiyun swi r29, r1, 104; \ 46*4882a593Smuzhiyun swi r30, r1, 108; \ 47*4882a593Smuzhiyun swi r31, r1, 112; 48*4882a593Smuzhiyun 49*4882a593Smuzhiyun#define RESTORE_REGS \ 50*4882a593Smuzhiyun lwi r2, r1, 4; \ 51*4882a593Smuzhiyun lwi r3, r1, 8; \ 52*4882a593Smuzhiyun lwi r4, r1, 12; \ 53*4882a593Smuzhiyun lwi r5, r1, 116; \ 54*4882a593Smuzhiyun lwi r6, r1, 16; \ 55*4882a593Smuzhiyun lwi r7, r1, 20; \ 56*4882a593Smuzhiyun lwi r8, r1, 24; \ 57*4882a593Smuzhiyun lwi r9, r1, 28; \ 58*4882a593Smuzhiyun lwi r10, r1, 32; \ 59*4882a593Smuzhiyun lwi r11, r1, 36; \ 60*4882a593Smuzhiyun lwi r12, r1, 40; \ 61*4882a593Smuzhiyun lwi r13, r1, 44; \ 62*4882a593Smuzhiyun lwi r14, r1, 48; \ 63*4882a593Smuzhiyun lwi r16, r1, 52; \ 64*4882a593Smuzhiyun lwi r17, r1, 56; \ 65*4882a593Smuzhiyun lwi r18, r1, 60; \ 66*4882a593Smuzhiyun lwi r19, r1, 64; \ 67*4882a593Smuzhiyun lwi r20, r1, 68; \ 68*4882a593Smuzhiyun lwi r21, r1, 72; \ 69*4882a593Smuzhiyun lwi r22, r1, 76; \ 70*4882a593Smuzhiyun lwi r23, r1, 80; \ 71*4882a593Smuzhiyun lwi r24, r1, 84; \ 72*4882a593Smuzhiyun lwi r25, r1, 88; \ 73*4882a593Smuzhiyun lwi r26, r1, 92; \ 74*4882a593Smuzhiyun lwi r27, r1, 96; \ 75*4882a593Smuzhiyun lwi r28, r1, 100; \ 76*4882a593Smuzhiyun lwi r29, r1, 104; \ 77*4882a593Smuzhiyun lwi r30, r1, 108; \ 78*4882a593Smuzhiyun lwi r31, r1, 112; \ 79*4882a593Smuzhiyun addik r1, r1, 120; 80*4882a593Smuzhiyun 81*4882a593SmuzhiyunENTRY(ftrace_stub) 82*4882a593Smuzhiyun rtsd r15, 8; 83*4882a593Smuzhiyun nop; 84*4882a593Smuzhiyun 85*4882a593SmuzhiyunENTRY(_mcount) 86*4882a593Smuzhiyun#ifdef CONFIG_DYNAMIC_FTRACE 87*4882a593SmuzhiyunENTRY(ftrace_caller) 88*4882a593Smuzhiyun /* MS: It is just barrier which is removed from C code */ 89*4882a593Smuzhiyun rtsd r15, 8 90*4882a593Smuzhiyun nop 91*4882a593Smuzhiyun#endif /* CONFIG_DYNAMIC_FTRACE */ 92*4882a593Smuzhiyun SAVE_REGS 93*4882a593Smuzhiyun swi r15, r1, 0; 94*4882a593Smuzhiyun#ifdef CONFIG_FUNCTION_GRAPH_TRACER 95*4882a593Smuzhiyun#ifndef CONFIG_DYNAMIC_FTRACE 96*4882a593Smuzhiyun lwi r5, r0, ftrace_graph_return; 97*4882a593Smuzhiyun addik r6, r0, ftrace_stub; /* asm implementation */ 98*4882a593Smuzhiyun cmpu r5, r5, r6; /* ftrace_graph_return != ftrace_stub */ 99*4882a593Smuzhiyun beqid r5, end_graph_tracer; 100*4882a593Smuzhiyun nop; 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun lwi r6, r0, ftrace_graph_entry; 103*4882a593Smuzhiyun addik r5, r0, ftrace_graph_entry_stub; /* implemented in C */ 104*4882a593Smuzhiyun cmpu r5, r5, r6; /* ftrace_graph_entry != ftrace_graph_entry_stub */ 105*4882a593Smuzhiyun beqid r5, end_graph_tracer; 106*4882a593Smuzhiyun nop; 107*4882a593Smuzhiyun#else /* CONFIG_DYNAMIC_FTRACE */ 108*4882a593SmuzhiyunNOALIGN_ENTRY(ftrace_call_graph) 109*4882a593Smuzhiyun /* MS: jump over graph function - replaced from C code */ 110*4882a593Smuzhiyun bri end_graph_tracer 111*4882a593Smuzhiyun#endif /* CONFIG_DYNAMIC_FTRACE */ 112*4882a593Smuzhiyun addik r5, r1, 120; /* MS: load parent addr */ 113*4882a593Smuzhiyun addik r6, r15, 0; /* MS: load current function addr */ 114*4882a593Smuzhiyun bralid r15, prepare_ftrace_return; 115*4882a593Smuzhiyun nop; 116*4882a593Smuzhiyun /* MS: graph was taken that's why - can jump over function trace */ 117*4882a593Smuzhiyun brid end; 118*4882a593Smuzhiyun nop; 119*4882a593Smuzhiyunend_graph_tracer: 120*4882a593Smuzhiyun#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 121*4882a593Smuzhiyun#ifndef CONFIG_DYNAMIC_FTRACE 122*4882a593Smuzhiyun /* MS: test function trace if is taken or not */ 123*4882a593Smuzhiyun lwi r20, r0, ftrace_trace_function; 124*4882a593Smuzhiyun addik r6, r0, ftrace_stub; 125*4882a593Smuzhiyun cmpu r5, r20, r6; /* ftrace_trace_function != ftrace_stub */ 126*4882a593Smuzhiyun beqid r5, end; /* MS: not taken -> jump over */ 127*4882a593Smuzhiyun nop; 128*4882a593Smuzhiyun#else /* CONFIG_DYNAMIC_FTRACE */ 129*4882a593SmuzhiyunNOALIGN_ENTRY(ftrace_call) 130*4882a593Smuzhiyun/* instruction for setup imm FUNC_part1, addik r20, r0, FUNC_part2 */ 131*4882a593Smuzhiyun nop 132*4882a593Smuzhiyun nop 133*4882a593Smuzhiyun#endif /* CONFIG_DYNAMIC_FTRACE */ 134*4882a593Smuzhiyun/* static normal trace */ 135*4882a593Smuzhiyun lwi r6, r1, 120; /* MS: load parent addr */ 136*4882a593Smuzhiyun addik r5, r15, -4; /* MS: load current function addr */ 137*4882a593Smuzhiyun /* MS: here is dependency on previous code */ 138*4882a593Smuzhiyun brald r15, r20; /* MS: jump to ftrace handler */ 139*4882a593Smuzhiyun nop; 140*4882a593Smuzhiyunend: 141*4882a593Smuzhiyun lwi r15, r1, 0; 142*4882a593Smuzhiyun RESTORE_REGS 143*4882a593Smuzhiyun 144*4882a593Smuzhiyun rtsd r15, 8; /* MS: jump back */ 145*4882a593Smuzhiyun nop; 146*4882a593Smuzhiyun 147*4882a593Smuzhiyun#ifdef CONFIG_FUNCTION_GRAPH_TRACER 148*4882a593SmuzhiyunENTRY(return_to_handler) 149*4882a593Smuzhiyun nop; /* MS: just barrier for rtsd r15, 8 */ 150*4882a593Smuzhiyun nop; 151*4882a593Smuzhiyun SAVE_REGS 152*4882a593Smuzhiyun swi r15, r1, 0; 153*4882a593Smuzhiyun 154*4882a593Smuzhiyun /* MS: find out returning address */ 155*4882a593Smuzhiyun bralid r15, ftrace_return_to_handler; 156*4882a593Smuzhiyun nop; 157*4882a593Smuzhiyun 158*4882a593Smuzhiyun /* MS: return value from ftrace_return_to_handler is my returning addr 159*4882a593Smuzhiyun * must be before restore regs because I have to restore r3 content */ 160*4882a593Smuzhiyun addik r15, r3, 0; 161*4882a593Smuzhiyun RESTORE_REGS 162*4882a593Smuzhiyun 163*4882a593Smuzhiyun rtsd r15, 8; /* MS: jump back */ 164*4882a593Smuzhiyun nop; 165*4882a593Smuzhiyun#endif /* CONFIG_FUNCTION_TRACER */ 166