From: Sahil Siddiq <sahilcdq0@gmail.com>
To: jonas@southpole.se, stefan.kristiansson@saunalahti.fi,
shorne@gmail.com, naveen@kernel.org, davem@davemloft.net,
mhiramat@kernel.org
Cc: tytso@mit.edu, wangruikang@iscas.ac.cn, namcao@linutronix.de,
pjw@kernel.org, kees@kernel.org, linux-openrisc@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
Sahil Siddiq <sahilcdq0@gmail.com>
Subject: [PATCH v2 1/4] openrisc: Add utilities and clean up simulation of instructions
Date: Thu, 1 Oct 2026 02:01:26 +0530 [thread overview]
Message-ID: <20260930203129.51048-2-sahilcdq0@gmail.com> (raw)
In-Reply-To: <20260407185650.79816-2-sahilcdq0@gmail.com>
Introduce new instruction-related utilities and macros for OpenRISC.
This is in preparation for patches that add tracing support such as
KProbes and Kretprobes.
Currently, PC is first updated and then saved in the link register
(r9) when simulating l.jal and l.jalr. This can result in a corrupted
page table (bad page map in process). Fix this by saving PC in r9
before updating it.
Move branch simulation to its own function, simulate_branch(), so it
can be reused. It's already being used by do_illegal_instruction().
It'll also be used by KProbes in the following commit.
Introduce simulate_pc() to simulate l.adrp. KProbes will require this
instruction to be simulated as well. simulate_branch() and simulate_pc()
need to be handled differently since branch instructions change the
value of PC while l.adrp depends on PC but doesn't change its value.
Use a static key to check if delay slots are disabled. Delay slots are
a part of the CPU's configuration and won't change at runtime. Since
they are often enabled in an OpenRISC CPU, using a static key will
reduce the overhead of checking this flag in the default case while
processing KProbes inserted at branch instructions and simulating them.
Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf
Signed-off-by: Sahil Siddiq <sahilcdq0@gmail.com>
---
arch/openrisc/include/asm/cpuinfo.h | 3 +
arch/openrisc/include/asm/insn-def.h | 64 +++++++++++++++++++--
arch/openrisc/include/asm/spr_defs.h | 1 +
arch/openrisc/kernel/Makefile | 2 +-
arch/openrisc/kernel/insn.c | 84 ++++++++++++++++++++++++++++
arch/openrisc/kernel/setup.c | 4 ++
arch/openrisc/kernel/traps.c | 79 +++++++++++---------------
7 files changed, 187 insertions(+), 50 deletions(-)
create mode 100644 arch/openrisc/kernel/insn.c
diff --git a/arch/openrisc/include/asm/cpuinfo.h b/arch/openrisc/include/asm/cpuinfo.h
index 3cfc4cf0b019..d6bb8744eba0 100644
--- a/arch/openrisc/include/asm/cpuinfo.h
+++ b/arch/openrisc/include/asm/cpuinfo.h
@@ -15,6 +15,7 @@
#ifndef __ASM_OPENRISC_CPUINFO_H
#define __ASM_OPENRISC_CPUINFO_H
+#include <linux/jump_label.h>
#include <asm/spr.h>
#include <asm/spr_defs.h>
@@ -34,6 +35,8 @@ struct cpuinfo_or1k {
u16 coreid;
};
+DECLARE_STATIC_KEY_TRUE(delay_slot);
+
extern struct cpuinfo_or1k cpuinfo_or1k[NR_CPUS];
extern void setup_cpuinfo(void);
diff --git a/arch/openrisc/include/asm/insn-def.h b/arch/openrisc/include/asm/insn-def.h
index 1e0c028a5b95..3680c0a94faf 100644
--- a/arch/openrisc/include/asm/insn-def.h
+++ b/arch/openrisc/include/asm/insn-def.h
@@ -3,13 +3,69 @@
* Copyright (C) 2025 Chen Miao
*/
+#include <asm/spr.h>
+#include <asm/spr_defs.h>
+#include <linux/bits.h>
+
#ifndef __ASM_OPENRISC_INSN_DEF_H
#define __ASM_OPENRISC_INSN_DEF_H
-/* or1k instructions are always 32 bits. */
-#define OPENRISC_INSN_SIZE 4
-
/* or1k nop instruction code */
-#define OPENRISC_INSN_NOP 0x15000000U
+#define OPENRISC_INSN_CSYNC 0x23000000U
+#define OPENRISC_INSN_MACRC 0x18010000U
+#define OPENRISC_MASK_MACRC 0xfc01ffffU
+#define OPENRISC_INSN_MSYNC 0x22000000U
+#define OPENRISC_INSN_NOP 0x15000000U
+#define OPENRISC_INSN_PSYNC 0x22800000U
+#define OPENRISC_INSN_SYS 0x20000000U
+#define OPENRISC_INSN_TRAP 0x21000000U
+
+#define OPENRISC_OPCODE_ADRP 0x02
+#define OPENRISC_OPCODE_BF 0x04
+#define OPENRISC_OPCODE_BNF 0x03
+#define OPENRISC_OPCODE_J 0x00
+#define OPENRISC_OPCODE_JAL 0x01
+#define OPENRISC_OPCODE_JALR 0x12
+#define OPENRISC_OPCODE_JR 0x11
+#define OPENRISC_OPCODE_LWA 0x1b
+#define OPENRISC_OPCODE_MFSPR 0x2d
+#define OPENRISC_OPCODE_MTSPR 0x30
+#define OPENRISC_OPCODE_RFE 0x09
+#define OPENRISC_OPCODE_SWA 0x33
+
+#define OPENRISC_ADRP_IMM_MASK GENMASK(18, 0)
+#define OPENRISC_ADRP_OFFSET_MASK GENMASK(31, 13)
+#define OPENRISC_ADRP_IMM_SHIFT 13
+#define OPENRISC_ADRP_REG_MASK GENMASK(25, 0)
+#define OPENRISC_ADRP_REG_SHIFT 21
+#define OPENRISC_JUMP_IMM_MASK GENMASK(25, 0)
+#define OPENRISC_JUMP_IMM_SHIFT 2
+#define OPENRISC_JUMP_REG_MASK GENMASK(15, 11)
+#define OPENRISC_JUMP_REG_SHIFT 11
+
+#define OPENRISC_MASK_SYS GENMASK(31, 16)
+#define OPENRISC_MASK_TRAP GENMASK(31, 16)
+#define OPENRISC_MASK_BCODE GENMASK(15, 0)
+
+#define OPENRISC_OPCODE_MASK 0x3f
+#define OPENRISC_OPCODE_SHIFT 0x1a
+
+struct pt_regs;
+
+#define OPENRISC_INSN_SIZE 4
+
+/* Helpers for working with l.trap */
+static inline unsigned long __emit_trap(unsigned long code)
+{
+ return (code & OPENRISC_MASK_BCODE) | OPENRISC_INSN_TRAP;
+}
+
+static __always_inline unsigned char get_6_bit_opcode(unsigned long insn)
+{
+ return (insn >> OPENRISC_OPCODE_SHIFT) & OPENRISC_OPCODE_MASK;
+}
+
+void simulate_pc(struct pt_regs *regs, unsigned long jmp);
+void simulate_branch(struct pt_regs *regs, unsigned long jmp);
#endif /* __ASM_OPENRISC_INSN_DEF_H */
diff --git a/arch/openrisc/include/asm/spr_defs.h b/arch/openrisc/include/asm/spr_defs.h
index f0b6b492e9f4..5d13a9b96263 100644
--- a/arch/openrisc/include/asm/spr_defs.h
+++ b/arch/openrisc/include/asm/spr_defs.h
@@ -179,6 +179,7 @@
#define SPR_CPUCFGR_OF32S 0x00000080 /* ORFPX32 supported */
#define SPR_CPUCFGR_OF64S 0x00000100 /* ORFPX64 supported */
#define SPR_CPUCFGR_OV64S 0x00000200 /* ORVDX64 supported */
+#define SPR_CPUCFGR_ND 0x00000400 /* No delay slot */
#define SPR_CPUCFGR_RES 0xfffffc00 /* Reserved */
/*
diff --git a/arch/openrisc/kernel/Makefile b/arch/openrisc/kernel/Makefile
index 19e0eb94f2eb..150779fbf010 100644
--- a/arch/openrisc/kernel/Makefile
+++ b/arch/openrisc/kernel/Makefile
@@ -5,7 +5,7 @@
always-$(KBUILD_BUILTIN) := vmlinux.lds
-obj-y := head.o setup.o or32_ksyms.o process.o dma.o \
+obj-y := head.o insn.o setup.o or32_ksyms.o process.o dma.o \
traps.o time.o irq.o entry.o ptrace.o signal.o \
sys_call_table.o unwinder.o cacheinfo.o
diff --git a/arch/openrisc/kernel/insn.c b/arch/openrisc/kernel/insn.c
new file mode 100644
index 000000000000..285658512b43
--- /dev/null
+++ b/arch/openrisc/kernel/insn.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * OpenRISC instruction utils
+ *
+ * Linux architectural port borrowing liberally from similar works of
+ * others. All original copyrights apply as per the original source
+ * declaration.
+ *
+ * OpenRISC implementation:
+ * Copyright (C) 2026 Sahil Siddiq <sahilcdq0@gmail.com>
+ */
+
+#include <linux/ptrace.h>
+#include <asm/insn-def.h>
+#include <asm/cpuinfo.h>
+
+DEFINE_STATIC_KEY_TRUE(delay_slot);
+
+void simulate_pc(struct pt_regs *regs, unsigned long pc_insn)
+{
+ int page_offset;
+ unsigned int rd, op;
+
+ page_offset = sign_extend32(
+ (pc_insn & OPENRISC_ADRP_IMM_MASK) << OPENRISC_ADRP_IMM_SHIFT, 31);
+ rd = (pc_insn & OPENRISC_ADRP_REG_MASK) >> OPENRISC_ADRP_REG_SHIFT;
+ op = get_6_bit_opcode(pc_insn);
+
+ switch (op) {
+ case OPENRISC_OPCODE_ADRP:
+ regs->gpr[rd] = page_offset + (regs->pc & OPENRISC_ADRP_OFFSET_MASK);
+ regs->pc += OPENRISC_INSN_SIZE;
+ return;
+ default:
+ break;
+ }
+}
+
+void simulate_branch(struct pt_regs *regs, unsigned long jmp_insn)
+{
+ int displacement;
+ unsigned int rb, op, link_offset, temp;
+
+ displacement = sign_extend32(
+ ((jmp_insn) & OPENRISC_JUMP_IMM_MASK) << OPENRISC_JUMP_IMM_SHIFT, 27);
+ rb = (jmp_insn & OPENRISC_JUMP_REG_MASK) >> OPENRISC_JUMP_REG_SHIFT;
+ op = get_6_bit_opcode(jmp_insn);
+ link_offset = OPENRISC_INSN_SIZE;
+
+ if (static_branch_likely(&delay_slot))
+ link_offset <<= 1;
+
+ switch (op) {
+ case OPENRISC_OPCODE_J: /* l.j */
+ regs->pc += displacement;
+ return;
+ case OPENRISC_OPCODE_JAL: /* l.jal */
+ regs->gpr[9] = regs->pc + link_offset;
+ regs->pc += displacement;
+ return;
+ case OPENRISC_OPCODE_BNF: /* l.bnf */
+ if (regs->sr & SPR_SR_F)
+ regs->pc += link_offset;
+ else
+ regs->pc += displacement;
+ return;
+ case OPENRISC_OPCODE_BF: /* l.bf */
+ if (regs->sr & SPR_SR_F)
+ regs->pc += displacement;
+ else
+ regs->pc += link_offset;
+ return;
+ case OPENRISC_OPCODE_JR: /* l.jr */
+ regs->pc = regs->gpr[rb];
+ return;
+ case OPENRISC_OPCODE_JALR: /* l.jalr */
+ temp = regs->pc + link_offset;
+ regs->pc = regs->gpr[rb];
+ regs->gpr[9] = temp;
+ return;
+ default:
+ break;
+ }
+}
diff --git a/arch/openrisc/kernel/setup.c b/arch/openrisc/kernel/setup.c
index 000a9cc10e6f..0f69c36472d5 100644
--- a/arch/openrisc/kernel/setup.c
+++ b/arch/openrisc/kernel/setup.c
@@ -255,6 +255,10 @@ void __init setup_arch(char **cmdline_p)
/* paging_init() sets up the MMU and marks all pages as reserved */
paging_init();
+ /* determine if the processor supports delay slots */
+ if (mfspr(SPR_CPUCFGR) & SPR_CPUCFGR_ND)
+ static_branch_disable(&delay_slot);
+
*cmdline_p = boot_command_line;
printk(KERN_INFO "OpenRISC Linux -- http://openrisc.io\n");
diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c
index c195be9cc9fc..c9ab630ec895 100644
--- a/arch/openrisc/kernel/traps.c
+++ b/arch/openrisc/kernel/traps.c
@@ -32,6 +32,7 @@
#include <asm/bug.h>
#include <asm/fpu.h>
+#include <asm/insn-def.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/unwinder.h>
@@ -215,6 +216,32 @@ asmlinkage void do_trap(struct pt_regs *regs, unsigned long address)
if (user_mode(regs)) {
force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc);
} else {
+ unsigned long trap, bcode;
+
+ if (get_kernel_nofault(trap, (unsigned long *)regs->pc) < 0)
+ return;
+
+ /*
+ * Trap instruction was probably removed and no further processing
+ * is required.
+ */
+ if ((trap & OPENRISC_MASK_TRAP) != OPENRISC_INSN_TRAP)
+ return;
+
+ bcode = (trap & OPENRISC_MASK_BCODE);
+ switch (bcode) {
+ case BRK_KPROBE_BP:
+ if (kprobe_breakpoint_handler(regs))
+ return;
+ break;
+ case BRK_KPROBE_SSTEPBP:
+ if (kprobe_singlestep_handler(regs))
+ return;
+ break;
+ default:
+ break;
+ }
+
pr_emerg("KERNEL: Illegal trap exception 0x%.8lx\n", regs->pc);
die("Die:", regs, SIGILL);
}
@@ -252,12 +279,12 @@ static inline int in_delay_slot(struct pt_regs *regs)
insn = *((unsigned int *)regs->pc);
op = insn >> 26;
switch (op) {
- case 0x00: /* l.j */
- case 0x01: /* l.jal */
- case 0x03: /* l.bnf */
- case 0x04: /* l.bf */
- case 0x11: /* l.jr */
- case 0x12: /* l.jalr */
+ case OPENRISC_OPCODE_J: /* l.j */
+ case OPENRISC_OPCODE_JAL: /* l.jal */
+ case OPENRISC_OPCODE_BNF: /* l.bnf */
+ case OPENRISC_OPCODE_BF: /* l.bf */
+ case OPENRISC_OPCODE_JR: /* l.jr */
+ case OPENRISC_OPCODE_JALR: /* l.jalr */
return 1;
default:
return 0;
@@ -269,47 +296,9 @@ static inline int in_delay_slot(struct pt_regs *regs)
static inline void adjust_pc(struct pt_regs *regs, unsigned long address)
{
- int displacement;
- unsigned int rb, op, jmp;
-
if (unlikely(in_delay_slot(regs))) {
/* In delay slot, instruction at pc is a branch, simulate it */
- jmp = *((unsigned int *)regs->pc);
-
- displacement = sign_extend32(((jmp) & 0x3ffffff) << 2, 27);
- rb = (jmp & 0x0000ffff) >> 11;
- op = jmp >> 26;
-
- switch (op) {
- case 0x00: /* l.j */
- regs->pc += displacement;
- return;
- case 0x01: /* l.jal */
- regs->pc += displacement;
- regs->gpr[9] = regs->pc + 8;
- return;
- case 0x03: /* l.bnf */
- if (regs->sr & SPR_SR_F)
- regs->pc += 8;
- else
- regs->pc += displacement;
- return;
- case 0x04: /* l.bf */
- if (regs->sr & SPR_SR_F)
- regs->pc += displacement;
- else
- regs->pc += 8;
- return;
- case 0x11: /* l.jr */
- regs->pc = regs->gpr[rb];
- return;
- case 0x12: /* l.jalr */
- regs->pc = regs->gpr[rb];
- regs->gpr[9] = regs->pc + 8;
- return;
- default:
- break;
- }
+ simulate_branch(regs, *((unsigned int *)regs->pc));
} else {
regs->pc += 4;
}
--
2.55.0
next prev parent reply other threads:[~2026-09-30 20:32 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-07 18:56 [RFC 0/2] openrisc: Add support for KProbes Sahil Siddiq
2026-04-07 18:56 ` [RFC 1/2] openrisc: Add utilities and clean up simulation of instructions Sahil Siddiq
2026-04-14 17:11 ` Stafford Horne
2026-04-15 6:10 ` Sahil
2026-04-15 6:39 ` Masami Hiramatsu
2026-04-16 4:57 ` Sahil
2026-09-30 20:31 ` [PATCH v2 0/4] openrisc: Add support for KProbes Sahil Siddiq
2026-09-30 21:18 ` Sahil
2026-09-30 20:31 ` Sahil Siddiq [this message]
2026-09-30 20:31 ` [PATCH v2 2/4] openrisc: Add KProbes Sahil Siddiq
2026-09-30 20:31 ` [PATCH v2 3/4] openrisc: Add unit tests for KProbes on branch instructions Sahil Siddiq
2026-09-30 20:31 ` [PATCH v2 4/4] openrisc: Add Kretprobes Sahil Siddiq
2026-04-07 18:56 ` [RFC 2/2] openrisc: Add KProbes Sahil Siddiq
2026-04-15 6:48 ` [RFC 0/2] openrisc: Add support for KProbes Masami Hiramatsu
2026-04-16 5:00 ` Sahil
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260930203129.51048-2-sahilcdq0@gmail.com \
--to=sahilcdq0@gmail.com \
--cc=davem@davemloft.net \
--cc=jonas@southpole.se \
--cc=kees@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-openrisc@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mhiramat@kernel.org \
--cc=namcao@linutronix.de \
--cc=naveen@kernel.org \
--cc=pjw@kernel.org \
--cc=shorne@gmail.com \
--cc=stefan.kristiansson@saunalahti.fi \
--cc=tytso@mit.edu \
--cc=wangruikang@iscas.ac.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®