162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* Copyright (C) 2017 Andes Technology Corporation */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/init.h> 562306a36Sopenharmony_ci#include <linux/linkage.h> 662306a36Sopenharmony_ci#include <linux/cfi_types.h> 762306a36Sopenharmony_ci#include <asm/asm.h> 862306a36Sopenharmony_ci#include <asm/csr.h> 962306a36Sopenharmony_ci#include <asm/unistd.h> 1062306a36Sopenharmony_ci#include <asm/thread_info.h> 1162306a36Sopenharmony_ci#include <asm/asm-offsets.h> 1262306a36Sopenharmony_ci#include <asm-generic/export.h> 1362306a36Sopenharmony_ci#include <asm/ftrace.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci .text 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci .macro SAVE_ABI_STATE 1862306a36Sopenharmony_ci addi sp, sp, -16 1962306a36Sopenharmony_ci REG_S s0, 0*SZREG(sp) 2062306a36Sopenharmony_ci REG_S ra, 1*SZREG(sp) 2162306a36Sopenharmony_ci addi s0, sp, 16 2262306a36Sopenharmony_ci .endm 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci /* 2562306a36Sopenharmony_ci * The call to ftrace_return_to_handler would overwrite the return 2662306a36Sopenharmony_ci * register if a0 was not saved. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci .macro SAVE_RET_ABI_STATE 2962306a36Sopenharmony_ci addi sp, sp, -4*SZREG 3062306a36Sopenharmony_ci REG_S s0, 2*SZREG(sp) 3162306a36Sopenharmony_ci REG_S ra, 3*SZREG(sp) 3262306a36Sopenharmony_ci REG_S a0, 1*SZREG(sp) 3362306a36Sopenharmony_ci REG_S a1, 0*SZREG(sp) 3462306a36Sopenharmony_ci addi s0, sp, 4*SZREG 3562306a36Sopenharmony_ci .endm 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci .macro RESTORE_ABI_STATE 3862306a36Sopenharmony_ci REG_L ra, 1*SZREG(sp) 3962306a36Sopenharmony_ci REG_L s0, 0*SZREG(sp) 4062306a36Sopenharmony_ci addi sp, sp, 16 4162306a36Sopenharmony_ci .endm 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci .macro RESTORE_RET_ABI_STATE 4462306a36Sopenharmony_ci REG_L ra, 3*SZREG(sp) 4562306a36Sopenharmony_ci REG_L s0, 2*SZREG(sp) 4662306a36Sopenharmony_ci REG_L a0, 1*SZREG(sp) 4762306a36Sopenharmony_ci REG_L a1, 0*SZREG(sp) 4862306a36Sopenharmony_ci addi sp, sp, 4*SZREG 4962306a36Sopenharmony_ci .endm 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciSYM_TYPED_FUNC_START(ftrace_stub) 5262306a36Sopenharmony_ci#ifdef CONFIG_DYNAMIC_FTRACE 5362306a36Sopenharmony_ci .global MCOUNT_NAME 5462306a36Sopenharmony_ci .set MCOUNT_NAME, ftrace_stub 5562306a36Sopenharmony_ci#endif 5662306a36Sopenharmony_ci ret 5762306a36Sopenharmony_ciSYM_FUNC_END(ftrace_stub) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER 6062306a36Sopenharmony_ciSYM_TYPED_FUNC_START(ftrace_stub_graph) 6162306a36Sopenharmony_ci ret 6262306a36Sopenharmony_ciSYM_FUNC_END(ftrace_stub_graph) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ciENTRY(return_to_handler) 6562306a36Sopenharmony_ci/* 6662306a36Sopenharmony_ci * On implementing the frame point test, the ideal way is to compare the 6762306a36Sopenharmony_ci * s0 (frame pointer, if enabled) on entry and the sp (stack pointer) on return. 6862306a36Sopenharmony_ci * However, the psABI of variable-length-argument functions does not allow this. 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * So alternatively we check the *old* frame pointer position, that is, the 7162306a36Sopenharmony_ci * value stored in -16(s0) on entry, and the s0 on return. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci SAVE_RET_ABI_STATE 7462306a36Sopenharmony_ci mv a0, sp 7562306a36Sopenharmony_ci call ftrace_return_to_handler 7662306a36Sopenharmony_ci mv a2, a0 7762306a36Sopenharmony_ci RESTORE_RET_ABI_STATE 7862306a36Sopenharmony_ci jalr a2 7962306a36Sopenharmony_ciENDPROC(return_to_handler) 8062306a36Sopenharmony_ci#endif 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#ifndef CONFIG_DYNAMIC_FTRACE 8362306a36Sopenharmony_ciENTRY(MCOUNT_NAME) 8462306a36Sopenharmony_ci la t4, ftrace_stub 8562306a36Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER 8662306a36Sopenharmony_ci la t0, ftrace_graph_return 8762306a36Sopenharmony_ci REG_L t1, 0(t0) 8862306a36Sopenharmony_ci bne t1, t4, do_ftrace_graph_caller 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci la t3, ftrace_graph_entry 9162306a36Sopenharmony_ci REG_L t2, 0(t3) 9262306a36Sopenharmony_ci la t6, ftrace_graph_entry_stub 9362306a36Sopenharmony_ci bne t2, t6, do_ftrace_graph_caller 9462306a36Sopenharmony_ci#endif 9562306a36Sopenharmony_ci la t3, ftrace_trace_function 9662306a36Sopenharmony_ci REG_L t5, 0(t3) 9762306a36Sopenharmony_ci bne t5, t4, do_trace 9862306a36Sopenharmony_ci ret 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER 10162306a36Sopenharmony_ci/* 10262306a36Sopenharmony_ci * A pseudo representation for the function graph tracer: 10362306a36Sopenharmony_ci * prepare_to_return(&ra_to_caller_of_caller, ra_to_caller) 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_cido_ftrace_graph_caller: 10662306a36Sopenharmony_ci addi a0, s0, -SZREG 10762306a36Sopenharmony_ci mv a1, ra 10862306a36Sopenharmony_ci#ifdef HAVE_FUNCTION_GRAPH_FP_TEST 10962306a36Sopenharmony_ci REG_L a2, -2*SZREG(s0) 11062306a36Sopenharmony_ci#endif 11162306a36Sopenharmony_ci SAVE_ABI_STATE 11262306a36Sopenharmony_ci call prepare_ftrace_return 11362306a36Sopenharmony_ci RESTORE_ABI_STATE 11462306a36Sopenharmony_ci ret 11562306a36Sopenharmony_ci#endif 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * A pseudo representation for the function tracer: 11962306a36Sopenharmony_ci * (*ftrace_trace_function)(ra_to_caller, ra_to_caller_of_caller) 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_cido_trace: 12262306a36Sopenharmony_ci REG_L a1, -SZREG(s0) 12362306a36Sopenharmony_ci mv a0, ra 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci SAVE_ABI_STATE 12662306a36Sopenharmony_ci jalr t5 12762306a36Sopenharmony_ci RESTORE_ABI_STATE 12862306a36Sopenharmony_ci ret 12962306a36Sopenharmony_ciENDPROC(MCOUNT_NAME) 13062306a36Sopenharmony_ci#endif 13162306a36Sopenharmony_ciEXPORT_SYMBOL(MCOUNT_NAME) 132