* [PATCH v2 5/7] riscv: Pass patch_text() the length in bytes
2024-03-27 16:04 [PATCH v2 0/7] riscv: Various text patching improvements Samuel Holland
@ 2024-03-27 16:04 ` Samuel Holland
2024-04-24 10:49 ` Conor Dooley
2024-05-22 16:35 ` [PATCH v2 0/7] riscv: Various text patching improvements Palmer Dabbelt
2024-06-27 17:50 ` patchwork-bot+linux-riscv
2 siblings, 1 reply; 5+ messages in thread
From: Samuel Holland @ 2024-03-27 16:04 UTC (permalink / raw)
To: Palmer Dabbelt
Cc: Björn Töpel, linux-riscv, linux-kernel, Samuel Holland,
Daniel Borkmann, bpf
patch_text_nosync() already handles an arbitrary length of code, so this
removes a superfluous loop and reduces the number of icache flushes.
Reviewed-by: Björn Töpel <bjorn@rivosinc.com>
Signed-off-by: Samuel Holland <samuel.holland@sifive.com>
---
Changes in v2:
- Remove unnecessary line wrapping
arch/riscv/include/asm/patch.h | 2 +-
arch/riscv/kernel/patch.c | 14 +++++---------
arch/riscv/kernel/probes/kprobes.c | 18 ++++++++++--------
arch/riscv/net/bpf_jit_comp64.c | 7 ++++---
4 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/arch/riscv/include/asm/patch.h b/arch/riscv/include/asm/patch.h
index 9f5d6e14c405..7228e266b9a1 100644
--- a/arch/riscv/include/asm/patch.h
+++ b/arch/riscv/include/asm/patch.h
@@ -9,7 +9,7 @@
int patch_insn_write(void *addr, const void *insn, size_t len);
int patch_text_nosync(void *addr, const void *insns, size_t len);
int patch_text_set_nosync(void *addr, u8 c, size_t len);
-int patch_text(void *addr, u32 *insns, int ninsns);
+int patch_text(void *addr, u32 *insns, size_t len);
extern int riscv_patch_in_stop_machine;
diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c
index 0d1700d1934c..243e1573410b 100644
--- a/arch/riscv/kernel/patch.c
+++ b/arch/riscv/kernel/patch.c
@@ -19,7 +19,7 @@
struct patch_insn {
void *addr;
u32 *insns;
- int ninsns;
+ size_t len;
atomic_t cpu_count;
};
@@ -231,14 +231,10 @@ NOKPROBE_SYMBOL(patch_text_nosync);
static int patch_text_cb(void *data)
{
struct patch_insn *patch = data;
- unsigned long len;
- int i, ret = 0;
+ int ret = 0;
if (atomic_inc_return(&patch->cpu_count) == num_online_cpus()) {
- for (i = 0; ret == 0 && i < patch->ninsns; i++) {
- len = GET_INSN_LENGTH(patch->insns[i]);
- ret = patch_insn_write(patch->addr + i * len, &patch->insns[i], len);
- }
+ ret = patch_insn_write(patch->addr, patch->insns, patch->len);
/*
* Make sure the patching store is effective *before* we
* increment the counter which releases all waiting CPUs
@@ -258,13 +254,13 @@ static int patch_text_cb(void *data)
}
NOKPROBE_SYMBOL(patch_text_cb);
-int patch_text(void *addr, u32 *insns, int ninsns)
+int patch_text(void *addr, u32 *insns, size_t len)
{
int ret;
struct patch_insn patch = {
.addr = addr,
.insns = insns,
- .ninsns = ninsns,
+ .len = len,
.cpu_count = ATOMIC_INIT(0),
};
diff --git a/arch/riscv/kernel/probes/kprobes.c b/arch/riscv/kernel/probes/kprobes.c
index fecbbcf40ac3..f3cbc3ec9e6a 100644
--- a/arch/riscv/kernel/probes/kprobes.c
+++ b/arch/riscv/kernel/probes/kprobes.c
@@ -23,13 +23,13 @@ post_kprobe_handler(struct kprobe *, struct kprobe_ctlblk *, struct pt_regs *);
static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
{
+ size_t len = GET_INSN_LENGTH(p->opcode);
u32 insn = __BUG_INSN_32;
- unsigned long offset = GET_INSN_LENGTH(p->opcode);
- p->ainsn.api.restore = (unsigned long)p->addr + offset;
+ p->ainsn.api.restore = (unsigned long)p->addr + len;
- patch_text_nosync(p->ainsn.api.insn, &p->opcode, 1);
- patch_text_nosync(p->ainsn.api.insn + offset, &insn, 1);
+ patch_text_nosync(p->ainsn.api.insn, &p->opcode, len);
+ patch_text_nosync(p->ainsn.api.insn + len, &insn, GET_INSN_LENGTH(insn));
}
static void __kprobes arch_prepare_simulate(struct kprobe *p)
@@ -116,16 +116,18 @@ void *alloc_insn_page(void)
/* install breakpoint in text */
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
- u32 insn = (p->opcode & __INSN_LENGTH_MASK) == __INSN_LENGTH_32 ?
- __BUG_INSN_32 : __BUG_INSN_16;
+ size_t len = GET_INSN_LENGTH(p->opcode);
+ u32 insn = len == 4 ? __BUG_INSN_32 : __BUG_INSN_16;
- patch_text(p->addr, &insn, 1);
+ patch_text(p->addr, &insn, len);
}
/* remove breakpoint from text */
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
- patch_text(p->addr, &p->opcode, 1);
+ size_t len = GET_INSN_LENGTH(p->opcode);
+
+ patch_text(p->addr, &p->opcode, len);
}
void __kprobes arch_remove_kprobe(struct kprobe *p)
diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
index aac190085472..6ed4035a8136 100644
--- a/arch/riscv/net/bpf_jit_comp64.c
+++ b/arch/riscv/net/bpf_jit_comp64.c
@@ -15,6 +15,7 @@
#include "bpf_jit.h"
#define RV_FENTRY_NINSNS 2
+#define RV_FENTRY_NBYTES (RV_FENTRY_NINSNS * 4)
#define RV_REG_TCC RV_REG_A6
#define RV_REG_TCC_SAVED RV_REG_S6 /* Store A6 in S6 if program do calls */
@@ -663,7 +664,7 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
if (ret)
return ret;
- if (memcmp(ip, old_insns, RV_FENTRY_NINSNS * 4))
+ if (memcmp(ip, old_insns, RV_FENTRY_NBYTES))
return -EFAULT;
ret = gen_jump_or_nops(new_addr, ip, new_insns, is_call);
@@ -672,8 +673,8 @@ int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type poke_type,
cpus_read_lock();
mutex_lock(&text_mutex);
- if (memcmp(ip, new_insns, RV_FENTRY_NINSNS * 4))
- ret = patch_text(ip, new_insns, RV_FENTRY_NINSNS);
+ if (memcmp(ip, new_insns, RV_FENTRY_NBYTES))
+ ret = patch_text(ip, new_insns, RV_FENTRY_NBYTES);
mutex_unlock(&text_mutex);
cpus_read_unlock();
--
2.43.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH v2 0/7] riscv: Various text patching improvements
2024-03-27 16:04 [PATCH v2 0/7] riscv: Various text patching improvements Samuel Holland
2024-03-27 16:04 ` [PATCH v2 5/7] riscv: Pass patch_text() the length in bytes Samuel Holland
@ 2024-05-22 16:35 ` Palmer Dabbelt
2024-06-27 17:50 ` patchwork-bot+linux-riscv
2 siblings, 0 replies; 5+ messages in thread
From: Palmer Dabbelt @ 2024-05-22 16:35 UTC (permalink / raw)
To: samuel.holland
Cc: Bjorn Topel, linux-riscv, linux-kernel, samuel.holland,
Ard Biesheuvel, daniel, jbaron, jpoimboe, peterz, rostedt, bpf
On Wed, 27 Mar 2024 09:04:39 PDT (-0700), samuel.holland@sifive.com wrote:
> Here are a few changes to minimize calls to stop_machine() and
> flush_icache_*() in the various text patching functions, as well as
> to simplify the code.
>
> This series is based on "[PATCH v3 0/2] riscv: fix patching with IPI"[1].
>
> [1]: https://lore.kernel.org/linux-riscv/20240229121056.203419-1-alexghiti@rivosinc.com/
>
> Changes in v2:
> - Remove unnecessary line wrapping
> - Further simplify patch_insn_set()/patch_insn_write() loop conditions
> - Use min() instead of min_t() since both sides are unsigned long
>
> Samuel Holland (7):
> riscv: jump_label: Batch icache maintenance
> riscv: jump_label: Simplify assembly syntax
> riscv: kprobes: Use patch_text_nosync() for insn slots
> riscv: Simplify text patching loops
> riscv: Pass patch_text() the length in bytes
> riscv: Use offset_in_page() in text patching functions
> riscv: Remove extra variable in patch_text_nosync()
>
> arch/riscv/include/asm/jump_label.h | 4 +-
> arch/riscv/include/asm/patch.h | 2 +-
> arch/riscv/kernel/jump_label.c | 16 +++++--
> arch/riscv/kernel/patch.c | 69 ++++++++++++++---------------
> arch/riscv/kernel/probes/kprobes.c | 19 ++++----
> arch/riscv/net/bpf_jit_comp64.c | 7 +--
> 6 files changed, 63 insertions(+), 54 deletions(-)
I don't have any issues with this, but given that we've run into some
possible text patching bug with this ftrace thing I'm just going to hold
off until 6.11 for these. Maybe that's a bit too conservative, but with
the bug only manifesting on HW it might be tough to sort out.
^ permalink raw reply [flat|nested] 5+ messages in thread