182112379SRussell King/* 282112379SRussell King * This program is free software; you can redistribute it and/or modify 382112379SRussell King * it under the terms of the GNU General Public License version 2 as 482112379SRussell King * published by the Free Software Foundation. 582112379SRussell King */ 682112379SRussell King 782112379SRussell King#include <asm/assembler.h> 882112379SRussell King#include <asm/ftrace.h> 982112379SRussell King#include <asm/unwind.h> 1082112379SRussell King 1182112379SRussell King#include "entry-header.S" 1282112379SRussell King 1382112379SRussell King/* 1482112379SRussell King * When compiling with -pg, gcc inserts a call to the mcount routine at the 1582112379SRussell King * start of every function. In mcount, apart from the function's address (in 1682112379SRussell King * lr), we need to get hold of the function's caller's address. 1782112379SRussell King * 1882112379SRussell King * Older GCCs (pre-4.4) inserted a call to a routine called mcount like this: 1982112379SRussell King * 2082112379SRussell King * bl mcount 2182112379SRussell King * 2282112379SRussell King * These versions have the limitation that in order for the mcount routine to 2382112379SRussell King * be able to determine the function's caller's address, an APCS-style frame 2482112379SRussell King * pointer (which is set up with something like the code below) is required. 2582112379SRussell King * 2682112379SRussell King * mov ip, sp 2782112379SRussell King * push {fp, ip, lr, pc} 2882112379SRussell King * sub fp, ip, #4 2982112379SRussell King * 3082112379SRussell King * With EABI, these frame pointers are not available unless -mapcs-frame is 3182112379SRussell King * specified, and if building as Thumb-2, not even then. 3282112379SRussell King * 3382112379SRussell King * Newer GCCs (4.4+) solve this problem by introducing a new version of mcount, 3482112379SRussell King * with call sites like: 3582112379SRussell King * 3682112379SRussell King * push {lr} 3782112379SRussell King * bl __gnu_mcount_nc 3882112379SRussell King * 3982112379SRussell King * With these compilers, frame pointers are not necessary. 4082112379SRussell King * 4182112379SRussell King * mcount can be thought of as a function called in the middle of a subroutine 4282112379SRussell King * call. As such, it needs to be transparent for both the caller and the 4382112379SRussell King * callee: the original lr needs to be restored when leaving mcount, and no 4482112379SRussell King * registers should be clobbered. (In the __gnu_mcount_nc implementation, we 4582112379SRussell King * clobber the ip register. This is OK because the ARM calling convention 4682112379SRussell King * allows it to be clobbered in subroutines and doesn't use it to hold 4782112379SRussell King * parameters.) 4882112379SRussell King * 4982112379SRussell King * When using dynamic ftrace, we patch out the mcount call by a "mov r0, r0" 5082112379SRussell King * for the mcount case, and a "pop {lr}" for the __gnu_mcount_nc case (see 5182112379SRussell King * arch/arm/kernel/ftrace.c). 5282112379SRussell King */ 5382112379SRussell King 5482112379SRussell King#ifndef CONFIG_OLD_MCOUNT 5582112379SRussell King#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)) 5682112379SRussell King#error Ftrace requires CONFIG_FRAME_POINTER=y with GCC older than 4.4.0. 5782112379SRussell King#endif 5882112379SRussell King#endif 5982112379SRussell King 6082112379SRussell King.macro mcount_adjust_addr rd, rn 6182112379SRussell King bic \rd, \rn, #1 @ clear the Thumb bit if present 6282112379SRussell King sub \rd, \rd, #MCOUNT_INSN_SIZE 6382112379SRussell King.endm 6482112379SRussell King 6582112379SRussell King.macro __mcount suffix 6682112379SRussell King mcount_enter 6782112379SRussell King ldr r0, =ftrace_trace_function 6882112379SRussell King ldr r2, [r0] 6982112379SRussell King adr r0, .Lftrace_stub 7082112379SRussell King cmp r0, r2 7182112379SRussell King bne 1f 7282112379SRussell King 7382112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER 7482112379SRussell King ldr r1, =ftrace_graph_return 7582112379SRussell King ldr r2, [r1] 7682112379SRussell King cmp r0, r2 7782112379SRussell King bne ftrace_graph_caller\suffix 7882112379SRussell King 7982112379SRussell King ldr r1, =ftrace_graph_entry 8082112379SRussell King ldr r2, [r1] 8182112379SRussell King ldr r0, =ftrace_graph_entry_stub 8282112379SRussell King cmp r0, r2 8382112379SRussell King bne ftrace_graph_caller\suffix 8482112379SRussell King#endif 8582112379SRussell King 8682112379SRussell King mcount_exit 8782112379SRussell King 8882112379SRussell King1: mcount_get_lr r1 @ lr of instrumented func 8982112379SRussell King mcount_adjust_addr r0, lr @ instrumented function 9014327c66SRussell King badr lr, 2f 9182112379SRussell King mov pc, r2 9282112379SRussell King2: mcount_exit 9382112379SRussell King.endm 9482112379SRussell King 95620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 96620176f3SAbel Vesa 97620176f3SAbel Vesa.macro __ftrace_regs_caller 98620176f3SAbel Vesa 99620176f3SAbel Vesa sub sp, sp, #8 @ space for PC and CPSR OLD_R0, 100620176f3SAbel Vesa @ OLD_R0 will overwrite previous LR 101620176f3SAbel Vesa 102620176f3SAbel Vesa add ip, sp, #12 @ move in IP the value of SP as it was 103620176f3SAbel Vesa @ before the push {lr} of the mcount mechanism 104620176f3SAbel Vesa 105620176f3SAbel Vesa str lr, [sp, #0] @ store LR instead of PC 106620176f3SAbel Vesa 107620176f3SAbel Vesa ldr lr, [sp, #8] @ get previous LR 108620176f3SAbel Vesa 109620176f3SAbel Vesa str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR 110620176f3SAbel Vesa 111620176f3SAbel Vesa stmdb sp!, {ip, lr} 112620176f3SAbel Vesa stmdb sp!, {r0-r11, lr} 113620176f3SAbel Vesa 114620176f3SAbel Vesa @ stack content at this point: 115620176f3SAbel Vesa @ 0 4 48 52 56 60 64 68 72 116620176f3SAbel Vesa @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 | 117620176f3SAbel Vesa 118620176f3SAbel Vesa mov r3, sp @ struct pt_regs* 119620176f3SAbel Vesa 120620176f3SAbel Vesa ldr r2, =function_trace_op 121620176f3SAbel Vesa ldr r2, [r2] @ pointer to the current 122620176f3SAbel Vesa @ function tracing op 123620176f3SAbel Vesa 124620176f3SAbel Vesa ldr r1, [sp, #S_LR] @ lr of instrumented func 125620176f3SAbel Vesa 126620176f3SAbel Vesa ldr lr, [sp, #S_PC] @ get LR 127620176f3SAbel Vesa 128620176f3SAbel Vesa mcount_adjust_addr r0, lr @ instrumented function 129620176f3SAbel Vesa 130620176f3SAbel Vesa .globl ftrace_regs_call 131620176f3SAbel Vesaftrace_regs_call: 132620176f3SAbel Vesa bl ftrace_stub 133620176f3SAbel Vesa 134620176f3SAbel Vesa#ifdef CONFIG_FUNCTION_GRAPH_TRACER 135620176f3SAbel Vesa .globl ftrace_graph_regs_call 136620176f3SAbel Vesaftrace_graph_regs_call: 137620176f3SAbel Vesa mov r0, r0 138620176f3SAbel Vesa#endif 139620176f3SAbel Vesa 140620176f3SAbel Vesa @ pop saved regs 141620176f3SAbel Vesa ldmia sp!, {r0-r12} @ restore r0 through r12 142620176f3SAbel Vesa ldr ip, [sp, #8] @ restore PC 143620176f3SAbel Vesa ldr lr, [sp, #4] @ restore LR 144620176f3SAbel Vesa ldr sp, [sp, #0] @ restore SP 145620176f3SAbel Vesa mov pc, ip @ return 146620176f3SAbel Vesa.endm 147620176f3SAbel Vesa 148620176f3SAbel Vesa#ifdef CONFIG_FUNCTION_GRAPH_TRACER 149620176f3SAbel Vesa.macro __ftrace_graph_regs_caller 150620176f3SAbel Vesa 151620176f3SAbel Vesa sub r0, fp, #4 @ lr of instrumented routine (parent) 152620176f3SAbel Vesa 153620176f3SAbel Vesa @ called from __ftrace_regs_caller 154620176f3SAbel Vesa ldr r1, [sp, #S_PC] @ instrumented routine (func) 155620176f3SAbel Vesa mcount_adjust_addr r1, r1 156620176f3SAbel Vesa 157620176f3SAbel Vesa mov r2, fp @ frame pointer 158620176f3SAbel Vesa bl prepare_ftrace_return 159620176f3SAbel Vesa 160620176f3SAbel Vesa @ pop registers saved in ftrace_regs_caller 161620176f3SAbel Vesa ldmia sp!, {r0-r12} @ restore r0 through r12 162620176f3SAbel Vesa ldr ip, [sp, #8] @ restore PC 163620176f3SAbel Vesa ldr lr, [sp, #4] @ restore LR 164620176f3SAbel Vesa ldr sp, [sp, #0] @ restore SP 165620176f3SAbel Vesa mov pc, ip @ return 166620176f3SAbel Vesa 167620176f3SAbel Vesa.endm 168620176f3SAbel Vesa#endif 169620176f3SAbel Vesa#endif 170620176f3SAbel Vesa 17182112379SRussell King.macro __ftrace_caller suffix 17282112379SRussell King mcount_enter 17382112379SRussell King 17482112379SRussell King mcount_get_lr r1 @ lr of instrumented func 17582112379SRussell King mcount_adjust_addr r0, lr @ instrumented function 17682112379SRussell King 177620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 178620176f3SAbel Vesa ldr r2, =function_trace_op 179620176f3SAbel Vesa ldr r2, [r2] @ pointer to the current 180620176f3SAbel Vesa @ function tracing op 181620176f3SAbel Vesa mov r3, #0 @ regs is NULL 182620176f3SAbel Vesa#endif 183620176f3SAbel Vesa 18482112379SRussell King .globl ftrace_call\suffix 18582112379SRussell Kingftrace_call\suffix: 18682112379SRussell King bl ftrace_stub 18782112379SRussell King 18882112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER 18982112379SRussell King .globl ftrace_graph_call\suffix 19082112379SRussell Kingftrace_graph_call\suffix: 19182112379SRussell King mov r0, r0 19282112379SRussell King#endif 19382112379SRussell King 19482112379SRussell King mcount_exit 19582112379SRussell King.endm 19682112379SRussell King 19782112379SRussell King.macro __ftrace_graph_caller 19882112379SRussell King sub r0, fp, #4 @ &lr of instrumented routine (&parent) 19982112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE 20082112379SRussell King @ called from __ftrace_caller, saved in mcount_enter 20182112379SRussell King ldr r1, [sp, #16] @ instrumented routine (func) 20282112379SRussell King mcount_adjust_addr r1, r1 20382112379SRussell King#else 20482112379SRussell King @ called from __mcount, untouched in lr 20582112379SRussell King mcount_adjust_addr r1, lr @ instrumented routine (func) 20682112379SRussell King#endif 20782112379SRussell King mov r2, fp @ frame pointer 20882112379SRussell King bl prepare_ftrace_return 20982112379SRussell King mcount_exit 21082112379SRussell King.endm 21182112379SRussell King 21282112379SRussell King#ifdef CONFIG_OLD_MCOUNT 21382112379SRussell King/* 21482112379SRussell King * mcount 21582112379SRussell King */ 21682112379SRussell King 21782112379SRussell King.macro mcount_enter 21882112379SRussell King stmdb sp!, {r0-r3, lr} 21982112379SRussell King.endm 22082112379SRussell King 22182112379SRussell King.macro mcount_get_lr reg 22282112379SRussell King ldr \reg, [fp, #-4] 22382112379SRussell King.endm 22482112379SRussell King 22582112379SRussell King.macro mcount_exit 22682112379SRussell King ldr lr, [fp, #-4] 22782112379SRussell King ldmia sp!, {r0-r3, pc} 22882112379SRussell King.endm 22982112379SRussell King 23082112379SRussell KingENTRY(mcount) 23182112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE 23282112379SRussell King stmdb sp!, {lr} 23382112379SRussell King ldr lr, [fp, #-4] 23482112379SRussell King ldmia sp!, {pc} 23582112379SRussell King#else 23682112379SRussell King __mcount _old 23782112379SRussell King#endif 23882112379SRussell KingENDPROC(mcount) 23982112379SRussell King 24082112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE 24182112379SRussell KingENTRY(ftrace_caller_old) 24282112379SRussell King __ftrace_caller _old 24382112379SRussell KingENDPROC(ftrace_caller_old) 24482112379SRussell King#endif 24582112379SRussell King 24682112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER 24782112379SRussell KingENTRY(ftrace_graph_caller_old) 24882112379SRussell King __ftrace_graph_caller 24982112379SRussell KingENDPROC(ftrace_graph_caller_old) 25082112379SRussell King#endif 25182112379SRussell King 25282112379SRussell King.purgem mcount_enter 25382112379SRussell King.purgem mcount_get_lr 25482112379SRussell King.purgem mcount_exit 25582112379SRussell King#endif 25682112379SRussell King 25782112379SRussell King/* 25882112379SRussell King * __gnu_mcount_nc 25982112379SRussell King */ 26082112379SRussell King 26182112379SRussell King.macro mcount_enter 26282112379SRussell King/* 26382112379SRussell King * This pad compensates for the push {lr} at the call site. Note that we are 26482112379SRussell King * unable to unwind through a function which does not otherwise save its lr. 26582112379SRussell King */ 26682112379SRussell King UNWIND(.pad #4) 26782112379SRussell King stmdb sp!, {r0-r3, lr} 26882112379SRussell King UNWIND(.save {r0-r3, lr}) 26982112379SRussell King.endm 27082112379SRussell King 27182112379SRussell King.macro mcount_get_lr reg 27282112379SRussell King ldr \reg, [sp, #20] 27382112379SRussell King.endm 27482112379SRussell King 27582112379SRussell King.macro mcount_exit 27682112379SRussell King ldmia sp!, {r0-r3, ip, lr} 27782112379SRussell King ret ip 27882112379SRussell King.endm 27982112379SRussell King 28082112379SRussell KingENTRY(__gnu_mcount_nc) 28182112379SRussell KingUNWIND(.fnstart) 28282112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE 28382112379SRussell King mov ip, lr 28482112379SRussell King ldmia sp!, {lr} 28582112379SRussell King ret ip 28682112379SRussell King#else 28782112379SRussell King __mcount 28882112379SRussell King#endif 28982112379SRussell KingUNWIND(.fnend) 29082112379SRussell KingENDPROC(__gnu_mcount_nc) 29182112379SRussell King 29282112379SRussell King#ifdef CONFIG_DYNAMIC_FTRACE 29382112379SRussell KingENTRY(ftrace_caller) 29482112379SRussell KingUNWIND(.fnstart) 29582112379SRussell King __ftrace_caller 29682112379SRussell KingUNWIND(.fnend) 29782112379SRussell KingENDPROC(ftrace_caller) 298620176f3SAbel Vesa 299620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 300620176f3SAbel VesaENTRY(ftrace_regs_caller) 301620176f3SAbel VesaUNWIND(.fnstart) 302620176f3SAbel Vesa __ftrace_regs_caller 303620176f3SAbel VesaUNWIND(.fnend) 304620176f3SAbel VesaENDPROC(ftrace_regs_caller) 305620176f3SAbel Vesa#endif 306620176f3SAbel Vesa 30782112379SRussell King#endif 30882112379SRussell King 30982112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER 31082112379SRussell KingENTRY(ftrace_graph_caller) 31182112379SRussell KingUNWIND(.fnstart) 31282112379SRussell King __ftrace_graph_caller 31382112379SRussell KingUNWIND(.fnend) 31482112379SRussell KingENDPROC(ftrace_graph_caller) 315620176f3SAbel Vesa 316620176f3SAbel Vesa#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 317620176f3SAbel VesaENTRY(ftrace_graph_regs_caller) 318620176f3SAbel VesaUNWIND(.fnstart) 319620176f3SAbel Vesa __ftrace_graph_regs_caller 320620176f3SAbel VesaUNWIND(.fnend) 321620176f3SAbel VesaENDPROC(ftrace_graph_regs_caller) 322620176f3SAbel Vesa#endif 32382112379SRussell King#endif 32482112379SRussell King 32582112379SRussell King.purgem mcount_enter 32682112379SRussell King.purgem mcount_get_lr 32782112379SRussell King.purgem mcount_exit 32882112379SRussell King 32982112379SRussell King#ifdef CONFIG_FUNCTION_GRAPH_TRACER 33082112379SRussell King .globl return_to_handler 33182112379SRussell Kingreturn_to_handler: 33282112379SRussell King stmdb sp!, {r0-r3} 33382112379SRussell King mov r0, fp @ frame pointer 33482112379SRussell King bl ftrace_return_to_handler 33582112379SRussell King mov lr, r0 @ r0 has real ret addr 33682112379SRussell King ldmia sp!, {r0-r3} 33782112379SRussell King ret lr 33882112379SRussell King#endif 33982112379SRussell King 34082112379SRussell KingENTRY(ftrace_stub) 34182112379SRussell King.Lftrace_stub: 34282112379SRussell King ret lr 34382112379SRussell KingENDPROC(ftrace_stub) 344