Skip to content

Commit 7caa976

Browse files
puranjaymohanpalmer-dabbelt
authored andcommitted
ftrace: riscv: move from REGS to ARGS
This commit replaces riscv's support for FTRACE_WITH_REGS with support for FTRACE_WITH_ARGS. This is required for the ongoing effort to stop relying on stop_machine() for RISCV's implementation of ftrace. The main relevant benefit that this change will bring for the above use-case is that now we don't have separate ftrace_caller and ftrace_regs_caller trampolines. This will allow the callsite to call ftrace_caller by modifying a single instruction. Now the callsite can do something similar to: When not tracing: | When tracing: func: func: auipc t0, ftrace_caller_top auipc t0, ftrace_caller_top nop <=========<Enable/Disable>=========> jalr t0, ftrace_caller_bottom [...] [...] The above assumes that we are dropping the support of calling a direct trampoline from the callsite. We need to drop this as the callsite can't change the target address to call, it can only enable/disable a call to a preset target (ftrace_caller in the above diagram). We can later optimize this by calling an intermediate dispatcher trampoline before ftrace_caller. Currently, ftrace_regs_caller saves all CPU registers in the format of struct pt_regs and allows the tracer to modify them. We don't need to save all of the CPU registers because at function entry only a subset of pt_regs is live: |----------+----------+---------------------------------------------| | Register | ABI Name | Description | |----------+----------+---------------------------------------------| | x1 | ra | Return address for traced function | | x2 | sp | Stack pointer | | x5 | t0 | Return address for ftrace_caller trampoline | | x8 | s0/fp | Frame pointer | | x10-11 | a0-1 | Function arguments/return values | | x12-17 | a2-7 | Function arguments | |----------+----------+---------------------------------------------| See RISCV calling convention[1] for the above table. Saving just the live registers decreases the amount of stack space required from 288 Bytes to 112 Bytes. Basic testing was done with this on the VisionFive 2 development board. Note: - Moving from REGS to ARGS will mean that RISCV will stop supporting KPROBES_ON_FTRACE as it requires full pt_regs to be saved. - KPROBES_ON_FTRACE will be supplanted by FPROBES see [2]. [1] https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf [2] https://lore.kernel.org/all/170887410337.564249.6360118840946697039.stgit@devnote2/ Signed-off-by: Puranjay Mohan <[email protected]> Tested-by: Björn Töpel <[email protected]> Reviewed-by: Björn Töpel <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 12cf29c commit 7caa976

File tree

6 files changed

+145
-142
lines changed

6 files changed

+145
-142
lines changed

arch/riscv/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ config RISCV
128128
select HAVE_DMA_CONTIGUOUS if MMU
129129
select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && MMU && (CLANG_SUPPORTS_DYNAMIC_FTRACE || GCC_SUPPORTS_DYNAMIC_FTRACE)
130130
select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
131-
select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE
131+
select HAVE_DYNAMIC_FTRACE_WITH_ARGS if HAVE_DYNAMIC_FTRACE
132132
select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL
133133
select HAVE_FUNCTION_GRAPH_TRACER
134134
select HAVE_FUNCTION_GRAPH_RETVAL if HAVE_FUNCTION_GRAPH_TRACER

arch/riscv/include/asm/ftrace.h

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,20 +124,82 @@ struct dyn_ftrace;
124124
int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
125125
#define ftrace_init_nop ftrace_init_nop
126126

127-
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
127+
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
128+
#define arch_ftrace_get_regs(regs) NULL
128129
struct ftrace_ops;
129-
struct ftrace_regs;
130+
struct ftrace_regs {
131+
unsigned long epc;
132+
unsigned long ra;
133+
unsigned long sp;
134+
unsigned long s0;
135+
unsigned long t1;
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+
};
148+
};
149+
};
150+
151+
static __always_inline unsigned long ftrace_regs_get_instruction_pointer(const struct ftrace_regs
152+
*fregs)
153+
{
154+
return fregs->epc;
155+
}
156+
157+
static __always_inline void ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
158+
unsigned long pc)
159+
{
160+
fregs->epc = pc;
161+
}
162+
163+
static __always_inline unsigned long ftrace_regs_get_stack_pointer(const struct ftrace_regs *fregs)
164+
{
165+
return fregs->sp;
166+
}
167+
168+
static __always_inline unsigned long ftrace_regs_get_argument(struct ftrace_regs *fregs,
169+
unsigned int n)
170+
{
171+
if (n < 8)
172+
return fregs->args[n];
173+
return 0;
174+
}
175+
176+
static __always_inline unsigned long ftrace_regs_get_return_value(const struct ftrace_regs *fregs)
177+
{
178+
return fregs->a0;
179+
}
180+
181+
static __always_inline void ftrace_regs_set_return_value(struct ftrace_regs *fregs,
182+
unsigned long ret)
183+
{
184+
fregs->a0 = ret;
185+
}
186+
187+
static __always_inline void ftrace_override_function_with_return(struct ftrace_regs *fregs)
188+
{
189+
fregs->epc = fregs->ra;
190+
}
191+
192+
int ftrace_regs_query_register_offset(const char *name);
193+
130194
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
131195
struct ftrace_ops *op, struct ftrace_regs *fregs);
132196
#define ftrace_graph_func ftrace_graph_func
133197

134-
static inline void __arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr)
198+
static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr)
135199
{
136-
regs->t1 = addr;
200+
fregs->t1 = addr;
137201
}
138-
#define arch_ftrace_set_direct_caller(fregs, addr) \
139-
__arch_ftrace_set_direct_caller(&(fregs)->regs, addr)
140-
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
202+
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
141203

142204
#endif /* __ASSEMBLY__ */
143205

arch/riscv/kernel/asm-offsets.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/kbuild.h>
1010
#include <linux/mm.h>
1111
#include <linux/sched.h>
12+
#include <linux/ftrace.h>
1213
#include <linux/suspend.h>
1314
#include <asm/kvm_host.h>
1415
#include <asm/thread_info.h>
@@ -488,4 +489,21 @@ void asm_offsets(void)
488489
DEFINE(STACKFRAME_SIZE_ON_STACK, ALIGN(sizeof(struct stackframe), STACK_ALIGN));
489490
OFFSET(STACKFRAME_FP, stackframe, fp);
490491
OFFSET(STACKFRAME_RA, stackframe, ra);
492+
493+
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
494+
DEFINE(FREGS_SIZE_ON_STACK, ALIGN(sizeof(struct ftrace_regs), STACK_ALIGN));
495+
DEFINE(FREGS_EPC, offsetof(struct ftrace_regs, epc));
496+
DEFINE(FREGS_RA, offsetof(struct ftrace_regs, ra));
497+
DEFINE(FREGS_SP, offsetof(struct ftrace_regs, sp));
498+
DEFINE(FREGS_S0, offsetof(struct ftrace_regs, s0));
499+
DEFINE(FREGS_T1, offsetof(struct ftrace_regs, t1));
500+
DEFINE(FREGS_A0, offsetof(struct ftrace_regs, a0));
501+
DEFINE(FREGS_A1, offsetof(struct ftrace_regs, a1));
502+
DEFINE(FREGS_A2, offsetof(struct ftrace_regs, a2));
503+
DEFINE(FREGS_A3, offsetof(struct ftrace_regs, a3));
504+
DEFINE(FREGS_A4, offsetof(struct ftrace_regs, a4));
505+
DEFINE(FREGS_A5, offsetof(struct ftrace_regs, a5));
506+
DEFINE(FREGS_A6, offsetof(struct ftrace_regs, a6));
507+
DEFINE(FREGS_A7, offsetof(struct ftrace_regs, a7));
508+
#endif
491509
}

arch/riscv/kernel/ftrace.c

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
127127
{
128128
int ret = __ftrace_modify_call((unsigned long)&ftrace_call,
129129
(unsigned long)func, true, true);
130-
if (!ret) {
131-
ret = __ftrace_modify_call((unsigned long)&ftrace_regs_call,
132-
(unsigned long)func, true, true);
133-
}
134130

135131
return ret;
136132
}
@@ -172,7 +168,7 @@ void arch_ftrace_update_code(int command)
172168
}
173169
#endif
174170

175-
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
171+
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
176172
int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
177173
unsigned long addr)
178174
{
@@ -214,16 +210,13 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
214210
}
215211

216212
#ifdef CONFIG_DYNAMIC_FTRACE
217-
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
213+
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
218214
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
219215
struct ftrace_ops *op, struct ftrace_regs *fregs)
220216
{
221-
struct pt_regs *regs = arch_ftrace_get_regs(fregs);
222-
unsigned long *parent = (unsigned long *)&regs->ra;
223-
224-
prepare_ftrace_return(parent, ip, frame_pointer(regs));
217+
prepare_ftrace_return(&fregs->ra, ip, fregs->s0);
225218
}
226-
#else /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
219+
#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
227220
extern void ftrace_graph_call(void);
228221
int ftrace_enable_ftrace_graph_caller(void)
229222
{
@@ -236,6 +229,6 @@ int ftrace_disable_ftrace_graph_caller(void)
236229
return __ftrace_modify_call((unsigned long)&ftrace_graph_call,
237230
(unsigned long)&prepare_ftrace_return, false, true);
238231
}
239-
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
232+
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
240233
#endif /* CONFIG_DYNAMIC_FTRACE */
241234
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */

0 commit comments

Comments
 (0)