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#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
15
16/*
17 * Clang prior to 13 had "mcount" instead of "_mcount":
18 * https://reviews.llvm.org/D98881
19 */
20#if defined(CONFIG_CC_IS_GCC) || CONFIG_CLANG_VERSION >= 130000
21#define MCOUNT_NAME _mcount
22#else
23#define MCOUNT_NAME mcount
24#endif
25
26#define ARCH_SUPPORTS_FTRACE_OPS 1
27#ifndef __ASSEMBLY__
28void MCOUNT_NAME(void);
29static inline unsigned long ftrace_call_adjust(unsigned long addr)
30{
31	return addr;
32}
33
34struct dyn_arch_ftrace {
35};
36#endif
37
38#ifdef CONFIG_DYNAMIC_FTRACE
39/*
40 * A general call in RISC-V is a pair of insts:
41 * 1) auipc: setting high-20 pc-related bits to ra register
42 * 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to
43 *          return address (original pc + 4)
44 *
45 * Dynamic ftrace generates probes to call sites, so we must deal with
46 * both auipc and jalr at the same time.
47 */
48
49#define MCOUNT_ADDR		((unsigned long)MCOUNT_NAME)
50#define JALR_SIGN_MASK		(0x00000800)
51#define JALR_OFFSET_MASK	(0x00000fff)
52#define AUIPC_OFFSET_MASK	(0xfffff000)
53#define AUIPC_PAD		(0x00001000)
54#define JALR_SHIFT		20
55#define JALR_BASIC		(0x000080e7)
56#define AUIPC_BASIC		(0x00000097)
57#define NOP4			(0x00000013)
58
59#define make_call(caller, callee, call)					\
60do {									\
61	call[0] = to_auipc_insn((unsigned int)((unsigned long)callee -	\
62				(unsigned long)caller));		\
63	call[1] = to_jalr_insn((unsigned int)((unsigned long)callee -	\
64			       (unsigned long)caller));			\
65} while (0)
66
67#define to_jalr_insn(offset)						\
68	(((offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_BASIC)
69
70#define to_auipc_insn(offset)						\
71	((offset & JALR_SIGN_MASK) ?					\
72	(((offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_BASIC) :	\
73	((offset & AUIPC_OFFSET_MASK) | AUIPC_BASIC))
74
75/*
76 * Let auipc+jalr be the basic *mcount unit*, so we make it 8 bytes here.
77 */
78#define MCOUNT_INSN_SIZE 8
79
80#ifndef __ASSEMBLY__
81struct dyn_ftrace;
82int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
83#define ftrace_init_nop ftrace_init_nop
84#endif
85
86#endif /* CONFIG_DYNAMIC_FTRACE */
87
88#endif /* _ASM_RISCV_FTRACE_H */
89