mcount_dyn.S 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (C) 2022 Loongson Technology Corporation Limited
  4. */
  5. #include <asm/ftrace.h>
  6. #include <asm/regdef.h>
  7. #include <asm/stackframe.h>
  8. .text
  9. /*
  10. * Due to -fpatchable-function-entry=2: the compiler inserted 2 NOPs before the
  11. * regular C function prologue. When PC arrived here, the last 2 instructions
  12. * are as follows:
  13. * move t0, ra
  14. * bl callsite (for modules, callsite is a tramplione)
  15. *
  16. * modules trampoline is as follows:
  17. * lu12i.w t1, callsite[31:12]
  18. * lu32i.d t1, callsite[51:32]
  19. * lu52i.d t1, t1, callsite[63:52]
  20. * jirl zero, t1, callsite[11:0] >> 2
  21. *
  22. * See arch/loongarch/kernel/ftrace_dyn.c for details. Here, pay attention to
  23. * that the T series regs are available and safe because each C functions
  24. * follows the LoongArch's psABI as well.
  25. */
  26. .macro ftrace_regs_entry allregs=0
  27. PTR_ADDI sp, sp, -PT_SIZE
  28. PTR_S t0, sp, PT_R1 /* Save parent ra at PT_R1(RA) */
  29. PTR_S a0, sp, PT_R4
  30. PTR_S a1, sp, PT_R5
  31. PTR_S a2, sp, PT_R6
  32. PTR_S a3, sp, PT_R7
  33. PTR_S a4, sp, PT_R8
  34. PTR_S a5, sp, PT_R9
  35. PTR_S a6, sp, PT_R10
  36. PTR_S a7, sp, PT_R11
  37. PTR_S fp, sp, PT_R22
  38. .if \allregs
  39. PTR_S tp, sp, PT_R2
  40. PTR_S t0, sp, PT_R12
  41. PTR_S t2, sp, PT_R14
  42. PTR_S t3, sp, PT_R15
  43. PTR_S t4, sp, PT_R16
  44. PTR_S t5, sp, PT_R17
  45. PTR_S t6, sp, PT_R18
  46. PTR_S t7, sp, PT_R19
  47. PTR_S t8, sp, PT_R20
  48. PTR_S u0, sp, PT_R21
  49. PTR_S s0, sp, PT_R23
  50. PTR_S s1, sp, PT_R24
  51. PTR_S s2, sp, PT_R25
  52. PTR_S s3, sp, PT_R26
  53. PTR_S s4, sp, PT_R27
  54. PTR_S s5, sp, PT_R28
  55. PTR_S s6, sp, PT_R29
  56. PTR_S s7, sp, PT_R30
  57. PTR_S s8, sp, PT_R31
  58. /* Clear it for later use as a flag sometimes. */
  59. PTR_S zero, sp, PT_R0
  60. .endif
  61. PTR_S ra, sp, PT_ERA /* Save trace function ra at PT_ERA */
  62. move t1, zero
  63. PTR_S t1, sp, PT_R13
  64. PTR_ADDI t8, sp, PT_SIZE
  65. PTR_S t8, sp, PT_R3
  66. .endm
  67. SYM_FUNC_START(ftrace_stub)
  68. jr ra
  69. SYM_FUNC_END(ftrace_stub)
  70. SYM_CODE_START(ftrace_common)
  71. UNWIND_HINT_UNDEFINED
  72. PTR_ADDI a0, ra, -8 /* arg0: ip */
  73. move a1, t0 /* arg1: parent_ip */
  74. la.pcrel t1, function_trace_op
  75. PTR_L a2, t1, 0 /* arg2: op */
  76. move a3, sp /* arg3: regs */
  77. SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
  78. bl ftrace_stub
  79. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  80. SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL)
  81. nop /* b ftrace_graph_caller */
  82. #endif
  83. /*
  84. * As we didn't use S series regs in this assmembly code and all calls
  85. * are C function which will save S series regs by themselves, there is
  86. * no need to restore S series regs. The T series is available and safe
  87. * at the callsite, so there is no need to restore the T series regs.
  88. */
  89. ftrace_common_return:
  90. PTR_L ra, sp, PT_R1
  91. PTR_L a0, sp, PT_R4
  92. PTR_L a1, sp, PT_R5
  93. PTR_L a2, sp, PT_R6
  94. PTR_L a3, sp, PT_R7
  95. PTR_L a4, sp, PT_R8
  96. PTR_L a5, sp, PT_R9
  97. PTR_L a6, sp, PT_R10
  98. PTR_L a7, sp, PT_R11
  99. PTR_L fp, sp, PT_R22
  100. PTR_L t0, sp, PT_ERA
  101. PTR_L t1, sp, PT_R13
  102. PTR_ADDI sp, sp, PT_SIZE
  103. bnez t1, .Ldirect
  104. jr t0
  105. .Ldirect:
  106. jr t1
  107. SYM_CODE_END(ftrace_common)
  108. SYM_CODE_START(ftrace_caller)
  109. UNWIND_HINT_UNDEFINED
  110. ftrace_regs_entry allregs=0
  111. b ftrace_common
  112. SYM_CODE_END(ftrace_caller)
  113. #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
  114. SYM_CODE_START(ftrace_regs_caller)
  115. UNWIND_HINT_UNDEFINED
  116. ftrace_regs_entry allregs=1
  117. b ftrace_common
  118. SYM_CODE_END(ftrace_regs_caller)
  119. #endif
  120. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  121. SYM_CODE_START(ftrace_graph_caller)
  122. UNWIND_HINT_UNDEFINED
  123. PTR_L a0, sp, PT_ERA
  124. PTR_ADDI a0, a0, -8 /* arg0: self_addr */
  125. PTR_ADDI a1, sp, PT_R1 /* arg1: parent */
  126. bl prepare_ftrace_return
  127. b ftrace_common_return
  128. SYM_CODE_END(ftrace_graph_caller)
  129. SYM_CODE_START(return_to_handler)
  130. UNWIND_HINT_UNDEFINED
  131. /* Save return value regs */
  132. PTR_ADDI sp, sp, -FGRET_REGS_SIZE
  133. PTR_S a0, sp, FGRET_REGS_A0
  134. PTR_S a1, sp, FGRET_REGS_A1
  135. PTR_S zero, sp, FGRET_REGS_FP
  136. move a0, sp
  137. bl ftrace_return_to_handler
  138. move ra, a0
  139. /* Restore return value regs */
  140. PTR_L a0, sp, FGRET_REGS_A0
  141. PTR_L a1, sp, FGRET_REGS_A1
  142. PTR_ADDI sp, sp, FGRET_REGS_SIZE
  143. jr ra
  144. SYM_CODE_END(return_to_handler)
  145. #endif
  146. #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
  147. SYM_CODE_START(ftrace_stub_direct_tramp)
  148. UNWIND_HINT_UNDEFINED
  149. jr t0
  150. SYM_CODE_END(ftrace_stub_direct_tramp)
  151. #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */