ftrace-entry.S 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. * mcount and friends -- ftrace stuff
  3. *
  4. * Copyright (C) 2009 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 setup the frame for us, the previous function
  18. * will be waiting there. mmmm pie.
  19. */
  20. ENTRY(__mcount)
  21. /* save third function arg early so we can do testing below */
  22. [--sp] = r2;
  23. /* load the function pointer to the tracer */
  24. p0.l = _ftrace_trace_function;
  25. p0.h = _ftrace_trace_function;
  26. r3 = [p0];
  27. /* optional micro optimization: don't call the stub tracer */
  28. r2.l = _ftrace_stub;
  29. r2.h = _ftrace_stub;
  30. cc = r2 == r3;
  31. if ! cc jump .Ldo_trace;
  32. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  33. /* if the ftrace_graph_return function pointer is not set to
  34. * the ftrace_stub entry, call prepare_ftrace_return().
  35. */
  36. p0.l = _ftrace_graph_return;
  37. p0.h = _ftrace_graph_return;
  38. r3 = [p0];
  39. cc = r2 == r3;
  40. if ! cc jump _ftrace_graph_caller;
  41. /* similarly, if the ftrace_graph_entry function pointer is not
  42. * set to the ftrace_graph_entry_stub entry, ...
  43. */
  44. p0.l = _ftrace_graph_entry;
  45. p0.h = _ftrace_graph_entry;
  46. r2.l = _ftrace_graph_entry_stub;
  47. r2.h = _ftrace_graph_entry_stub;
  48. r3 = [p0];
  49. cc = r2 == r3;
  50. if ! cc jump _ftrace_graph_caller;
  51. #endif
  52. r2 = [sp++];
  53. rts;
  54. .Ldo_trace:
  55. /* save first/second function arg and the return register */
  56. [--sp] = r0;
  57. [--sp] = r1;
  58. [--sp] = rets;
  59. /* setup the tracer function */
  60. p0 = r3;
  61. /* tracer(ulong frompc, ulong selfpc):
  62. * frompc: the pc that did the call to ...
  63. * selfpc: ... this location
  64. * the selfpc itself will need adjusting for the mcount call
  65. */
  66. r1 = rets;
  67. r0 = [fp + 4];
  68. r1 += -MCOUNT_INSN_SIZE;
  69. /* call the tracer */
  70. call (p0);
  71. /* restore state and get out of dodge */
  72. .Lfinish_trace:
  73. rets = [sp++];
  74. r1 = [sp++];
  75. r0 = [sp++];
  76. r2 = [sp++];
  77. .globl _ftrace_stub
  78. _ftrace_stub:
  79. rts;
  80. ENDPROC(__mcount)
  81. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  82. /* The prepare_ftrace_return() function is similar to the trace function
  83. * except it takes a pointer to the location of the frompc. This is so
  84. * the prepare_ftrace_return() can hijack it temporarily for probing
  85. * purposes.
  86. */
  87. ENTRY(_ftrace_graph_caller)
  88. /* save first/second function arg and the return register */
  89. [--sp] = r0;
  90. [--sp] = r1;
  91. [--sp] = rets;
  92. r0 = fp;
  93. r1 = rets;
  94. r0 += 4;
  95. r1 += -MCOUNT_INSN_SIZE;
  96. call _prepare_ftrace_return;
  97. jump .Lfinish_trace;
  98. ENDPROC(_ftrace_graph_caller)
  99. /* Undo the rewrite caused by ftrace_graph_caller(). The common function
  100. * ftrace_return_to_handler() will return the original rets so we can
  101. * restore it and be on our way.
  102. */
  103. ENTRY(_return_to_handler)
  104. /* make sure original return values are saved */
  105. [--sp] = p0;
  106. [--sp] = r0;
  107. [--sp] = r1;
  108. /* get original return address */
  109. call _ftrace_return_to_handler;
  110. rets = r0;
  111. /* anomaly 05000371 - make sure we have at least three instructions
  112. * between rets setting and the return
  113. */
  114. r1 = [sp++];
  115. r0 = [sp++];
  116. p0 = [sp++];
  117. rts;
  118. ENDPROC(_return_to_handler)
  119. #endif