162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017 Steven Rostedt, VMware Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/linkage.h> 762306a36Sopenharmony_ci#include <asm/page_types.h> 862306a36Sopenharmony_ci#include <asm/segment.h> 962306a36Sopenharmony_ci#include <asm/export.h> 1062306a36Sopenharmony_ci#include <asm/ftrace.h> 1162306a36Sopenharmony_ci#include <asm/nospec-branch.h> 1262306a36Sopenharmony_ci#include <asm/frame.h> 1362306a36Sopenharmony_ci#include <asm/asm-offsets.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER 1662306a36Sopenharmony_ci# define MCOUNT_FRAME 1 /* using frame = true */ 1762306a36Sopenharmony_ci#else 1862306a36Sopenharmony_ci# define MCOUNT_FRAME 0 /* using frame = false */ 1962306a36Sopenharmony_ci#endif 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciSYM_FUNC_START(__fentry__) 2262306a36Sopenharmony_ci RET 2362306a36Sopenharmony_ciSYM_FUNC_END(__fentry__) 2462306a36Sopenharmony_ciEXPORT_SYMBOL(__fentry__) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciSYM_CODE_START(ftrace_caller) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER 2962306a36Sopenharmony_ci /* 3062306a36Sopenharmony_ci * Frame pointers are of ip followed by bp. 3162306a36Sopenharmony_ci * Since fentry is an immediate jump, we are left with 3262306a36Sopenharmony_ci * parent-ip, function-ip. We need to add a frame with 3362306a36Sopenharmony_ci * parent-ip followed by ebp. 3462306a36Sopenharmony_ci */ 3562306a36Sopenharmony_ci pushl 4(%esp) /* parent ip */ 3662306a36Sopenharmony_ci pushl %ebp 3762306a36Sopenharmony_ci movl %esp, %ebp 3862306a36Sopenharmony_ci pushl 2*4(%esp) /* function ip */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* For mcount, the function ip is directly above */ 4162306a36Sopenharmony_ci pushl %ebp 4262306a36Sopenharmony_ci movl %esp, %ebp 4362306a36Sopenharmony_ci#endif 4462306a36Sopenharmony_ci pushl %eax 4562306a36Sopenharmony_ci pushl %ecx 4662306a36Sopenharmony_ci pushl %edx 4762306a36Sopenharmony_ci pushl $0 /* Pass NULL as regs pointer */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER 5062306a36Sopenharmony_ci /* Load parent ebp into edx */ 5162306a36Sopenharmony_ci movl 4*4(%esp), %edx 5262306a36Sopenharmony_ci#else 5362306a36Sopenharmony_ci /* There's no frame pointer, load the appropriate stack addr instead */ 5462306a36Sopenharmony_ci lea 4*4(%esp), %edx 5562306a36Sopenharmony_ci#endif 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci movl (MCOUNT_FRAME+4)*4(%esp), %eax /* load the rip */ 5862306a36Sopenharmony_ci /* Get the parent ip */ 5962306a36Sopenharmony_ci movl 4(%edx), %edx /* edx has ebp */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci movl function_trace_op, %ecx 6262306a36Sopenharmony_ci subl $MCOUNT_INSN_SIZE, %eax 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci.globl ftrace_call 6562306a36Sopenharmony_ciftrace_call: 6662306a36Sopenharmony_ci call ftrace_stub 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci addl $4, %esp /* skip NULL pointer */ 6962306a36Sopenharmony_ci popl %edx 7062306a36Sopenharmony_ci popl %ecx 7162306a36Sopenharmony_ci popl %eax 7262306a36Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER 7362306a36Sopenharmony_ci popl %ebp 7462306a36Sopenharmony_ci addl $4,%esp /* skip function ip */ 7562306a36Sopenharmony_ci popl %ebp /* this is the orig bp */ 7662306a36Sopenharmony_ci addl $4, %esp /* skip parent ip */ 7762306a36Sopenharmony_ci#endif 7862306a36Sopenharmony_ci.Lftrace_ret: 7962306a36Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER 8062306a36Sopenharmony_ci.globl ftrace_graph_call 8162306a36Sopenharmony_ciftrace_graph_call: 8262306a36Sopenharmony_ci jmp ftrace_stub 8362306a36Sopenharmony_ci#endif 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* This is weak to keep gas from relaxing the jumps */ 8662306a36Sopenharmony_ciSYM_INNER_LABEL_ALIGN(ftrace_stub, SYM_L_WEAK) 8762306a36Sopenharmony_ci RET 8862306a36Sopenharmony_ciSYM_CODE_END(ftrace_caller) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ciSYM_CODE_START(ftrace_regs_caller) 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * We're here from an mcount/fentry CALL, and the stack frame looks like: 9362306a36Sopenharmony_ci * 9462306a36Sopenharmony_ci * <previous context> 9562306a36Sopenharmony_ci * RET-IP 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * The purpose of this function is to call out in an emulated INT3 9862306a36Sopenharmony_ci * environment with a stack frame like: 9962306a36Sopenharmony_ci * 10062306a36Sopenharmony_ci * <previous context> 10162306a36Sopenharmony_ci * gap / RET-IP 10262306a36Sopenharmony_ci * gap 10362306a36Sopenharmony_ci * gap 10462306a36Sopenharmony_ci * gap 10562306a36Sopenharmony_ci * pt_regs 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * We do _NOT_ restore: ss, flags, cs, gs, fs, es, ds 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci subl $3*4, %esp # RET-IP + 3 gaps 11062306a36Sopenharmony_ci pushl %ss # ss 11162306a36Sopenharmony_ci pushl %esp # points at ss 11262306a36Sopenharmony_ci addl $5*4, (%esp) # make it point at <previous context> 11362306a36Sopenharmony_ci pushfl # flags 11462306a36Sopenharmony_ci pushl $__KERNEL_CS # cs 11562306a36Sopenharmony_ci pushl 7*4(%esp) # ip <- RET-IP 11662306a36Sopenharmony_ci pushl $0 # orig_eax 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci pushl %gs 11962306a36Sopenharmony_ci pushl %fs 12062306a36Sopenharmony_ci pushl %es 12162306a36Sopenharmony_ci pushl %ds 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci pushl %eax 12462306a36Sopenharmony_ci pushl %ebp 12562306a36Sopenharmony_ci pushl %edi 12662306a36Sopenharmony_ci pushl %esi 12762306a36Sopenharmony_ci pushl %edx 12862306a36Sopenharmony_ci pushl %ecx 12962306a36Sopenharmony_ci pushl %ebx 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci ENCODE_FRAME_POINTER 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci movl PT_EIP(%esp), %eax # 1st argument: IP 13462306a36Sopenharmony_ci subl $MCOUNT_INSN_SIZE, %eax 13562306a36Sopenharmony_ci movl 21*4(%esp), %edx # 2nd argument: parent ip 13662306a36Sopenharmony_ci movl function_trace_op, %ecx # 3rd argument: ftrace_pos 13762306a36Sopenharmony_ci pushl %esp # 4th argument: pt_regs 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ciSYM_INNER_LABEL(ftrace_regs_call, SYM_L_GLOBAL) 14062306a36Sopenharmony_ci call ftrace_stub 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci addl $4, %esp # skip 4th argument 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* place IP below the new SP */ 14562306a36Sopenharmony_ci movl PT_OLDESP(%esp), %eax 14662306a36Sopenharmony_ci movl PT_EIP(%esp), %ecx 14762306a36Sopenharmony_ci movl %ecx, -4(%eax) 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* place EAX below that */ 15062306a36Sopenharmony_ci movl PT_EAX(%esp), %ecx 15162306a36Sopenharmony_ci movl %ecx, -8(%eax) 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci popl %ebx 15462306a36Sopenharmony_ci popl %ecx 15562306a36Sopenharmony_ci popl %edx 15662306a36Sopenharmony_ci popl %esi 15762306a36Sopenharmony_ci popl %edi 15862306a36Sopenharmony_ci popl %ebp 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci lea -8(%eax), %esp 16162306a36Sopenharmony_ci popl %eax 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci jmp .Lftrace_ret 16462306a36Sopenharmony_ciSYM_CODE_END(ftrace_regs_caller) 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ciSYM_FUNC_START(ftrace_stub_direct_tramp) 16762306a36Sopenharmony_ci CALL_DEPTH_ACCOUNT 16862306a36Sopenharmony_ci RET 16962306a36Sopenharmony_ciSYM_FUNC_END(ftrace_stub_direct_tramp) 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#ifdef CONFIG_FUNCTION_GRAPH_TRACER 17262306a36Sopenharmony_ciSYM_CODE_START(ftrace_graph_caller) 17362306a36Sopenharmony_ci pushl %eax 17462306a36Sopenharmony_ci pushl %ecx 17562306a36Sopenharmony_ci pushl %edx 17662306a36Sopenharmony_ci movl 3*4(%esp), %eax 17762306a36Sopenharmony_ci /* Even with frame pointers, fentry doesn't have one here */ 17862306a36Sopenharmony_ci lea 4*4(%esp), %edx 17962306a36Sopenharmony_ci movl $0, %ecx 18062306a36Sopenharmony_ci subl $MCOUNT_INSN_SIZE, %eax 18162306a36Sopenharmony_ci call prepare_ftrace_return 18262306a36Sopenharmony_ci popl %edx 18362306a36Sopenharmony_ci popl %ecx 18462306a36Sopenharmony_ci popl %eax 18562306a36Sopenharmony_ci RET 18662306a36Sopenharmony_ciSYM_CODE_END(ftrace_graph_caller) 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci.globl return_to_handler 18962306a36Sopenharmony_cireturn_to_handler: 19062306a36Sopenharmony_ci pushl $0 19162306a36Sopenharmony_ci pushl %edx 19262306a36Sopenharmony_ci pushl %eax 19362306a36Sopenharmony_ci movl %esp, %eax 19462306a36Sopenharmony_ci call ftrace_return_to_handler 19562306a36Sopenharmony_ci movl %eax, %ecx 19662306a36Sopenharmony_ci popl %eax 19762306a36Sopenharmony_ci popl %edx 19862306a36Sopenharmony_ci addl $4, %esp # skip ebp 19962306a36Sopenharmony_ci JMP_NOSPEC ecx 20062306a36Sopenharmony_ci#endif 201