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 UNWIND_HINT_UNDEFINED 77 PTR_ADDI a0, ra, -8 /* arg0: ip */ 78 move a1, t0 /* arg1: parent_ip */ 79 la.pcrel t1, function_trace_op 80 PTR_L a2, t1, 0 /* arg2: op */ 81 move a3, sp /* arg3: regs */ 82 83SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) 84 bl ftrace_stub 85#ifdef CONFIG_FUNCTION_GRAPH_TRACER 86SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) 87 nop /* b ftrace_graph_caller */ 88#endif 89 90/* 91 * As we didn't use S series regs in this assmembly code and all calls 92 * are C function which will save S series regs by themselves, there is 93 * no need to restore S series regs. The T series is available and safe 94 * at the callsite, so there is no need to restore the T series regs. 95 */ 96ftrace_common_return: 97 PTR_L ra, sp, PT_R1 98 PTR_L a0, sp, PT_R4 99 PTR_L a1, sp, PT_R5 100 PTR_L a2, sp, PT_R6 101 PTR_L a3, sp, PT_R7 102 PTR_L a4, sp, PT_R8 103 PTR_L a5, sp, PT_R9 104 PTR_L a6, sp, PT_R10 105 PTR_L a7, sp, PT_R11 106 PTR_L fp, sp, PT_R22 107 PTR_L t0, sp, PT_ERA 108 PTR_L t1, sp, PT_R13 109 PTR_ADDI sp, sp, PT_SIZE 110 bnez t1, .Ldirect 111 jr t0 112.Ldirect: 113 jr t1 114SYM_CODE_END(ftrace_common) 115 116SYM_CODE_START(ftrace_caller) 117 UNWIND_HINT_UNDEFINED 118 ftrace_regs_entry allregs=0 119 b ftrace_common 120SYM_CODE_END(ftrace_caller) 121 122#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 123SYM_CODE_START(ftrace_regs_caller) 124 UNWIND_HINT_UNDEFINED 125 ftrace_regs_entry allregs=1 126 b ftrace_common 127SYM_CODE_END(ftrace_regs_caller) 128#endif 129 130#ifdef CONFIG_FUNCTION_GRAPH_TRACER 131SYM_CODE_START(ftrace_graph_caller) 132 UNWIND_HINT_UNDEFINED 133 PTR_L a0, sp, PT_ERA 134 PTR_ADDI a0, a0, -8 /* arg0: self_addr */ 135 PTR_ADDI a1, sp, PT_R1 /* arg1: parent */ 136 bl prepare_ftrace_return 137 b ftrace_common_return 138SYM_CODE_END(ftrace_graph_caller) 139 140SYM_CODE_START(return_to_handler) 141 UNWIND_HINT_UNDEFINED 142 /* Save return value regs */ 143 PTR_ADDI sp, sp, -FGRET_REGS_SIZE 144 PTR_S a0, sp, FGRET_REGS_A0 145 PTR_S a1, sp, FGRET_REGS_A1 146 PTR_S zero, sp, FGRET_REGS_FP 147 148 move a0, sp 149 bl ftrace_return_to_handler 150 move ra, a0 151 152 /* Restore return value regs */ 153 PTR_L a0, sp, FGRET_REGS_A0 154 PTR_L a1, sp, FGRET_REGS_A1 155 PTR_ADDI sp, sp, FGRET_REGS_SIZE 156 157 jr ra 158SYM_CODE_END(return_to_handler) 159#endif 160 161#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS 162SYM_CODE_START(ftrace_stub_direct_tramp) 163 UNWIND_HINT_UNDEFINED 164 jr t0 165SYM_CODE_END(ftrace_stub_direct_tramp) 166#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ 167