ftrace-entry.S 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * mcount and friends -- ftrace stuff
  3. *
  4. * Copyright (C) 2009-2010 Analog Devices Inc.
  5. * Licensed under the GPL-2 or later.
  6. */
  7. #include <linux/linkage.h>
  8. #include <asm/ftrace.h>
  9. .text
  10. #ifdef CONFIG_DYNAMIC_FTRACE
  11. /* Simple stub so we can boot the kernel until runtime patching has
  12. * disabled all calls to this. Then it'll be unused.
  13. */
  14. ENTRY(__mcount)
  15. # if ANOMALY_05000371
  16. nop; nop; nop; nop;
  17. # endif
  18. rts;
  19. ENDPROC(__mcount)
  20. /* GCC will have called us before setting up the function prologue, so we
  21. * can clobber the normal scratch registers, but we need to make sure to
  22. * save/restore the registers used for argument passing (R0-R2) in case
  23. * the profiled function is using them. With data registers, R3 is the
  24. * only one we can blow away. With pointer registers, we have P0-P2.
  25. *
  26. * Upon entry, the RETS will point to the top of the current profiled
  27. * function. And since GCC pushed the previous RETS for us, the previous
  28. * function will be waiting there. mmmm pie.
  29. */
  30. ENTRY(_ftrace_caller)
  31. /* save first/second/third function arg and the return register */
  32. [--sp] = r2;
  33. [--sp] = r0;
  34. [--sp] = r1;
  35. [--sp] = rets;
  36. /* function_trace_call(unsigned long ip, unsigned long parent_ip):
  37. * ip: this point was called by ...
  38. * parent_ip: ... this function
  39. * the ip itself will need adjusting for the mcount call
  40. */
  41. r0 = rets;
  42. r1 = [sp + 16]; /* skip the 4 local regs on stack */
  43. r0 += -MCOUNT_INSN_SIZE;
  44. .globl _ftrace_call
  45. _ftrace_call:
  46. call _ftrace_stub
  47. # ifdef CONFIG_FUNCTION_GRAPH_TRACER
  48. .globl _ftrace_graph_call
  49. _ftrace_graph_call:
  50. nop; /* jump _ftrace_graph_caller; */
  51. # endif
  52. /* restore state and get out of dodge */
  53. .Lfinish_trace:
  54. rets = [sp++];
  55. r1 = [sp++];
  56. r0 = [sp++];
  57. r2 = [sp++];
  58. .globl _ftrace_stub
  59. _ftrace_stub:
  60. rts;
  61. ENDPROC(_ftrace_caller)
  62. #else
  63. /* See documentation for _ftrace_caller */
  64. ENTRY(__mcount)
  65. /* save third function arg early so we can do testing below */
  66. [--sp] = r2;
  67. /* load the function pointer to the tracer */
  68. p0.l = _ftrace_trace_function;
  69. p0.h = _ftrace_trace_function;
  70. r3 = [p0];
  71. /* optional micro optimization: don't call the stub tracer */
  72. r2.l = _ftrace_stub;
  73. r2.h = _ftrace_stub;
  74. cc = r2 == r3;
  75. if ! cc jump .Ldo_trace;
  76. # ifdef CONFIG_FUNCTION_GRAPH_TRACER
  77. /* if the ftrace_graph_return function pointer is not set to
  78. * the ftrace_stub entry, call prepare_ftrace_return().
  79. */
  80. p0.l = _ftrace_graph_return;
  81. p0.h = _ftrace_graph_return;
  82. r3 = [p0];
  83. cc = r2 == r3;
  84. if ! cc jump _ftrace_graph_caller;
  85. /* similarly, if the ftrace_graph_entry function pointer is not
  86. * set to the ftrace_graph_entry_stub entry, ...
  87. */
  88. p0.l = _ftrace_graph_entry;
  89. p0.h = _ftrace_graph_entry;
  90. r2.l = _ftrace_graph_entry_stub;
  91. r2.h = _ftrace_graph_entry_stub;
  92. r3 = [p0];
  93. cc = r2 == r3;
  94. if ! cc jump _ftrace_graph_caller;
  95. # endif
  96. r2 = [sp++];
  97. rts;
  98. .Ldo_trace:
  99. /* save first/second function arg and the return register */
  100. [--sp] = r0;
  101. [--sp] = r1;
  102. [--sp] = rets;
  103. /* setup the tracer function */
  104. p0 = r3;
  105. /* function_trace_call(unsigned long ip, unsigned long parent_ip):
  106. * ip: this point was called by ...
  107. * parent_ip: ... this function
  108. * the ip itself will need adjusting for the mcount call
  109. */
  110. r0 = rets;
  111. r1 = [sp + 16]; /* skip the 4 local regs on stack */
  112. r0 += -MCOUNT_INSN_SIZE;
  113. /* call the tracer */
  114. call (p0);
  115. /* restore state and get out of dodge */
  116. .Lfinish_trace:
  117. rets = [sp++];
  118. r1 = [sp++];
  119. r0 = [sp++];
  120. r2 = [sp++];
  121. .globl _ftrace_stub
  122. _ftrace_stub:
  123. rts;
  124. ENDPROC(__mcount)
  125. #endif
  126. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  127. /* The prepare_ftrace_return() function is similar to the trace function
  128. * except it takes a pointer to the location of the frompc. This is so
  129. * the prepare_ftrace_return() can hijack it temporarily for probing
  130. * purposes.
  131. */
  132. ENTRY(_ftrace_graph_caller)
  133. # ifndef CONFIG_DYNAMIC_FTRACE
  134. /* save first/second function arg and the return register */
  135. [--sp] = r0;
  136. [--sp] = r1;
  137. [--sp] = rets;
  138. /* prepare_ftrace_return(parent, self_addr, frame_pointer) */
  139. r0 = sp; /* unsigned long *parent */
  140. r1 = rets; /* unsigned long self_addr */
  141. # else
  142. r0 = sp; /* unsigned long *parent */
  143. r1 = [sp]; /* unsigned long self_addr */
  144. # endif
  145. # ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
  146. r2 = fp; /* unsigned long frame_pointer */
  147. # endif
  148. r0 += 16; /* skip the 4 local regs on stack */
  149. r1 += -MCOUNT_INSN_SIZE;
  150. call _prepare_ftrace_return;
  151. jump .Lfinish_trace;
  152. ENDPROC(_ftrace_graph_caller)
  153. /* Undo the rewrite caused by ftrace_graph_caller(). The common function
  154. * ftrace_return_to_handler() will return the original rets so we can
  155. * restore it and be on our way.
  156. */
  157. ENTRY(_return_to_handler)
  158. /* make sure original return values are saved */
  159. [--sp] = p0;
  160. [--sp] = r0;
  161. [--sp] = r1;
  162. /* get original return address */
  163. # ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
  164. r0 = fp; /* Blackfin is sane, so omit this */
  165. # endif
  166. call _ftrace_return_to_handler;
  167. rets = r0;
  168. /* anomaly 05000371 - make sure we have at least three instructions
  169. * between rets setting and the return
  170. */
  171. r1 = [sp++];
  172. r0 = [sp++];
  173. p0 = [sp++];
  174. rts;
  175. ENDPROC(_return_to_handler)
  176. #endif