entry-ftrace.S 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. #include <asm/assembler.h>
  3. #include <asm/ftrace.h>
  4. #include <asm/unwind.h>
  5. #include "entry-header.S"
  6. /*
  7. * When compiling with -pg, gcc inserts a call to the mcount routine at the
  8. * start of every function. In mcount, apart from the function's address (in
  9. * lr), we need to get hold of the function's caller's address.
  10. *
  11. * Newer GCCs (4.4+) solve this problem by using a version of mcount with call
  12. * sites like:
  13. *
  14. * push {lr}
  15. * bl __gnu_mcount_nc
  16. *
  17. * With these compilers, frame pointers are not necessary.
  18. *
  19. * mcount can be thought of as a function called in the middle of a subroutine
  20. * call. As such, it needs to be transparent for both the caller and the
  21. * callee: the original lr needs to be restored when leaving mcount, and no
  22. * registers should be clobbered.
  23. *
  24. * When using dynamic ftrace, we patch out the mcount call by a "add sp, #4"
  25. * instead of the __gnu_mcount_nc call (see arch/arm/kernel/ftrace.c).
  26. */
  27. .macro mcount_adjust_addr rd, rn
  28. bic \rd, \rn, #1 @ clear the Thumb bit if present
  29. sub \rd, \rd, #MCOUNT_INSN_SIZE
  30. .endm
  31. .macro __mcount suffix
  32. mcount_enter
  33. ldr_va r2, ftrace_trace_function
  34. badr r0, .Lftrace_stub
  35. cmp r0, r2
  36. bne 1f
  37. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  38. ldr_va r2, ftrace_graph_return
  39. cmp r0, r2
  40. bne ftrace_graph_caller\suffix
  41. ldr_va r2, ftrace_graph_entry
  42. mov_l r0, ftrace_graph_entry_stub
  43. cmp r0, r2
  44. bne ftrace_graph_caller\suffix
  45. #endif
  46. mcount_exit
  47. 1: mcount_get_lr r1 @ lr of instrumented func
  48. mcount_adjust_addr r0, lr @ instrumented function
  49. badr lr, 2f
  50. mov pc, r2
  51. 2: mcount_exit
  52. .endm
  53. #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
  54. .macro __ftrace_regs_caller
  55. str lr, [sp, #-8]! @ store LR as PC and make space for CPSR/OLD_R0,
  56. @ OLD_R0 will overwrite previous LR
  57. ldr lr, [sp, #8] @ get previous LR
  58. str r0, [sp, #8] @ write r0 as OLD_R0 over previous LR
  59. str lr, [sp, #-4]! @ store previous LR as LR
  60. add lr, sp, #16 @ move in LR the value of SP as it was
  61. @ before the push {lr} of the mcount mechanism
  62. push {r0-r11, ip, lr}
  63. @ stack content at this point:
  64. @ 0 4 48 52 56 60 64 68 72
  65. @ R0 | R1 | ... | IP | SP + 4 | previous LR | LR | PSR | OLD_R0 |
  66. mov r3, sp @ struct pt_regs*
  67. ldr_va r2, function_trace_op @ pointer to the current
  68. @ function tracing op
  69. ldr r1, [sp, #S_LR] @ lr of instrumented func
  70. ldr lr, [sp, #S_PC] @ get LR
  71. mcount_adjust_addr r0, lr @ instrumented function
  72. .globl ftrace_regs_call
  73. ftrace_regs_call:
  74. bl ftrace_stub
  75. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  76. .globl ftrace_graph_regs_call
  77. ftrace_graph_regs_call:
  78. ARM( mov r0, r0 )
  79. THUMB( nop.w )
  80. #endif
  81. @ pop saved regs
  82. pop {r0-r11, ip, lr} @ restore r0 through r12
  83. ldr lr, [sp], #4 @ restore LR
  84. ldr pc, [sp], #12
  85. .endm
  86. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  87. .macro __ftrace_graph_regs_caller
  88. #ifdef CONFIG_UNWINDER_FRAME_POINTER
  89. sub r0, fp, #4 @ lr of instrumented routine (parent)
  90. #else
  91. add r0, sp, #S_LR
  92. #endif
  93. @ called from __ftrace_regs_caller
  94. ldr r1, [sp, #S_PC] @ instrumented routine (func)
  95. mcount_adjust_addr r1, r1
  96. mov r2, fpreg @ frame pointer
  97. add r3, sp, #PT_REGS_SIZE
  98. bl prepare_ftrace_return
  99. @ pop registers saved in ftrace_regs_caller
  100. pop {r0-r11, ip, lr} @ restore r0 through r12
  101. ldr lr, [sp], #4 @ restore LR
  102. ldr pc, [sp], #12
  103. .endm
  104. #endif
  105. #endif
  106. .macro __ftrace_caller suffix
  107. mcount_enter
  108. mcount_get_lr r1 @ lr of instrumented func
  109. mcount_adjust_addr r0, lr @ instrumented function
  110. #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
  111. ldr_va r2, function_trace_op @ pointer to the current
  112. @ function tracing op
  113. mov r3, #0 @ regs is NULL
  114. #endif
  115. .globl ftrace_call\suffix
  116. ftrace_call\suffix:
  117. bl ftrace_stub
  118. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  119. .globl ftrace_graph_call\suffix
  120. ftrace_graph_call\suffix:
  121. ARM( mov r0, r0 )
  122. THUMB( nop.w )
  123. #endif
  124. mcount_exit
  125. .endm
  126. .macro __ftrace_graph_caller
  127. #ifdef CONFIG_UNWINDER_FRAME_POINTER
  128. sub r0, fp, #4 @ &lr of instrumented routine (&parent)
  129. #else
  130. add r0, sp, #20
  131. #endif
  132. #ifdef CONFIG_DYNAMIC_FTRACE
  133. @ called from __ftrace_caller, saved in mcount_enter
  134. ldr r1, [sp, #16] @ instrumented routine (func)
  135. mcount_adjust_addr r1, r1
  136. #else
  137. @ called from __mcount, untouched in lr
  138. mcount_adjust_addr r1, lr @ instrumented routine (func)
  139. #endif
  140. mov r2, fpreg @ frame pointer
  141. add r3, sp, #24
  142. bl prepare_ftrace_return
  143. mcount_exit
  144. .endm
  145. /*
  146. * __gnu_mcount_nc
  147. */
  148. .macro mcount_enter
  149. /*
  150. * This pad compensates for the push {lr} at the call site. Note that we are
  151. * unable to unwind through a function which does not otherwise save its lr.
  152. */
  153. UNWIND(.pad #4)
  154. stmdb sp!, {r0-r3, lr}
  155. UNWIND(.save {r0-r3, lr})
  156. .endm
  157. .macro mcount_get_lr reg
  158. ldr \reg, [sp, #20]
  159. .endm
  160. .macro mcount_exit
  161. ldmia sp!, {r0-r3}
  162. ldr lr, [sp, #4]
  163. ldr pc, [sp], #8
  164. .endm
  165. ENTRY(__gnu_mcount_nc)
  166. UNWIND(.fnstart)
  167. #ifdef CONFIG_DYNAMIC_FTRACE
  168. push {lr}
  169. ldr lr, [sp, #4]
  170. ldr pc, [sp], #8
  171. #else
  172. __mcount
  173. #endif
  174. UNWIND(.fnend)
  175. ENDPROC(__gnu_mcount_nc)
  176. #ifdef CONFIG_DYNAMIC_FTRACE
  177. ENTRY(ftrace_caller)
  178. UNWIND(.fnstart)
  179. __ftrace_caller
  180. UNWIND(.fnend)
  181. ENDPROC(ftrace_caller)
  182. #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
  183. ENTRY(ftrace_regs_caller)
  184. UNWIND(.fnstart)
  185. __ftrace_regs_caller
  186. UNWIND(.fnend)
  187. ENDPROC(ftrace_regs_caller)
  188. #endif
  189. #endif
  190. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  191. ENTRY(ftrace_graph_caller)
  192. UNWIND(.fnstart)
  193. __ftrace_graph_caller
  194. UNWIND(.fnend)
  195. ENDPROC(ftrace_graph_caller)
  196. #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
  197. ENTRY(ftrace_graph_regs_caller)
  198. UNWIND(.fnstart)
  199. __ftrace_graph_regs_caller
  200. UNWIND(.fnend)
  201. ENDPROC(ftrace_graph_regs_caller)
  202. #endif
  203. #endif
  204. .purgem mcount_enter
  205. .purgem mcount_get_lr
  206. .purgem mcount_exit
  207. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  208. ENTRY(return_to_handler)
  209. stmdb sp!, {r0-r3}
  210. add r0, sp, #16 @ sp at exit of instrumented routine
  211. bl ftrace_return_to_handler
  212. mov lr, r0 @ r0 has real ret addr
  213. ldmia sp!, {r0-r3}
  214. ret lr
  215. ENDPROC(return_to_handler)
  216. #endif
  217. ENTRY(ftrace_stub)
  218. .Lftrace_stub:
  219. ret lr
  220. ENDPROC(ftrace_stub)
  221. #ifdef CONFIG_DYNAMIC_FTRACE
  222. __INIT
  223. .macro init_tramp, dst:req
  224. ENTRY(\dst\()_from_init)
  225. ldr pc, =\dst
  226. ENDPROC(\dst\()_from_init)
  227. .endm
  228. init_tramp ftrace_caller
  229. #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
  230. init_tramp ftrace_regs_caller
  231. #endif
  232. #endif