14733f09dSQing Zhang/* SPDX-License-Identifier: GPL-2.0 */ 24733f09dSQing Zhang/* 34733f09dSQing Zhang * Copyright (C) 2022 Loongson Technology Corporation Limited 44733f09dSQing Zhang */ 54733f09dSQing Zhang 64733f09dSQing Zhang#include <asm/ftrace.h> 74733f09dSQing Zhang#include <asm/regdef.h> 84733f09dSQing Zhang#include <asm/stackframe.h> 94733f09dSQing Zhang 104733f09dSQing Zhang .text 114733f09dSQing Zhang/* 124733f09dSQing Zhang * Due to -fpatchable-function-entry=2: the compiler inserted 2 NOPs before the 134733f09dSQing Zhang * regular C function prologue. When PC arrived here, the last 2 instructions 144733f09dSQing Zhang * are as follows: 154733f09dSQing Zhang * move t0, ra 164733f09dSQing Zhang * bl callsite (for modules, callsite is a tramplione) 174733f09dSQing Zhang * 184733f09dSQing Zhang * modules trampoline is as follows: 194733f09dSQing Zhang * lu12i.w t1, callsite[31:12] 204733f09dSQing Zhang * lu32i.d t1, callsite[51:32] 214733f09dSQing Zhang * lu52i.d t1, t1, callsite[63:52] 224733f09dSQing Zhang * jirl zero, t1, callsite[11:0] >> 2 234733f09dSQing Zhang * 244733f09dSQing Zhang * See arch/loongarch/kernel/ftrace_dyn.c for details. Here, pay attention to 254733f09dSQing Zhang * that the T series regs are available and safe because each C functions 264733f09dSQing Zhang * follows the LoongArch's psABI as well. 274733f09dSQing Zhang */ 284733f09dSQing Zhang 298778ba2cSQing Zhang .macro ftrace_regs_entry allregs=0 304733f09dSQing Zhang PTR_ADDI sp, sp, -PT_SIZE 314733f09dSQing Zhang PTR_S t0, sp, PT_R1 /* Save parent ra at PT_R1(RA) */ 324733f09dSQing Zhang PTR_S a0, sp, PT_R4 334733f09dSQing Zhang PTR_S a1, sp, PT_R5 344733f09dSQing Zhang PTR_S a2, sp, PT_R6 354733f09dSQing Zhang PTR_S a3, sp, PT_R7 364733f09dSQing Zhang PTR_S a4, sp, PT_R8 374733f09dSQing Zhang PTR_S a5, sp, PT_R9 384733f09dSQing Zhang PTR_S a6, sp, PT_R10 394733f09dSQing Zhang PTR_S a7, sp, PT_R11 404733f09dSQing Zhang PTR_S fp, sp, PT_R22 418778ba2cSQing Zhang .if \allregs 428778ba2cSQing Zhang PTR_S tp, sp, PT_R2 438778ba2cSQing Zhang PTR_S t0, sp, PT_R12 448778ba2cSQing Zhang PTR_S t2, sp, PT_R14 458778ba2cSQing Zhang PTR_S t3, sp, PT_R15 468778ba2cSQing Zhang PTR_S t4, sp, PT_R16 478778ba2cSQing Zhang PTR_S t5, sp, PT_R17 488778ba2cSQing Zhang PTR_S t6, sp, PT_R18 498778ba2cSQing Zhang PTR_S t7, sp, PT_R19 508778ba2cSQing Zhang PTR_S t8, sp, PT_R20 518778ba2cSQing Zhang PTR_S u0, sp, PT_R21 528778ba2cSQing Zhang PTR_S s0, sp, PT_R23 538778ba2cSQing Zhang PTR_S s1, sp, PT_R24 548778ba2cSQing Zhang PTR_S s2, sp, PT_R25 558778ba2cSQing Zhang PTR_S s3, sp, PT_R26 568778ba2cSQing Zhang PTR_S s4, sp, PT_R27 578778ba2cSQing Zhang PTR_S s5, sp, PT_R28 588778ba2cSQing Zhang PTR_S s6, sp, PT_R29 598778ba2cSQing Zhang PTR_S s7, sp, PT_R30 608778ba2cSQing Zhang PTR_S s8, sp, PT_R31 618778ba2cSQing Zhang /* Clear it for later use as a flag sometimes. */ 628778ba2cSQing Zhang PTR_S zero, sp, PT_R0 638778ba2cSQing Zhang .endif 644733f09dSQing Zhang PTR_S ra, sp, PT_ERA /* Save trace function ra at PT_ERA */ 659cdc3b6aSYouling Tang move t1, zero 669cdc3b6aSYouling Tang PTR_S t1, sp, PT_R13 674733f09dSQing Zhang PTR_ADDI t8, sp, PT_SIZE 684733f09dSQing Zhang PTR_S t8, sp, PT_R3 694733f09dSQing Zhang .endm 704733f09dSQing Zhang 714733f09dSQing ZhangSYM_FUNC_START(ftrace_stub) 724733f09dSQing Zhang jr ra 734733f09dSQing ZhangSYM_FUNC_END(ftrace_stub) 744733f09dSQing Zhang 754733f09dSQing ZhangSYM_CODE_START(ftrace_common) 764733f09dSQing Zhang PTR_ADDI a0, ra, -8 /* arg0: ip */ 774733f09dSQing Zhang move a1, t0 /* arg1: parent_ip */ 784733f09dSQing Zhang la.pcrel t1, function_trace_op 794733f09dSQing Zhang PTR_L a2, t1, 0 /* arg2: op */ 804733f09dSQing Zhang move a3, sp /* arg3: regs */ 814733f09dSQing Zhang 824733f09dSQing ZhangSYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) 834733f09dSQing Zhang bl ftrace_stub 845fcfad3dSQing Zhang#ifdef CONFIG_FUNCTION_GRAPH_TRACER 855fcfad3dSQing ZhangSYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) 865fcfad3dSQing Zhang nop /* b ftrace_graph_caller */ 875fcfad3dSQing Zhang#endif 885fcfad3dSQing Zhang 894733f09dSQing Zhang/* 904733f09dSQing Zhang * As we didn't use S series regs in this assmembly code and all calls 914733f09dSQing Zhang * are C function which will save S series regs by themselves, there is 924733f09dSQing Zhang * no need to restore S series regs. The T series is available and safe 934733f09dSQing Zhang * at the callsite, so there is no need to restore the T series regs. 944733f09dSQing Zhang */ 954733f09dSQing Zhangftrace_common_return: 964733f09dSQing Zhang PTR_L ra, sp, PT_R1 974733f09dSQing Zhang PTR_L a0, sp, PT_R4 984733f09dSQing Zhang PTR_L a1, sp, PT_R5 994733f09dSQing Zhang PTR_L a2, sp, PT_R6 1004733f09dSQing Zhang PTR_L a3, sp, PT_R7 1014733f09dSQing Zhang PTR_L a4, sp, PT_R8 1024733f09dSQing Zhang PTR_L a5, sp, PT_R9 1034733f09dSQing Zhang PTR_L a6, sp, PT_R10 1044733f09dSQing Zhang PTR_L a7, sp, PT_R11 1054733f09dSQing Zhang PTR_L fp, sp, PT_R22 1064733f09dSQing Zhang PTR_L t0, sp, PT_ERA 1079cdc3b6aSYouling Tang PTR_L t1, sp, PT_R13 1084733f09dSQing Zhang PTR_ADDI sp, sp, PT_SIZE 1099cdc3b6aSYouling Tang bnez t1, .Ldirect 1104733f09dSQing Zhang jr t0 1119cdc3b6aSYouling Tang.Ldirect: 1129cdc3b6aSYouling Tang jr t1 1134733f09dSQing ZhangSYM_CODE_END(ftrace_common) 1144733f09dSQing Zhang 1154733f09dSQing ZhangSYM_CODE_START(ftrace_caller) 1168778ba2cSQing Zhang ftrace_regs_entry allregs=0 1174733f09dSQing Zhang b ftrace_common 1184733f09dSQing ZhangSYM_CODE_END(ftrace_caller) 1195fcfad3dSQing Zhang 1208778ba2cSQing Zhang#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 1218778ba2cSQing ZhangSYM_CODE_START(ftrace_regs_caller) 1228778ba2cSQing Zhang ftrace_regs_entry allregs=1 1238778ba2cSQing Zhang b ftrace_common 1248778ba2cSQing ZhangSYM_CODE_END(ftrace_regs_caller) 1258778ba2cSQing Zhang#endif 1268778ba2cSQing Zhang 1275fcfad3dSQing Zhang#ifdef CONFIG_FUNCTION_GRAPH_TRACER 1285fcfad3dSQing ZhangSYM_CODE_START(ftrace_graph_caller) 1295fcfad3dSQing Zhang PTR_L a0, sp, PT_ERA 1305fcfad3dSQing Zhang PTR_ADDI a0, a0, -8 /* arg0: self_addr */ 1315fcfad3dSQing Zhang PTR_ADDI a1, sp, PT_R1 /* arg1: parent */ 1325fcfad3dSQing Zhang bl prepare_ftrace_return 1335fcfad3dSQing Zhang b ftrace_common_return 1345fcfad3dSQing ZhangSYM_CODE_END(ftrace_graph_caller) 1355fcfad3dSQing Zhang 1365fcfad3dSQing ZhangSYM_CODE_START(return_to_handler) 1375fcfad3dSQing Zhang /* Save return value regs */ 138*5779e3c0SDonglin Peng PTR_ADDI sp, sp, -FGRET_REGS_SIZE 139*5779e3c0SDonglin Peng PTR_S a0, sp, FGRET_REGS_A0 140*5779e3c0SDonglin Peng PTR_S a1, sp, FGRET_REGS_A1 141*5779e3c0SDonglin Peng PTR_S zero, sp, FGRET_REGS_FP 1425fcfad3dSQing Zhang 143*5779e3c0SDonglin Peng move a0, sp 1445fcfad3dSQing Zhang bl ftrace_return_to_handler 1455fcfad3dSQing Zhang move ra, a0 1465fcfad3dSQing Zhang 1475fcfad3dSQing Zhang /* Restore return value regs */ 148*5779e3c0SDonglin Peng PTR_L a0, sp, FGRET_REGS_A0 149*5779e3c0SDonglin Peng PTR_L a1, sp, FGRET_REGS_A1 150*5779e3c0SDonglin Peng PTR_ADDI sp, sp, FGRET_REGS_SIZE 1515fcfad3dSQing Zhang 1525fcfad3dSQing Zhang jr ra 1535fcfad3dSQing ZhangSYM_CODE_END(return_to_handler) 1545fcfad3dSQing Zhang#endif 1559cdc3b6aSYouling Tang 1569cdc3b6aSYouling Tang#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS 1579cdc3b6aSYouling TangSYM_CODE_START(ftrace_stub_direct_tramp) 1589cdc3b6aSYouling Tang jr t0 1599cdc3b6aSYouling TangSYM_CODE_END(ftrace_stub_direct_tramp) 1609cdc3b6aSYouling Tang#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ 161