/* SPDX-License-Identifier: GPL-2.0-only */1/*2* arch/arm64/kernel/entry-ftrace.S3*4* Copyright (C) 2013 Linaro Limited5* Author: AKASHI Takahiro <[email protected]>6*/78#include <linux/linkage.h>9#include <linux/cfi_types.h>10#include <asm/asm-offsets.h>11#include <asm/assembler.h>12#include <asm/ftrace.h>13#include <asm/insn.h>1415#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS16/*17* Due to -fpatchable-function-entry=2, the compiler has placed two NOPs before18* the regular function prologue. For an enabled callsite, ftrace_init_nop() and19* ftrace_make_call() have patched those NOPs to:20*21* MOV X9, LR22* BL ftrace_caller23*24* Each instrumented function follows the AAPCS, so here x0-x8 and x18-x30 are25* live (x18 holds the Shadow Call Stack pointer), and x9-x17 are safe to26* clobber.27*28* We save the callsite's context into a struct ftrace_regs before invoking any29* ftrace callbacks. So that we can get a sensible backtrace, we create frame30* records for the callsite and the ftrace entry assembly. This is not31* sufficient for reliable stacktrace: until we create the callsite stack32* record, its caller is missing from the LR and existing chain of frame33* records.34*/35SYM_CODE_START(ftrace_caller)36bti c3738#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS39/*40* The literal pointer to the ops is at an 8-byte aligned boundary41* which is either 12 or 16 bytes before the BL instruction in the call42* site. See ftrace_call_adjust() for details.43*44* Therefore here the LR points at `literal + 16` or `literal + 20`,45* and we can find the address of the literal in either case by46* aligning to an 8-byte boundary and subtracting 16. We do the47* alignment first as this allows us to fold the subtraction into the48* LDR.49*/50bic x11, x30, 0x751ldr x11, [x11, #-(4 * AARCH64_INSN_SIZE)] // op5253#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS54/*55* If the op has a direct call, handle it immediately without56* saving/restoring registers.57*/58ldr x17, [x11, #FTRACE_OPS_DIRECT_CALL] // op->direct_call59cbnz x17, ftrace_caller_direct60#endif61#endif6263/* Save original SP */64mov x10, sp6566/* Make room for ftrace regs, plus two frame records */67sub sp, sp, #(FREGS_SIZE + 32)6869/* Save function arguments */70stp x0, x1, [sp, #FREGS_X0]71stp x2, x3, [sp, #FREGS_X2]72stp x4, x5, [sp, #FREGS_X4]73stp x6, x7, [sp, #FREGS_X6]74str x8, [sp, #FREGS_X8]7576#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS77str xzr, [sp, #FREGS_DIRECT_TRAMP]78#endif7980/* Save the callsite's FP, LR, SP */81str x29, [sp, #FREGS_FP]82str x9, [sp, #FREGS_LR]83str x10, [sp, #FREGS_SP]8485/* Save the PC after the ftrace callsite */86str x30, [sp, #FREGS_PC]8788/* Create a frame record for the callsite above the ftrace regs */89stp x29, x9, [sp, #FREGS_SIZE + 16]90add x29, sp, #FREGS_SIZE + 169192/* Create our frame record above the ftrace regs */93stp x29, x30, [sp, #FREGS_SIZE]94add x29, sp, #FREGS_SIZE9596/* Prepare arguments for the the tracer func */97sub x0, x30, #AARCH64_INSN_SIZE // ip (callsite's BL insn)98mov x1, x9 // parent_ip (callsite's LR)99mov x3, sp // regs100101#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS102mov x2, x11 // op103ldr x4, [x2, #FTRACE_OPS_FUNC] // op->func104blr x4 // op->func(ip, parent_ip, op, regs)105106#else107ldr_l x2, function_trace_op // op108109SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)110bl ftrace_stub // func(ip, parent_ip, op, regs)111#endif112113/*114* At the callsite x0-x8 and x19-x30 were live. Any C code will have preserved115* x19-x29 per the AAPCS, and we created frame records upon entry, so we need116* to restore x0-x8, x29, and x30.117*/118/* Restore function arguments */119ldp x0, x1, [sp, #FREGS_X0]120ldp x2, x3, [sp, #FREGS_X2]121ldp x4, x5, [sp, #FREGS_X4]122ldp x6, x7, [sp, #FREGS_X6]123ldr x8, [sp, #FREGS_X8]124125/* Restore the callsite's FP */126ldr x29, [sp, #FREGS_FP]127128#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS129ldr x17, [sp, #FREGS_DIRECT_TRAMP]130cbnz x17, ftrace_caller_direct_late131#endif132133/* Restore the callsite's LR and PC */134ldr x30, [sp, #FREGS_LR]135ldr x9, [sp, #FREGS_PC]136137/* Restore the callsite's SP */138add sp, sp, #FREGS_SIZE + 32139140ret x9141142#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS143SYM_INNER_LABEL(ftrace_caller_direct_late, SYM_L_LOCAL)144/*145* Head to a direct trampoline in x17 after having run other tracers.146* The ftrace_regs are live, and x0-x8 and FP have been restored. The147* LR, PC, and SP have not been restored.148*/149150/*151* Restore the callsite's LR and PC matching the trampoline calling152* convention.153*/154ldr x9, [sp, #FREGS_LR]155ldr x30, [sp, #FREGS_PC]156157/* Restore the callsite's SP */158add sp, sp, #FREGS_SIZE + 32159160SYM_INNER_LABEL(ftrace_caller_direct, SYM_L_LOCAL)161/*162* Head to a direct trampoline in x17.163*164* We use `BR X17` as this can safely land on a `BTI C` or `PACIASP` in165* the trampoline, and will not unbalance any return stack.166*/167br x17168#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */169SYM_CODE_END(ftrace_caller)170171#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS172SYM_CODE_START(ftrace_stub_direct_tramp)173bti c174mov x10, x30175mov x30, x9176ret x10177SYM_CODE_END(ftrace_stub_direct_tramp)178#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */179180#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */181182/*183* Gcc with -pg will put the following code in the beginning of each function:184* mov x0, x30185* bl _mcount186* [function's body ...]187* "bl _mcount" may be replaced to "bl ftrace_caller" or NOP if dynamic188* ftrace is enabled.189*190* Please note that x0 as an argument will not be used here because we can191* get lr(x30) of instrumented function at any time by winding up call stack192* as long as the kernel is compiled without -fomit-frame-pointer.193* (or CONFIG_FRAME_POINTER, this is forced on arm64)194*195* stack layout after mcount_enter in _mcount():196*197* current sp/fp => 0:+-----+198* in _mcount() | x29 | -> instrumented function's fp199* +-----+200* | x30 | -> _mcount()'s lr (= instrumented function's pc)201* old sp => +16:+-----+202* when instrumented | |203* function calls | ... |204* _mcount() | |205* | |206* instrumented => +xx:+-----+207* function's fp | x29 | -> parent's fp208* +-----+209* | x30 | -> instrumented function's lr (= parent's pc)210* +-----+211* | ... |212*/213214.macro mcount_enter215stp x29, x30, [sp, #-16]!216mov x29, sp217.endm218219.macro mcount_exit220ldp x29, x30, [sp], #16221ret222.endm223224.macro mcount_adjust_addr rd, rn225sub \rd, \rn, #AARCH64_INSN_SIZE226.endm227228/* for instrumented function's parent */229.macro mcount_get_parent_fp reg230ldr \reg, [x29]231ldr \reg, [\reg]232.endm233234/* for instrumented function */235.macro mcount_get_pc0 reg236mcount_adjust_addr \reg, x30237.endm238239.macro mcount_get_pc reg240ldr \reg, [x29, #8]241mcount_adjust_addr \reg, \reg242.endm243244.macro mcount_get_lr reg245ldr \reg, [x29]246ldr \reg, [\reg, #8]247.endm248249.macro mcount_get_lr_addr reg250ldr \reg, [x29]251add \reg, \reg, #8252.endm253254/*255* _mcount() is used to build the kernel with -pg option, but all the branch256* instructions to _mcount() are replaced to NOP initially at kernel start up,257* and later on, NOP to branch to ftrace_caller() when enabled or branch to258* NOP when disabled per-function base.259*/260SYM_FUNC_START(_mcount)261ret262SYM_FUNC_END(_mcount)263EXPORT_SYMBOL(_mcount)264NOKPROBE(_mcount)265266/*267* void ftrace_caller(unsigned long return_address)268* @return_address: return address to instrumented function269*270* This function is a counterpart of _mcount() in 'static' ftrace, and271* makes calls to:272* - tracer function to probe instrumented function's entry,273* - ftrace_graph_caller to set up an exit hook274*/275SYM_FUNC_START(ftrace_caller)276mcount_enter277278mcount_get_pc0 x0 // function's pc279mcount_get_lr x1 // function's lr280281SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) // tracer(pc, lr);282nop // This will be replaced with "bl xxx"283// where xxx can be any kind of tracer.284285#ifdef CONFIG_FUNCTION_GRAPH_TRACER286SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller();287nop // If enabled, this will be replaced288// "b ftrace_graph_caller"289#endif290291mcount_exit292SYM_FUNC_END(ftrace_caller)293294#ifdef CONFIG_FUNCTION_GRAPH_TRACER295/*296* void ftrace_graph_caller(void)297*298* Called from _mcount() or ftrace_caller() when function_graph tracer is299* selected.300* This function w/ prepare_ftrace_return() fakes link register's value on301* the call stack in order to intercept instrumented function's return path302* and run return_to_handler() later on its exit.303*/304SYM_FUNC_START(ftrace_graph_caller)305mcount_get_pc x0 // function's pc306mcount_get_lr_addr x1 // pointer to function's saved lr307mcount_get_parent_fp x2 // parent's fp308bl prepare_ftrace_return // prepare_ftrace_return(pc, &lr, fp)309310mcount_exit311SYM_FUNC_END(ftrace_graph_caller)312#endif /* CONFIG_FUNCTION_GRAPH_TRACER */313#endif /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */314315SYM_TYPED_FUNC_START(ftrace_stub)316ret317SYM_FUNC_END(ftrace_stub)318319#ifdef CONFIG_FUNCTION_GRAPH_TRACER320SYM_TYPED_FUNC_START(ftrace_stub_graph)321ret322SYM_FUNC_END(ftrace_stub_graph)323324/*325* void return_to_handler(void)326*327* Run ftrace_return_to_handler() before going back to parent.328* @fp is checked against the value passed by ftrace_graph_caller().329*/330SYM_CODE_START(return_to_handler)331/* Make room for ftrace_regs */332sub sp, sp, #FREGS_SIZE333334/* Save return value regs */335stp x0, x1, [sp, #FREGS_X0]336stp x2, x3, [sp, #FREGS_X2]337stp x4, x5, [sp, #FREGS_X4]338stp x6, x7, [sp, #FREGS_X6]339340/* Save the callsite's FP */341str x29, [sp, #FREGS_FP]342343mov x0, sp344bl ftrace_return_to_handler // addr = ftrace_return_to_hander(fregs);345mov x30, x0 // restore the original return address346347/* Restore return value regs */348ldp x0, x1, [sp, #FREGS_X0]349ldp x2, x3, [sp, #FREGS_X2]350ldp x4, x5, [sp, #FREGS_X4]351ldp x6, x7, [sp, #FREGS_X6]352add sp, sp, #FREGS_SIZE353354ret355SYM_CODE_END(return_to_handler)356#endif /* CONFIG_FUNCTION_GRAPH_TRACER */357358359