1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* Copyright (C) 2017 Andes Technology Corporation */ |
3 | |
4 | #include <linux/init.h> |
5 | #include <linux/linkage.h> |
6 | #include <linux/cfi_types.h> |
7 | #include <linux/export.h> |
8 | #include <asm/asm.h> |
9 | #include <asm/csr.h> |
10 | #include <asm/unistd.h> |
11 | #include <asm/thread_info.h> |
12 | #include <asm/asm-offsets.h> |
13 | #include <asm/ftrace.h> |
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, -4*SZREG |
30 | REG_S s0, 2*SZREG(sp) |
31 | REG_S ra, 3*SZREG(sp) |
32 | REG_S a0, 1*SZREG(sp) |
33 | REG_S a1, 0*SZREG(sp) |
34 | addi s0, sp, 4*SZREG |
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, 3*SZREG(sp) |
45 | REG_L s0, 2*SZREG(sp) |
46 | REG_L a0, 1*SZREG(sp) |
47 | REG_L a1, 0*SZREG(sp) |
48 | addi sp, sp, 4*SZREG |
49 | .endm |
50 | |
51 | SYM_TYPED_FUNC_START(ftrace_stub) |
52 | #ifdef CONFIG_DYNAMIC_FTRACE |
53 | .global _mcount |
54 | .set _mcount, ftrace_stub |
55 | #endif |
56 | ret |
57 | SYM_FUNC_END(ftrace_stub) |
58 | |
59 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
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 | #endif |
81 | |
82 | #ifndef CONFIG_DYNAMIC_FTRACE |
83 | SYM_FUNC_START(_mcount) |
84 | la t4, ftrace_stub |
85 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
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 | #endif |
95 | la t3, ftrace_trace_function |
96 | REG_L t5, 0(t3) |
97 | bne t5, t4, .Ldo_trace |
98 | ret |
99 | |
100 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
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 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST |
109 | REG_L a2, -2*SZREG(s0) |
110 | #endif |
111 | SAVE_ABI_STATE |
112 | call prepare_ftrace_return |
113 | RESTORE_ABI_STATE |
114 | ret |
115 | #endif |
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 | #endif |
131 | EXPORT_SYMBOL(_mcount) |
132 | |