18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (C) 2017  Steven Rostedt, VMware Inc.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/linkage.h>
78c2ecf20Sopenharmony_ci#include <asm/page_types.h>
88c2ecf20Sopenharmony_ci#include <asm/segment.h>
98c2ecf20Sopenharmony_ci#include <asm/export.h>
108c2ecf20Sopenharmony_ci#include <asm/ftrace.h>
118c2ecf20Sopenharmony_ci#include <asm/nospec-branch.h>
128c2ecf20Sopenharmony_ci#include <asm/frame.h>
138c2ecf20Sopenharmony_ci#include <asm/asm-offsets.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER
168c2ecf20Sopenharmony_ci# define MCOUNT_FRAME			1	/* using frame = true  */
178c2ecf20Sopenharmony_ci#else
188c2ecf20Sopenharmony_ci# define MCOUNT_FRAME			0	/* using frame = false */
198c2ecf20Sopenharmony_ci#endif
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ciSYM_FUNC_START(__fentry__)
228c2ecf20Sopenharmony_ci	RET
238c2ecf20Sopenharmony_ciSYM_FUNC_END(__fentry__)
248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__fentry__)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ciSYM_CODE_START(ftrace_caller)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER
298c2ecf20Sopenharmony_ci	/*
308c2ecf20Sopenharmony_ci	 * Frame pointers are of ip followed by bp.
318c2ecf20Sopenharmony_ci	 * Since fentry is an immediate jump, we are left with
328c2ecf20Sopenharmony_ci	 * parent-ip, function-ip. We need to add a frame with
338c2ecf20Sopenharmony_ci	 * parent-ip followed by ebp.
348c2ecf20Sopenharmony_ci	 */
358c2ecf20Sopenharmony_ci	pushl	4(%esp)				/* parent ip */
368c2ecf20Sopenharmony_ci	pushl	%ebp
378c2ecf20Sopenharmony_ci	movl	%esp, %ebp
388c2ecf20Sopenharmony_ci	pushl	2*4(%esp)			/* function ip */
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* For mcount, the function ip is directly above */
418c2ecf20Sopenharmony_ci	pushl	%ebp
428c2ecf20Sopenharmony_ci	movl	%esp, %ebp
438c2ecf20Sopenharmony_ci#endif
448c2ecf20Sopenharmony_ci	pushl	%eax
458c2ecf20Sopenharmony_ci	pushl	%ecx
468c2ecf20Sopenharmony_ci	pushl	%edx
478c2ecf20Sopenharmony_ci	pushl	$0				/* Pass NULL as regs pointer */
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER
508c2ecf20Sopenharmony_ci	/* Load parent ebp into edx */
518c2ecf20Sopenharmony_ci	movl	4*4(%esp), %edx
528c2ecf20Sopenharmony_ci#else
538c2ecf20Sopenharmony_ci	/* There's no frame pointer, load the appropriate stack addr instead */
548c2ecf20Sopenharmony_ci	lea	4*4(%esp), %edx
558c2ecf20Sopenharmony_ci#endif
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	movl	(MCOUNT_FRAME+4)*4(%esp), %eax	/* load the rip */
588c2ecf20Sopenharmony_ci	/* Get the parent ip */
598c2ecf20Sopenharmony_ci	movl	4(%edx), %edx			/* edx has ebp */
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	movl	function_trace_op, %ecx
628c2ecf20Sopenharmony_ci	subl	$MCOUNT_INSN_SIZE, %eax
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci.globl ftrace_call
658c2ecf20Sopenharmony_ciftrace_call:
668c2ecf20Sopenharmony_ci	call	ftrace_stub
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	addl	$4, %esp			/* skip NULL pointer */
698c2ecf20Sopenharmony_ci	popl	%edx
708c2ecf20Sopenharmony_ci	popl	%ecx
718c2ecf20Sopenharmony_ci	popl	%eax
728c2ecf20Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER
738c2ecf20Sopenharmony_ci	popl	%ebp
748c2ecf20Sopenharmony_ci	addl	$4,%esp				/* skip function ip */
758c2ecf20Sopenharmony_ci	popl	%ebp				/* this is the orig bp */
768c2ecf20Sopenharmony_ci	addl	$4, %esp			/* skip parent ip */
778c2ecf20Sopenharmony_ci#endif
788c2ecf20Sopenharmony_ci.Lftrace_ret:
798c2ecf20Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER
808c2ecf20Sopenharmony_ci.globl ftrace_graph_call
818c2ecf20Sopenharmony_ciftrace_graph_call:
828c2ecf20Sopenharmony_ci	jmp	ftrace_stub
838c2ecf20Sopenharmony_ci#endif
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/* This is weak to keep gas from relaxing the jumps */
868c2ecf20Sopenharmony_ciSYM_INNER_LABEL_ALIGN(ftrace_stub, SYM_L_WEAK)
878c2ecf20Sopenharmony_ci	RET
888c2ecf20Sopenharmony_ciSYM_CODE_END(ftrace_caller)
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ciSYM_CODE_START(ftrace_regs_caller)
918c2ecf20Sopenharmony_ci	/*
928c2ecf20Sopenharmony_ci	 * We're here from an mcount/fentry CALL, and the stack frame looks like:
938c2ecf20Sopenharmony_ci	 *
948c2ecf20Sopenharmony_ci	 *  <previous context>
958c2ecf20Sopenharmony_ci	 *  RET-IP
968c2ecf20Sopenharmony_ci	 *
978c2ecf20Sopenharmony_ci	 * The purpose of this function is to call out in an emulated INT3
988c2ecf20Sopenharmony_ci	 * environment with a stack frame like:
998c2ecf20Sopenharmony_ci	 *
1008c2ecf20Sopenharmony_ci	 *  <previous context>
1018c2ecf20Sopenharmony_ci	 *  gap / RET-IP
1028c2ecf20Sopenharmony_ci	 *  gap
1038c2ecf20Sopenharmony_ci	 *  gap
1048c2ecf20Sopenharmony_ci	 *  gap
1058c2ecf20Sopenharmony_ci	 *  pt_regs
1068c2ecf20Sopenharmony_ci	 *
1078c2ecf20Sopenharmony_ci	 * We do _NOT_ restore: ss, flags, cs, gs, fs, es, ds
1088c2ecf20Sopenharmony_ci	 */
1098c2ecf20Sopenharmony_ci	subl	$3*4, %esp	# RET-IP + 3 gaps
1108c2ecf20Sopenharmony_ci	pushl	%ss		# ss
1118c2ecf20Sopenharmony_ci	pushl	%esp		# points at ss
1128c2ecf20Sopenharmony_ci	addl	$5*4, (%esp)	#   make it point at <previous context>
1138c2ecf20Sopenharmony_ci	pushfl			# flags
1148c2ecf20Sopenharmony_ci	pushl	$__KERNEL_CS	# cs
1158c2ecf20Sopenharmony_ci	pushl	7*4(%esp)	# ip <- RET-IP
1168c2ecf20Sopenharmony_ci	pushl	$0		# orig_eax
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	pushl	%gs
1198c2ecf20Sopenharmony_ci	pushl	%fs
1208c2ecf20Sopenharmony_ci	pushl	%es
1218c2ecf20Sopenharmony_ci	pushl	%ds
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	pushl	%eax
1248c2ecf20Sopenharmony_ci	pushl	%ebp
1258c2ecf20Sopenharmony_ci	pushl	%edi
1268c2ecf20Sopenharmony_ci	pushl	%esi
1278c2ecf20Sopenharmony_ci	pushl	%edx
1288c2ecf20Sopenharmony_ci	pushl	%ecx
1298c2ecf20Sopenharmony_ci	pushl	%ebx
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	ENCODE_FRAME_POINTER
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	movl	PT_EIP(%esp), %eax	# 1st argument: IP
1348c2ecf20Sopenharmony_ci	subl	$MCOUNT_INSN_SIZE, %eax
1358c2ecf20Sopenharmony_ci	movl	21*4(%esp), %edx	# 2nd argument: parent ip
1368c2ecf20Sopenharmony_ci	movl	function_trace_op, %ecx	# 3rd argument: ftrace_pos
1378c2ecf20Sopenharmony_ci	pushl	%esp			# 4th argument: pt_regs
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ciSYM_INNER_LABEL(ftrace_regs_call, SYM_L_GLOBAL)
1408c2ecf20Sopenharmony_ci	call	ftrace_stub
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	addl	$4, %esp		# skip 4th argument
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/* place IP below the new SP */
1458c2ecf20Sopenharmony_ci	movl	PT_OLDESP(%esp), %eax
1468c2ecf20Sopenharmony_ci	movl	PT_EIP(%esp), %ecx
1478c2ecf20Sopenharmony_ci	movl	%ecx, -4(%eax)
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	/* place EAX below that */
1508c2ecf20Sopenharmony_ci	movl	PT_EAX(%esp), %ecx
1518c2ecf20Sopenharmony_ci	movl	%ecx, -8(%eax)
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	popl	%ebx
1548c2ecf20Sopenharmony_ci	popl	%ecx
1558c2ecf20Sopenharmony_ci	popl	%edx
1568c2ecf20Sopenharmony_ci	popl	%esi
1578c2ecf20Sopenharmony_ci	popl	%edi
1588c2ecf20Sopenharmony_ci	popl	%ebp
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	lea	-8(%eax), %esp
1618c2ecf20Sopenharmony_ci	popl	%eax
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	jmp	.Lftrace_ret
1648c2ecf20Sopenharmony_ciSYM_CODE_END(ftrace_regs_caller)
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER
1678c2ecf20Sopenharmony_ciSYM_CODE_START(ftrace_graph_caller)
1688c2ecf20Sopenharmony_ci	pushl	%eax
1698c2ecf20Sopenharmony_ci	pushl	%ecx
1708c2ecf20Sopenharmony_ci	pushl	%edx
1718c2ecf20Sopenharmony_ci	movl	3*4(%esp), %eax
1728c2ecf20Sopenharmony_ci	/* Even with frame pointers, fentry doesn't have one here */
1738c2ecf20Sopenharmony_ci	lea	4*4(%esp), %edx
1748c2ecf20Sopenharmony_ci	movl	$0, %ecx
1758c2ecf20Sopenharmony_ci	subl	$MCOUNT_INSN_SIZE, %eax
1768c2ecf20Sopenharmony_ci	call	prepare_ftrace_return
1778c2ecf20Sopenharmony_ci	popl	%edx
1788c2ecf20Sopenharmony_ci	popl	%ecx
1798c2ecf20Sopenharmony_ci	popl	%eax
1808c2ecf20Sopenharmony_ci	RET
1818c2ecf20Sopenharmony_ciSYM_CODE_END(ftrace_graph_caller)
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci.globl return_to_handler
1848c2ecf20Sopenharmony_cireturn_to_handler:
1858c2ecf20Sopenharmony_ci	pushl	%eax
1868c2ecf20Sopenharmony_ci	pushl	%edx
1878c2ecf20Sopenharmony_ci	movl	$0, %eax
1888c2ecf20Sopenharmony_ci	call	ftrace_return_to_handler
1898c2ecf20Sopenharmony_ci	movl	%eax, %ecx
1908c2ecf20Sopenharmony_ci	popl	%edx
1918c2ecf20Sopenharmony_ci	popl	%eax
1928c2ecf20Sopenharmony_ci	JMP_NOSPEC ecx
1938c2ecf20Sopenharmony_ci#endif
194