|
|
@@ -76,7 +76,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
|
|
|
|
|
if (offset < -SZ_128M || offset >= SZ_128M) {
|
|
|
#ifdef CONFIG_ARM64_MODULE_PLTS
|
|
|
- struct plt_entry trampoline;
|
|
|
+ struct plt_entry trampoline, *dst;
|
|
|
struct module *mod;
|
|
|
|
|
|
/*
|
|
|
@@ -104,24 +104,27 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
|
|
* is added in the future, but for now, the pr_err() below
|
|
|
* deals with a theoretical issue only.
|
|
|
*/
|
|
|
+ dst = mod->arch.ftrace_trampoline;
|
|
|
trampoline = get_plt_entry(addr);
|
|
|
- if (!plt_entries_equal(mod->arch.ftrace_trampoline,
|
|
|
- &trampoline)) {
|
|
|
- if (!plt_entries_equal(mod->arch.ftrace_trampoline,
|
|
|
- &(struct plt_entry){})) {
|
|
|
+ if (!plt_entries_equal(dst, &trampoline)) {
|
|
|
+ if (!plt_entries_equal(dst, &(struct plt_entry){})) {
|
|
|
pr_err("ftrace: far branches to multiple entry points unsupported inside a single module\n");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
/* point the trampoline to our ftrace entry point */
|
|
|
module_disable_ro(mod);
|
|
|
- *mod->arch.ftrace_trampoline = trampoline;
|
|
|
+ *dst = trampoline;
|
|
|
module_enable_ro(mod, true);
|
|
|
|
|
|
- /* update trampoline before patching in the branch */
|
|
|
- smp_wmb();
|
|
|
+ /*
|
|
|
+ * Ensure updated trampoline is visible to instruction
|
|
|
+ * fetch before we patch in the branch.
|
|
|
+ */
|
|
|
+ __flush_icache_range((unsigned long)&dst[0],
|
|
|
+ (unsigned long)&dst[1]);
|
|
|
}
|
|
|
- addr = (unsigned long)(void *)mod->arch.ftrace_trampoline;
|
|
|
+ addr = (unsigned long)dst;
|
|
|
#else /* CONFIG_ARM64_MODULE_PLTS */
|
|
|
return -EINVAL;
|
|
|
#endif /* CONFIG_ARM64_MODULE_PLTS */
|