xref: /linux/arch/riscv/include/asm/ftrace.h (revision 119b1e61a769aa98e68599f44721661a4d8c55f3)
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(&regs->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