| /* SPDX-License-Identifier: GPL-2.0 */ | |
| /* Copyright (C) 2017 Andes Technology Corporation */ | |
| #include <linux/init.h> | |
| #include <linux/linkage.h> | |
| #include <asm/asm.h> | |
| #include <asm/csr.h> | |
| #include <asm/unistd.h> | |
| #include <asm/thread_info.h> | |
| #include <asm/asm-offsets.h> | |
| #include <asm-generic/export.h> | |
| #include <asm/ftrace.h> | |
| .text | |
| .macro SAVE_ABI_STATE | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| addi sp, sp, -48 | |
| sd s0, 32(sp) | |
| sd ra, 40(sp) | |
| addi s0, sp, 48 | |
| sd t0, 24(sp) | |
| sd t1, 16(sp) | |
| #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | |
| sd t2, 8(sp) | |
| #endif | |
| #else | |
| addi sp, sp, -16 | |
| sd s0, 0(sp) | |
| sd ra, 8(sp) | |
| addi s0, sp, 16 | |
| #endif | |
| .endm | |
| .macro RESTORE_ABI_STATE | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| ld s0, 32(sp) | |
| ld ra, 40(sp) | |
| addi sp, sp, 48 | |
| #else | |
| ld ra, 8(sp) | |
| ld s0, 0(sp) | |
| addi sp, sp, 16 | |
| #endif | |
| .endm | |
| .macro RESTORE_GRAPH_ARGS | |
| ld a0, 24(sp) | |
| ld a1, 16(sp) | |
| #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | |
| ld a2, 8(sp) | |
| #endif | |
| .endm | |
| ENTRY(ftrace_graph_caller) | |
| addi sp, sp, -16 | |
| sd s0, 0(sp) | |
| sd ra, 8(sp) | |
| addi s0, sp, 16 | |
| ftrace_graph_call: | |
| .global ftrace_graph_call | |
| /* | |
| * Calling ftrace_enable/disable_ftrace_graph_caller would overwrite the | |
| * call below. Check ftrace_modify_all_code for details. | |
| */ | |
| call ftrace_stub | |
| ld ra, 8(sp) | |
| ld s0, 0(sp) | |
| addi sp, sp, 16 | |
| ret | |
| ENDPROC(ftrace_graph_caller) | |
| ENTRY(ftrace_caller) | |
| /* | |
| * a0: the address in the caller when calling ftrace_caller | |
| * a1: the caller's return address | |
| * a2: the address of global variable function_trace_op | |
| */ | |
| ld a1, -8(s0) | |
| addi a0, ra, -MCOUNT_INSN_SIZE | |
| la t5, function_trace_op | |
| ld a2, 0(t5) | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| /* | |
| * the graph tracer (specifically, prepare_ftrace_return) needs these | |
| * arguments but for now the function tracer occupies the regs, so we | |
| * save them in temporary regs to recover later. | |
| */ | |
| addi t0, s0, -8 | |
| mv t1, a0 | |
| #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | |
| ld t2, -16(s0) | |
| #endif | |
| #endif | |
| SAVE_ABI_STATE | |
| ftrace_call: | |
| .global ftrace_call | |
| /* | |
| * For the dynamic ftrace to work, here we should reserve at least | |
| * 8 bytes for a functional auipc-jalr pair. The following call | |
| * serves this purpose. | |
| * | |
| * Calling ftrace_update_ftrace_func would overwrite the nops below. | |
| * Check ftrace_modify_all_code for details. | |
| */ | |
| call ftrace_stub | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| RESTORE_GRAPH_ARGS | |
| call ftrace_graph_caller | |
| #endif | |
| RESTORE_ABI_STATE | |
| ret | |
| ENDPROC(ftrace_caller) | |
| #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS | |
| .macro SAVE_ALL | |
| addi sp, sp, -(PT_SIZE_ON_STACK+16) | |
| sd s0, (PT_SIZE_ON_STACK)(sp) | |
| sd ra, (PT_SIZE_ON_STACK+8)(sp) | |
| addi s0, sp, (PT_SIZE_ON_STACK+16) | |
| sd x1, PT_RA(sp) | |
| sd x2, PT_SP(sp) | |
| sd x3, PT_GP(sp) | |
| sd x4, PT_TP(sp) | |
| sd x5, PT_T0(sp) | |
| sd x6, PT_T1(sp) | |
| sd x7, PT_T2(sp) | |
| sd x8, PT_S0(sp) | |
| sd x9, PT_S1(sp) | |
| sd x10, PT_A0(sp) | |
| sd x11, PT_A1(sp) | |
| sd x12, PT_A2(sp) | |
| sd x13, PT_A3(sp) | |
| sd x14, PT_A4(sp) | |
| sd x15, PT_A5(sp) | |
| sd x16, PT_A6(sp) | |
| sd x17, PT_A7(sp) | |
| sd x18, PT_S2(sp) | |
| sd x19, PT_S3(sp) | |
| sd x20, PT_S4(sp) | |
| sd x21, PT_S5(sp) | |
| sd x22, PT_S6(sp) | |
| sd x23, PT_S7(sp) | |
| sd x24, PT_S8(sp) | |
| sd x25, PT_S9(sp) | |
| sd x26, PT_S10(sp) | |
| sd x27, PT_S11(sp) | |
| sd x28, PT_T3(sp) | |
| sd x29, PT_T4(sp) | |
| sd x30, PT_T5(sp) | |
| sd x31, PT_T6(sp) | |
| .endm | |
| .macro RESTORE_ALL | |
| ld x1, PT_RA(sp) | |
| ld x2, PT_SP(sp) | |
| ld x3, PT_GP(sp) | |
| ld x4, PT_TP(sp) | |
| ld x5, PT_T0(sp) | |
| ld x6, PT_T1(sp) | |
| ld x7, PT_T2(sp) | |
| ld x8, PT_S0(sp) | |
| ld x9, PT_S1(sp) | |
| ld x10, PT_A0(sp) | |
| ld x11, PT_A1(sp) | |
| ld x12, PT_A2(sp) | |
| ld x13, PT_A3(sp) | |
| ld x14, PT_A4(sp) | |
| ld x15, PT_A5(sp) | |
| ld x16, PT_A6(sp) | |
| ld x17, PT_A7(sp) | |
| ld x18, PT_S2(sp) | |
| ld x19, PT_S3(sp) | |
| ld x20, PT_S4(sp) | |
| ld x21, PT_S5(sp) | |
| ld x22, PT_S6(sp) | |
| ld x23, PT_S7(sp) | |
| ld x24, PT_S8(sp) | |
| ld x25, PT_S9(sp) | |
| ld x26, PT_S10(sp) | |
| ld x27, PT_S11(sp) | |
| ld x28, PT_T3(sp) | |
| ld x29, PT_T4(sp) | |
| ld x30, PT_T5(sp) | |
| ld x31, PT_T6(sp) | |
| ld s0, (PT_SIZE_ON_STACK)(sp) | |
| ld ra, (PT_SIZE_ON_STACK+8)(sp) | |
| addi sp, sp, (PT_SIZE_ON_STACK+16) | |
| .endm | |
| .macro RESTORE_GRAPH_REG_ARGS | |
| ld a0, PT_T0(sp) | |
| ld a1, PT_T1(sp) | |
| #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | |
| ld a2, PT_T2(sp) | |
| #endif | |
| .endm | |
| /* | |
| * Most of the contents are the same as ftrace_caller. | |
| */ | |
| ENTRY(ftrace_regs_caller) | |
| /* | |
| * a3: the address of all registers in the stack | |
| */ | |
| ld a1, -8(s0) | |
| addi a0, ra, -MCOUNT_INSN_SIZE | |
| la t5, function_trace_op | |
| ld a2, 0(t5) | |
| addi a3, sp, -(PT_SIZE_ON_STACK+16) | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| addi t0, s0, -8 | |
| mv t1, a0 | |
| #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | |
| ld t2, -16(s0) | |
| #endif | |
| #endif | |
| SAVE_ALL | |
| ftrace_regs_call: | |
| .global ftrace_regs_call | |
| call ftrace_stub | |
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
| RESTORE_GRAPH_REG_ARGS | |
| call ftrace_graph_caller | |
| #endif | |
| RESTORE_ALL | |
| ret | |
| ENDPROC(ftrace_regs_caller) | |
| #endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ |