ftrace_32.S 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (C) 2017 Steven Rostedt, VMware Inc.
  4. */
  5. #include <linux/linkage.h>
  6. #include <asm/page_types.h>
  7. #include <asm/segment.h>
  8. #include <asm/export.h>
  9. #include <asm/ftrace.h>
  10. #include <asm/nospec-branch.h>
  11. #include <asm/frame.h>
  12. #include <asm/asm-offsets.h>
  13. #ifdef CONFIG_FRAME_POINTER
  14. # define MCOUNT_FRAME 1 /* using frame = true */
  15. #else
  16. # define MCOUNT_FRAME 0 /* using frame = false */
  17. #endif
  18. SYM_FUNC_START(__fentry__)
  19. ret
  20. SYM_FUNC_END(__fentry__)
  21. EXPORT_SYMBOL(__fentry__)
  22. SYM_CODE_START(ftrace_caller)
  23. #ifdef CONFIG_FRAME_POINTER
  24. /*
  25. * Frame pointers are of ip followed by bp.
  26. * Since fentry is an immediate jump, we are left with
  27. * parent-ip, function-ip. We need to add a frame with
  28. * parent-ip followed by ebp.
  29. */
  30. pushl 4(%esp) /* parent ip */
  31. pushl %ebp
  32. movl %esp, %ebp
  33. pushl 2*4(%esp) /* function ip */
  34. /* For mcount, the function ip is directly above */
  35. pushl %ebp
  36. movl %esp, %ebp
  37. #endif
  38. pushl %eax
  39. pushl %ecx
  40. pushl %edx
  41. pushl $0 /* Pass NULL as regs pointer */
  42. #ifdef CONFIG_FRAME_POINTER
  43. /* Load parent ebp into edx */
  44. movl 4*4(%esp), %edx
  45. #else
  46. /* There's no frame pointer, load the appropriate stack addr instead */
  47. lea 4*4(%esp), %edx
  48. #endif
  49. movl (MCOUNT_FRAME+4)*4(%esp), %eax /* load the rip */
  50. /* Get the parent ip */
  51. movl 4(%edx), %edx /* edx has ebp */
  52. movl function_trace_op, %ecx
  53. subl $MCOUNT_INSN_SIZE, %eax
  54. .globl ftrace_call
  55. ftrace_call:
  56. call ftrace_stub
  57. addl $4, %esp /* skip NULL pointer */
  58. popl %edx
  59. popl %ecx
  60. popl %eax
  61. #ifdef CONFIG_FRAME_POINTER
  62. popl %ebp
  63. addl $4,%esp /* skip function ip */
  64. popl %ebp /* this is the orig bp */
  65. addl $4, %esp /* skip parent ip */
  66. #endif
  67. .Lftrace_ret:
  68. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  69. .globl ftrace_graph_call
  70. ftrace_graph_call:
  71. jmp ftrace_stub
  72. #endif
  73. /* This is weak to keep gas from relaxing the jumps */
  74. SYM_INNER_LABEL_ALIGN(ftrace_stub, SYM_L_WEAK)
  75. ret
  76. SYM_CODE_END(ftrace_caller)
  77. SYM_CODE_START(ftrace_regs_caller)
  78. /*
  79. * We're here from an mcount/fentry CALL, and the stack frame looks like:
  80. *
  81. * <previous context>
  82. * RET-IP
  83. *
  84. * The purpose of this function is to call out in an emulated INT3
  85. * environment with a stack frame like:
  86. *
  87. * <previous context>
  88. * gap / RET-IP
  89. * gap
  90. * gap
  91. * gap
  92. * pt_regs
  93. *
  94. * We do _NOT_ restore: ss, flags, cs, gs, fs, es, ds
  95. */
  96. subl $3*4, %esp # RET-IP + 3 gaps
  97. pushl %ss # ss
  98. pushl %esp # points at ss
  99. addl $5*4, (%esp) # make it point at <previous context>
  100. pushfl # flags
  101. pushl $__KERNEL_CS # cs
  102. pushl 7*4(%esp) # ip <- RET-IP
  103. pushl $0 # orig_eax
  104. pushl %gs
  105. pushl %fs
  106. pushl %es
  107. pushl %ds
  108. pushl %eax
  109. pushl %ebp
  110. pushl %edi
  111. pushl %esi
  112. pushl %edx
  113. pushl %ecx
  114. pushl %ebx
  115. ENCODE_FRAME_POINTER
  116. movl PT_EIP(%esp), %eax # 1st argument: IP
  117. subl $MCOUNT_INSN_SIZE, %eax
  118. movl 21*4(%esp), %edx # 2nd argument: parent ip
  119. movl function_trace_op, %ecx # 3rd argument: ftrace_pos
  120. pushl %esp # 4th argument: pt_regs
  121. SYM_INNER_LABEL(ftrace_regs_call, SYM_L_GLOBAL)
  122. call ftrace_stub
  123. addl $4, %esp # skip 4th argument
  124. /* place IP below the new SP */
  125. movl PT_OLDESP(%esp), %eax
  126. movl PT_EIP(%esp), %ecx
  127. movl %ecx, -4(%eax)
  128. /* place EAX below that */
  129. movl PT_EAX(%esp), %ecx
  130. movl %ecx, -8(%eax)
  131. popl %ebx
  132. popl %ecx
  133. popl %edx
  134. popl %esi
  135. popl %edi
  136. popl %ebp
  137. lea -8(%eax), %esp
  138. popl %eax
  139. jmp .Lftrace_ret
  140. SYM_CODE_END(ftrace_regs_caller)
  141. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  142. SYM_CODE_START(ftrace_graph_caller)
  143. pushl %eax
  144. pushl %ecx
  145. pushl %edx
  146. movl 3*4(%esp), %eax
  147. /* Even with frame pointers, fentry doesn't have one here */
  148. lea 4*4(%esp), %edx
  149. movl $0, %ecx
  150. subl $MCOUNT_INSN_SIZE, %eax
  151. call prepare_ftrace_return
  152. popl %edx
  153. popl %ecx
  154. popl %eax
  155. ret
  156. SYM_CODE_END(ftrace_graph_caller)
  157. .globl return_to_handler
  158. return_to_handler:
  159. pushl %eax
  160. pushl %edx
  161. movl $0, %eax
  162. call ftrace_return_to_handler
  163. movl %eax, %ecx
  164. popl %edx
  165. popl %eax
  166. JMP_NOSPEC ecx
  167. #endif