1/* SPDX-License-Identifier: GPL-2.0 */ 2/* 3 * Copyright (C) 2022 Loongson Technology Corporation Limited 4 */ 5 6#include <asm/ftrace.h> 7#include <asm/regdef.h> 8#include <asm/stackframe.h> 9 10 .text 11/* 12 * Due to -fpatchable-function-entry=2: the compiler inserted 2 NOPs before the 13 * regular C function prologue. When PC arrived here, the last 2 instructions 14 * are as follows: 15 * move t0, ra 16 * bl callsite (for modules, callsite is a tramplione) 17 * 18 * modules trampoline is as follows: 19 * lu12i.w t1, callsite[31:12] 20 * lu32i.d t1, callsite[51:32] 21 * lu52i.d t1, t1, callsite[63:52] 22 * jirl zero, t1, callsite[11:0] >> 2 23 * 24 * See arch/loongarch/kernel/ftrace_dyn.c for details. Here, pay attention to 25 * that the T series regs are available and safe because each C functions 26 * follows the LoongArch's psABI as well. 27 */ 28 29 .macro ftrace_regs_entry allregs=0 30 PTR_ADDI sp, sp, -PT_SIZE 31 PTR_S t0, sp, PT_R1 /* Save parent ra at PT_R1(RA) */ 32 PTR_S a0, sp, PT_R4 33 PTR_S a1, sp, PT_R5 34 PTR_S a2, sp, PT_R6 35 PTR_S a3, sp, PT_R7 36 PTR_S a4, sp, PT_R8 37 PTR_S a5, sp, PT_R9 38 PTR_S a6, sp, PT_R10 39 PTR_S a7, sp, PT_R11 40 PTR_S fp, sp, PT_R22 41 .if \allregs 42 PTR_S tp, sp, PT_R2 43 PTR_S t0, sp, PT_R12 44 PTR_S t2, sp, PT_R14 45 PTR_S t3, sp, PT_R15 46 PTR_S t4, sp, PT_R16 47 PTR_S t5, sp, PT_R17 48 PTR_S t6, sp, PT_R18 49 PTR_S t7, sp, PT_R19 50 PTR_S t8, sp, PT_R20 51 PTR_S u0, sp, PT_R21 52 PTR_S s0, sp, PT_R23 53 PTR_S s1, sp, PT_R24 54 PTR_S s2, sp, PT_R25 55 PTR_S s3, sp, PT_R26 56 PTR_S s4, sp, PT_R27 57 PTR_S s5, sp, PT_R28 58 PTR_S s6, sp, PT_R29 59 PTR_S s7, sp, PT_R30 60 PTR_S s8, sp, PT_R31 61 /* Clear it for later use as a flag sometimes. */ 62 PTR_S zero, sp, PT_R0 63 .endif 64 PTR_S ra, sp, PT_ERA /* Save trace function ra at PT_ERA */ 65 move t1, zero 66 PTR_S t1, sp, PT_R13 67 PTR_ADDI t8, sp, PT_SIZE 68 PTR_S t8, sp, PT_R3 69 .endm 70 71SYM_FUNC_START(ftrace_stub) 72 jr ra 73SYM_FUNC_END(ftrace_stub) 74 75SYM_CODE_START(ftrace_common) 76 PTR_ADDI a0, ra, -8 /* arg0: ip */ 77 move a1, t0 /* arg1: parent_ip */ 78 la.pcrel t1, function_trace_op 79 PTR_L a2, t1, 0 /* arg2: op */ 80 move a3, sp /* arg3: regs */ 81 82SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) 83 bl ftrace_stub 84#ifdef CONFIG_FUNCTION_GRAPH_TRACER 85SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) 86 nop /* b ftrace_graph_caller */ 87#endif 88 89/* 90 * As we didn't use S series regs in this assmembly code and all calls 91 * are C function which will save S series regs by themselves, there is 92 * no need to restore S series regs. The T series is available and safe 93 * at the callsite, so there is no need to restore the T series regs. 94 */ 95ftrace_common_return: 96 PTR_L ra, sp, PT_R1 97 PTR_L a0, sp, PT_R4 98 PTR_L a1, sp, PT_R5 99 PTR_L a2, sp, PT_R6 100 PTR_L a3, sp, PT_R7 101 PTR_L a4, sp, PT_R8 102 PTR_L a5, sp, PT_R9 103 PTR_L a6, sp, PT_R10 104 PTR_L a7, sp, PT_R11 105 PTR_L fp, sp, PT_R22 106 PTR_L t0, sp, PT_ERA 107 PTR_L t1, sp, PT_R13 108 PTR_ADDI sp, sp, PT_SIZE 109 bnez t1, .Ldirect 110 jr t0 111.Ldirect: 112 jr t1 113SYM_CODE_END(ftrace_common) 114 115SYM_CODE_START(ftrace_caller) 116 ftrace_regs_entry allregs=0 117 b ftrace_common 118SYM_CODE_END(ftrace_caller) 119 120#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 121SYM_CODE_START(ftrace_regs_caller) 122 ftrace_regs_entry allregs=1 123 b ftrace_common 124SYM_CODE_END(ftrace_regs_caller) 125#endif 126 127#ifdef CONFIG_FUNCTION_GRAPH_TRACER 128SYM_CODE_START(ftrace_graph_caller) 129 PTR_L a0, sp, PT_ERA 130 PTR_ADDI a0, a0, -8 /* arg0: self_addr */ 131 PTR_ADDI a1, sp, PT_R1 /* arg1: parent */ 132 bl prepare_ftrace_return 133 b ftrace_common_return 134SYM_CODE_END(ftrace_graph_caller) 135 136SYM_CODE_START(return_to_handler) 137 /* Save return value regs */ 138 PTR_ADDI sp, sp, -FGRET_REGS_SIZE 139 PTR_S a0, sp, FGRET_REGS_A0 140 PTR_S a1, sp, FGRET_REGS_A1 141 PTR_S zero, sp, FGRET_REGS_FP 142 143 move a0, sp 144 bl ftrace_return_to_handler 145 move ra, a0 146 147 /* Restore return value regs */ 148 PTR_L a0, sp, FGRET_REGS_A0 149 PTR_L a1, sp, FGRET_REGS_A1 150 PTR_ADDI sp, sp, FGRET_REGS_SIZE 151 152 jr ra 153SYM_CODE_END(return_to_handler) 154#endif 155 156#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS 157SYM_CODE_START(ftrace_stub_direct_tramp) 158 jr t0 159SYM_CODE_END(ftrace_stub_direct_tramp) 160#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ 161