Skip to content

Commit d943705

Browse files
covanampalmer-dabbelt
authored andcommitted
riscv: kprobes: simulate c.beqz and c.bnez
kprobes currently rejects instruction c.beqz and c.bnez. Implement them. Signed-off-by: Nam Cao <[email protected]> Reviewed-by: Charlie Jenkins <[email protected]> Link: https://lore.kernel.org/r/1d879dba4e4ee9a82e27625d6483b5c9cfed684f.1690704360.git.namcaov@gmail.com Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent b18256d commit d943705

File tree

3 files changed

+48
-2
lines changed

3 files changed

+48
-2
lines changed

arch/riscv/kernel/probes/decode-insn.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api)
3030
*/
3131
#ifdef CONFIG_RISCV_ISA_C
3232
RISCV_INSN_REJECTED(c_jal, insn);
33-
RISCV_INSN_REJECTED(c_beqz, insn);
34-
RISCV_INSN_REJECTED(c_bnez, insn);
3533
RISCV_INSN_REJECTED(c_ebreak, insn);
3634

3735
RISCV_INSN_SET_SIMULATE(c_j, insn);
3836
RISCV_INSN_SET_SIMULATE(c_jr, insn);
3937
RISCV_INSN_SET_SIMULATE(c_jalr, insn);
38+
RISCV_INSN_SET_SIMULATE(c_beqz, insn);
39+
RISCV_INSN_SET_SIMULATE(c_bnez, insn);
4040
#endif
4141

4242
RISCV_INSN_SET_SIMULATE(jal, insn);

arch/riscv/kernel/probes/simulate-insn.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,47 @@ bool __kprobes simulate_c_jalr(u32 opcode, unsigned long addr, struct pt_regs *r
249249
{
250250
return simulate_c_jr_jalr(opcode, addr, regs, true);
251251
}
252+
253+
static bool __kprobes simulate_c_bnez_beqz(u32 opcode, unsigned long addr, struct pt_regs *regs,
254+
bool is_bnez)
255+
{
256+
/*
257+
* 15 13 12 10 9 7 6 2 1 0
258+
* | funct3 | offset[8|4:3] | rs1' | offset[7:6|2:1|5] | op |
259+
* 3 3 3 5 2
260+
*/
261+
262+
s32 offset;
263+
u32 rs1;
264+
unsigned long rs1_val;
265+
266+
rs1 = 0x8 | ((opcode >> 7) & 0x7);
267+
268+
if (!rv_insn_reg_get_val(regs, rs1, &rs1_val))
269+
return false;
270+
271+
if ((rs1_val != 0 && is_bnez) || (rs1_val == 0 && !is_bnez)) {
272+
offset = ((opcode >> 3) & 0x3) << 1;
273+
offset |= ((opcode >> 10) & 0x3) << 3;
274+
offset |= ((opcode >> 2) & 0x1) << 5;
275+
offset |= ((opcode >> 5) & 0x3) << 6;
276+
offset |= ((opcode >> 12) & 0x1) << 8;
277+
offset = sign_extend32(offset, 8);
278+
} else {
279+
offset = 2;
280+
}
281+
282+
instruction_pointer_set(regs, addr + offset);
283+
284+
return true;
285+
}
286+
287+
bool __kprobes simulate_c_bnez(u32 opcode, unsigned long addr, struct pt_regs *regs)
288+
{
289+
return simulate_c_bnez_beqz(opcode, addr, regs, true);
290+
}
291+
292+
bool __kprobes simulate_c_beqz(u32 opcode, unsigned long addr, struct pt_regs *regs)
293+
{
294+
return simulate_c_bnez_beqz(opcode, addr, regs, false);
295+
}

arch/riscv/kernel/probes/simulate-insn.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,7 @@ bool simulate_jalr(u32 opcode, unsigned long addr, struct pt_regs *regs);
2727
bool simulate_c_j(u32 opcode, unsigned long addr, struct pt_regs *regs);
2828
bool simulate_c_jr(u32 opcode, unsigned long addr, struct pt_regs *regs);
2929
bool simulate_c_jalr(u32 opcode, unsigned long addr, struct pt_regs *regs);
30+
bool simulate_c_bnez(u32 opcode, unsigned long addr, struct pt_regs *regs);
31+
bool simulate_c_beqz(u32 opcode, unsigned long addr, struct pt_regs *regs);
3032

3133
#endif /* _RISCV_KERNEL_PROBES_SIMULATE_INSN_H */

0 commit comments

Comments
 (0)