1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* Copyright (C) 2017 Andes Technology Corporation */
3
4 #ifndef _ASM_RISCV_FTRACE_H
5 #define _ASM_RISCV_FTRACE_H
6
7 /*
8 * The graph frame test is not possible if CONFIG_FRAME_POINTER is not enabled.
9 * Check arch/riscv/kernel/mcount.S for detail.
10 */
11 #if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER)
12 #define HAVE_FUNCTION_GRAPH_FP_TEST
13 #endif
14
15 #define ARCH_SUPPORTS_FTRACE_OPS 1
16 #ifndef __ASSEMBLY__
17
18 extern void *return_address(unsigned int level);
19
20 #define ftrace_return_address(n) return_address(n)
21
22 void _mcount(void);
23 unsigned long ftrace_call_adjust(unsigned long addr);
24 unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip);
25 #define ftrace_get_symaddr(fentry_ip) arch_ftrace_get_symaddr(fentry_ip)
26
27 /*
28 * Let's do like x86/arm64 and ignore the compat syscalls.
29 */
30 #define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS
arch_trace_is_compat_syscall(struct pt_regs * regs)31 static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
32 {
33 return is_compat_task();
34 }
35
36 #define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
arch_syscall_match_sym_name(const char * sym,const char * name)37 static inline bool arch_syscall_match_sym_name(const char *sym,
38 const char *name)
39 {
40 /*
41 * Since all syscall functions have __riscv_ prefix, we must skip it.
42 * However, as we described above, we decided to ignore compat
43 * syscalls, so we don't care about __riscv_compat_ prefix here.
44 */
45 return !strcmp(sym + 8, name);
46 }
47
48 struct dyn_arch_ftrace {
49 };
50 #endif
51
52 #ifdef CONFIG_DYNAMIC_FTRACE
53 /*
54 * A general call in RISC-V is a pair of insts:
55 * 1) auipc: setting high-20 pc-related bits to ra register
56 * 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to
57 * return address (original pc + 4)
58 *
59 * The first 2 instructions for each tracable function is compiled to 2 nop
60 * instructions. Then, the kernel initializes the first instruction to auipc at
61 * boot time (<ftrace disable>). The second instruction is patched to jalr to
62 * start the trace.
63 *
64 *<Image>:
65 * 0: nop
66 * 4: nop
67 *
68 *<ftrace enable>:
69 * 0: auipc t0, 0x?
70 * 4: jalr t0, ?(t0)
71 *
72 *<ftrace disable>:
73 * 0: auipc t0, 0x?
74 * 4: nop
75 *
76 * Dynamic ftrace generates probes to call sites, so we must deal with
77 * both auipc and jalr at the same time.
78 */
79
80 #define MCOUNT_ADDR ((unsigned long)_mcount)
81 #define JALR_SIGN_MASK (0x00000800)
82 #define JALR_OFFSET_MASK (0x00000fff)
83 #define AUIPC_OFFSET_MASK (0xfffff000)
84 #define AUIPC_PAD (0x00001000)
85 #define JALR_SHIFT 20
86 #define JALR_T0 (0x000282e7)
87 #define AUIPC_T0 (0x00000297)
88 #define JALR_RANGE (JALR_SIGN_MASK - 1)
89
90 #define to_jalr_t0(offset) \
91 (((offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_T0)
92
93 #define to_auipc_t0(offset) \
94 ((offset & JALR_SIGN_MASK) ? \
95 (((offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_T0) : \
96 ((offset & AUIPC_OFFSET_MASK) | AUIPC_T0))
97
98 #define make_call_t0(caller, callee, call) \
99 do { \
100 unsigned int offset = \
101 (unsigned long) (callee) - (unsigned long) (caller); \
102 call[0] = to_auipc_t0(offset); \
103 call[1] = to_jalr_t0(offset); \
104 } while (0)
105
106 /*
107 * Only the jalr insn in the auipc+jalr is patched, so we make it 4
108 * bytes here.
109 */
110 #define MCOUNT_INSN_SIZE 4
111 #define MCOUNT_AUIPC_SIZE 4
112 #define MCOUNT_JALR_SIZE 4
113 #define MCOUNT_NOP4_SIZE 4
114
115 #ifndef __ASSEMBLY__
116 struct dyn_ftrace;
117 int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
118 #define ftrace_init_nop ftrace_init_nop
119
120 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
121 #define arch_ftrace_get_regs(regs) NULL
122 #define HAVE_ARCH_FTRACE_REGS
123 struct ftrace_ops;
124 struct ftrace_regs;
125 #define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs))
126
127 struct __arch_ftrace_regs {
128 unsigned long epc;
129 unsigned long ra;
130 unsigned long sp;
131 unsigned long s0;
132 unsigned long t1;
133 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
134 unsigned long direct_tramp;
135 #endif
136 union {
137 unsigned long args[8];
138 struct {
139 unsigned long a0;
140 unsigned long a1;
141 unsigned long a2;
142 unsigned long a3;
143 unsigned long a4;
144 unsigned long a5;
145 unsigned long a6;
146 unsigned long a7;
147 #ifdef CONFIG_CC_IS_CLANG
148 unsigned long t2;
149 unsigned long t3;
150 unsigned long t4;
151 unsigned long t5;
152 unsigned long t6;
153 #endif
154 };
155 };
156 };
157
ftrace_regs_get_instruction_pointer(const struct ftrace_regs * fregs)158 static __always_inline unsigned long ftrace_regs_get_instruction_pointer(const struct ftrace_regs
159 *fregs)
160 {
161 return arch_ftrace_regs(fregs)->epc;
162 }
163
ftrace_regs_set_instruction_pointer(struct ftrace_regs * fregs,unsigned long pc)164 static __always_inline void ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
165 unsigned long pc)
166 {
167 arch_ftrace_regs(fregs)->epc = pc;
168 }
169
ftrace_regs_get_stack_pointer(const struct ftrace_regs * fregs)170 static __always_inline unsigned long ftrace_regs_get_stack_pointer(const struct ftrace_regs *fregs)
171 {
172 return arch_ftrace_regs(fregs)->sp;
173 }
174
ftrace_regs_get_frame_pointer(const struct ftrace_regs * fregs)175 static __always_inline unsigned long ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs)
176 {
177 return arch_ftrace_regs(fregs)->s0;
178 }
179
ftrace_regs_get_argument(struct ftrace_regs * fregs,unsigned int n)180 static __always_inline unsigned long ftrace_regs_get_argument(struct ftrace_regs *fregs,
181 unsigned int n)
182 {
183 if (n < 8)
184 return arch_ftrace_regs(fregs)->args[n];
185 return 0;
186 }
187
ftrace_regs_get_return_value(const struct ftrace_regs * fregs)188 static __always_inline unsigned long ftrace_regs_get_return_value(const struct ftrace_regs *fregs)
189 {
190 return arch_ftrace_regs(fregs)->a0;
191 }
192
ftrace_regs_get_return_address(const struct ftrace_regs * fregs)193 static __always_inline unsigned long ftrace_regs_get_return_address(const struct ftrace_regs *fregs)
194 {
195 return arch_ftrace_regs(fregs)->ra;
196 }
197
ftrace_regs_set_return_value(struct ftrace_regs * fregs,unsigned long ret)198 static __always_inline void ftrace_regs_set_return_value(struct ftrace_regs *fregs,
199 unsigned long ret)
200 {
201 arch_ftrace_regs(fregs)->a0 = ret;
202 }
203
ftrace_override_function_with_return(struct ftrace_regs * fregs)204 static __always_inline void ftrace_override_function_with_return(struct ftrace_regs *fregs)
205 {
206 arch_ftrace_regs(fregs)->epc = arch_ftrace_regs(fregs)->ra;
207 }
208
209 static __always_inline struct pt_regs *
ftrace_partial_regs(const struct ftrace_regs * fregs,struct pt_regs * regs)210 ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs)
211 {
212 struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs);
213
214 memcpy(®s->a_regs, afregs->args, sizeof(afregs->args));
215 regs->epc = afregs->epc;
216 regs->ra = afregs->ra;
217 regs->sp = afregs->sp;
218 regs->s0 = afregs->s0;
219 regs->t1 = afregs->t1;
220 return regs;
221 }
222
223 int ftrace_regs_query_register_offset(const char *name);
224
225 void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
226 struct ftrace_ops *op, struct ftrace_regs *fregs);
227 #define ftrace_graph_func ftrace_graph_func
228
229 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
arch_ftrace_set_direct_caller(struct ftrace_regs * fregs,unsigned long addr)230 static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr)
231 {
232 arch_ftrace_regs(fregs)->t1 = addr;
233 }
234 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
235
236 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
237
238 #endif /* __ASSEMBLY__ */
239
240 #endif /* CONFIG_DYNAMIC_FTRACE */
241
242 #endif /* _ASM_RISCV_FTRACE_H */
243