ftrace-entry.S 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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 pushed the previous RETS for us, the previous
  18. * function 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. /* function_trace_call(unsigned long ip, unsigned long parent_ip):
  62. * ip: this point was called by ...
  63. * parent_ip: ... this function
  64. * the ip itself will need adjusting for the mcount call
  65. */
  66. r0 = rets;
  67. r1 = [sp + 16]; /* skip the 4 local regs on stack */
  68. r0 += -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. /* prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) */
  93. r0 = sp;
  94. r1 = rets;
  95. r0 += 16; /* skip the 4 local regs on stack */
  96. r1 += -MCOUNT_INSN_SIZE;
  97. call _prepare_ftrace_return;
  98. jump .Lfinish_trace;
  99. ENDPROC(_ftrace_graph_caller)
  100. /* Undo the rewrite caused by ftrace_graph_caller(). The common function
  101. * ftrace_return_to_handler() will return the original rets so we can
  102. * restore it and be on our way.
  103. */
  104. ENTRY(_return_to_handler)
  105. /* make sure original return values are saved */
  106. [--sp] = p0;
  107. [--sp] = r0;
  108. [--sp] = r1;
  109. /* get original return address */
  110. call _ftrace_return_to_handler;
  111. rets = r0;
  112. /* anomaly 05000371 - make sure we have at least three instructions
  113. * between rets setting and the return
  114. */
  115. r1 = [sp++];
  116. r0 = [sp++];
  117. p0 = [sp++];
  118. rts;
  119. ENDPROC(_return_to_handler)
  120. #endif