Commit b6143d10 authored by Will Deacon's avatar Will Deacon Committed by Catalin Marinas

arm64: ftrace: Ensure module ftrace trampoline is coherent with I-side

The initial support for dynamic ftrace trampolines in modules made use
of an indirect branch which loaded its target from the beginning of
a special section (e71a4e1b ("arm64: ftrace: add support for far
branches to dynamic ftrace")). Since no instructions were being patched,
no cache maintenance was needed. However, later in be0f272b ("arm64:
ftrace: emit ftrace-mod.o contents through code") this code was reworked
to output the trampoline instructions directly into the PLT entry but,
unfortunately, the necessary cache maintenance was overlooked.

Add a call to __flush_icache_range() after writing the new trampoline
instructions but before patching in the branch to the trampoline.

Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: James Morse <james.morse@arm.com>
Cc: <stable@vger.kernel.org>
Fixes: be0f272b ("arm64: ftrace: emit ftrace-mod.o contents through code")
Signed-off-by: default avatarWill Deacon <will@kernel.org>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 5717fe5a
...@@ -73,7 +73,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) ...@@ -73,7 +73,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
if (offset < -SZ_128M || offset >= SZ_128M) { if (offset < -SZ_128M || offset >= SZ_128M) {
#ifdef CONFIG_ARM64_MODULE_PLTS #ifdef CONFIG_ARM64_MODULE_PLTS
struct plt_entry trampoline; struct plt_entry trampoline, *dst;
struct module *mod; struct module *mod;
/* /*
...@@ -106,23 +106,27 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) ...@@ -106,23 +106,27 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
* to check if the actual opcodes are in fact identical, * to check if the actual opcodes are in fact identical,
* regardless of the offset in memory so use memcmp() instead. * regardless of the offset in memory so use memcmp() instead.
*/ */
trampoline = get_plt_entry(addr, mod->arch.ftrace_trampoline); dst = mod->arch.ftrace_trampoline;
if (memcmp(mod->arch.ftrace_trampoline, &trampoline, trampoline = get_plt_entry(addr, dst);
sizeof(trampoline))) { if (memcmp(dst, &trampoline, sizeof(trampoline))) {
if (plt_entry_is_initialized(mod->arch.ftrace_trampoline)) { if (plt_entry_is_initialized(dst)) {
pr_err("ftrace: far branches to multiple entry points unsupported inside a single module\n"); pr_err("ftrace: far branches to multiple entry points unsupported inside a single module\n");
return -EINVAL; return -EINVAL;
} }
/* point the trampoline to our ftrace entry point */ /* point the trampoline to our ftrace entry point */
module_disable_ro(mod); module_disable_ro(mod);
*mod->arch.ftrace_trampoline = trampoline; *dst = trampoline;
module_enable_ro(mod, true); 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 */ #else /* CONFIG_ARM64_MODULE_PLTS */
return -EINVAL; return -EINVAL;
#endif /* CONFIG_ARM64_MODULE_PLTS */ #endif /* CONFIG_ARM64_MODULE_PLTS */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment