Skip to content

Commit 82dfb5f

Browse files
Merge patch series "riscv: kprobes: simulate some instructions"
Nam Cao <[email protected]> says: Simulate some currently rejected instructions. Still to be simulated are: - c.jal - c.ebreak * b4-shazam-merge: riscv: kprobes: simulate c.beqz and c.bnez riscv: kprobes: simulate c.jr and c.jalr instructions riscv: kprobes: simulate c.j instruction Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
2 parents 3ed8513 + d943705 commit 82dfb5f

File tree

3 files changed

+116
-5
lines changed

3 files changed

+116
-5
lines changed

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@ riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api)
2929
* TODO: the REJECTED ones below need to be implemented
3030
*/
3131
#ifdef CONFIG_RISCV_ISA_C
32-
RISCV_INSN_REJECTED(c_j, insn);
33-
RISCV_INSN_REJECTED(c_jr, insn);
3432
RISCV_INSN_REJECTED(c_jal, insn);
35-
RISCV_INSN_REJECTED(c_jalr, insn);
36-
RISCV_INSN_REJECTED(c_beqz, insn);
37-
RISCV_INSN_REJECTED(c_bnez, insn);
3833
RISCV_INSN_REJECTED(c_ebreak, insn);
34+
35+
RISCV_INSN_SET_SIMULATE(c_j, insn);
36+
RISCV_INSN_SET_SIMULATE(c_jr, insn);
37+
RISCV_INSN_SET_SIMULATE(c_jalr, insn);
38+
RISCV_INSN_SET_SIMULATE(c_beqz, insn);
39+
RISCV_INSN_SET_SIMULATE(c_bnez, insn);
3940
#endif
4041

4142
RISCV_INSN_SET_SIMULATE(jal, insn);

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

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,108 @@ bool __kprobes simulate_branch(u32 opcode, unsigned long addr, struct pt_regs *r
188188

189189
return true;
190190
}
191+
192+
bool __kprobes simulate_c_j(u32 opcode, unsigned long addr, struct pt_regs *regs)
193+
{
194+
/*
195+
* 15 13 12 2 1 0
196+
* | funct3 | offset[11|4|9:8|10|6|7|3:1|5] | opcode |
197+
* 3 11 2
198+
*/
199+
200+
s32 offset;
201+
202+
offset = ((opcode >> 3) & 0x7) << 1;
203+
offset |= ((opcode >> 11) & 0x1) << 4;
204+
offset |= ((opcode >> 2) & 0x1) << 5;
205+
offset |= ((opcode >> 7) & 0x1) << 6;
206+
offset |= ((opcode >> 6) & 0x1) << 7;
207+
offset |= ((opcode >> 9) & 0x3) << 8;
208+
offset |= ((opcode >> 8) & 0x1) << 10;
209+
offset |= ((opcode >> 12) & 0x1) << 11;
210+
211+
instruction_pointer_set(regs, addr + sign_extend32(offset, 11));
212+
213+
return true;
214+
}
215+
216+
static bool __kprobes simulate_c_jr_jalr(u32 opcode, unsigned long addr, struct pt_regs *regs,
217+
bool is_jalr)
218+
{
219+
/*
220+
* 15 12 11 7 6 2 1 0
221+
* | funct4 | rs1 | rs2 | op |
222+
* 4 5 5 2
223+
*/
224+
225+
unsigned long jump_addr;
226+
227+
u32 rs1 = (opcode >> 7) & 0x1f;
228+
229+
if (rs1 == 0) /* C.JR is only valid when rs1 != x0 */
230+
return false;
231+
232+
if (!rv_insn_reg_get_val(regs, rs1, &jump_addr))
233+
return false;
234+
235+
if (is_jalr && !rv_insn_reg_set_val(regs, 1, addr + 2))
236+
return false;
237+
238+
instruction_pointer_set(regs, jump_addr);
239+
240+
return true;
241+
}
242+
243+
bool __kprobes simulate_c_jr(u32 opcode, unsigned long addr, struct pt_regs *regs)
244+
{
245+
return simulate_c_jr_jalr(opcode, addr, regs, false);
246+
}
247+
248+
bool __kprobes simulate_c_jalr(u32 opcode, unsigned long addr, struct pt_regs *regs)
249+
{
250+
return simulate_c_jr_jalr(opcode, addr, regs, true);
251+
}
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: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,10 @@ bool simulate_auipc(u32 opcode, unsigned long addr, struct pt_regs *regs);
2424
bool simulate_branch(u32 opcode, unsigned long addr, struct pt_regs *regs);
2525
bool simulate_jal(u32 opcode, unsigned long addr, struct pt_regs *regs);
2626
bool simulate_jalr(u32 opcode, unsigned long addr, struct pt_regs *regs);
27+
bool simulate_c_j(u32 opcode, unsigned long addr, struct pt_regs *regs);
28+
bool simulate_c_jr(u32 opcode, unsigned long addr, struct pt_regs *regs);
29+
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);
2732

2833
#endif /* _RISCV_KERNEL_PROBES_SIMULATE_INSN_H */

0 commit comments

Comments
 (0)