summaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel/insn.c
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2018-06-11 14:22:09 +0100
committerWill Deacon <will.deacon@arm.com>2018-07-05 17:24:36 +0100
commit3b8c9f1cdfc506e94e992ae66b68bbe416f89610 (patch)
treeb57aba6cc3433283aaf8e327e9f2a43d4eb9a2cf /arch/arm64/kernel/insn.c
parent7373fed2f258e640031387616a2275a6fc0d7231 (diff)
downloadlinux-3b8c9f1cdfc506e94e992ae66b68bbe416f89610.tar.bz2
arm64: IPI each CPU after invalidating the I-cache for kernel mappings
When invalidating the instruction cache for a kernel mapping via flush_icache_range(), it is also necessary to flush the pipeline for other CPUs so that instructions fetched into the pipeline before the I-cache invalidation are discarded. For example, if module 'foo' is unloaded and then module 'bar' is loaded into the same area of memory, a CPU could end up executing instructions from 'foo' when branching into 'bar' if these instructions were fetched into the pipeline before 'foo' was unloaded. Whilst this is highly unlikely to occur in practice, particularly as any exception acts as a context-synchronizing operation, following the letter of the architecture requires us to execute an ISB on each CPU in order for the new instruction stream to be visible. Acked-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm64/kernel/insn.c')
-rw-r--r--arch/arm64/kernel/insn.c18
1 files changed, 4 insertions, 14 deletions
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 816d03c4c913..0f6a2e0cfde0 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -216,8 +216,8 @@ int __kprobes aarch64_insn_patch_text_nosync(void *addr, u32 insn)
ret = aarch64_insn_write(tp, insn);
if (ret == 0)
- flush_icache_range((uintptr_t)tp,
- (uintptr_t)tp + AARCH64_INSN_SIZE);
+ __flush_icache_range((uintptr_t)tp,
+ (uintptr_t)tp + AARCH64_INSN_SIZE);
return ret;
}
@@ -283,18 +283,8 @@ int __kprobes aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt)
if (ret)
return ret;
- if (aarch64_insn_hotpatch_safe(insn, insns[0])) {
- /*
- * ARMv8 architecture doesn't guarantee all CPUs see
- * the new instruction after returning from function
- * aarch64_insn_patch_text_nosync(). So send IPIs to
- * all other CPUs to achieve instruction
- * synchronization.
- */
- ret = aarch64_insn_patch_text_nosync(addrs[0], insns[0]);
- kick_all_cpus_sync();
- return ret;
- }
+ if (aarch64_insn_hotpatch_safe(insn, insns[0]))
+ return aarch64_insn_patch_text_nosync(addrs[0], insns[0]);
}
return aarch64_insn_patch_text_sync(addrs, insns, cnt);