1/* SPDX-License-Identifier: GPL-2.0 */ 2/* Copyright (C) 2017 Andes Technology Corporation */ 3 4#include <linux/init.h> 5#include <linux/linkage.h> 6#include <linux/export.h> 7#include <asm/asm.h> 8#include <asm/csr.h> 9#include <asm/unistd.h> 10#include <asm/thread_info.h> 11#include <asm/asm-offsets.h> 12#include <asm/ftrace.h> 13 14 .text 15 16#define ABI_SIZE_ON_STACK 80 17#define ABI_A0 0 18#define ABI_A1 8 19#define ABI_A2 16 20#define ABI_A3 24 21#define ABI_A4 32 22#define ABI_A5 40 23#define ABI_A6 48 24#define ABI_A7 56 25#define ABI_T0 64 26#define ABI_RA 72 27 28 .macro SAVE_ABI 29 addi sp, sp, -ABI_SIZE_ON_STACK 30 31 REG_S a0, ABI_A0(sp) 32 REG_S a1, ABI_A1(sp) 33 REG_S a2, ABI_A2(sp) 34 REG_S a3, ABI_A3(sp) 35 REG_S a4, ABI_A4(sp) 36 REG_S a5, ABI_A5(sp) 37 REG_S a6, ABI_A6(sp) 38 REG_S a7, ABI_A7(sp) 39 REG_S t0, ABI_T0(sp) 40 REG_S ra, ABI_RA(sp) 41 .endm 42 43 .macro RESTORE_ABI 44 REG_L a0, ABI_A0(sp) 45 REG_L a1, ABI_A1(sp) 46 REG_L a2, ABI_A2(sp) 47 REG_L a3, ABI_A3(sp) 48 REG_L a4, ABI_A4(sp) 49 REG_L a5, ABI_A5(sp) 50 REG_L a6, ABI_A6(sp) 51 REG_L a7, ABI_A7(sp) 52 REG_L t0, ABI_T0(sp) 53 REG_L ra, ABI_RA(sp) 54 55 addi sp, sp, ABI_SIZE_ON_STACK 56 .endm 57 58/** 59* SAVE_ABI_REGS - save regs against the ftrace_regs struct 60* 61* After the stack is established, 62* 63* 0(sp) stores the PC of the traced function which can be accessed 64* by &(fregs)->epc in tracing function. 65* 66* 8(sp) stores the function return address (i.e. parent IP) that 67* can be accessed by &(fregs)->ra in tracing function. 68* 69* The other regs are saved at the respective localtion and accessed 70* by the respective ftrace_regs member. 71* 72* Here is the layout of stack for your reference. 73* 74* PT_SIZE_ON_STACK -> +++++++++ 75* + ..... + 76* + a0-a7 + --++++-> ftrace_caller saved 77* + t1 + --++++-> direct tramp address 78* + s0 + --+ // frame pointer 79* + sp + + 80* + ra + --+ // parent IP 81* sp -> + epc + --+ // PC 82* +++++++++ 83**/ 84 .macro SAVE_ABI_REGS 85 addi sp, sp, -FREGS_SIZE_ON_STACK 86 REG_S t0, FREGS_EPC(sp) 87 REG_S x1, FREGS_RA(sp) 88#ifdef HAVE_FUNCTION_GRAPH_FP_TEST 89 REG_S x8, FREGS_S0(sp) 90#endif 91 REG_S x6, FREGS_T1(sp) 92#ifdef CONFIG_CC_IS_CLANG 93 REG_S x7, FREGS_T2(sp) 94 REG_S x28, FREGS_T3(sp) 95 REG_S x29, FREGS_T4(sp) 96 REG_S x30, FREGS_T5(sp) 97 REG_S x31, FREGS_T6(sp) 98#endif 99 // save the arguments 100 REG_S x10, FREGS_A0(sp) 101 REG_S x11, FREGS_A1(sp) 102 REG_S x12, FREGS_A2(sp) 103 REG_S x13, FREGS_A3(sp) 104 REG_S x14, FREGS_A4(sp) 105 REG_S x15, FREGS_A5(sp) 106 REG_S x16, FREGS_A6(sp) 107 REG_S x17, FREGS_A7(sp) 108 mv a0, sp 109 addi a0, a0, FREGS_SIZE_ON_STACK 110 REG_S a0, FREGS_SP(sp) // Put original SP on stack 111 .endm 112 113 .macro RESTORE_ABI_REGS 114 REG_L t0, FREGS_EPC(sp) 115 REG_L x1, FREGS_RA(sp) 116#ifdef HAVE_FUNCTION_GRAPH_FP_TEST 117 REG_L x8, FREGS_S0(sp) 118#endif 119 REG_L x6, FREGS_T1(sp) 120#ifdef CONFIG_CC_IS_CLANG 121 REG_L x7, FREGS_T2(sp) 122 REG_L x28, FREGS_T3(sp) 123 REG_L x29, FREGS_T4(sp) 124 REG_L x30, FREGS_T5(sp) 125 REG_L x31, FREGS_T6(sp) 126#endif 127 // restore the arguments 128 REG_L x10, FREGS_A0(sp) 129 REG_L x11, FREGS_A1(sp) 130 REG_L x12, FREGS_A2(sp) 131 REG_L x13, FREGS_A3(sp) 132 REG_L x14, FREGS_A4(sp) 133 REG_L x15, FREGS_A5(sp) 134 REG_L x16, FREGS_A6(sp) 135 REG_L x17, FREGS_A7(sp) 136 137 addi sp, sp, FREGS_SIZE_ON_STACK 138 .endm 139 140 .macro PREPARE_ARGS 141 addi a0, t0, -MCOUNT_JALR_SIZE // ip (callsite's jalr insn) 142#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS 143 mv a1, ra // parent_ip 144 REG_L a2, -16(t0) // op 145 REG_L ra, FTRACE_OPS_FUNC(a2) // op->func 146#else 147 la a1, function_trace_op 148 REG_L a2, 0(a1) // op 149 mv a1, ra // parent_ip 150#endif 151 mv a3, sp // regs 152 .endm 153 154SYM_FUNC_START(ftrace_caller) 155#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS 156 /* 157 * When CALL_OPS is enabled (2 or 4) nops [8B] are placed before the 158 * function entry, these are later overwritten with the pointer to the 159 * associated struct ftrace_ops. 160 * 161 * -8: &ftrace_ops of the associated tracer function. 162 *<ftrace enable>: 163 * 0: auipc t0/ra, 0x? 164 * 4: jalr t0/ra, ?(t0/ra) 165 * 166 * -8: &ftrace_nop_ops 167 *<ftrace disable>: 168 * 0: nop 169 * 4: nop 170 * 171 * t0 is set to ip+8 after the jalr is executed at the callsite, 172 * so we find the associated op at t0-16. 173 */ 174 REG_L t1, -16(t0) // op Should be SZ_REG instead of 16 175 176#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS 177 /* 178 * If the op has a direct call, handle it immediately without 179 * saving/restoring registers. 180 */ 181 REG_L t1, FTRACE_OPS_DIRECT_CALL(t1) 182 bnez t1, ftrace_caller_direct 183#endif 184#endif 185 SAVE_ABI_REGS 186 PREPARE_ARGS 187 188#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS 189 jalr ra 190#else 191SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) 192 REG_L ra, ftrace_call_dest 193 jalr ra, 0(ra) 194#endif 195 RESTORE_ABI_REGS 196#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS 197 bnez t1, ftrace_caller_direct 198#endif 199 jr t0 200#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS 201SYM_INNER_LABEL(ftrace_caller_direct, SYM_L_LOCAL) 202 jr t1 203#endif 204SYM_FUNC_END(ftrace_caller) 205 206#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS 207SYM_CODE_START(ftrace_stub_direct_tramp) 208 jr t0 209SYM_CODE_END(ftrace_stub_direct_tramp) 210#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ 211