1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2022 Loongson Technology Corporation Limited 4 */ 5 6 #include <linux/init.h> 7 #include <linux/ftrace.h> 8 #include <linux/syscalls.h> 9 #include <linux/uaccess.h> 10 11 #include <asm/asm.h> 12 #include <asm/asm-offsets.h> 13 #include <asm/cacheflush.h> 14 #include <asm/inst.h> 15 #include <asm/loongarch.h> 16 #include <asm/syscall.h> 17 18 #include <asm-generic/sections.h> 19 20 #ifdef CONFIG_FUNCTION_GRAPH_TRACER 21 22 /* 23 * As `call _mcount` follows LoongArch psABI, ra-saved operation and 24 * stack operation can be found before this insn. 25 */ 26 27 static int ftrace_get_parent_ra_addr(unsigned long insn_addr, int *ra_off) 28 { 29 int limit = 32; 30 union loongarch_instruction *insn; 31 32 insn = (union loongarch_instruction *)insn_addr; 33 34 do { 35 insn--; 36 limit--; 37 38 if (is_ra_save_ins(insn)) 39 *ra_off = -((1 << 12) - insn->reg2i12_format.immediate); 40 41 } while (!is_stack_alloc_ins(insn) && limit); 42 43 if (!limit) 44 return -EINVAL; 45 46 return 0; 47 } 48 49 void prepare_ftrace_return(unsigned long self_addr, 50 unsigned long callsite_sp, unsigned long old) 51 { 52 int ra_off; 53 unsigned long return_hooker = (unsigned long)&return_to_handler; 54 55 if (unlikely(ftrace_graph_is_dead())) 56 return; 57 58 if (unlikely(atomic_read(¤t->tracing_graph_pause))) 59 return; 60 61 if (ftrace_get_parent_ra_addr(self_addr, &ra_off)) 62 goto out; 63 64 if (!function_graph_enter(old, self_addr, 0, NULL)) 65 *(unsigned long *)(callsite_sp + ra_off) = return_hooker; 66 67 return; 68 69 out: 70 ftrace_graph_stop(); 71 WARN_ON(1); 72 } 73 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 74