Skip to content

Commit edf2d54

Browse files
Alexandre Ghitipalmer-dabbelt
authored andcommitted
riscv: patch: Flush the icache right after patching to avoid illegal insns
We cannot delay the icache flush after patching some functions as we may have patched a function that will get called before the icache flush. The only way to completely avoid such scenario is by flushing the icache as soon as we patch a function. This will probably be costly as we don't batch the icache maintenance anymore. Fixes: 6ca445d ("riscv: Fix early ftrace nop patching") Reported-by: Conor Dooley <[email protected]> Closes: https://lore.kernel.org/linux-riscv/20240613-lubricant-breath-061192a9489a@wendy/ Signed-off-by: Alexandre Ghiti <[email protected]> Reviewed-by: Andy Chiu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 04a2aef commit edf2d54

File tree

2 files changed

+20
-13
lines changed

2 files changed

+20
-13
lines changed

arch/riscv/kernel/ftrace.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,6 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
120120
out = ftrace_make_nop(mod, rec, MCOUNT_ADDR);
121121
mutex_unlock(&text_mutex);
122122

123-
if (!mod)
124-
local_flush_icache_range(rec->ip, rec->ip + MCOUNT_INSN_SIZE);
125-
126123
return out;
127124
}
128125

@@ -156,9 +153,9 @@ static int __ftrace_modify_code(void *data)
156153
} else {
157154
while (atomic_read(&param->cpu_count) <= num_online_cpus())
158155
cpu_relax();
159-
}
160156

161-
local_flush_icache_all();
157+
local_flush_icache_all();
158+
}
162159

163160
return 0;
164161
}

arch/riscv/kernel/patch.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,14 @@ static int __patch_insn_set(void *addr, u8 c, size_t len)
8989

9090
memset(waddr, c, len);
9191

92+
/*
93+
* We could have just patched a function that is about to be
94+
* called so make sure we don't execute partially patched
95+
* instructions by flushing the icache as soon as possible.
96+
*/
97+
local_flush_icache_range((unsigned long)waddr,
98+
(unsigned long)waddr + len);
99+
92100
patch_unmap(FIX_TEXT_POKE0);
93101

94102
if (across_pages)
@@ -135,6 +143,14 @@ static int __patch_insn_write(void *addr, const void *insn, size_t len)
135143

136144
ret = copy_to_kernel_nofault(waddr, insn, len);
137145

146+
/*
147+
* We could have just patched a function that is about to be
148+
* called so make sure we don't execute partially patched
149+
* instructions by flushing the icache as soon as possible.
150+
*/
151+
local_flush_icache_range((unsigned long)waddr,
152+
(unsigned long)waddr + len);
153+
138154
patch_unmap(FIX_TEXT_POKE0);
139155

140156
if (across_pages)
@@ -189,9 +205,6 @@ int patch_text_set_nosync(void *addr, u8 c, size_t len)
189205

190206
ret = patch_insn_set(tp, c, len);
191207

192-
if (!ret)
193-
flush_icache_range((uintptr_t)tp, (uintptr_t)tp + len);
194-
195208
return ret;
196209
}
197210
NOKPROBE_SYMBOL(patch_text_set_nosync);
@@ -224,9 +237,6 @@ int patch_text_nosync(void *addr, const void *insns, size_t len)
224237

225238
ret = patch_insn_write(tp, insns, len);
226239

227-
if (!ret)
228-
flush_icache_range((uintptr_t) tp, (uintptr_t) tp + len);
229-
230240
return ret;
231241
}
232242
NOKPROBE_SYMBOL(patch_text_nosync);
@@ -253,9 +263,9 @@ static int patch_text_cb(void *data)
253263
} else {
254264
while (atomic_read(&patch->cpu_count) <= num_online_cpus())
255265
cpu_relax();
256-
}
257266

258-
local_flush_icache_all();
267+
local_flush_icache_all();
268+
}
259269

260270
return ret;
261271
}

0 commit comments

Comments
 (0)