18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/* Copyright (C) 2017 Andes Technology Corporation */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/init.h>
58c2ecf20Sopenharmony_ci#include <linux/linkage.h>
68c2ecf20Sopenharmony_ci#include <asm/asm.h>
78c2ecf20Sopenharmony_ci#include <asm/csr.h>
88c2ecf20Sopenharmony_ci#include <asm/unistd.h>
98c2ecf20Sopenharmony_ci#include <asm/thread_info.h>
108c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h>
118c2ecf20Sopenharmony_ci#include <asm-generic/export.h>
128c2ecf20Sopenharmony_ci#include <asm/ftrace.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci	.text
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci	.macro SAVE_ABI_STATE
178c2ecf20Sopenharmony_ci	addi	sp, sp, -16
188c2ecf20Sopenharmony_ci	sd	s0, 0(sp)
198c2ecf20Sopenharmony_ci	sd	ra, 8(sp)
208c2ecf20Sopenharmony_ci	addi	s0, sp, 16
218c2ecf20Sopenharmony_ci	.endm
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	/*
248c2ecf20Sopenharmony_ci	 * The call to ftrace_return_to_handler would overwrite the return
258c2ecf20Sopenharmony_ci	 * register if a0 was not saved.
268c2ecf20Sopenharmony_ci	 */
278c2ecf20Sopenharmony_ci	.macro SAVE_RET_ABI_STATE
288c2ecf20Sopenharmony_ci	addi	sp, sp, -32
298c2ecf20Sopenharmony_ci	sd	s0, 16(sp)
308c2ecf20Sopenharmony_ci	sd	ra, 24(sp)
318c2ecf20Sopenharmony_ci	sd	a0, 8(sp)
328c2ecf20Sopenharmony_ci	addi	s0, sp, 32
338c2ecf20Sopenharmony_ci	.endm
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	.macro RESTORE_ABI_STATE
368c2ecf20Sopenharmony_ci	ld	ra, 8(sp)
378c2ecf20Sopenharmony_ci	ld	s0, 0(sp)
388c2ecf20Sopenharmony_ci	addi	sp, sp, 16
398c2ecf20Sopenharmony_ci	.endm
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	.macro RESTORE_RET_ABI_STATE
428c2ecf20Sopenharmony_ci	ld	ra, 24(sp)
438c2ecf20Sopenharmony_ci	ld	s0, 16(sp)
448c2ecf20Sopenharmony_ci	ld	a0, 8(sp)
458c2ecf20Sopenharmony_ci	addi	sp, sp, 32
468c2ecf20Sopenharmony_ci	.endm
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciENTRY(ftrace_stub)
498c2ecf20Sopenharmony_ci#ifdef CONFIG_DYNAMIC_FTRACE
508c2ecf20Sopenharmony_ci       .global MCOUNT_NAME
518c2ecf20Sopenharmony_ci       .set    MCOUNT_NAME, ftrace_stub
528c2ecf20Sopenharmony_ci#endif
538c2ecf20Sopenharmony_ci	ret
548c2ecf20Sopenharmony_ciENDPROC(ftrace_stub)
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER
578c2ecf20Sopenharmony_ciENTRY(return_to_handler)
588c2ecf20Sopenharmony_ci/*
598c2ecf20Sopenharmony_ci * On implementing the frame point test, the ideal way is to compare the
608c2ecf20Sopenharmony_ci * s0 (frame pointer, if enabled) on entry and the sp (stack pointer) on return.
618c2ecf20Sopenharmony_ci * However, the psABI of variable-length-argument functions does not allow this.
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * So alternatively we check the *old* frame pointer position, that is, the
648c2ecf20Sopenharmony_ci * value stored in -16(s0) on entry, and the s0 on return.
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_ci#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
678c2ecf20Sopenharmony_ci	mv	t6, s0
688c2ecf20Sopenharmony_ci#endif
698c2ecf20Sopenharmony_ci	SAVE_RET_ABI_STATE
708c2ecf20Sopenharmony_ci#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
718c2ecf20Sopenharmony_ci	mv	a0, t6
728c2ecf20Sopenharmony_ci#endif
738c2ecf20Sopenharmony_ci	call	ftrace_return_to_handler
748c2ecf20Sopenharmony_ci	mv	a1, a0
758c2ecf20Sopenharmony_ci	RESTORE_RET_ABI_STATE
768c2ecf20Sopenharmony_ci	jalr	a1
778c2ecf20Sopenharmony_ciENDPROC(return_to_handler)
788c2ecf20Sopenharmony_ci#endif
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci#ifndef CONFIG_DYNAMIC_FTRACE
818c2ecf20Sopenharmony_ciENTRY(MCOUNT_NAME)
828c2ecf20Sopenharmony_ci	la	t4, ftrace_stub
838c2ecf20Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER
848c2ecf20Sopenharmony_ci	la	t0, ftrace_graph_return
858c2ecf20Sopenharmony_ci	ld	t1, 0(t0)
868c2ecf20Sopenharmony_ci	bne	t1, t4, do_ftrace_graph_caller
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	la	t3, ftrace_graph_entry
898c2ecf20Sopenharmony_ci	ld	t2, 0(t3)
908c2ecf20Sopenharmony_ci	la	t6, ftrace_graph_entry_stub
918c2ecf20Sopenharmony_ci	bne	t2, t6, do_ftrace_graph_caller
928c2ecf20Sopenharmony_ci#endif
938c2ecf20Sopenharmony_ci	la	t3, ftrace_trace_function
948c2ecf20Sopenharmony_ci	ld	t5, 0(t3)
958c2ecf20Sopenharmony_ci	bne	t5, t4, do_trace
968c2ecf20Sopenharmony_ci	ret
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER
998c2ecf20Sopenharmony_ci/*
1008c2ecf20Sopenharmony_ci * A pseudo representation for the function graph tracer:
1018c2ecf20Sopenharmony_ci * prepare_to_return(&ra_to_caller_of_caller, ra_to_caller)
1028c2ecf20Sopenharmony_ci */
1038c2ecf20Sopenharmony_cido_ftrace_graph_caller:
1048c2ecf20Sopenharmony_ci	addi	a0, s0, -8
1058c2ecf20Sopenharmony_ci	mv	a1, ra
1068c2ecf20Sopenharmony_ci#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
1078c2ecf20Sopenharmony_ci	ld	a2, -16(s0)
1088c2ecf20Sopenharmony_ci#endif
1098c2ecf20Sopenharmony_ci	SAVE_ABI_STATE
1108c2ecf20Sopenharmony_ci	call	prepare_ftrace_return
1118c2ecf20Sopenharmony_ci	RESTORE_ABI_STATE
1128c2ecf20Sopenharmony_ci	ret
1138c2ecf20Sopenharmony_ci#endif
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci/*
1168c2ecf20Sopenharmony_ci * A pseudo representation for the function tracer:
1178c2ecf20Sopenharmony_ci * (*ftrace_trace_function)(ra_to_caller, ra_to_caller_of_caller)
1188c2ecf20Sopenharmony_ci */
1198c2ecf20Sopenharmony_cido_trace:
1208c2ecf20Sopenharmony_ci	ld	a1, -8(s0)
1218c2ecf20Sopenharmony_ci	mv	a0, ra
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	SAVE_ABI_STATE
1248c2ecf20Sopenharmony_ci	jalr	t5
1258c2ecf20Sopenharmony_ci	RESTORE_ABI_STATE
1268c2ecf20Sopenharmony_ci	ret
1278c2ecf20Sopenharmony_ciENDPROC(MCOUNT_NAME)
1288c2ecf20Sopenharmony_ci#endif
1298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(MCOUNT_NAME)
130