|  | /* 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 */ |