ftrace-entry.S 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. /* GCC will have called us before setting up the function prologue, so we
  11. * can clobber the normal scratch registers, but we need to make sure to
  12. * save/restore the registers used for argument passing (R0-R2) in case
  13. * the profiled function is using them. With data registers, R3 is the
  14. * only one we can blow away. With pointer registers, we have P0-P2.
  15. *
  16. * Upon entry, the RETS will point to the top of the current profiled
  17. * function. And since GCC pushed the previous RETS for us, the previous
  18. * function will be waiting there. mmmm pie.
  19. */
  20. ENTRY(__mcount)
  21. #ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
  22. /* optional micro optimization: return if stopped */
  23. p1.l = _function_trace_stop;
  24. p1.h = _function_trace_stop;
  25. r3 = [p1];
  26. cc = r3 == 0;
  27. if ! cc jump _ftrace_stub (bp);
  28. #endif
  29. /* save third function arg early so we can do testing below */
  30. [--sp] = r2;
  31. /* load the function pointer to the tracer */
  32. p0.l = _ftrace_trace_function;
  33. p0.h = _ftrace_trace_function;
  34. r3 = [p0];
  35. /* optional micro optimization: don't call the stub tracer */
  36. r2.l = _ftrace_stub;
  37. r2.h = _ftrace_stub;
  38. cc = r2 == r3;
  39. if ! cc jump .Ldo_trace;
  40. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  41. /* if the ftrace_graph_return function pointer is not set to
  42. * the ftrace_stub entry, call prepare_ftrace_return().
  43. */
  44. p0.l = _ftrace_graph_return;
  45. p0.h = _ftrace_graph_return;
  46. r3 = [p0];
  47. cc = r2 == r3;
  48. if ! cc jump _ftrace_graph_caller;
  49. /* similarly, if the ftrace_graph_entry function pointer is not
  50. * set to the ftrace_graph_entry_stub entry, ...
  51. */
  52. p0.l = _ftrace_graph_entry;
  53. p0.h = _ftrace_graph_entry;
  54. r2.l = _ftrace_graph_entry_stub;
  55. r2.h = _ftrace_graph_entry_stub;
  56. r3 = [p0];
  57. cc = r2 == r3;
  58. if ! cc jump _ftrace_graph_caller;
  59. #endif
  60. r2 = [sp++];
  61. rts;
  62. .Ldo_trace:
  63. /* save first/second function arg and the return register */
  64. [--sp] = r0;
  65. [--sp] = r1;
  66. [--sp] = rets;
  67. /* setup the tracer function */
  68. p0 = r3;
  69. /* function_trace_call(unsigned long ip, unsigned long parent_ip):
  70. * ip: this point was called by ...
  71. * parent_ip: ... this function
  72. * the ip itself will need adjusting for the mcount call
  73. */
  74. r0 = rets;
  75. r1 = [sp + 16]; /* skip the 4 local regs on stack */
  76. r0 += -MCOUNT_INSN_SIZE;
  77. /* call the tracer */
  78. call (p0);
  79. /* restore state and get out of dodge */
  80. .Lfinish_trace:
  81. rets = [sp++];
  82. r1 = [sp++];
  83. r0 = [sp++];
  84. r2 = [sp++];
  85. .globl _ftrace_stub
  86. _ftrace_stub:
  87. rts;
  88. ENDPROC(__mcount)
  89. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  90. /* The prepare_ftrace_return() function is similar to the trace function
  91. * except it takes a pointer to the location of the frompc. This is so
  92. * the prepare_ftrace_return() can hijack it temporarily for probing
  93. * purposes.
  94. */
  95. ENTRY(_ftrace_graph_caller)
  96. /* save first/second function arg and the return register */
  97. [--sp] = r0;
  98. [--sp] = r1;
  99. [--sp] = rets;
  100. /* prepare_ftrace_return(parent, self_addr, frame_pointer) */
  101. r0 = sp; /* unsigned long *parent */
  102. r1 = rets; /* unsigned long self_addr */
  103. #ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
  104. r2 = fp; /* unsigned long frame_pointer */
  105. #endif
  106. r0 += 16; /* skip the 4 local regs on stack */
  107. r1 += -MCOUNT_INSN_SIZE;
  108. call _prepare_ftrace_return;
  109. jump .Lfinish_trace;
  110. ENDPROC(_ftrace_graph_caller)
  111. /* Undo the rewrite caused by ftrace_graph_caller(). The common function
  112. * ftrace_return_to_handler() will return the original rets so we can
  113. * restore it and be on our way.
  114. */
  115. ENTRY(_return_to_handler)
  116. /* make sure original return values are saved */
  117. [--sp] = p0;
  118. [--sp] = r0;
  119. [--sp] = r1;
  120. /* get original return address */
  121. #ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST
  122. r0 = fp; /* Blackfin is sane, so omit this */
  123. #endif
  124. call _ftrace_return_to_handler;
  125. rets = r0;
  126. /* anomaly 05000371 - make sure we have at least three instructions
  127. * between rets setting and the return
  128. */
  129. r1 = [sp++];
  130. r0 = [sp++];
  131. p0 = [sp++];
  132. rts;
  133. ENDPROC(_return_to_handler)
  134. #endif