diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h index a4dbac07e4ef..8545b3ff8317 100644 --- a/arch/arm/include/asm/ftrace.h +++ b/arch/arm/include/asm/ftrace.h @@ -25,6 +25,27 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) /* With Thumb-2, the recorded addresses have the lsb set */ return addr & ~1; } + +#ifdef CONFIG_ARM_MODULE_PLTS +static inline void ftrace_set_mod(struct dyn_arch_ftrace *arch, struct module *mod) +{ + arch->mod = mod; +} + +static inline struct module *ftrace_get_mod(struct dyn_arch_ftrace *arch) +{ + return arch->mod; +} +#else +static inline void ftrace_set_mod(struct dyn_arch_ftrace *arch, struct module *mod) +{ +} + +static inline struct module *ftrace_get_mod(struct dyn_arch_ftrace *arch) +{ + return NULL; +} +#endif #endif #endif diff --git a/arch/arm/include/asm/insn.h b/arch/arm/include/asm/insn.h index f20e08ac85ae..71c3edefe629 100644 --- a/arch/arm/include/asm/insn.h +++ b/arch/arm/include/asm/insn.h @@ -13,18 +13,24 @@ arm_gen_nop(void) } unsigned long -__arm_gen_branch(unsigned long pc, unsigned long addr, bool link); +__arm_gen_branch(unsigned long pc, unsigned long addr, bool link, bool check); static inline unsigned long arm_gen_branch(unsigned long pc, unsigned long addr) { - return __arm_gen_branch(pc, addr, false); + return __arm_gen_branch(pc, addr, false, true); } static inline unsigned long arm_gen_branch_link(unsigned long pc, unsigned long addr) { - return __arm_gen_branch(pc, addr, true); + return __arm_gen_branch(pc, addr, true, true); +} + +static inline unsigned long +arm_gen_branch_link_nocheck(unsigned long pc, unsigned long addr) +{ + return __arm_gen_branch(pc, addr, true, false); } #endif diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index fa867a57100f..63ea34edd222 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -70,20 +70,28 @@ int ftrace_arch_code_modify_post_process(void) static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) { - s32 offset = addr - pc; - s32 blim = 0xfe000008; - s32 flim = 0x02000004; + return arm_gen_branch_link(pc, addr); +} - if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { - blim = 0xff000004; - flim = 0x01000002; - } +static unsigned long +ftrace_call_replace_mod(struct module *mod, unsigned long pc, unsigned long addr) +{ +#ifdef CONFIG_ARM_MODULE_PLTS + unsigned long new; - if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS) && - (offset < blim || offset > flim)) - return 0; + if (likely(!mod)) + return arm_gen_branch_link(pc, addr); + new = arm_gen_branch_link_nocheck(pc, addr); + if (!new) { + addr = get_module_plt(mod, pc, addr); + new = arm_gen_branch_link(pc, addr); + } + + return new; +#else return arm_gen_branch_link(pc, addr); +#endif } static int ftrace_modify_code(unsigned long pc, unsigned long old, @@ -141,18 +149,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) old = ftrace_nop_replace(rec); - new = ftrace_call_replace(ip, aaddr); - -#ifdef CONFIG_ARM_MODULE_PLTS - if (!new) { - struct module *mod = rec->arch.mod; - - if (mod) { - aaddr = get_module_plt(mod, ip, aaddr); - new = ftrace_call_replace(ip, aaddr); - } - } -#endif + new = ftrace_call_replace_mod(ftrace_get_mod(&rec->arch), ip, aaddr); return ftrace_modify_code(rec->ip, old, new, true); } @@ -183,23 +180,11 @@ int ftrace_make_nop(struct module *mod, unsigned long new; int ret; -#ifdef CONFIG_ARM_MODULE_PLTS /* mod is only supplied during module loading */ - if (!mod) - mod = rec->arch.mod; - else - rec->arch.mod = mod; -#endif - - old = ftrace_call_replace(ip, aaddr); - -#ifdef CONFIG_ARM_MODULE_PLTS - if (!old && mod) { - aaddr = get_module_plt(mod, ip, aaddr); - old = ftrace_call_replace(ip, aaddr); - } -#endif + if (mod) + ftrace_set_mod(&rec->arch, mod); + old = ftrace_call_replace_mod(ftrace_get_mod(&rec->arch), ip, aaddr); new = ftrace_nop_replace(rec); ret = ftrace_modify_code(ip, old, new, true); diff --git a/arch/arm/kernel/insn.c b/arch/arm/kernel/insn.c index 2e844b70386b..37ec5734309e 100644 --- a/arch/arm/kernel/insn.c +++ b/arch/arm/kernel/insn.c @@ -4,7 +4,7 @@ #include static unsigned long -__arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link) +__arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link, bool check) { unsigned long s, j1, j2, i1, i2, imm10, imm11; unsigned long first, second; @@ -12,7 +12,7 @@ __arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link) offset = (long)addr - (long)(pc + 4); if (offset < -16777216 || offset > 16777214) { - WARN_ON_ONCE(1); + WARN_ON_ONCE(check); return 0; } @@ -34,7 +34,7 @@ __arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link) } static unsigned long -__arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link) +__arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link, bool check) { unsigned long opcode = 0xea000000; long offset; @@ -44,7 +44,7 @@ __arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link) offset = (long)addr - (long)(pc + 8); if (unlikely(offset < -33554432 || offset > 33554428)) { - WARN_ON_ONCE(1); + WARN_ON_ONCE(check); return 0; } @@ -54,10 +54,10 @@ __arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link) } unsigned long -__arm_gen_branch(unsigned long pc, unsigned long addr, bool link) +__arm_gen_branch(unsigned long pc, unsigned long addr, bool link, bool check) { if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) - return __arm_gen_branch_thumb2(pc, addr, link); + return __arm_gen_branch_thumb2(pc, addr, link, check); else - return __arm_gen_branch_arm(pc, addr, link); + return __arm_gen_branch_arm(pc, addr, link, check); }