110626c32SAlan Kao /* SPDX-License-Identifier: GPL-2.0 */
210626c32SAlan Kao /* Copyright (C) 2017 Andes Technology Corporation */
310626c32SAlan Kao
46b57ba8eSZong Li #ifndef _ASM_RISCV_FTRACE_H
56b57ba8eSZong Li #define _ASM_RISCV_FTRACE_H
66b57ba8eSZong Li
710626c32SAlan Kao /*
810626c32SAlan Kao * The graph frame test is not possible if CONFIG_FRAME_POINTER is not enabled.
910626c32SAlan Kao * Check arch/riscv/kernel/mcount.S for detail.
1010626c32SAlan Kao */
1110626c32SAlan Kao #if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER)
1210626c32SAlan Kao #define HAVE_FUNCTION_GRAPH_FP_TEST
1310626c32SAlan Kao #endif
14c15ac4fdSAlan Kao
1571e736a7SAlan Kao #define ARCH_SUPPORTS_FTRACE_OPS 1
16c15ac4fdSAlan Kao #ifndef __ASSEMBLER__
1768034138SZong Li
1868034138SZong Li extern void *return_address(unsigned int level);
1968034138SZong Li
2068034138SZong Li #define ftrace_return_address(n) return_address(n)
2168034138SZong Li
22de5f3984SNathan Chancellor void _mcount(void);
23c15ac4fdSAlan Kao unsigned long ftrace_call_adjust(unsigned long addr);
24c15ac4fdSAlan Kao unsigned long arch_ftrace_get_symaddr(unsigned long fentry_ip);
25c15ac4fdSAlan Kao #define ftrace_get_symaddr(fentry_ip) arch_ftrace_get_symaddr(fentry_ip)
26c15ac4fdSAlan Kao
27c15ac4fdSAlan Kao /*
28a87e7d3eSAlexandre Ghiti * Let's do like x86/arm64 and ignore the compat syscalls.
29a87e7d3eSAlexandre Ghiti */
30a87e7d3eSAlexandre Ghiti #define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS
arch_trace_is_compat_syscall(struct pt_regs * regs)31a87e7d3eSAlexandre Ghiti static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
32a87e7d3eSAlexandre Ghiti {
33a87e7d3eSAlexandre Ghiti return is_compat_task();
34a87e7d3eSAlexandre Ghiti }
35a87e7d3eSAlexandre Ghiti
36a87e7d3eSAlexandre Ghiti #define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
arch_syscall_match_sym_name(const char * sym,const char * name)37a87e7d3eSAlexandre Ghiti static inline bool arch_syscall_match_sym_name(const char *sym,
38a87e7d3eSAlexandre Ghiti const char *name)
39a87e7d3eSAlexandre Ghiti {
40a87e7d3eSAlexandre Ghiti /*
41a87e7d3eSAlexandre Ghiti * Since all syscall functions have __riscv_ prefix, we must skip it.
42a87e7d3eSAlexandre Ghiti * However, as we described above, we decided to ignore compat
43a87e7d3eSAlexandre Ghiti * syscalls, so we don't care about __riscv_compat_ prefix here.
44a87e7d3eSAlexandre Ghiti */
45a87e7d3eSAlexandre Ghiti return !strcmp(sym + 8, name);
46a87e7d3eSAlexandre Ghiti }
47a87e7d3eSAlexandre Ghiti
48a87e7d3eSAlexandre Ghiti struct dyn_arch_ftrace {
49c15ac4fdSAlan Kao };
50c15ac4fdSAlan Kao #endif
51c15ac4fdSAlan Kao
52c15ac4fdSAlan Kao #ifdef CONFIG_DYNAMIC_FTRACE
53c15ac4fdSAlan Kao /*
54c15ac4fdSAlan Kao * A general call in RISC-V is a pair of insts:
55c15ac4fdSAlan Kao * 1) auipc: setting high-20 pc-related bits to ra register
56c15ac4fdSAlan Kao * 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to
57c15ac4fdSAlan Kao * return address (original pc + 4)
58c15ac4fdSAlan Kao *
59c15ac4fdSAlan Kao * The first 2 instructions for each tracable function is compiled to 2 nop
606724a76cSGuo Ren * instructions. Then, the kernel initializes the first instruction to auipc at
616724a76cSGuo Ren * boot time (<ftrace disable>). The second instruction is patched to jalr to
626724a76cSGuo Ren * start the trace.
636724a76cSGuo Ren *
646724a76cSGuo Ren *<Image>:
656724a76cSGuo Ren * 0: nop
666724a76cSGuo Ren * 4: nop
676724a76cSGuo Ren *
68c15ac4fdSAlan Kao *<ftrace enable>:
69c15ac4fdSAlan Kao * 0: auipc t0, 0x?
70c15ac4fdSAlan Kao * 4: jalr t0, ?(t0)
71c15ac4fdSAlan Kao *
72de5f3984SNathan Chancellor *<ftrace disable>:
73c15ac4fdSAlan Kao * 0: auipc t0, 0x?
74c15ac4fdSAlan Kao * 4: nop
75c15ac4fdSAlan Kao *
76c15ac4fdSAlan Kao * Dynamic ftrace generates probes to call sites, so we must deal with
77c15ac4fdSAlan Kao * both auipc and jalr at the same time.
786724a76cSGuo Ren */
796724a76cSGuo Ren
806724a76cSGuo Ren #define MCOUNT_ADDR ((unsigned long)_mcount)
816724a76cSGuo Ren #define JALR_SIGN_MASK (0x00000800)
82c15ac4fdSAlan Kao #define JALR_OFFSET_MASK (0x00000fff)
83c15ac4fdSAlan Kao #define AUIPC_OFFSET_MASK (0xfffff000)
846724a76cSGuo Ren #define AUIPC_PAD (0x00001000)
856724a76cSGuo Ren #define JALR_SHIFT 20
866724a76cSGuo Ren #define JALR_T0 (0x000282e7)
876724a76cSGuo Ren #define AUIPC_T0 (0x00000297)
886724a76cSGuo Ren #define JALR_RANGE (JALR_SIGN_MASK - 1)
896724a76cSGuo Ren
906724a76cSGuo Ren #define to_jalr_t0(offset) \
916724a76cSGuo Ren (((offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_T0)
926724a76cSGuo Ren
93c15ac4fdSAlan Kao #define to_auipc_t0(offset) \
946724a76cSGuo Ren ((offset & JALR_SIGN_MASK) ? \
956724a76cSGuo Ren (((offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_T0) : \
966724a76cSGuo Ren ((offset & AUIPC_OFFSET_MASK) | AUIPC_T0))
976724a76cSGuo Ren
98c15ac4fdSAlan Kao #define make_call_t0(caller, callee, call) \
99c15ac4fdSAlan Kao do { \
1006724a76cSGuo Ren unsigned int offset = \
1016724a76cSGuo Ren (unsigned long) (callee) - (unsigned long) (caller); \
102c15ac4fdSAlan Kao call[0] = to_auipc_t0(offset); \
1036724a76cSGuo Ren call[1] = to_jalr_t0(offset); \
104c15ac4fdSAlan Kao } while (0)
1056724a76cSGuo Ren
1066724a76cSGuo Ren /*
1076724a76cSGuo Ren * Only the jalr insn in the auipc+jalr is patched, so we make it 4
1086724a76cSGuo Ren * bytes here.
1096724a76cSGuo Ren */
1106724a76cSGuo Ren #define MCOUNT_INSN_SIZE 4
1116724a76cSGuo Ren #define MCOUNT_AUIPC_SIZE 4
1126724a76cSGuo Ren #define MCOUNT_JALR_SIZE 4
1136724a76cSGuo Ren #define MCOUNT_NOP4_SIZE 4
1146724a76cSGuo Ren
115c15ac4fdSAlan Kao #ifndef __ASSEMBLER__
116c15ac4fdSAlan Kao struct dyn_ftrace;
117c15ac4fdSAlan Kao int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
118c15ac4fdSAlan Kao #define ftrace_init_nop ftrace_init_nop
119c15ac4fdSAlan Kao
12066d18dbdSPalmer Dabbelt #ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
12166d18dbdSPalmer Dabbelt #define arch_ftrace_get_regs(regs) NULL
12266d18dbdSPalmer Dabbelt #define HAVE_ARCH_FTRACE_REGS
12366d18dbdSPalmer Dabbelt struct ftrace_ops;
12466d18dbdSPalmer Dabbelt struct ftrace_regs;
12535e61e88SSong Shuai #define arch_ftrace_regs(fregs) ((struct __arch_ftrace_regs *)(fregs))
1267caa9765SPuranjay Mohan
1277caa9765SPuranjay Mohan struct __arch_ftrace_regs {
128*e4cf33caSSteven Rostedt unsigned long epc;
12935e61e88SSong Shuai unsigned long ra;
1307888af41SSteven Rostedt unsigned long sp;
1317888af41SSteven Rostedt unsigned long s0;
1327888af41SSteven Rostedt unsigned long t1;
1337888af41SSteven Rostedt #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
1347caa9765SPuranjay Mohan unsigned long direct_tramp;
1357caa9765SPuranjay Mohan #endif
1367caa9765SPuranjay Mohan union {
1377caa9765SPuranjay Mohan unsigned long args[8];
1387caa9765SPuranjay Mohan struct {
1397caa9765SPuranjay Mohan unsigned long a0;
1407caa9765SPuranjay Mohan unsigned long a1;
1417caa9765SPuranjay Mohan unsigned long a2;
1427caa9765SPuranjay Mohan unsigned long a3;
1437caa9765SPuranjay Mohan unsigned long a4;
1447caa9765SPuranjay Mohan unsigned long a5;
1457caa9765SPuranjay Mohan unsigned long a6;
1467caa9765SPuranjay Mohan unsigned long a7;
1477caa9765SPuranjay Mohan #ifdef CONFIG_CC_IS_CLANG
1487caa9765SPuranjay Mohan unsigned long t2;
1497caa9765SPuranjay Mohan unsigned long t3;
1507caa9765SPuranjay Mohan unsigned long t4;
1517caa9765SPuranjay Mohan unsigned long t5;
1527caa9765SPuranjay Mohan unsigned long t6;
1537caa9765SPuranjay Mohan #endif
1547caa9765SPuranjay Mohan };
1557caa9765SPuranjay Mohan };
1567caa9765SPuranjay Mohan };
1577888af41SSteven Rostedt
ftrace_regs_get_instruction_pointer(const struct ftrace_regs * fregs)1587caa9765SPuranjay Mohan static __always_inline unsigned long ftrace_regs_get_instruction_pointer(const struct ftrace_regs
1597caa9765SPuranjay Mohan *fregs)
1607caa9765SPuranjay Mohan {
1617caa9765SPuranjay Mohan return arch_ftrace_regs(fregs)->epc;
1627caa9765SPuranjay Mohan }
1637888af41SSteven Rostedt
ftrace_regs_set_instruction_pointer(struct ftrace_regs * fregs,unsigned long pc)1647caa9765SPuranjay Mohan static __always_inline void ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
1657caa9765SPuranjay Mohan unsigned long pc)
1667caa9765SPuranjay Mohan {
1677caa9765SPuranjay Mohan arch_ftrace_regs(fregs)->epc = pc;
1687888af41SSteven Rostedt }
1697caa9765SPuranjay Mohan
ftrace_regs_get_stack_pointer(const struct ftrace_regs * fregs)1707caa9765SPuranjay Mohan static __always_inline unsigned long ftrace_regs_get_stack_pointer(const struct ftrace_regs *fregs)
1717caa9765SPuranjay Mohan {
1727caa9765SPuranjay Mohan return arch_ftrace_regs(fregs)->sp;
1737caa9765SPuranjay Mohan }
1747caa9765SPuranjay Mohan
ftrace_regs_get_frame_pointer(const struct ftrace_regs * fregs)1757888af41SSteven Rostedt static __always_inline unsigned long ftrace_regs_get_frame_pointer(const struct ftrace_regs *fregs)
1767caa9765SPuranjay Mohan {
1777caa9765SPuranjay Mohan return arch_ftrace_regs(fregs)->s0;
1787caa9765SPuranjay Mohan }
1797caa9765SPuranjay Mohan
ftrace_regs_get_argument(struct ftrace_regs * fregs,unsigned int n)1807caa9765SPuranjay Mohan static __always_inline unsigned long ftrace_regs_get_argument(struct ftrace_regs *fregs,
1817888af41SSteven Rostedt unsigned int n)
1827caa9765SPuranjay Mohan {
1837caa9765SPuranjay Mohan if (n < 8)
1847caa9765SPuranjay Mohan return arch_ftrace_regs(fregs)->args[n];
1857caa9765SPuranjay Mohan return 0;
1867caa9765SPuranjay Mohan }
1877888af41SSteven Rostedt
ftrace_regs_get_return_value(const struct ftrace_regs * fregs)1887caa9765SPuranjay Mohan static __always_inline unsigned long ftrace_regs_get_return_value(const struct ftrace_regs *fregs)
1897caa9765SPuranjay Mohan {
1907caa9765SPuranjay Mohan return arch_ftrace_regs(fregs)->a0;
1917caa9765SPuranjay Mohan }
1927888af41SSteven Rostedt
ftrace_regs_get_return_address(const struct ftrace_regs * fregs)1937caa9765SPuranjay Mohan static __always_inline unsigned long ftrace_regs_get_return_address(const struct ftrace_regs *fregs)
1947caa9765SPuranjay Mohan {
1957caa9765SPuranjay Mohan return arch_ftrace_regs(fregs)->ra;
1967caa9765SPuranjay Mohan }
19735e61e88SSong Shuai
ftrace_regs_set_return_value(struct ftrace_regs * fregs,unsigned long ret)19835e61e88SSong Shuai static __always_inline void ftrace_regs_set_return_value(struct ftrace_regs *fregs,
19935e61e88SSong Shuai unsigned long ret)
200196c79f1SSong Shuai {
2017caa9765SPuranjay Mohan arch_ftrace_regs(fregs)->a0 = ret;
202196c79f1SSong Shuai }
2037888af41SSteven Rostedt
ftrace_override_function_with_return(struct ftrace_regs * fregs)204196c79f1SSong Shuai static __always_inline void ftrace_override_function_with_return(struct ftrace_regs *fregs)
2057caa9765SPuranjay Mohan {
20635e61e88SSong Shuai arch_ftrace_regs(fregs)->epc = arch_ftrace_regs(fregs)->ra;
20735e61e88SSong Shuai }
20866d18dbdSPalmer Dabbelt
2092a8db5ecSConor Dooley static __always_inline struct pt_regs *
ftrace_partial_regs(const struct ftrace_regs * fregs,struct pt_regs * regs)2106b57ba8eSZong Li ftrace_partial_regs(const struct ftrace_regs *fregs, struct pt_regs *regs)
211b97aec08SDonglin Peng {
212b97aec08SDonglin Peng struct __arch_ftrace_regs *afregs = arch_ftrace_regs(fregs);
213b97aec08SDonglin Peng
214b97aec08SDonglin Peng memcpy(®s->a_regs, afregs->args, sizeof(afregs->args));
215b97aec08SDonglin Peng regs->epc = afregs->epc;
216b97aec08SDonglin Peng regs->ra = afregs->ra;
217b97aec08SDonglin Peng regs->sp = afregs->sp;
218b97aec08SDonglin Peng regs->s0 = afregs->s0;
219b97aec08SDonglin Peng regs->t1 = afregs->t1;
220b97aec08SDonglin Peng return regs;
221b97aec08SDonglin Peng }
222b97aec08SDonglin Peng
223b97aec08SDonglin Peng int ftrace_regs_query_register_offset(const char *name);
224b97aec08SDonglin Peng
225b97aec08SDonglin Peng void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
226b97aec08SDonglin Peng struct ftrace_ops *op, struct ftrace_regs *fregs);
227b97aec08SDonglin Peng #define ftrace_graph_func ftrace_graph_func
228b97aec08SDonglin Peng
229b97aec08SDonglin Peng #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
arch_ftrace_set_direct_caller(struct ftrace_regs * fregs,unsigned long addr)230b97aec08SDonglin Peng static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr)
231b97aec08SDonglin Peng {
2326b57ba8eSZong Li 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 /* __ASSEMBLER__ */
239
240 #endif /* CONFIG_DYNAMIC_FTRACE */
241
242 #endif /* _ASM_RISCV_FTRACE_H */
243