mirror of
https://github.com/torvalds/linux.git
synced 2024-12-30 14:52:05 +00:00
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 (e71a4e1beb
("arm64: ftrace: add support for far branches to dynamic ftrace")). Since no instructions were being patched, no cache maintenance was needed. However, later inbe0f272bfc
("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:be0f272bfc
("arm64: ftrace: emit ftrace-mod.o contents through code") Signed-off-by: Will Deacon <will@kernel.org> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
parent
5717fe5ab3
commit
b6143d10d2
@ -73,7 +73,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;
|
||||
|
||||
/*
|
||||
@ -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,
|
||||
* regardless of the offset in memory so use memcmp() instead.
|
||||
*/
|
||||
trampoline = get_plt_entry(addr, mod->arch.ftrace_trampoline);
|
||||
if (memcmp(mod->arch.ftrace_trampoline, &trampoline,
|
||||
sizeof(trampoline))) {
|
||||
if (plt_entry_is_initialized(mod->arch.ftrace_trampoline)) {
|
||||
dst = mod->arch.ftrace_trampoline;
|
||||
trampoline = get_plt_entry(addr, dst);
|
||||
if (memcmp(dst, &trampoline, sizeof(trampoline))) {
|
||||
if (plt_entry_is_initialized(dst)) {
|
||||
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user