Commit 6ca445d8 authored by Alexandre Ghiti's avatar Alexandre Ghiti Committed by Palmer Dabbelt

riscv: Fix early ftrace nop patching

Commit c97bf629 ("riscv: Fix text patching when IPI are used")
converted ftrace_make_nop() to use patch_insn_write() which does not
emit any icache flush relying entirely on __ftrace_modify_code() to do
that.

But we missed that ftrace_make_nop() was called very early directly when
converting mcount calls into nops (actually on riscv it converts 2B nops
emitted by the compiler into 4B nops).

This caused crashes on multiple HW as reported by Conor and Björn since
the booting core could have half-patched instructions in its icache
which would trigger an illegal instruction trap: fix this by emitting a
local flush icache when early patching nops.

Fixes: c97bf629 ("riscv: Fix text patching when IPI are used")
Signed-off-by: default avatarAlexandre Ghiti <alexghiti@rivosinc.com>
Reported-by: default avatarConor Dooley <conor.dooley@microchip.com>
Tested-by: default avatarConor Dooley <conor.dooley@microchip.com>
Reviewed-by: default avatarBjörn Töpel <bjorn@rivosinc.com>
Tested-by: default avatarBjörn Töpel <bjorn@rivosinc.com>
Link: https://lore.kernel.org/r/20240523115134.70380-1-alexghiti@rivosinc.comSigned-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parent 46cad6cd
...@@ -13,6 +13,12 @@ static inline void local_flush_icache_all(void) ...@@ -13,6 +13,12 @@ static inline void local_flush_icache_all(void)
asm volatile ("fence.i" ::: "memory"); asm volatile ("fence.i" ::: "memory");
} }
static inline void local_flush_icache_range(unsigned long start,
unsigned long end)
{
local_flush_icache_all();
}
#define PG_dcache_clean PG_arch_1 #define PG_dcache_clean PG_arch_1
static inline void flush_dcache_folio(struct folio *folio) static inline void flush_dcache_folio(struct folio *folio)
......
...@@ -120,6 +120,9 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec) ...@@ -120,6 +120,9 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
out = ftrace_make_nop(mod, rec, MCOUNT_ADDR); out = ftrace_make_nop(mod, rec, MCOUNT_ADDR);
mutex_unlock(&text_mutex); mutex_unlock(&text_mutex);
if (!mod)
local_flush_icache_range(rec->ip, rec->ip + MCOUNT_INSN_SIZE);
return out; return out;
} }
......
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