| 1 | /* SPDX-License-Identifier: GPL-2.0 */
|
| 2 | /* Copyright (C) 2017 Andes Technology Corporation */
|
| 3 |
|
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 |
|
| 15 | .text
|
| 16 |
|
| 17 | .macro SAVE_ABI_STATE
|
| 18 | addi sp, sp, -16
|
| 19 | REG_S s0, 0*SZREG(sp)
|
| 20 | REG_S ra, 1*SZREG(sp)
|
| 21 | addi s0, sp, 16
|
| 22 | .endm
|
| 23 |
|
| 24 | /*
|
| 25 | * The call to ftrace_return_to_handler would overwrite the return
|
| 26 | * register if a0 was not saved.
|
| 27 | */
|
| 28 | .macro SAVE_RET_ABI_STATE
|
| 29 | addi sp, sp, -FREGS_SIZE_ON_STACK
|
| 30 | REG_S ra, FREGS_RA(sp)
|
| 31 | REG_S s0, FREGS_S0(sp)
|
| 32 | REG_S a0, FREGS_A0(sp)
|
| 33 | REG_S a1, FREGS_A1(sp)
|
| 34 | addi s0, sp, FREGS_SIZE_ON_STACK
|
| 35 | .endm
|
| 36 |
|
| 37 | .macro RESTORE_ABI_STATE
|
| 38 | REG_L ra, 1*SZREG(sp)
|
| 39 | REG_L s0, 0*SZREG(sp)
|
| 40 | addi sp, sp, 16
|
| 41 | .endm
|
| 42 |
|
| 43 | .macro RESTORE_RET_ABI_STATE
|
| 44 | REG_L ra, FREGS_RA(sp)
|
| 45 | REG_L s0, FREGS_S0(sp)
|
| 46 | REG_L a0, FREGS_A0(sp)
|
| 47 | REG_L a1, FREGS_A1(sp)
|
| 48 | addi sp, sp, FREGS_SIZE_ON_STACK
|
| 49 | .endm
|
| 50 |
|
| 51 | SYM_TYPED_FUNC_START(ftrace_stub)
|
| 52 | |
| 53 | .global _mcount
|
| 54 | .set _mcount, ftrace_stub
|
| 55 | |
| 56 | ret
|
| 57 | SYM_FUNC_END(ftrace_stub)
|
| 58 |
|
| 59 | |
| 60 | SYM_TYPED_FUNC_START(ftrace_stub_graph)
|
| 61 | ret
|
| 62 | SYM_FUNC_END(ftrace_stub_graph)
|
| 63 |
|
| 64 | SYM_FUNC_START(return_to_handler)
|
| 65 | /*
|
| 66 | * On implementing the frame point test, the ideal way is to compare the
|
| 67 | * s0 (frame pointer, if enabled) on entry and the sp (stack pointer) on return.
|
| 68 | * However, the psABI of variable-length-argument functions does not allow this.
|
| 69 | *
|
| 70 | * So alternatively we check the *old* frame pointer position, that is, the
|
| 71 | * value stored in -16(s0) on entry, and the s0 on return.
|
| 72 | */
|
| 73 | SAVE_RET_ABI_STATE
|
| 74 | mv a0, sp
|
| 75 | call ftrace_return_to_handler
|
| 76 | mv a2, a0
|
| 77 | RESTORE_RET_ABI_STATE
|
| 78 | jalr a2
|
| 79 | SYM_FUNC_END(return_to_handler)
|
| 80 | |
| 81 |
|
| 82 | |
| 83 | SYM_FUNC_START(_mcount)
|
| 84 | la t4, ftrace_stub
|
| 85 | |
| 86 | la t0, ftrace_graph_return
|
| 87 | REG_L t1, 0(t0)
|
| 88 | bne t1, t4, .Ldo_ftrace_graph_caller
|
| 89 |
|
| 90 | la t3, ftrace_graph_entry
|
| 91 | REG_L t2, 0(t3)
|
| 92 | la t6, ftrace_graph_entry_stub
|
| 93 | bne t2, t6, .Ldo_ftrace_graph_caller
|
| 94 | |
| 95 | la t3, ftrace_trace_function
|
| 96 | REG_L t5, 0(t3)
|
| 97 | bne t5, t4, .Ldo_trace
|
| 98 | ret
|
| 99 |
|
| 100 | |
| 101 | /*
|
| 102 | * A pseudo representation for the function graph tracer:
|
| 103 | * prepare_to_return(&ra_to_caller_of_caller, ra_to_caller)
|
| 104 | */
|
| 105 | .Ldo_ftrace_graph_caller:
|
| 106 | addi a0, s0, -SZREG
|
| 107 | mv a1, ra
|
| 108 | |
| 109 | REG_L a2, -2*SZREG(s0)
|
| 110 | |
| 111 | SAVE_ABI_STATE
|
| 112 | call prepare_ftrace_return
|
| 113 | RESTORE_ABI_STATE
|
| 114 | ret
|
| 115 | |
| 116 |
|
| 117 | /*
|
| 118 | * A pseudo representation for the function tracer:
|
| 119 | * (*ftrace_trace_function)(ra_to_caller, ra_to_caller_of_caller)
|
| 120 | */
|
| 121 | .Ldo_trace:
|
| 122 | REG_L a1, -SZREG(s0)
|
| 123 | mv a0, ra
|
| 124 |
|
| 125 | SAVE_ABI_STATE
|
| 126 | jalr t5
|
| 127 | RESTORE_ABI_STATE
|
| 128 | ret
|
| 129 | SYM_FUNC_END(_mcount)
|
| 130 | |
| 131 | EXPORT_SYMBOL(_mcount)
|