* [PATCH v2 00/16] riscv: Generate riscv instruction functions
@ 2026-06-22 4:01 Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 01/16] riscv: Introduce instruction table generation Charlie Jenkins via B4 Relay
` (15 more replies)
0 siblings, 16 replies; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
There is a lot of code that is manually manipulating riscv instructions.
Constructing these headers for new instructions is time consuming and
error prone.
The first patch in this series introduces the instruction definition
table along with a script that runs at compile time to create all of the
associated instruction manipulation functions. The remaining patches
migrate all of the manual instruction code to use these generated
functions.
The instruction definition table is generated from the
riscv-unified-db[1], an open source RVI project for instruction
specifications. I got this table generation merged into
riscv-unified-db, that PR can be accessed on github [2].
A lot of the validation for these changes is from running all possible
32-bit or 16-bit integers through these functions to see that any given
instruction will produce to expected result. I give more detail on the
test cases in the notes of the first couple of patches.
For the KVM patches, I also introduce two test cases to ensure that the
instruction manipulation is working as expected.
[1] https://github.com/riscv/riscv-unified-db
[2] https://github.com/riscv/riscv-unified-db/pull/1780
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
Changes in v2:
- rebased on v7.1
- I dropped the patch fixing the mmio bug in kvm because in the
meantime that bug has been fixed in a different patch
- Calls to panic() for instructions not support on current hardware have
been changed into BUG_ON()
- Fixed incorrect handling of branches in simulate_*()
- Added CONFIG_RISCV_KPROBES_SIMULATE_KUNIT for more detailed
simulate_*() testing
- Updated insn.tbl based on new merged in changes to riscv-unified-db
- Link to v1: https://lore.kernel.org/r/20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com
---
Charlie Jenkins (16):
riscv: Introduce instruction table generation
riscv: alternatives: Use generated instruction headers for patching code
riscv: kgdb: Use generated instruction headers
riscv: Add kprobes instruction simulation KUnit
riscv: kprobes: Use generated instruction headers
riscv: cfi: Use generated instruction headers
riscv: Use generated instruction headers for misaligned loads/stores
riscv: kvm: Use generated instruction headers for csr code
KVM: device: Add test device
KVM: riscv: selftests: Add mmio test
riscv: kvm: Use generated instruction headers for mmio emulation
riscv: kvm: Add emulated test csr
KVM: riscv: selftests: Add csr emulation test
riscv: kvm: Use generated instruction headers for csr emulation
riscv: kexec: Use generated instruction headers for kexec relocations
riscv: Remove unused instruction headers
arch/riscv/Kconfig.debug | 1 +
arch/riscv/Makefile | 3 +
arch/riscv/include/asm/Kbuild | 1 +
arch/riscv/include/asm/insn.h | 563 +-------
arch/riscv/include/asm/kvm_host.h | 10 +
arch/riscv/include/asm/kvm_vcpu_insn.h | 5 +-
arch/riscv/include/asm/kvm_vcpu_test_csr.h | 15 +
arch/riscv/kernel/alternative.c | 23 +-
arch/riscv/kernel/cfi.c | 6 +-
arch/riscv/kernel/kgdb.c | 102 +-
arch/riscv/kernel/machine_kexec_file.c | 55 +-
arch/riscv/kernel/probes/decode-insn.c | 7 +-
arch/riscv/kernel/probes/simulate-insn.c | 253 ++--
arch/riscv/kernel/probes/simulate-insn.h | 7 +-
arch/riscv/kernel/tests/Kconfig.debug | 13 +
arch/riscv/kernel/tests/kprobes/Makefile | 2 +
.../kernel/tests/kprobes/test-kprobes-simulate.c | 250 ++++
arch/riscv/kernel/tests/kprobes/test-kprobes.h | 6 +
arch/riscv/kernel/traps_misaligned.c | 183 ++-
arch/riscv/kvm/Kconfig.debug | 16 +
arch/riscv/kvm/Makefile | 1 +
arch/riscv/kvm/vcpu_insn.c | 232 ++--
arch/riscv/kvm/vcpu_test_csr.c | 21 +
arch/riscv/tools/Makefile | 22 +
arch/riscv/tools/insn.tbl | 1392 ++++++++++++++++++++
arch/riscv/tools/insn_tbl.sh | 256 ++++
include/uapi/linux/kvm.h | 2 +
lib/Kconfig.debug | 6 +
tools/testing/selftests/kvm/Makefile.kvm | 2 +
tools/testing/selftests/kvm/riscv/csr_test.c | 126 ++
tools/testing/selftests/kvm/riscv/mmio_test.c | 184 +++
virt/kvm/Kconfig.debug | 16 +
virt/kvm/Makefile.kvm | 1 +
virt/kvm/kvm_main.c | 8 +
virt/kvm/mmio_test.c | 95 ++
virt/kvm/mmio_test.h | 18 +
36 files changed, 2897 insertions(+), 1006 deletions(-)
---
base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
change-id: 20260114-riscv_insn_table-38495495dfd3
Best regards,
--
Charlie Jenkins <thecharlesjenkins@gmail.com>
^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH v2 01/16] riscv: Introduce instruction table generation
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:13 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 02/16] riscv: alternatives: Use generated instruction headers for patching code Charlie Jenkins via B4 Relay
` (14 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Eliminate the need to hand-write riscv instructions by using a shell
script to autogenerate a header from an instruction table. This is modeled
after the syscall table infrastructure.
The table is generated externally by riscv-unified-db [1], but is
in a simple format to make it possible to use other tools or modify
manually.
[1] https://github.com/riscv-software-src/riscv-unified-db
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
This change immediately modifies all of the riscv_insn_* macros. I don't
have a clean way of sharing my test cases but what I did was compare the
old and new versions of the functions using the following test case:
for (unsigned int i = 0; i < ((1ULL << 32) - 1); i++) {\
bool old = riscv_insn_is_##name(i);\
bool new = new_riscv_insn_is_##name(i);\
if (old != new) {\
printf(#name " %u\n", i);\
}\
}
for (unsigned int i = 0; i < ((1ULL << 32) - 1); i++) {\
bool old = riscv_insn_is_##name(i);\
bool new = new_riscv_insn_is_##name(i);\
\
if (old != new) {\
printf(#name " %u\n", i);\
return;\
}\
}
void check()
{
check_64(auipc)
check_64(jalr)
check_64(jal)
check_64(beq)
check_64(bne)
check_64(blt)
check_64(bge)
check_64(bltu)
check_64(bgeu)
check_64(ebreak)
check_64(sret)
check_64(fence)
check_32(c_jr)
check_32(c_jalr)
check_32(c_j)
check_32(c_beqz)
check_32(c_bnez)
check_32(c_ebreak)
}
This does a simple brute force to check all possible numbers. The
only difference with the new version is that the fence instruction
refers to the literal "fence" instruction whereas the previous version
could have matched on to fence, fence.i, or fence.tso. This does not
make a material difference because riscv_insn_is_fence() isn't currently
in use.
---
arch/riscv/Makefile | 3 +
arch/riscv/include/asm/Kbuild | 1 +
arch/riscv/include/asm/insn.h | 72 +--
arch/riscv/tools/Makefile | 22 +
arch/riscv/tools/insn.tbl | 1392 +++++++++++++++++++++++++++++++++++++++++
arch/riscv/tools/insn_tbl.sh | 256 ++++++++
6 files changed, 1704 insertions(+), 42 deletions(-)
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index ce0cc737f870..d14caa8720f8 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -176,6 +176,9 @@ BOOT_TARGETS := Image Image.gz Image.bz2 Image.lz4 Image.lzma Image.lzo Image.zs
all: $(notdir $(KBUILD_IMAGE))
+archprepare:
+ $(Q)$(MAKE) $(build)=arch/riscv/tools insn
+
loader.bin: loader
Image.gz Image.bz2 Image.lz4 Image.lzma Image.lzo Image.zst Image.xz loader xipImage vmlinuz.efi: Image
diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild
index 7721b63642f4..16be4de3d0b1 100644
--- a/arch/riscv/include/asm/Kbuild
+++ b/arch/riscv/include/asm/Kbuild
@@ -2,6 +2,7 @@
syscall-y += syscall_table_32.h
syscall-y += syscall_table_64.h
+generated-y += insn_gen.h
generic-y += early_ioremap.h
generic-y += flat.h
generic-y += fprobe.h
diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h
index c3005573e8c9..d562b2b40ba1 100644
--- a/arch/riscv/include/asm/insn.h
+++ b/arch/riscv/include/asm/insn.h
@@ -8,6 +8,36 @@
#include <linux/bits.h>
+/*
+ * Generate a function to check if a sequence of bits matches an instruction
+ */
+#define __RISCV_INSN_FUNCS(name) \
+static __always_inline bool riscv_insn_is_##name(u32 _insn) \
+{ \
+ BUILD_BUG_ON(~(riscv_insn_##name##_MASK) & (riscv_insn_##name##_MATCH)); \
+ return (_insn & (riscv_insn_##name##_MASK)) == (riscv_insn_##name##_MATCH); \
+}
+
+/*
+ * Generate a function to check if a sequence of bits matches an instruction
+ * with constraints. Some instructions require inputs to be specific values.
+ */
+#define __RISCV_INSN_FUNCS_CONSTRAINED(name, constraints) \
+static __always_inline bool riscv_insn_is_##name(u32 _insn) \
+{ \
+ BUILD_BUG_ON(~(riscv_insn_##name##_MASK) & (riscv_insn_##name##_MATCH)); \
+ return ((_insn & (riscv_insn_##name##_MASK)) == (riscv_insn_##name##_MATCH)) && \
+ (constraints); \
+}
+
+#define __RISCV_INSN_FUNCS_UNSUPPORTED(name) \
+static __always_inline bool riscv_insn_is_##name(u32 _insn) \
+{ \
+ return 0; \
+}
+
+#include <asm/insn_gen.h>
+
#define RV_INSN_FUNCT3_MASK GENMASK(14, 12)
#define RV_INSN_FUNCT3_OPOFF 12
#define RV_INSN_OPCODE_MASK GENMASK(6, 0)
@@ -233,36 +263,6 @@
#define __INSN_OPCODE_MASK _UL(0x7F)
#define __INSN_BRANCH_OPCODE _UL(RVG_OPCODE_BRANCH)
-#define __RISCV_INSN_FUNCS(name, mask, val) \
-static __always_inline bool riscv_insn_is_##name(u32 code) \
-{ \
- BUILD_BUG_ON(~(mask) & (val)); \
- return (code & (mask)) == (val); \
-} \
-
-#if __riscv_xlen == 32
-/* C.JAL is an RV32C-only instruction */
-__RISCV_INSN_FUNCS(c_jal, RVC_MASK_C_JAL, RVC_MATCH_C_JAL)
-#else
-#define riscv_insn_is_c_jal(opcode) 0
-#endif
-__RISCV_INSN_FUNCS(auipc, RVG_MASK_AUIPC, RVG_MATCH_AUIPC)
-__RISCV_INSN_FUNCS(jalr, RVG_MASK_JALR, RVG_MATCH_JALR)
-__RISCV_INSN_FUNCS(jal, RVG_MASK_JAL, RVG_MATCH_JAL)
-__RISCV_INSN_FUNCS(c_j, RVC_MASK_C_J, RVC_MATCH_C_J)
-__RISCV_INSN_FUNCS(beq, RVG_MASK_BEQ, RVG_MATCH_BEQ)
-__RISCV_INSN_FUNCS(bne, RVG_MASK_BNE, RVG_MATCH_BNE)
-__RISCV_INSN_FUNCS(blt, RVG_MASK_BLT, RVG_MATCH_BLT)
-__RISCV_INSN_FUNCS(bge, RVG_MASK_BGE, RVG_MATCH_BGE)
-__RISCV_INSN_FUNCS(bltu, RVG_MASK_BLTU, RVG_MATCH_BLTU)
-__RISCV_INSN_FUNCS(bgeu, RVG_MASK_BGEU, RVG_MATCH_BGEU)
-__RISCV_INSN_FUNCS(c_beqz, RVC_MASK_C_BEQZ, RVC_MATCH_C_BEQZ)
-__RISCV_INSN_FUNCS(c_bnez, RVC_MASK_C_BNEZ, RVC_MATCH_C_BNEZ)
-__RISCV_INSN_FUNCS(c_ebreak, RVC_MASK_C_EBREAK, RVC_MATCH_C_EBREAK)
-__RISCV_INSN_FUNCS(ebreak, RVG_MASK_EBREAK, RVG_MATCH_EBREAK)
-__RISCV_INSN_FUNCS(sret, RVG_MASK_SRET, RVG_MATCH_SRET)
-__RISCV_INSN_FUNCS(fence, RVG_MASK_FENCE, RVG_MATCH_FENCE);
-
/* special case to catch _any_ system instruction */
static __always_inline bool riscv_insn_is_system(u32 code)
{
@@ -275,18 +275,6 @@ static __always_inline bool riscv_insn_is_branch(u32 code)
return (code & RV_INSN_OPCODE_MASK) == RVG_OPCODE_BRANCH;
}
-static __always_inline bool riscv_insn_is_c_jr(u32 code)
-{
- return (code & RVC_MASK_C_JR) == RVC_MATCH_C_JR &&
- (code & RVC_INSN_J_RS1_MASK) != 0;
-}
-
-static __always_inline bool riscv_insn_is_c_jalr(u32 code)
-{
- return (code & RVC_MASK_C_JALR) == RVC_MATCH_C_JALR &&
- (code & RVC_INSN_J_RS1_MASK) != 0;
-}
-
#define INSN_MATCH_LB 0x3
#define INSN_MASK_LB 0x707f
#define INSN_MATCH_LH 0x1003
diff --git a/arch/riscv/tools/Makefile b/arch/riscv/tools/Makefile
new file mode 100644
index 000000000000..5f40439c12e9
--- /dev/null
+++ b/arch/riscv/tools/Makefile
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+
+gen := arch/$(ARCH)/include/generated/asm
+insn_tbl := $(src)/insn_tbl.sh
+insn := $(src)/insn.tbl
+
+gen-y := $(gen)/insn_gen.h
+
+targets += $(addprefix ../../../,$(gen-y))
+
+PHONY += insn
+
+insn: $(gen-y)
+
+# Create output directory if not already present
+$(shell mkdir -p $(gen))
+
+quiet_cmd_insn_tbl = INST_TBL $@
+ cmd_insn_tbl = $(CONFIG_SHELL) $(insn_tbl) $< $@
+
+$(gen)/insn_gen.h: $(insn) $(insn_tbl) FORCE
+ $(call if_changed,insn_tbl)
diff --git a/arch/riscv/tools/insn.tbl b/arch/riscv/tools/insn.tbl
new file mode 100644
index 000000000000..5dc3392a5543
--- /dev/null
+++ b/arch/riscv/tools/insn.tbl
@@ -0,0 +1,1392 @@
+# SPDX-License-Identifier: BSD-3-Clause-Clear
+#
+# GENERATED WITH https://github.com/riscv-software-src/riscv-unified-db
+# "./bin/generate inst-table -o test_table.txt"
+#
+# Each line of the instruction table should have the following format:
+# NAME BASE FIXED_BITS [VARIABLE_LIST]
+# NAME instruction name
+# BASE instruction base size (common[,(32|64)])
+# "common" means the instruction is valid on both architecture sizes
+# "32" or "64" means the instruction is valid on that size
+# if the instruction is valid on both architectures but has unique
+# encodings, use a 32-bit entry "common,32" and 64-bit entry
+# FIXED_BITS bitfields of the fixed bits of an instruction concatenated with '|'
+# continuous grouping of fixed bits are in the form of 'bits<offset'
+# VARIABLE_LIST a variable sized list of all variables in the instruction definition
+# in the form of name[~][<num][!num...]=(high[-low])|...
+# symbols after the name represent different modifiers:
+# ~ sign extension, can only appear once
+# < left shift by 'num' amount on extraction, can only appear once
+# ! mark 'num' as an invalid input for this variable
+andn common 0100000<25|111<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+clmul common 0000101<25|001<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+clmulh common 0000101<25|011<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+orn common 0100000<25|110<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+rev8 common,32 011010011000<20|101<12|0010011<0 xs1=19-15 xd=11-7
+rev8 common,64 011010111000<20|101<12|0010011<0 xs1=19-15 xd=11-7
+rol common 0110000<25|001<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+rolw 64 0110000<25|001<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+ror common 0110000<25|101<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+rori common,32 0110000<25|101<12|0010011<0 shamt=24-20 xs1=19-15 xd=11-7
+rori common,64 011000<26|101<12|0010011<0 shamt=25-20 xs1=19-15 xd=11-7
+roriw 64 0110000<25|101<12|0011011<0 shamt=24-20 xs1=19-15 xd=11-7
+rorw 64 0110000<25|101<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+xnor common 0100000<25|100<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+c.add common 1001<12|10<0 xs2!0=6-2 xd!0=11-7
+c.addi common 000<13|01<0 imm~!0=12|6-2 xd!0=11-7
+c.addi16sp common 011<13|00010<7|01<0 imm~!0<4=12|4-3|5|2|6
+c.addi4spn common 000<13|00<0 imm!0<2=10-7|12-11|5|6 xd=4-2
+c.addiw 64 001<13|01<0 imm~=12|6-2 xd!0=11-7
+c.addw 64 100111<10|01<5|01<0 xs2=4-2 xd=9-7
+c.and common 100011<10|11<5|01<0 xs2=4-2 xd=9-7
+c.andi common 100<13|10<10|01<0 imm~=12|6-2 xd=9-7
+c.beqz common 110<13|01<0 imm~<1=12|6-5|2|11-10|4-3 xs1=9-7
+c.bnez common 111<13|01<0 imm~<1=12|6-5|2|11-10|4-3 xs1=9-7
+c.ebreak common 1001000000000010<0
+c.j common 101<13|01<0 imm~<1=12|8|10-9|6|7|2|11|5-3
+c.jal 32 001<13|01<0 imm~<1=12|8|10-9|6|7|2|11|5-3
+c.jalr common 1001<12|0000010<0 xs1!0=11-7
+c.jr common 1000<12|0000010<0 xs1!0=11-7
+c.ld common,32 011<13|00<0 imm<3=6-5|12-10 xd!1!3!5!7=4-2 xs1=9-7
+c.ld common,64 011<13|00<0 imm<3=6-5|12-10 xd=4-2 xs1=9-7
+c.ldsp common,32 011<13|10<0 imm<3=4-2|12|6-5 xd!0!1!3!5!7!9!11!13!15!17!19!21!23!25!27!29!31=11-7
+c.ldsp common,64 011<13|10<0 imm<3=4-2|12|6-5 xd=11-7
+c.li common 010<13|01<0 imm~=12|6-2 xd!0=11-7
+c.lui common 011<13|01<0 imm~<12=12|6-2 xd!0!2=11-7
+c.lw common 010<13|00<0 imm<2=5|12-10|6 xd=4-2 xs1=9-7
+c.lwsp common 010<13|10<0 imm<2=3-2|12|6-4 xd!0=11-7
+c.mv common 1000<12|10<0 xd!0=11-7 xs2!0=6-2
+c.nop common 0000000000000001<0
+c.or common 100011<10|10<5|01<0 xs2=4-2 xd=9-7
+c.sd common,32 111<13|00<0 imm<3=6-5|12-10 xs2!1!3!5!7=4-2 xs1=9-7
+c.sd common,64 111<13|00<0 imm<3=6-5|12-10 xs2=4-2 xs1=9-7
+c.sdsp common,32 111<13|10<0 xs2!1!3!5!7!9!11!13!15!17!19!21!23!25!27!29!31=6-2 imm<3=9-7|12-10
+c.sdsp common,64 111<13|10<0 xs2=6-2 imm<3=9-7|12-10
+c.slli common,32 0000<12|10<0 shamt!0=6-2 xd=11-7
+c.slli common,64 000<13|10<0 shamt!0=12|6-2 xd=11-7
+c.srai common,32 100001<10|01<0 shamt!0=6-2 xd=9-7
+c.srai common,64 100<13|01<10|01<0 shamt!0=12|6-2 xd=9-7
+c.srli common,32 100000<10|01<0 shamt!0=6-2 xd=9-7
+c.srli common,64 100<13|00<10|01<0 shamt!0=12|6-2 xd=9-7
+c.sub common 100011<10|00<5|01<0 xs2=4-2 xd=9-7
+c.subw 64 100111<10|00<5|01<0 xs2=4-2 xd=9-7
+c.sw common 110<13|00<0 imm<2=5|12-10|6 xs2=4-2 xs1=9-7
+c.swsp common 110<13|10<0 imm<2=8-7|12-9 xs2=6-2
+c.xor common 100011<10|01<5|01<0 xs2=4-2 xd=9-7
+fadd.d common 0000001<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fclass.d common 111000100000<20|001<12|1010011<0 fs1=19-15 xd=11-7
+fcvt.d.l 64 110100100010<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.d.lu 64 110100100011<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.d.s common 010000100000<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.d.w common 110100100000<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.d.wu common 110100100001<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.l.d 64 110000100010<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.lu.d 64 110000100011<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.s.d common 010000000001<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.w.d common 110000100000<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.wu.d common 110000100001<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvtmod.w.d common 110000101000<20|1010011<0 fs1=19-15 rm!0!2!3!4!5!6!7=14-12 xd=11-7
+fdiv.d common 0001101<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+feq.d common 1010001<25|010<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fld common 011<12|0000111<0 imm=31-20 xs1=19-15 fd=11-7
+fle.d common 1010001<25|000<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fleq.d common 1010001<25|100<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fli.d common 111100100001<20|000<12|1010011<0 xs1=19-15 fd=11-7
+flt.d common 1010001<25|001<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fltq.d common 1010001<25|101<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fmadd.d common 01<25|1000011<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmax.d common 0010101<25|001<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmaxm.d common 0010101<25|011<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmin.d common 0010101<25|000<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fminm.d common 0010101<25|010<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmsub.d common 01<25|1000111<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmul.d common 0001001<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmv.d.x 64 111100100000<20|000<12|1010011<0 xs1=19-15 fd=11-7
+fmv.x.d 64 111000100000<20|000<12|1010011<0 fs1=19-15 xd=11-7
+fmvh.x.d 32 111000100001<20|000<12|1010011<0 fs1=19-15 xd=11-7
+fmvp.d.x 32 1011001<25|000<12|1010011<0 xs2=24-20 xs1=19-15 fd=11-7
+fnmadd.d common 01<25|1001111<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fnmsub.d common 01<25|1001011<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fround.d common 010000100100<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+froundnx.d common 010000100101<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fsd common 011<12|0100111<0 imm=31-25|11-7 fs2=24-20 xs1=19-15
+fsgnj.d common 0010001<25|000<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsgnjn.d common 0010001<25|001<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsgnjx.d common 0010001<25|010<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsqrt.d common 010110100000<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fsub.d common 0000101<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fadd.s common 0000000<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fclass.s common 111000000000<20|001<12|1010011<0 fs1=19-15 xd=11-7
+fcvt.l.s 64 110000000010<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.lu.s 64 110000000011<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.s.l 64 110100000010<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.s.lu 64 110100000011<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.s.w common 110100000000<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.s.wu common 110100000001<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.w.s common 110000000000<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.wu.s common 110000000001<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fdiv.s common 0001100<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+feq.s common 1010000<25|010<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fle.s common 1010000<25|000<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fleq.s common 1010000<25|100<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+flt.s common 1010000<25|001<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fltq.s common 1010000<25|101<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+flw common 010<12|0000111<0 imm=31-20 xs1=19-15 fd=11-7
+fmadd.s common 00<25|1000011<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmax.s common 0010100<25|001<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmin.s common 0010100<25|000<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmsub.s common 00<25|1000111<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmul.s common 0001000<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmv.w.x common 111100000000<20|000<12|1010011<0 xs1=19-15 fd=11-7
+fmv.x.w common 111000000000<20|000<12|1010011<0 fs1=19-15 xd=11-7
+fnmadd.s common 00<25|1001111<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fnmsub.s common 00<25|1001011<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fsgnj.s common 0010000<25|000<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsgnjn.s common 0010000<25|001<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsgnjx.s common 0010000<25|010<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsqrt.s common 010110000000<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fsub.s common 0000100<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fsw common 010<12|0100111<0 imm=31-25|11-7 fs2=24-20 xs1=19-15
+hfence.gvma common 0110001<25|000000001110011<0 xs2=24-20 xs1=19-15
+hfence.vvma common 0010001<25|000000001110011<0 xs2=24-20 xs1=19-15
+hlv.b common 011000000000<20|100<12|1110011<0 xs1=19-15 xd=11-7
+hlv.bu common 011000000001<20|100<12|1110011<0 xs1=19-15 xd=11-7
+hlv.d 64 011011000000<20|100<12|1110011<0 xs1=19-15 xd=11-7
+hlv.h common 011001000000<20|100<12|1110011<0 xs1=19-15 xd=11-7
+hlv.hu common 011001000001<20|100<12|1110011<0 xs1=19-15 xd=11-7
+hlv.w common 011010000000<20|100<12|1110011<0 xs1=19-15 xd=11-7
+hlv.wu 64 011010000001<20|100<12|1110011<0 xs1=19-15 xd=11-7
+hlvx.hu common 011001000011<20|100<12|1110011<0 xs1=19-15 xd=11-7
+hlvx.wu common 011010000011<20|100<12|1110011<0 xs1=19-15 xd=11-7
+hsv.b common 0110001<25|100000001110011<0 xs2=24-20 xs1=19-15
+hsv.d 64 0110111<25|100000001110011<0 xs2=24-20 xs1=19-15
+hsv.h common 0110011<25|100000001110011<0 xs2=24-20 xs1=19-15
+hsv.w common 0110101<25|100000001110011<0 xs2=24-20 xs1=19-15
+add common 0000000<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+addi common 000<12|0010011<0 imm~=31-20 xs1=19-15 xd=11-7
+addiw 64 000<12|0011011<0 imm~=31-20 xs1=19-15 xd=11-7
+addw 64 0000000<25|000<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+and common 0000000<25|111<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+andi common 111<12|0010011<0 imm~=31-20 xs1=19-15 xd=11-7
+auipc common 0010111<0 imm~<12=31-12 xd=11-7
+beq common 000<12|1100011<0 imm~<1=31|7|30-25|11-8 xs2=24-20 xs1=19-15
+bge common 101<12|1100011<0 imm~<1=31|7|30-25|11-8 xs2=24-20 xs1=19-15
+bgeu common 111<12|1100011<0 imm~<1=31|7|30-25|11-8 xs2=24-20 xs1=19-15
+blt common 100<12|1100011<0 imm~<1=31|7|30-25|11-8 xs2=24-20 xs1=19-15
+bltu common 110<12|1100011<0 imm~<1=31|7|30-25|11-8 xs2=24-20 xs1=19-15
+bne common 001<12|1100011<0 imm~<1=31|7|30-25|11-8 xs2=24-20 xs1=19-15
+ebreak common 00000000000100000000000001110011<0
+ecall common 00000000000000000000000001110011<0
+fence.tso common 100000110011<20|000<12|0001111<0 xs1=19-15 xd=11-7
+fence common 000<12|0001111<0 fm=31-28 pred=27-24 succ=23-20 xs1=19-15 xd=11-7
+jal common 1101111<0 imm~<1=31|19-12|20|30-21 xd=11-7
+jalr common 000<12|1100111<0 imm~=31-20 xs1=19-15 xd=11-7
+lb common 000<12|0000011<0 imm~=31-20 xs1=19-15 xd=11-7
+lbu common 100<12|0000011<0 imm~=31-20 xs1=19-15 xd=11-7
+ld common,32 011<12|0000011<0 imm~=31-20 xs1=19-15 xd!1!3!5!7!9!11!13!15!17!19!21!23!25!27!29!31=11-7
+ld common,64 011<12|0000011<0 imm~=31-20 xs1=19-15 xd=11-7
+lh common 001<12|0000011<0 imm~=31-20 xs1=19-15 xd=11-7
+lhu common 101<12|0000011<0 imm~=31-20 xs1=19-15 xd=11-7
+lui common 0110111<0 imm~<12=31-12 xd=11-7
+lw common 010<12|0000011<0 imm~=31-20 xs1=19-15 xd=11-7
+lwu 64 110<12|0000011<0 imm~=31-20 xs1=19-15 xd=11-7
+mret common 00110000001000000000000001110011<0
+or common 0000000<25|110<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+ori common 110<12|0010011<0 imm~=31-20 xs1=19-15 xd=11-7
+sb common 000<12|0100011<0 imm~=31-25|11-7 xs2=24-20 xs1=19-15
+sd common,32 011<12|0100011<0 imm~=31-25|11-7 xs2!1!3!5!7!9!11!13!15!17!19!21!23!25!27!29!31=24-20 xs1=19-15
+sd common,64 011<12|0100011<0 imm~=31-25|11-7 xs2=24-20 xs1=19-15
+sh common 001<12|0100011<0 imm~=31-25|11-7 xs2=24-20 xs1=19-15
+sll common 0000000<25|001<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+slli common,32 0000000<25|001<12|0010011<0 shamt=24-20 xs1=19-15 xd=11-7
+slli common,64 000000<26|001<12|0010011<0 shamt=25-20 xs1=19-15 xd=11-7
+slliw 64 0000000<25|001<12|0011011<0 shamt=24-20 xs1=19-15 xd=11-7
+sllw 64 0000000<25|001<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+slt common 0000000<25|010<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+slti common 010<12|0010011<0 imm~=31-20 xs1=19-15 xd=11-7
+sltiu common 011<12|0010011<0 imm~=31-20 xs1=19-15 xd=11-7
+sltu common 0000000<25|011<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+sra common 0100000<25|101<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+srai common,32 0100000<25|101<12|0010011<0 shamt=24-20 xs1=19-15 xd=11-7
+srai common,64 010000<26|101<12|0010011<0 shamt=25-20 xs1=19-15 xd=11-7
+sraiw 64 0100000<25|101<12|0011011<0 shamt=24-20 xs1=19-15 xd=11-7
+sraw 64 0100000<25|101<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+srl common 0000000<25|101<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+srli common,32 0000000<25|101<12|0010011<0 shamt=24-20 xs1=19-15 xd=11-7
+srli common,64 000000<26|101<12|0010011<0 shamt=25-20 xs1=19-15 xd=11-7
+srliw 64 0000000<25|101<12|0011011<0 shamt=24-20 xs1=19-15 xd=11-7
+srlw 64 0000000<25|101<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+sub common 0100000<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+subw 64 0100000<25|000<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+sw common 010<12|0100011<0 imm~=31-25|11-7 xs2=24-20 xs1=19-15
+wfi common 00010000010100000000000001110011<0
+xor common 0000000<25|100<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+xori common 100<12|0010011<0 imm~=31-20 xs1=19-15 xd=11-7
+div common 0000001<25|100<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+divu common 0000001<25|101<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+divuw 64 0000001<25|101<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+divw 64 0000001<25|100<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+mul common 0000001<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+mulh common 0000001<25|001<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+mulhsu common 0000001<25|010<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+mulhu common 0000001<25|011<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+mulw 64 0000001<25|000<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+rem common 0000001<25|110<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+remu common 0000001<25|111<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+remuw 64 0000001<25|111<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+remw 64 0000001<25|110<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+fadd.q common 0000011<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fclass.q common 111001100000<20|001<12|1010011<0 fs1=19-15 xd=11-7
+fcvt.d.q common 010000100011<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.h.q common 010001000011<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.l.q 64 110001100010<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.lu.q 64 110001100011<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.q.d common 010001100001<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.q.h common 010001100010<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.q.l 64 110101100010<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.q.lu 64 110101100011<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.q.s common 010001100000<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.q.w common 110101100000<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.q.wu common 110101100001<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.s.q common 010000000011<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.w.q common 110001100000<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.wu.q common 110001100001<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fdiv.q common 0001111<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+feq.q common 1010011<25|010<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fle.q common 1010011<25|000<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fleq.q common 1010011<25|100<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fli.q common 111101100001<20|000<12|1010011<0 xs1=19-15 fd=11-7
+flq common 100<12|0000111<0 imm=31-20 xs1=19-15 fd=11-7
+flt.q common 1010011<25|001<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fltq.q common 1010011<25|101<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmadd.q common 11<25|1000011<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmax.q common 0010111<25|001<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmaxm.q common 0010111<25|011<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmin.q common 0010111<25|000<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fminm.q common 0010111<25|010<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmsub.q common 11<25|1000111<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmul.q common 0001011<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmvh.x.q 64 111001100001<20|000<12|1010011<0 fs1=19-15 xd=11-7
+fmvp.q.x 64 1011011<25|000<12|1010011<0 xs2=24-20 xs1=19-15 fd=11-7
+fnmadd.q common 11<25|1001111<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fnmsub.q common 11<25|1001011<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fround.q common 010001100100<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+froundnx.q common 010001100101<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fsgnj.q common 0010011<25|000<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsgnjn.q common 0010011<25|001<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsgnjx.q common 0010011<25|010<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsq common 100<12|0100111<0 imm=31-25|11-7 fs2=24-20 xs1=19-15
+fsqrt.q common 010111100000<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fsub.q common 0000111<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+sfence.vma common 0001001<25|000000001110011<0 xs2=24-20 xs1=19-15
+sret common 00010000001000000000000001110011<0
+dret common 01111011001000000000000001110011<0
+sctrclr common 00010000010000000000000001110011<0
+mnret common 01110000001000000000000001110011<0
+hinval.gvma common 0110011<25|000000001110011<0 xs2=24-20 xs1=19-15
+hinval.vvma common 0010011<25|000000001110011<0 xs2=24-20 xs1=19-15
+sfence.inval.ir common 00011000000100000000000001110011<0
+sfence.w.inval common 00011000000000000000000001110011<0
+sinval.vma common 0001011<25|000000001110011<0 xs2=24-20 xs1=19-15
+vaadd.vv common 001001<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vaadd.vx common 001001<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vaaddu.vv common 001000<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vaaddu.vx common 001000<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vadc.vim common 0100000<25|011<12|1010111<0 vs2=24-20 imm~=19-15 vd=11-7
+vadc.vvm common 0100000<25|000<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vadc.vxm common 0100000<25|100<12|1010111<0 vs2=24-20 xs1=19-15 vd=11-7
+vadd.vi common 000000<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vadd.vv common 000000<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vadd.vx common 000000<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vand.vi common 001001<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vand.vv common 001001<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vand.vx common 001001<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vasub.vv common 001011<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vasub.vx common 001011<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vasubu.vv common 001010<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vasubu.vx common 001010<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vcompress.vm common 0101111<25|010<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vcpop.m common 010000<26|10000010<12|1010111<0 vm=25-25 vs2=24-20 xd=11-7
+vdiv.vv common 100001<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vdiv.vx common 100001<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vdivu.vv common 100000<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vdivu.vx common 100000<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vfadd.vf common 000000<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfadd.vv common 000000<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfclass.v common 010011<26|10000001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfcvt.f.x.v common 010010<26|00011001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfcvt.f.xu.v common 010010<26|00010001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfcvt.rtz.x.f.v common 010010<26|00111001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfcvt.rtz.xu.f.v common 010010<26|00110001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfcvt.x.f.v common 010010<26|00001001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfcvt.xu.f.v common 010010<26|00000001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfdiv.vf common 100000<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfdiv.vv common 100000<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfirst.m common 010000<26|10001010<12|1010111<0 vm=25-25 vs2=24-20 xd=11-7
+vfmacc.vf common 101100<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfmacc.vv common 101100<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfmadd.vf common 101000<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfmadd.vv common 101000<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfmax.vf common 000110<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfmax.vv common 000110<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfmerge.vfm common 0101110<25|101<12|1010111<0 vs2=24-20 fs1=19-15 vd=11-7
+vfmin.vf common 000100<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfmin.vv common 000100<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfmsac.vf common 101110<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfmsac.vv common 101110<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfmsub.vf common 101010<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfmsub.vv common 101010<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfmul.vf common 100100<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfmul.vv common 100100<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfmv.f.s common 0100001<25|00000001<12|1010111<0 vs2=24-20 fd=11-7
+vfmv.s.f common 010000100000<20|101<12|1010111<0 fs1=19-15 vd=11-7
+vfmv.v.f common 010111100000<20|101<12|1010111<0 fs1=19-15 vd=11-7
+vfncvt.f.f.w common 010010<26|10100001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfncvt.f.x.w common 010010<26|10011001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfncvt.f.xu.w common 010010<26|10010001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfncvt.rod.f.f.w common 010010<26|10101001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfncvt.rtz.x.f.w common 010010<26|10111001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfncvt.rtz.xu.f.w common 010010<26|10110001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfncvt.x.f.w common 010010<26|10001001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfncvt.xu.f.w common 010010<26|10000001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfnmacc.vf common 101101<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfnmacc.vv common 101101<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfnmadd.vf common 101001<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfnmadd.vv common 101001<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfnmsac.vf common 101111<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfnmsac.vv common 101111<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfnmsub.vf common 101011<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfnmsub.vv common 101011<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfrdiv.vf common 100001<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfrec7.v common 010011<26|00101001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfredmax.vs common 000111<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfredmin.vs common 000101<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfredosum.vs common 000011<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfredusum.vs common 000001<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfrsqrt7.v common 010011<26|00100001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfrsub.vf common 100111<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfsgnj.vf common 001000<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfsgnj.vv common 001000<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfsgnjn.vf common 001001<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfsgnjn.vv common 001001<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfsgnjx.vf common 001010<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfsgnjx.vv common 001010<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfslide1down.vf common 001111<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfslide1up.vf common 001110<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfsqrt.v common 010011<26|00000001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfsub.vf common 000010<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfsub.vv common 000010<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfwadd.vf common 110000<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfwadd.vv common 110000<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfwadd.wf common 110100<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfwadd.wv common 110100<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfwcvt.f.f.v common 010010<26|01100001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfwcvt.f.x.v common 010010<26|01011001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfwcvt.f.xu.v common 010010<26|01010001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfwcvt.rtz.x.f.v common 010010<26|01111001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfwcvt.rtz.xu.f.v common 010010<26|01110001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfwcvt.x.f.v common 010010<26|01001001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfwcvt.xu.f.v common 010010<26|01000001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfwmacc.vf common 111100<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfwmacc.vv common 111100<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfwmsac.vf common 111110<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfwmsac.vv common 111110<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfwmul.vf common 111000<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfwmul.vv common 111000<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfwnmacc.vf common 111101<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfwnmacc.vv common 111101<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfwnmsac.vf common 111111<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfwnmsac.vv common 111111<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfwredosum.vs common 110011<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfwredusum.vs common 110001<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfwsub.vf common 110010<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfwsub.vv common 110010<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vfwsub.wf common 110110<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfwsub.wv common 110110<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vid.v common 010100<26|0000010001010<12|1010111<0 vm=25-25 vd=11-7
+viota.m common 010100<26|10000010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vl1re16.v common 000000101000<20|101<12|0000111<0 xs1=19-15 vd=11-7
+vl1re32.v common 000000101000<20|110<12|0000111<0 xs1=19-15 vd=11-7
+vl1re64.v common 000000101000<20|111<12|0000111<0 xs1=19-15 vd=11-7
+vl1re8.v common 000000101000<20|000<12|0000111<0 xs1=19-15 vd=11-7
+vl2re16.v common 001000101000<20|101<12|0000111<0 xs1=19-15 vd=11-7
+vl2re32.v common 001000101000<20|110<12|0000111<0 xs1=19-15 vd=11-7
+vl2re64.v common 001000101000<20|111<12|0000111<0 xs1=19-15 vd=11-7
+vl2re8.v common 001000101000<20|000<12|0000111<0 xs1=19-15 vd=11-7
+vl4re16.v common 011000101000<20|101<12|0000111<0 xs1=19-15 vd=11-7
+vl4re32.v common 011000101000<20|110<12|0000111<0 xs1=19-15 vd=11-7
+vl4re64.v common 011000101000<20|111<12|0000111<0 xs1=19-15 vd=11-7
+vl4re8.v common 011000101000<20|000<12|0000111<0 xs1=19-15 vd=11-7
+vl8re16.v common 111000101000<20|101<12|0000111<0 xs1=19-15 vd=11-7
+vl8re32.v common 111000101000<20|110<12|0000111<0 xs1=19-15 vd=11-7
+vl8re64.v common 111000101000<20|111<12|0000111<0 xs1=19-15 vd=11-7
+vl8re8.v common 111000101000<20|000<12|0000111<0 xs1=19-15 vd=11-7
+vle16.v common 000000<26|00000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vle16ff.v common 000000<26|10000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vle32.v common 000000<26|00000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vle32ff.v common 000000<26|10000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vle64.v common 000000<26|00000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vle64ff.v common 000000<26|10000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vle8.v common 000000<26|00000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vle8ff.v common 000000<26|10000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlm.v common 000000101011<20|000<12|0000111<0 xs1=19-15 vd=11-7
+vloxei16.v common 000011<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxei32.v common 000011<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxei64.v common 000011<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxei8.v common 000011<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg2ei16.v common 001011<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg2ei32.v common 001011<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg2ei64.v common 001011<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg2ei8.v common 001011<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg3ei16.v common 010011<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg3ei32.v common 010011<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg3ei64.v common 010011<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg3ei8.v common 010011<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg4ei16.v common 011011<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg4ei32.v common 011011<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg4ei64.v common 011011<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg4ei8.v common 011011<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg5ei16.v common 100011<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg5ei32.v common 100011<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg5ei64.v common 100011<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg5ei8.v common 100011<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg6ei16.v common 101011<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg6ei32.v common 101011<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg6ei64.v common 101011<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg6ei8.v common 101011<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg7ei16.v common 110011<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg7ei32.v common 110011<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg7ei64.v common 110011<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg7ei8.v common 110011<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg8ei16.v common 111011<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg8ei32.v common 111011<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg8ei64.v common 111011<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vloxseg8ei8.v common 111011<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vlse16.v common 000010<26|101<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlse32.v common 000010<26|110<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlse64.v common 000010<26|111<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlse8.v common 000010<26|000<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlseg2e16.v common 001000<26|00000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg2e16ff.v common 001000<26|10000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg2e32.v common 001000<26|00000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg2e32ff.v common 001000<26|10000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg2e64.v common 001000<26|00000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg2e64ff.v common 001000<26|10000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg2e8.v common 001000<26|00000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg2e8ff.v common 001000<26|10000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg3e16.v common 010000<26|00000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg3e16ff.v common 010000<26|10000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg3e32.v common 010000<26|00000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg3e32ff.v common 010000<26|10000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg3e64.v common 010000<26|00000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg3e64ff.v common 010000<26|10000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg3e8.v common 010000<26|00000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg3e8ff.v common 010000<26|10000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg4e16.v common 011000<26|00000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg4e16ff.v common 011000<26|10000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg4e32.v common 011000<26|00000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg4e32ff.v common 011000<26|10000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg4e64.v common 011000<26|00000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg4e64ff.v common 011000<26|10000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg4e8.v common 011000<26|00000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg4e8ff.v common 011000<26|10000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg5e16.v common 100000<26|00000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg5e16ff.v common 100000<26|10000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg5e32.v common 100000<26|00000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg5e32ff.v common 100000<26|10000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg5e64.v common 100000<26|00000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg5e64ff.v common 100000<26|10000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg5e8.v common 100000<26|00000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg5e8ff.v common 100000<26|10000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg6e16.v common 101000<26|00000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg6e16ff.v common 101000<26|10000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg6e32.v common 101000<26|00000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg6e32ff.v common 101000<26|10000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg6e64.v common 101000<26|00000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg6e64ff.v common 101000<26|10000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg6e8.v common 101000<26|00000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg6e8ff.v common 101000<26|10000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg7e16.v common 110000<26|00000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg7e16ff.v common 110000<26|10000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg7e32.v common 110000<26|00000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg7e32ff.v common 110000<26|10000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg7e64.v common 110000<26|00000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg7e64ff.v common 110000<26|10000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg7e8.v common 110000<26|00000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg7e8ff.v common 110000<26|10000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg8e16.v common 111000<26|00000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg8e16ff.v common 111000<26|10000<20|101<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg8e32.v common 111000<26|00000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg8e32ff.v common 111000<26|10000<20|110<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg8e64.v common 111000<26|00000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg8e64ff.v common 111000<26|10000<20|111<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg8e8.v common 111000<26|00000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlseg8e8ff.v common 111000<26|10000<20|000<12|0000111<0 vm=25-25 xs1=19-15 vd=11-7
+vlsseg2e16.v common 001010<26|101<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg2e32.v common 001010<26|110<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg2e64.v common 001010<26|111<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg2e8.v common 001010<26|000<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg3e16.v common 010010<26|101<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg3e32.v common 010010<26|110<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg3e64.v common 010010<26|111<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg3e8.v common 010010<26|000<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg4e16.v common 011010<26|101<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg4e32.v common 011010<26|110<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg4e64.v common 011010<26|111<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg4e8.v common 011010<26|000<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg5e16.v common 100010<26|101<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg5e32.v common 100010<26|110<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg5e64.v common 100010<26|111<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg5e8.v common 100010<26|000<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg6e16.v common 101010<26|101<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg6e32.v common 101010<26|110<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg6e64.v common 101010<26|111<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg6e8.v common 101010<26|000<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg7e16.v common 110010<26|101<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg7e32.v common 110010<26|110<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg7e64.v common 110010<26|111<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg7e8.v common 110010<26|000<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg8e16.v common 111010<26|101<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg8e32.v common 111010<26|110<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg8e64.v common 111010<26|111<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vlsseg8e8.v common 111010<26|000<12|0000111<0 vm=25-25 xs2=24-20 xs1=19-15 vd=11-7
+vluxei16.v common 000001<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxei32.v common 000001<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxei64.v common 000001<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxei8.v common 000001<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg2ei16.v common 001001<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg2ei32.v common 001001<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg2ei64.v common 001001<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg2ei8.v common 001001<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg3ei16.v common 010001<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg3ei32.v common 010001<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg3ei64.v common 010001<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg3ei8.v common 010001<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg4ei16.v common 011001<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg4ei32.v common 011001<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg4ei64.v common 011001<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg4ei8.v common 011001<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg5ei16.v common 100001<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg5ei32.v common 100001<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg5ei64.v common 100001<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg5ei8.v common 100001<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg6ei16.v common 101001<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg6ei32.v common 101001<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg6ei64.v common 101001<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg6ei8.v common 101001<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg7ei16.v common 110001<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg7ei32.v common 110001<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg7ei64.v common 110001<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg7ei8.v common 110001<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg8ei16.v common 111001<26|101<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg8ei32.v common 111001<26|110<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg8ei64.v common 111001<26|111<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vluxseg8ei8.v common 111001<26|000<12|0000111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmacc.vv common 101101<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmacc.vx common 101101<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmadc.vi common 0100011<25|011<12|1010111<0 vs2=24-20 imm~=19-15 vd=11-7
+vmadc.vim common 0100010<25|011<12|1010111<0 vs2=24-20 imm~=19-15 vd=11-7
+vmadc.vv common 0100011<25|000<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmadc.vvm common 0100010<25|000<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmadc.vx common 0100011<25|100<12|1010111<0 vs2=24-20 xs1=19-15 vd=11-7
+vmadc.vxm common 0100010<25|100<12|1010111<0 vs2=24-20 xs1=19-15 vd=11-7
+vmadd.vv common 101001<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmadd.vx common 101001<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmand.mm common 0110011<25|010<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmandn.mm common 0110001<25|010<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmax.vv common 000111<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmax.vx common 000111<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmaxu.vv common 000110<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmaxu.vx common 000110<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmerge.vim common 0101110<25|011<12|1010111<0 vs2=24-20 imm~=19-15 vd=11-7
+vmerge.vvm common 0101110<25|000<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmerge.vxm common 0101110<25|100<12|1010111<0 vs2=24-20 xs1=19-15 vd=11-7
+vmfeq.vf common 011000<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vmfeq.vv common 011000<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmfge.vf common 011111<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vmfgt.vf common 011101<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vmfle.vf common 011001<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vmfle.vv common 011001<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmflt.vf common 011011<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vmflt.vv common 011011<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmfne.vf common 011100<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vmfne.vv common 011100<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmin.vv common 000101<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmin.vx common 000101<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vminu.vv common 000100<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vminu.vx common 000100<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmnand.mm common 0111011<25|010<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmnor.mm common 0111101<25|010<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmor.mm common 0110101<25|010<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmorn.mm common 0111001<25|010<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmsbc.vv common 0100111<25|000<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmsbc.vvm common 0100110<25|000<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmsbc.vx common 0100111<25|100<12|1010111<0 vs2=24-20 xs1=19-15 vd=11-7
+vmsbc.vxm common 0100110<25|100<12|1010111<0 vs2=24-20 xs1=19-15 vd=11-7
+vmsbf.m common 010100<26|00001010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vmseq.vi common 011000<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vmseq.vv common 011000<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmseq.vx common 011000<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmsgt.vi common 011111<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vmsgt.vx common 011111<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmsgtu.vi common 011110<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vmsgtu.vx common 011110<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmsif.m common 010100<26|00011010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vmsle.vi common 011101<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vmsle.vv common 011101<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmsle.vx common 011101<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmsleu.vi common 011100<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vmsleu.vv common 011100<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmsleu.vx common 011100<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmslt.vv common 011011<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmslt.vx common 011011<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmsltu.vv common 011010<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmsltu.vx common 011010<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmsne.vi common 011001<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vmsne.vv common 011001<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmsne.vx common 011001<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmsof.m common 010100<26|00010010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vmul.vv common 100101<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmul.vx common 100101<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmulh.vv common 100111<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmulh.vx common 100111<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmulhsu.vv common 100110<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmulhsu.vx common 100110<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmulhu.vv common 100100<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vmulhu.vx common 100100<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vmv.s.x common 010000100000<20|110<12|1010111<0 xs1=19-15 vd=11-7
+vmv.v.i common 010111100000<20|011<12|1010111<0 imm=19-15 vd=11-7
+vmv.v.v common 010111100000<20|000<12|1010111<0 vs1=19-15 vd=11-7
+vmv.v.x common 010111100000<20|100<12|1010111<0 xs1=19-15 vd=11-7
+vmv.x.s common 0100001<25|00000010<12|1010111<0 vs2=24-20 xd=11-7
+vmv1r.v common 1001111<25|00000011<12|1010111<0 vs2=24-20 vd=11-7
+vmv2r.v common 1001111<25|00001011<12|1010111<0 vs2=24-20 vd=11-7
+vmv4r.v common 1001111<25|00011011<12|1010111<0 vs2=24-20 vd=11-7
+vmv8r.v common 1001111<25|00111011<12|1010111<0 vs2=24-20 vd=11-7
+vmxnor.mm common 0111111<25|010<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vmxor.mm common 0110111<25|010<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vnclip.wi common 101111<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vnclip.wv common 101111<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vnclip.wx common 101111<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vnclipu.wi common 101110<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vnclipu.wv common 101110<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vnclipu.wx common 101110<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vnmsac.vv common 101111<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vnmsac.vx common 101111<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vnmsub.vv common 101011<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vnmsub.vx common 101011<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vnsra.wi common 101101<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vnsra.wv common 101101<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vnsra.wx common 101101<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vnsrl.wi common 101100<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vnsrl.wv common 101100<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vnsrl.wx common 101100<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vor.vi common 001010<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vor.vv common 001010<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vor.vx common 001010<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vredand.vs common 000001<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vredmax.vs common 000111<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vredmaxu.vs common 000110<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vredmin.vs common 000101<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vredminu.vs common 000100<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vredor.vs common 000010<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vredsum.vs common 000000<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vredxor.vs common 000011<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vrem.vv common 100011<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vrem.vx common 100011<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vremu.vv common 100010<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vremu.vx common 100010<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vrgather.vi common 001100<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vrgather.vv common 001100<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vrgather.vx common 001100<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vrgatherei16.vv common 001110<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vrsub.vi common 000011<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vrsub.vx common 000011<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vs1r.v common 000000101000<20|000<12|0100111<0 xs1=19-15 vs3=11-7
+vs2r.v common 001000101000<20|000<12|0100111<0 xs1=19-15 vs3=11-7
+vs4r.v common 011000101000<20|000<12|0100111<0 xs1=19-15 vs3=11-7
+vs8r.v common 111000101000<20|000<12|0100111<0 xs1=19-15 vs3=11-7
+vsadd.vi common 100001<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vsadd.vv common 100001<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vsadd.vx common 100001<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vsaddu.vi common 100000<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vsaddu.vv common 100000<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vsaddu.vx common 100000<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vsbc.vvm common 0100100<25|000<12|1010111<0 vs2=24-20 vs1=19-15 vd=11-7
+vsbc.vxm common 0100100<25|100<12|1010111<0 vs2=24-20 xs1=19-15 vd=11-7
+vse16.v common 000000<26|00000<20|101<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vse32.v common 000000<26|00000<20|110<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vse64.v common 000000<26|00000<20|111<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vse8.v common 000000<26|00000<20|000<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsetivli common 11<30|111<12|1010111<0 vtypei=29-20 uimm=19-15 xd=11-7
+vsetvl common 1000000<25|111<12|1010111<0 xs2=24-20 xs1=19-15 xd=11-7
+vsetvli common 0<31|111<12|1010111<0 vtypei=30-20 xs1=19-15 xd=11-7
+vsext.vf2 common 010010<26|00111010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vsext.vf4 common 010010<26|00101010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vsext.vf8 common 010010<26|00011010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vslide1down.vx common 001111<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vslide1up.vx common 001110<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vslidedown.vi common 001111<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vslidedown.vx common 001111<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vslideup.vi common 001110<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vslideup.vx common 001110<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vsll.vi common 100101<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vsll.vv common 100101<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vsll.vx common 100101<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vsm.v common 000000101011<20|000<12|0100111<0 xs1=19-15 vs3=11-7
+vsmul.vv common 100111<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vsmul.vx common 100111<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vsoxei16.v common 000011<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxei32.v common 000011<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxei64.v common 000011<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxei8.v common 000011<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg2ei16.v common 001011<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg2ei32.v common 001011<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg2ei64.v common 001011<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg2ei8.v common 001011<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg3ei16.v common 010011<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg3ei32.v common 010011<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg3ei64.v common 010011<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg3ei8.v common 010011<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg4ei16.v common 011011<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg4ei32.v common 011011<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg4ei64.v common 011011<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg4ei8.v common 011011<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg5ei16.v common 100011<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg5ei32.v common 100011<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg5ei64.v common 100011<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg5ei8.v common 100011<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg6ei16.v common 101011<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg6ei32.v common 101011<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg6ei64.v common 101011<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg6ei8.v common 101011<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg7ei16.v common 110011<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg7ei32.v common 110011<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg7ei64.v common 110011<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg7ei8.v common 110011<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg8ei16.v common 111011<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg8ei32.v common 111011<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg8ei64.v common 111011<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsoxseg8ei8.v common 111011<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsra.vi common 101001<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vsra.vv common 101001<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vsra.vx common 101001<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vsrl.vi common 101000<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vsrl.vv common 101000<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vsrl.vx common 101000<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vsse16.v common 000010<26|101<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vsse32.v common 000010<26|110<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vsse64.v common 000010<26|111<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vsse8.v common 000010<26|000<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vsseg2e16.v common 001000<26|00000<20|101<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg2e32.v common 001000<26|00000<20|110<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg2e64.v common 001000<26|00000<20|111<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg2e8.v common 001000<26|00000<20|000<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg3e16.v common 010000<26|00000<20|101<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg3e32.v common 010000<26|00000<20|110<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg3e64.v common 010000<26|00000<20|111<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg3e8.v common 010000<26|00000<20|000<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg4e16.v common 011000<26|00000<20|101<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg4e32.v common 011000<26|00000<20|110<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg4e64.v common 011000<26|00000<20|111<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg4e8.v common 011000<26|00000<20|000<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg5e16.v common 100000<26|00000<20|101<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg5e32.v common 100000<26|00000<20|110<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg5e64.v common 100000<26|00000<20|111<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg5e8.v common 100000<26|00000<20|000<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg6e16.v common 101000<26|00000<20|101<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg6e32.v common 101000<26|00000<20|110<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg6e64.v common 101000<26|00000<20|111<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg6e8.v common 101000<26|00000<20|000<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg7e16.v common 110000<26|00000<20|101<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg7e32.v common 110000<26|00000<20|110<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg7e64.v common 110000<26|00000<20|111<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg7e8.v common 110000<26|00000<20|000<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg8e16.v common 111000<26|00000<20|101<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg8e32.v common 111000<26|00000<20|110<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg8e64.v common 111000<26|00000<20|111<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vsseg8e8.v common 111000<26|00000<20|000<12|0100111<0 vm=25-25 xs1=19-15 vs3=11-7
+vssra.vi common 101011<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vssra.vv common 101011<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vssra.vx common 101011<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vssrl.vi common 101010<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vssrl.vv common 101010<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vssrl.vx common 101010<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vssseg2e16.v common 001010<26|101<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg2e32.v common 001010<26|110<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg2e64.v common 001010<26|111<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg2e8.v common 001010<26|000<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg3e16.v common 010010<26|101<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg3e32.v common 010010<26|110<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg3e64.v common 010010<26|111<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg3e8.v common 010010<26|000<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg4e16.v common 011010<26|101<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg4e32.v common 011010<26|110<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg4e64.v common 011010<26|111<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg4e8.v common 011010<26|000<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg5e16.v common 100010<26|101<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg5e32.v common 100010<26|110<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg5e64.v common 100010<26|111<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg5e8.v common 100010<26|000<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg6e16.v common 101010<26|101<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg6e32.v common 101010<26|110<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg6e64.v common 101010<26|111<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg6e8.v common 101010<26|000<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg7e16.v common 110010<26|101<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg7e32.v common 110010<26|110<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg7e64.v common 110010<26|111<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg7e8.v common 110010<26|000<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg8e16.v common 111010<26|101<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg8e32.v common 111010<26|110<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg8e64.v common 111010<26|111<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssseg8e8.v common 111010<26|000<12|0100111<0 vm=25-25 xs2=24-20 xs1=19-15 vs3=11-7
+vssub.vv common 100011<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vssub.vx common 100011<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vssubu.vv common 100010<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vssubu.vx common 100010<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vsub.vv common 000010<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vsub.vx common 000010<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vsuxei16.v common 000001<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxei32.v common 000001<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxei64.v common 000001<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxei8.v common 000001<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg2ei16.v common 001001<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg2ei32.v common 001001<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg2ei64.v common 001001<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg2ei8.v common 001001<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg3ei16.v common 010001<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg3ei32.v common 010001<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg3ei64.v common 010001<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg3ei8.v common 010001<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg4ei16.v common 011001<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg4ei32.v common 011001<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg4ei64.v common 011001<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg4ei8.v common 011001<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg5ei16.v common 100001<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg5ei32.v common 100001<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg5ei64.v common 100001<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg5ei8.v common 100001<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg6ei16.v common 101001<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg6ei32.v common 101001<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg6ei64.v common 101001<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg6ei8.v common 101001<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg7ei16.v common 110001<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg7ei32.v common 110001<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg7ei64.v common 110001<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg7ei8.v common 110001<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg8ei16.v common 111001<26|101<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg8ei32.v common 111001<26|110<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg8ei64.v common 111001<26|111<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vsuxseg8ei8.v common 111001<26|000<12|0100111<0 vm=25-25 vs2=24-20 xs1=19-15 vs3=11-7
+vwadd.vv common 110001<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwadd.vx common 110001<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwadd.wv common 110101<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwadd.wx common 110101<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwaddu.vv common 110000<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwaddu.vx common 110000<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwaddu.wv common 110100<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwaddu.wx common 110100<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwmacc.vv common 111101<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwmacc.vx common 111101<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwmaccsu.vv common 111111<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwmaccsu.vx common 111111<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwmaccu.vv common 111100<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwmaccu.vx common 111100<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwmaccus.vx common 111110<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwmul.vv common 111011<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwmul.vx common 111011<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwmulsu.vv common 111010<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwmulsu.vx common 111010<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwmulu.vv common 111000<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwmulu.vx common 111000<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwredsum.vs common 110001<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwredsumu.vs common 110000<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwsub.vv common 110011<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwsub.vx common 110011<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwsub.wv common 110111<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwsub.wx common 110111<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwsubu.vv common 110010<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwsubu.vx common 110010<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwsubu.wv common 110110<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwsubu.wx common 110110<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vxor.vi common 001011<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm~=19-15 vd=11-7
+vxor.vv common 001011<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vxor.vx common 001011<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vzext.vf2 common 010010<26|00110010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vzext.vf4 common 010010<26|00100010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vzext.vf8 common 010010<26|00010010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+amoadd.d.aq 64 0000010<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.d.aqrl 64 0000011<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.d.rl 64 0000001<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.d 64 0000000<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.w.aq common 0000010<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.w.aqrl common 0000011<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.w.rl common 0000001<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.w common 0000000<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.d.aq 64 0110010<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.d.aqrl 64 0110011<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.d.rl 64 0110001<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.d 64 0110000<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.w.aq common 0110010<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.w.aqrl common 0110011<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.w.rl common 0110001<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.w common 0110000<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.d.aq 64 1010010<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.d.aqrl 64 1010011<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.d.rl 64 1010001<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.d 64 1010000<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.w.aq common 1010010<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.w.aqrl common 1010011<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.w.rl common 1010001<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.w common 1010000<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.d.aq 64 1110010<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.d.aqrl 64 1110011<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.d.rl 64 1110001<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.d 64 1110000<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.w.aq common 1110010<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.w.aqrl common 1110011<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.w.rl common 1110001<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.w common 1110000<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.d.aq 64 1000010<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.d.aqrl 64 1000011<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.d.rl 64 1000001<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.d 64 1000000<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.w.aq common 1000010<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.w.aqrl common 1000011<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.w.rl common 1000001<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.w common 1000000<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.d.aq 64 1100010<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.d.aqrl 64 1100011<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.d.rl 64 1100001<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.d 64 1100000<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.w.aq common 1100010<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.w.aqrl common 1100011<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.w.rl common 1100001<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.w common 1100000<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.d.aq 64 0100010<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.d.aqrl 64 0100011<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.d.rl 64 0100001<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.d 64 0100000<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.w.aq common 0100010<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.w.aqrl common 0100011<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.w.rl common 0100001<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.w common 0100000<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.d.aq 64 0000110<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.d.aqrl 64 0000111<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.d.rl 64 0000101<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.d 64 0000100<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.w.aq common 0000110<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.w.aqrl common 0000111<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.w.rl common 0000101<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.w common 0000100<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.d.aq 64 0010010<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.d.aqrl 64 0010011<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.d.rl 64 0010001<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.d 64 0010000<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.w.aq common 0010010<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.w.aqrl common 0010011<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.w.rl common 0010001<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.w common 0010000<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.b.aq common 0000010<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.b.aqrl common 0000011<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.b.rl common 0000001<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.b common 0000000<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.h.aq common 0000010<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.h.aqrl common 0000011<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.h.rl common 0000001<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoadd.h common 0000000<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.b.aq common 0110010<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.b.aqrl common 0110011<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.b.rl common 0110001<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.b common 0110000<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.h.aq common 0110010<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.h.aqrl common 0110011<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.h.rl common 0110001<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoand.h common 0110000<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.b.aq common 0010110<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.b.aqrl common 0010111<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.b.rl common 0010101<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.b common 0010100<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.h.aq common 0010110<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.h.aqrl common 0010111<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.h.rl common 0010101<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.h common 0010100<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.b.aq common 1010010<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.b.aqrl common 1010011<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.b.rl common 1010001<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.b common 1010000<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.h.aq common 1010010<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.h.aqrl common 1010011<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.h.rl common 1010001<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomax.h common 1010000<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.b.aq common 1110010<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.b.aqrl common 1110011<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.b.rl common 1110001<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.b common 1110000<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.h.aq common 1110010<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.h.aqrl common 1110011<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.h.rl common 1110001<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomaxu.h common 1110000<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.b.aq common 1000010<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.b.aqrl common 1000011<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.b.rl common 1000001<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.b common 1000000<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.h.aq common 1000010<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.h.aqrl common 1000011<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.h.rl common 1000001<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amomin.h common 1000000<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.b.aq common 1100010<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.b.aqrl common 1100011<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.b.rl common 1100001<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.b common 1100000<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.h.aq common 1100010<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.h.aqrl common 1100011<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.h.rl common 1100001<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amominu.h common 1100000<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.b.aq common 0100010<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.b.aqrl common 0100011<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.b.rl common 0100001<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.b common 0100000<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.h.aq common 0100010<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.h.aqrl common 0100011<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.h.rl common 0100001<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoor.h common 0100000<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.b.aq common 0000110<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.b.aqrl common 0000111<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.b.rl common 0000101<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.b common 0000100<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.h.aq common 0000110<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.h.aqrl common 0000111<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.h.rl common 0000101<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoswap.h common 0000100<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.b.aq common 0010010<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.b.aqrl common 0010011<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.b.rl common 0010001<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.b common 0010000<25|000<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.h.aq common 0010010<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.h.aqrl common 0010011<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.h.rl common 0010001<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amoxor.h common 0010000<25|001<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.d.aq common 0010110<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.d.aqrl common 0010111<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.d.rl common 0010101<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.d common 0010100<25|011<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.q.aq 64 0010110<25|100<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.q.aqrl 64 0010111<25|100<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.q.rl 64 0010101<25|100<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.q 64 0010100<25|100<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.w.aq common 0010110<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.w.aqrl common 0010111<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.w.rl common 0010101<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+amocas.w common 0010100<25|010<12|0101111<0 xs2=24-20 xs1=19-15 xd=11-7
+lb.aq common 001101000000<20|000<12|0101111<0 xs1=19-15 xd=11-7
+lb.aqrl common 001101100000<20|000<12|0101111<0 xs1=19-15 xd=11-7
+ld.aq common 001101000000<20|011<12|0101111<0 xs1=19-15 xd=11-7
+ld.aqrl common 001101100000<20|011<12|0101111<0 xs1=19-15 xd=11-7
+lh.aq common 001101000000<20|001<12|0101111<0 xs1=19-15 xd=11-7
+lh.aqrl common 001101100000<20|001<12|0101111<0 xs1=19-15 xd=11-7
+lw.aq common 001101000000<20|010<12|0101111<0 xs1=19-15 xd=11-7
+lw.aqrl common 001101100000<20|010<12|0101111<0 xs1=19-15 xd=11-7
+sb.aqrl common 0011111<25|000000000101111<0 xs2=24-20 xs1=19-15
+sb.rl common 0011101<25|000000000101111<0 xs2=24-20 xs1=19-15
+sd.aqrl common 0011111<25|011000000101111<0 xs2=24-20 xs1=19-15
+sd.rl common 0011101<25|011000000101111<0 xs2=24-20 xs1=19-15
+sh.aqrl common 0011111<25|001000000101111<0 xs2=24-20 xs1=19-15
+sh.rl common 0011101<25|001000000101111<0 xs2=24-20 xs1=19-15
+sw.aqrl common 0011111<25|010000000101111<0 xs2=24-20 xs1=19-15
+sw.rl common 0011101<25|010000000101111<0 xs2=24-20 xs1=19-15
+lr.d.aq 64 00010<27|00000<20|011<12|0101111<0 aq!0=26 rl!1=25 xs1=19-15 xd=11-7
+lr.d.aqrl 64 00010<27|00000<20|011<12|0101111<0 aq!0=26 rl!0=25 xs1=19-15 xd=11-7
+lr.d.rl 64 00010<27|00000<20|011<12|0101111<0 aq!1=26 rl!0=25 xs1=19-15 xd=11-7
+lr.d 64 00010<27|00000<20|011<12|0101111<0 aq!1=26 rl!1=25 xs1=19-15 xd=11-7
+lr.w.aq common 00010<27|00000<20|010<12|0101111<0 aq!0=26 rl!1=25 xs1=19-15 xd=11-7
+lr.w.aqrl common 00010<27|00000<20|010<12|0101111<0 aq!0=26 rl!0=25 xs1=19-15 xd=11-7
+lr.w.rl common 00010<27|00000<20|010<12|0101111<0 aq!1=26 rl!0=25 xs1=19-15 xd=11-7
+lr.w common 00010<27|00000<20|010<12|0101111<0 aq!1=26 rl!1=25 xs1=19-15 xd=11-7
+sc.d.aq 64 00011<27|011<12|0101111<0 aq!0=26 rl!1=25 xs2=24-20 xs1=19-15 xd=11-7
+sc.d.aqrl 64 00011<27|011<12|0101111<0 aq!0=26 rl!0=25 xs2=24-20 xs1=19-15 xd=11-7
+sc.d.rl 64 00011<27|011<12|0101111<0 aq!1=26 rl!0=25 xs2=24-20 xs1=19-15 xd=11-7
+sc.d 64 00011<27|011<12|0101111<0 aq!1=26 rl!1=25 xs2=24-20 xs1=19-15 xd=11-7
+sc.w.aq common 00011<27|010<12|0101111<0 aq!0=26 rl!1=25 xs2=24-20 xs1=19-15 xd=11-7
+sc.w.aqrl common 00011<27|010<12|0101111<0 aq!0=26 rl!0=25 xs2=24-20 xs1=19-15 xd=11-7
+sc.w.rl common 00011<27|010<12|0101111<0 aq!1=26 rl!0=25 xs2=24-20 xs1=19-15 xd=11-7
+sc.w common 00011<27|010<12|0101111<0 aq!1=26 rl!1=25 xs2=24-20 xs1=19-15 xd=11-7
+wrs.nto common 00000000110100000000000001110011<0
+wrs.sto common 00000001110100000000000001110011<0
+add.uw 64 0000100<25|000<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+sh1add.uw 64 0010000<25|010<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+sh1add common 0010000<25|010<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+sh2add.uw 64 0010000<25|100<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+sh2add common 0010000<25|100<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+sh3add.uw 64 0010000<25|110<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+sh3add common 0010000<25|110<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+slli.uw 64 000010<26|001<12|0011011<0 shamt=25-20 xs1=19-15 xd=11-7
+clz common 011000000000<20|001<12|0010011<0 xs1=19-15 xd=11-7
+clzw 64 011000000000<20|001<12|0011011<0 xs1=19-15 xd=11-7
+cpop common 011000000010<20|001<12|0010011<0 xs1=19-15 xd=11-7
+cpopw 64 011000000010<20|001<12|0011011<0 xs1=19-15 xd=11-7
+ctz common 011000000001<20|001<12|0010011<0 xs1=19-15 xd=11-7
+ctzw 64 011000000001<20|001<12|0011011<0 xs1=19-15 xd=11-7
+max common 0000101<25|110<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+maxu common 0000101<25|111<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+min common 0000101<25|100<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+minu common 0000101<25|101<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+orc.b common 001010000111<20|101<12|0010011<0 xs1=19-15 xd=11-7
+sext.b common 011000000100<20|001<12|0010011<0 xs1=19-15 xd=11-7
+sext.h common 011000000101<20|001<12|0010011<0 xs1=19-15 xd=11-7
+zext.h common,32 000010000000<20|100<12|0110011<0 xs1=19-15 xd=11-7
+zext.h common,64 000010000000<20|100<12|0111011<0 xs1=19-15 xd=11-7
+clmulr common 0000101<25|010<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+brev8 common 011010000111<20|101<12|0010011<0 xs1=19-15 xd=11-7
+pack common 0000100<25|100<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+packh common 0000100<25|111<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+packw 64 0000100<25|100<12|0111011<0 xs2=24-20 xs1=19-15 xd=11-7
+unzip 32 000010001111<20|101<12|0010011<0 xs1=19-15 xd=11-7
+zip 32 000010001111<20|001<12|0010011<0 xs1=19-15 xd=11-7
+xperm4 common 0010100<25|010<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+xperm8 common 0010100<25|100<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+bclr common 0100100<25|001<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+bclri common,32 0100100<25|001<12|0010011<0 shamt=24-20 xs1=19-15 xd=11-7
+bclri common,64 010010<26|001<12|0010011<0 shamt=25-20 xs1=19-15 xd=11-7
+bext common 0100100<25|101<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+bexti common,32 0100100<25|101<12|0010011<0 shamt=24-20 xs1=19-15 xd=11-7
+bexti common,64 010010<26|101<12|0010011<0 shamt=25-20 xs1=19-15 xd=11-7
+binv common 0110100<25|001<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+binvi common,32 0110100<25|001<12|0010011<0 shamt=24-20 xs1=19-15 xd=11-7
+binvi common,64 011010<26|001<12|0010011<0 shamt=25-20 xs1=19-15 xd=11-7
+bset common 0010100<25|001<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+bseti common,32 0010100<25|001<12|0010011<0 shamt=24-20 xs1=19-15 xd=11-7
+bseti common,64 001010<26|001<12|0010011<0 shamt=25-20 xs1=19-15 xd=11-7
+c.lbu common 100000<10|00<0 imm=5|6 xd=4-2 xs1=9-7
+c.lh common 100001<10|1<6|00<0 imm<1=5 xd=4-2 xs1=9-7
+c.lhu common 100001<10|0<6|00<0 imm<1=5 xd=4-2 xs1=9-7
+c.mul common 100111<10|10<5|01<0 xd=9-7 xs2=4-2
+c.not common 100111<10|1110101<0 xd=9-7
+c.sb common 100010<10|00<0 imm=5|6 xs2=4-2 xs1=9-7
+c.sext.b common 100111<10|1100101<0 xd=9-7
+c.sext.h common 100111<10|1101101<0 xd=9-7
+c.sh common 100011<10|0<6|00<0 imm<1=5 xs2=4-2 xs1=9-7
+c.zext.b common 100111<10|1100001<0 xd=9-7
+c.zext.h common 100111<10|1101001<0 xd=9-7
+c.zext.w 64 100111<10|1110001<0 xd=9-7
+c.fld common 001<13|00<0 imm<3=6-5|12-10 fd=4-2 xs1=9-7
+c.fldsp common 001<13|10<0 imm<3=4-2|12|6-5 fd=11-7
+c.fsd common 101<13|00<0 imm<3=6-5|12-10 fs2=4-2 xs1=9-7
+c.fsdsp common 101<13|10<0 imm<3=9-7|12-10 fs2=6-2
+c.flw 32 011<13|00<0 imm<2=5|12-10|6 fd=4-2 xs1=9-7
+c.flwsp 32 011<13|10<0 imm<2=3-2|12|6-4 fd=11-7
+c.fsw 32 111<13|00<0 imm<2=5|12-10|6 fs2=4-2 xs1=9-7
+c.fswsp 32 111<13|10<0 imm<2=8-7|12-9 fs2=6-2
+c.mop.1 common 0110000010000001<0
+c.mop.11 common 0110010110000001<0
+c.mop.13 common 0110011010000001<0
+c.mop.15 common 0110011110000001<0
+c.mop.3 common 0110000110000001<0
+c.mop.5 common 0110001010000001<0
+c.mop.7 common 0110001110000001<0
+c.mop.9 common 0110010010000001<0
+cm.mva01s common 101011<10|11<5|10<0 r1s=9-7 r2s=4-2
+cm.mvsa01 common 101011<10|01<5|10<0 r1s=9-7 r2s=4-2
+cm.pop common 10111010<8|10<0 rlist!0!1!2!3=7-4 spimm<4=3-2
+cm.popret common 10111110<8|10<0 rlist!0!1!2!3=7-4 spimm<4=3-2
+cm.popretz common 10111100<8|10<0 rlist!0!1!2!3=7-4 spimm<4=3-2
+cm.push common 10111000<8|10<0 rlist!0!1!2!3=7-4 spimm=3-2
+cm.jalt common 101000<10|10<0 index!0!1!2!3!4!5!6!7!8!9!10!11!12!13!14!15!16!17!18!19!20!21!22!23!24!25!26!27!28!29!30!31=9-2
+cm.jt common 101000000<7|10<0 index=6-2
+fli.s common 111100000001<20|000<12|1010011<0 xs1=19-15 fd=11-7
+fmaxm.s common 0010100<25|011<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fminm.s common 0010100<25|010<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fround.s common 010000000100<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+froundnx.s common 010000000101<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.bf16.s common 010001001000<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.s.bf16 common 010000000110<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fadd.h common 0000010<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fclass.h common 111001000000<20|001<12|1010011<0 fs1=19-15 xd=11-7
+fcvt.d.h common 010000100010<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.h.d common 010001000001<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.h.l 64 110101000010<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.h.lu 64 110101000011<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.h.s common 010001000000<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.h.w common 110101000000<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.h.wu common 110101000001<20|1010011<0 xs1=19-15 rm=14-12 fd=11-7
+fcvt.l.h 64 110001000010<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.lu.h 64 110001000011<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.s.h common 010000000010<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fcvt.w.h common 110001000000<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fcvt.wu.h common 110001000001<20|1010011<0 fs1=19-15 rm=14-12 xd=11-7
+fdiv.h common 0001110<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+feq.h common 1010010<25|010<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fle.h common 1010010<25|000<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fleq.h common 1010010<25|100<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+flh common 001<12|0000111<0 imm=31-20 xs1=19-15 fd=11-7
+fli.h common 111101000001<20|000<12|1010011<0 xs1=19-15 fd=11-7
+flt.h common 1010010<25|001<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fltq.h common 1010010<25|101<12|1010011<0 fs2=24-20 fs1=19-15 xd=11-7
+fmadd.h common 10<25|1000011<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmax.h common 0010110<25|001<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmaxm.h common 0010110<25|011<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmin.h common 0010110<25|000<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fminm.h common 0010110<25|010<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fmsub.h common 10<25|1000111<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmul.h common 0001010<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fmv.h.x common 111101000000<20|000<12|1010011<0 xs1=19-15 fd=11-7
+fmv.x.h common 111001000000<20|000<12|1010011<0 fs1=19-15 xd=11-7
+fnmadd.h common 10<25|1001111<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fnmsub.h common 10<25|1001011<0 fs3=31-27 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+fround.h common 010001000100<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+froundnx.h common 010001000101<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fsgnj.h common 0010010<25|000<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsgnjn.h common 0010010<25|001<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsgnjx.h common 0010010<25|010<12|1010011<0 fs2=24-20 fs1=19-15 fd=11-7
+fsh common 001<12|0100111<0 imm=31-25|11-7 xs1=19-15 fs2=24-20
+fsqrt.h common 010111000000<20|1010011<0 fs1=19-15 rm=14-12 fd=11-7
+fsub.h common 0000110<25|1010011<0 fs2=24-20 fs1=19-15 rm=14-12 fd=11-7
+cbo.clean common 000000000001<20|010000000001111<0 xs1=19-15
+cbo.flush common 000000000010<20|010000000001111<0 xs1=19-15
+cbo.inval common 000000000000<20|010000000001111<0 xs1=19-15
+prefetch.i common 00000<20|110000000010011<0 imm~<5=31-25 xs1=19-15
+prefetch.r common 00001<20|110000000010011<0 imm~<5=31-25 xs1=19-15
+prefetch.w common 00011<20|110000000010011<0 imm~<5=31-25 xs1=19-15
+cbo.zero common 000000000100<20|010000000001111<0 xs1=19-15
+lpad common 000000010111<0 imm<12=31-12
+ssamoswap.d common 01001<27|011<12|0101111<0 aq=26-26 rl=25-25 xs2=24-20 xs1=19-15 xd=11-7
+ssamoswap.w common 01001<27|010<12|0101111<0 aq=26-26 rl=25-25 xs2=24-20 xs1=19-15 xd=11-7
+sspopchk.x1 common 11001101110000001100000001110011<0
+sspopchk.x5 common 11001101110000101100000001110011<0
+sspush.x1 common 11001110000100000100000001110011<0
+sspush.x5 common 11001110010100000100000001110011<0
+ssrdp common 11001101110000000100<12|1110011<0 xd!0=11-7
+czero.eqz common 0000111<25|101<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+czero.nez common 0000111<25|111<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+csrrc common 011<12|1110011<0 csr=31-20 xs1=19-15 xd=11-7
+csrrci common 111<12|1110011<0 csr=31-20 imm=19-15 xd=11-7
+csrrs common 010<12|1110011<0 csr=31-20 xs1=19-15 xd=11-7
+csrrsi common 110<12|1110011<0 csr=31-20 imm=19-15 xd=11-7
+csrrw common 001<12|1110011<0 csr=31-20 xs1=19-15 xd=11-7
+csrrwi common 101<12|1110011<0 csr=31-20 imm=19-15 xd=11-7
+fence.i common 001<12|0001111<0 imm=31-20 xs1=19-15 xd=11-7
+c.ntl.all common 1001000000010110<0
+c.ntl.p1 common 1001000000001010<0
+c.ntl.pall common 1001000000001110<0
+c.ntl.s1 common 1001000000010010<0
+ntl.all common 00000000010100000000000000110011<0
+ntl.p1 common 00000000001000000000000000110011<0
+ntl.pall common 00000000001100000000000000110011<0
+ntl.s1 common 00000000010000000000000000110011<0
+pause common 00000001000000000000000000001111<0
+mop.r.0 common 100000011100<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.1 common 100000011101<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.10 common 100010011110<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.11 common 100010011111<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.12 common 100011011100<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.13 common 100011011101<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.14 common 100011011110<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.15 common 100011011111<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.16 common 110000011100<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.17 common 110000011101<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.18 common 110000011110<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.19 common 110000011111<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.2 common 100000011110<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.20 common 110001011100<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.21 common 110001011101<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.22 common 110001011110<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.23 common 110001011111<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.24 common 110010011100<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.25 common 110010011101<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.26 common 110010011110<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.27 common 110010011111<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.28 common 110011011100<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.29 common 110011011101<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.3 common 100000011111<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.30 common 110011011110<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.31 common 110011011111<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.4 common 100001011100<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.5 common 100001011101<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.6 common 100001011110<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.7 common 100001011111<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.8 common 100010011100<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.r.9 common 100010011101<20|100<12|1110011<0 xs1=19-15 xd=11-7
+mop.rr.0 common 1000001<25|100<12|1110011<0 xs2=24-20 xs1=19-15 xd=11-7
+mop.rr.1 common 1000011<25|100<12|1110011<0 xs2=24-20 xs1=19-15 xd=11-7
+mop.rr.2 common 1000101<25|100<12|1110011<0 xs2=24-20 xs1=19-15 xd=11-7
+mop.rr.3 common 1000111<25|100<12|1110011<0 xs2=24-20 xs1=19-15 xd=11-7
+mop.rr.4 common 1100001<25|100<12|1110011<0 xs2=24-20 xs1=19-15 xd=11-7
+mop.rr.5 common 1100011<25|100<12|1110011<0 xs2=24-20 xs1=19-15 xd=11-7
+mop.rr.6 common 1100101<25|100<12|1110011<0 xs2=24-20 xs1=19-15 xd=11-7
+mop.rr.7 common 1100111<25|100<12|1110011<0 xs2=24-20 xs1=19-15 xd=11-7
+aes64ks1i 64 00110001<24|001<12|0010011<0 rnum=23-20 xs1=19-15 xd=11-7
+aes64ks2 64 0111111<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+aes32dsi 32 10101<25|000<12|0110011<0 bs=31-30 xs2=24-20 xs1=19-15 xd=11-7
+aes32dsmi 32 10111<25|000<12|0110011<0 bs=31-30 xs2=24-20 xs1=19-15 xd=11-7
+aes64ds 64 0011101<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+aes64dsm 64 0011111<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+aes64im 64 001100000000<20|001<12|0010011<0 xs1=19-15 xd=11-7
+aes32esi 32 10001<25|000<12|0110011<0 bs=31-30 xs2=24-20 xs1=19-15 xd=11-7
+aes32esmi 32 10011<25|000<12|0110011<0 bs=31-30 xs2=24-20 xs1=19-15 xd=11-7
+aes64es 64 0011001<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+aes64esm 64 0011011<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+sha256sig0 common 000100000010<20|001<12|0010011<0 xs1=19-15 xd=11-7
+sha256sig1 common 000100000011<20|001<12|0010011<0 xs1=19-15 xd=11-7
+sha256sum0 common 000100000000<20|001<12|0010011<0 xs1=19-15 xd=11-7
+sha256sum1 common 000100000001<20|001<12|0010011<0 xs1=19-15 xd=11-7
+sha512sig0 64 000100000110<20|001<12|0010011<0 xs1=19-15 xd=11-7
+sha512sig0h 32 0101110<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+sha512sig0l 32 0101010<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+sha512sig1 64 000100000111<20|001<12|0010011<0 xs1=19-15 xd=11-7
+sha512sig1h 32 0101111<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+sha512sig1l 32 0101011<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+sha512sum0 64 000100000100<20|001<12|0010011<0 xs1=19-15 xd=11-7
+sha512sum0r 32 0101000<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+sha512sum1 64 000100000101<20|001<12|0010011<0 xs1=19-15 xd=11-7
+sha512sum1r 32 0101001<25|000<12|0110011<0 xs2=24-20 xs1=19-15 xd=11-7
+sm3p0 common 000100001000<20|001<12|0010011<0 xs1=19-15 xd=11-7
+sm3p1 common 000100001001<20|001<12|0010011<0 xs1=19-15 xd=11-7
+sm4ed common 11000<25|000<12|0110011<0 bs=31-30 xs2=24-20 xs1=19-15 xd=11-7
+sm4ks common 11010<25|000<12|0110011<0 bs=31-30 xs2=24-20 xs1=19-15 xd=11-7
+vandn.vv common 000001<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vandn.vx common 000001<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vbrev.v common 010010<26|01010010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vbrev8.v common 010010<26|01000010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vclz.v common 010010<26|01100010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vcpop.v common 010010<26|01110010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vctz.v common 010010<26|01101010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vrev8.v common 010010<26|01001010<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vrol.vv common 010101<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vrol.vx common 010101<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vror.vi common 01010<27|011<12|1010111<0 imm=26|19-15 vm=25-25 vs2=24-20 vd=11-7
+vror.vv common 010100<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vror.vx common 010100<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vwsll.vi common 110101<26|011<12|1010111<0 vm=25-25 vs2=24-20 imm=19-15 vd=11-7
+vwsll.vv common 110101<26|000<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vwsll.vx common 110101<26|100<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vclmul.vv common 001100<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vclmul.vx common 001100<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vclmulh.vv common 001101<26|010<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vclmulh.vx common 001101<26|110<12|1010111<0 vm=25-25 vs2=24-20 xs1=19-15 vd=11-7
+vfncvtbf16.f.f.w common 010010<26|11101001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfwcvtbf16.f.f.v common 010010<26|01101001<12|1010111<0 vm=25-25 vs2=24-20 vd=11-7
+vfwmaccbf16.vf common 111011<26|101<12|1010111<0 vm=25-25 vs2=24-20 fs1=19-15 vd=11-7
+vfwmaccbf16.vv common 111011<26|001<12|1010111<0 vm=25-25 vs2=24-20 vs1=19-15 vd=11-7
+vghsh.vv common 1011001<25|010<12|1110111<0 vs2=24-20 vs1=19-15 vd=11-7
+vgmul.vv common 1010001<25|10001010<12|1110111<0 vs2=24-20 vd=11-7
+vaesdf.vs common 1010011<25|00001010<12|1110111<0 vs2=24-20 vd=11-7
+vaesdf.vv common 1010001<25|00001010<12|1110111<0 vs2=24-20 vd=11-7
+vaesdm.vs common 1010011<25|00000010<12|1110111<0 vs2=24-20 vd=11-7
+vaesdm.vv common 1010001<25|00000010<12|1110111<0 vs2=24-20 vd=11-7
+vaesef.vs common 1010011<25|00011010<12|1110111<0 vs2=24-20 vd=11-7
+vaesef.vv common 1010001<25|00011010<12|1110111<0 vs2=24-20 vd=11-7
+vaesem.vs common 1010011<25|00010010<12|1110111<0 vs2=24-20 vd=11-7
+vaesem.vv common 1010001<25|00010010<12|1110111<0 vs2=24-20 vd=11-7
+vaeskf1.vi common 1000101<25|010<12|1110111<0 vs2=24-20 imm=19-15 vd=11-7
+vaeskf2.vi common 1010101<25|010<12|1110111<0 vs2=24-20 imm=19-15 vd=11-7
+vaesz.vs common 1010011<25|00111010<12|1110111<0 vs2=24-20 vd=11-7
+vsha2ch.vv common 1011101<25|010<12|1110111<0 vs2=24-20 vs1=19-15 vd=11-7
+vsha2cl.vv common 1011111<25|010<12|1110111<0 vs2=24-20 vs1=19-15 vd=11-7
+vsha2ms.vv common 1011011<25|010<12|1110111<0 vs2=24-20 vs1=19-15 vd=11-7
+vsm3c.vi common 1010111<25|010<12|1110111<0 vs2=24-20 imm=19-15 vd=11-7
+vsm3me.vv common 1000001<25|010<12|1110111<0 vs2=24-20 vs1=19-15 vd=11-7
+vsm4k.vi common 1000011<25|010<12|1110111<0 vs2=24-20 imm=19-15 vd=11-7
+vsm4r.vs common 1010011<25|10000010<12|1110111<0 vs2=24-20 vd=11-7
+vsm4r.vv common 1010001<25|10000010<12|1110111<0 vs2=24-20 vd=11-7
+
diff --git a/arch/riscv/tools/insn_tbl.sh b/arch/riscv/tools/insn_tbl.sh
new file mode 100755
index 000000000000..aede14c80146
--- /dev/null
+++ b/arch/riscv/tools/insn_tbl.sh
@@ -0,0 +1,256 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Generate riscv instruction helper header.
+# The generated helpers for each instruction are:
+# - riscv_insn_<insn>_MASK useful to help check if arbitrary binary is <insn>
+# - riscv_insn_<insn>_MATCH useful to help check if arbitrary binary is <insn>
+# - riscv_insn_<insn> useful to construct <insn>
+# - riscv_insn_<insn>_<var> useful to extract <var> from <insn>
+#
+# Each line of the instruction table should have the following format:
+# NAME BASE FIXED_BITS [VARIABLE_LIST]
+# NAME instruction name
+# BASE instruction base size (common[,(32|64)])
+# "common" means the instruction is valid on both architecture sizes
+# "32" or "64" means the instruction is valid on that size
+# if the instruction is valid on both architectures but has unique
+# encodings, use a 32-bit entry "common,32" and 64-bit entry
+# FIXED_BITS bitfields of the fixed bits of an instruction concatenated with '|'
+# continuous grouping of fixed bits are in the form of 'bits<offset'
+# VARIABLE_LIST a variable sized list of all variables in the instruction definition
+# in the form of name[~][<num][!num...]=(high[-low])|...
+# symbols after the name represent different modifiers:
+# ~ sign extension, can only appear once
+# < left shift by 'num' amount on extraction, can only appear once
+# ! mark 'num' as an invalid input for this variable#
+
+set -e
+
+usage() {
+ echo >&2 "usage: $0 BASE INFILE OUTFILE" >&2
+ echo >&2
+ echo >&2 " INFILE input instruction table"
+ echo >&2 " OUTFILE output header file"
+ exit 1
+}
+
+if [ $# -ne 2 ]; then
+ usage
+fi
+
+infile="$1"
+outfile="$2"
+
+file=$(readlink -f $0)
+
+echo "/* Auto-generated rv${base} header from script arch/${file#*arch/} */" > $outfile
+
+echo "#ifndef RISCV_INSN_GEN_H" >> $outfile
+echo "#define RISCV_INSN_GEN_H" >> $outfile
+echo >> $outfile
+
+printf "#include <linux/bits.h>" >> $outfile
+echo >> $outfile
+
+grep -E "^[a-z\.0-9]+[[:space:]]+" "$infile" | {
+ while read name base fixed variables; do
+ echo "/* $name */"
+
+ non_compressed_insn=${name##c.*}
+ invalid_inst_functions=""
+ variable_params=""
+ constraints=""
+ match=""
+ mask=""
+ make=""
+
+ # All compressed instructions start with "c."
+ size=${non_compressed_insn:+32};
+ size=${size:-16};
+
+ # Replace all . with _
+ formatted_inst_name=$name
+ while [ ! ${formatted_inst_name##*.*} ]; do
+ prefix=${formatted_inst_name%.*}
+ suffix=${formatted_inst_name##*.}
+ contains_dot=${formatted_inst_name##*.*}
+ formatted_inst_name=${contains_dot:-${prefix}_${suffix}}
+ done
+
+ # Collect all fixed bits of an instruction
+ OLD_IFS=$IFS
+ IFS='|'
+ for segment in $fixed; do
+ bits=${segment%<*}
+ offset=${segment#*<}
+
+ len=${#bits}
+
+ mask="${mask} | 0b"
+
+ while [ $len -gt 0 ]; do
+ len=$((len - 1))
+ mask=${mask}1
+ done
+
+ if [ ${offset} -gt 0 ]; then
+ s=" << ${offset}"
+ else
+ s=""
+ fi
+
+ mask="${mask}${s}"
+
+ match="${match} | 0b${bits}${s}"
+ done
+ IFS=$OLD_IFS
+
+ # Instruction only appears in one base
+ only_base=
+ if [ "${base}" != "${base%32}" ]; then
+ echo "#if __riscv_xlen == 32"
+ only_base=32
+ elif [ "${base}" != "${base%64}" ]; then
+ echo "#if __riscv_xlen == 64"
+ only_base=64
+ fi
+
+ # Standard name for the instruction parameter in generated functions
+ insn="_insn"
+
+ for variable in ${variables}; do
+ variable_name="${variable%%[<~=!]*}"
+ parts="${variable#*=}"
+ insert_mask=""
+ sign_extend=""
+ left_shift=""
+ extract=""
+ insert=""
+
+ # Standard name for the variable parameter in generated functions
+ var="_${variable_name}"
+ variable_params="${variable_params}u32 ${var}, "
+
+ if [ "${variable}" != "${variable#*~}" ]; then
+ sign_extend="1"
+ fi
+
+ if [ "${variable}" != "${variable#*<}" ]; then
+ left_shift="${variable#*<}"
+ left_shift="${left_shift%%[=<~!]*}"
+ else
+ left_shift="0"
+ fi
+
+ if [ "${variable}" != "${variable#*!}" ]; then
+ raw_constraints="${variable#*!}"
+ raw_constraints="${raw_constraints%%[=<~!]**}"
+
+ OLD_IFS=$IFS
+ IFS='!'
+ for constraint in $raw_constraints; do
+ constraints="${constraints}(riscv_insn_${formatted_inst_name}_extract_${variable_name}(${insn}) != ${constraint}) && "
+ done
+ IFS=$OLD_IFS
+ fi
+
+ offset=0
+ while true; do
+ part=${parts##*|}
+
+ if [ "${part#*-}" = "${part}" ]; then
+ high="${part}"
+ low="${part}"
+ len=1
+ else
+ high="${part%-*}"
+ low="${part#*-}"
+ len=$((high - low + 1))
+ fi
+
+ # Don't emit shift if 0
+ first_shift=${low}
+ if [ "${first_shift}" = "0" ]; then
+ first_shift=
+ fi
+
+ second_shift=$((offset + left_shift))
+ if [ "${second_shift}" = "0" ]; then
+ second_shift=
+ fi
+
+ extract="${extract} | ((${insn}${first_shift:+ >> }${first_shift} & GENMASK($((len - 1)), 0))${second_shift:+ << }${second_shift})"
+ insert_mask="${insert_mask} & ~GENMASK(${high}, ${low})"
+ insert="${insert} | (((${var}${second_shift:+ >> }${second_shift}) & GENMASK($((len - 1)), 0))${first_shift:+ << }${first_shift})"
+ offset=$((offset + len))
+
+ if [ "${parts}" = "${part}" ]; then
+ # Processed all parts of variable
+ break
+ fi
+
+ parts=${parts%|*}
+ done
+
+ extract="${extract# | }"
+
+ if [ ${sign_extend} ]; then
+ extract="sign_extend32(${extract}, $((offset + left_shift - 1)))"
+ type="s"
+ else
+ type="u"
+ fi
+
+ printf "static __always_inline ${type}${size} riscv_insn_${formatted_inst_name}_extract_${variable_name}(u${size} ${insn})\n"
+ printf "{\n"
+ printf "\treturn ${extract};\n"
+ printf "}\n"
+ printf "static __always_inline void riscv_insn_${formatted_inst_name}_insert_${variable_name}(u${size} *${insn}, ${type}32 ${var})\n"
+ printf "{\n"
+ printf "\t*_insn &= ${insert_mask# & };\n"
+ printf "\t*_insn |= ${insert# | };\n"
+ printf "}\n"
+
+ if [ "${only_base}" ]; then
+ invalid_inst_functions="${invalid_inst_functions}static __always_inline ${type}${size} riscv_insn_${formatted_inst_name}_extract_${variable_name}(u${size} ${insn}) {\n\tBUILD_BUG_ON_MSG(1, \"${name} is not supported on non ${only_base}-bit systems.\");\n}\n"
+ fi
+
+ make="${make} riscv_insn_${formatted_inst_name}_insert_${variable_name}(&${insn}, ${var});\n"
+ done
+
+ variable_params="${variable_params%, }"
+ variable_params="${variable_params:-void}"
+
+ printf "#define riscv_insn_${formatted_inst_name}_MASK (${mask# | })\n"
+ printf "#define riscv_insn_${formatted_inst_name}_MATCH (${match# | })\n"
+ printf "static __always_inline u${size} riscv_insn_${formatted_inst_name}(${variable_params})\n"
+ printf "{\n"
+ printf "\tu${size} ${insn} = riscv_insn_${formatted_inst_name}_MATCH;\n"
+ printf "${make} return ${insn};\n"
+ printf "}\n"
+
+ # Check against instructions that have a variable that may contain invalid values
+ if [ "$constraints" ]; then
+ printf "__RISCV_INSN_FUNCS_CONSTRAINED(${formatted_inst_name}, ${constraints% && });\n"
+ else
+ printf "__RISCV_INSN_FUNCS(${formatted_inst_name});\n"
+ fi
+
+ # If common does not appear in the base, then this instruction only appears in one base
+ if [ "$base" = "${base#common}" ]; then
+ printf "#else\n"
+ printf "__RISCV_INSN_FUNCS_UNSUPPORTED(${formatted_inst_name});\n"
+ printf "${invalid_inst_functions%\\n}\n"
+ fi
+
+ # Instruction has a base variant
+ if [ "$base" != "${base%[24]}" ]; then
+ echo "#endif"
+ fi
+
+ echo
+ done
+
+ echo "#endif /* RISCV_INST_GEN_H */"
+} >> $outfile
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 02/16] riscv: alternatives: Use generated instruction headers for patching code
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 01/16] riscv: Introduce instruction table generation Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:28 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 03/16] riscv: kgdb: Use generated instruction headers Charlie Jenkins via B4 Relay
` (13 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Migrate the alternatives patching code to use the generated instruction
headers instead of the hand-written instruction composition functions.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
These function expansions are very simple and almost expand to the same
thing in the new and old version. The main difference is
riscv_insn_auipc_extract_imm() in the new version expands to:
((_insn >> 12 & GENMASK(19, 0)) << 12)
while it expands to the following in the old version:
((_insn >> 0) & GENMASK(31, 12))
These are the same thing, but GCC is unable to properly optimize the
second one so the first one ends up using almost half as many
instructions. With this finding and other similar examples, I made
the generated headers construct in the first way to help GCC optimize
all of these functions.
Brute force can also be checked with this code:
void check_auipc_jalr() {
for (unsigned int auipc = 0; auipc < ((1ULL << 12) - 1); auipc++) {
for (unsigned int jalr = 0; jalr < ((1ULL << 20) - 1); jalr++) {
unsigned int auipc_t=riscv_insn_auipc(auipc, 0), jalr_t=riscv_insn_jalr(jalr, 0, 0), auipc_t2=riscv_insn_auipc(auipc, 0), jalr_t2=riscv_insn_jalr(jalr, 0, 0);
riscv_alternative_fix_auipc_jalr(&auipc_t, &jalr_t, 0);
riscv_alternative_fix_auipc_jalr2(&auipc_t2, &jalr_t2, 0);
if (auipc_t != auipc_t2) {
printf("auipcs don't match %u, %u: %u != %u\n", auipc, jalr, auipc_t, auipc_t2);
return;
}
if (jalr_t != jalr_t2) {
printf("jalrs don't match %u: %u != %u\n", i, jalr_t, jalr_t2);
}
}
}
}
---
arch/riscv/include/asm/insn.h | 74 -----------------------------------------
arch/riscv/kernel/alternative.c | 23 +++++++++----
2 files changed, 17 insertions(+), 80 deletions(-)
diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h
index d562b2b40ba1..d0e137f9bcd7 100644
--- a/arch/riscv/include/asm/insn.h
+++ b/arch/riscv/include/asm/insn.h
@@ -514,78 +514,4 @@ static __always_inline bool riscv_insn_is_branch(u32 code)
#define RVV_EXTRACT_VL_VS_WIDTH(x) RVFDQ_EXTRACT_FL_FS_WIDTH(x)
-/*
- * Get the immediate from a J-type instruction.
- *
- * @insn: instruction to process
- * Return: immediate
- */
-static inline s32 riscv_insn_extract_jtype_imm(u32 insn)
-{
- return RV_EXTRACT_JTYPE_IMM(insn);
-}
-
-/*
- * Update a J-type instruction with an immediate value.
- *
- * @insn: pointer to the jtype instruction
- * @imm: the immediate to insert into the instruction
- */
-static inline void riscv_insn_insert_jtype_imm(u32 *insn, s32 imm)
-{
- /* drop the old IMMs, all jal IMM bits sit at 31:12 */
- *insn &= ~GENMASK(31, 12);
- *insn |= (RV_X_MASK(imm, RV_J_IMM_10_1_OFF, RV_J_IMM_10_1_MASK) << RV_J_IMM_10_1_OPOFF) |
- (RV_X_MASK(imm, RV_J_IMM_11_OFF, RV_J_IMM_11_MASK) << RV_J_IMM_11_OPOFF) |
- (RV_X_MASK(imm, RV_J_IMM_19_12_OFF, RV_J_IMM_19_12_MASK) << RV_J_IMM_19_12_OPOFF) |
- (RV_X_MASK(imm, RV_J_IMM_SIGN_OFF, 1) << RV_J_IMM_SIGN_OPOFF);
-}
-
-/*
- * Put together one immediate from a U-type and I-type instruction pair.
- *
- * The U-type contains an upper immediate, meaning bits[31:12] with [11:0]
- * being zero, while the I-type contains a 12bit immediate.
- * Combined these can encode larger 32bit values and are used for example
- * in auipc + jalr pairs to allow larger jumps.
- *
- * @utype_insn: instruction containing the upper immediate
- * @itype_insn: instruction
- * Return: combined immediate
- */
-static inline s32 riscv_insn_extract_utype_itype_imm(u32 utype_insn, u32 itype_insn)
-{
- s32 imm;
-
- imm = RV_EXTRACT_UTYPE_IMM(utype_insn);
- imm += RV_EXTRACT_ITYPE_IMM(itype_insn);
-
- return imm;
-}
-
-/*
- * Update a set of two instructions (U-type + I-type) with an immediate value.
- *
- * Used for example in auipc+jalrs pairs the U-type instructions contains
- * a 20bit upper immediate representing bits[31:12], while the I-type
- * instruction contains a 12bit immediate representing bits[11:0].
- *
- * This also takes into account that both separate immediates are
- * considered as signed values, so if the I-type immediate becomes
- * negative (BIT(11) set) the U-type part gets adjusted.
- *
- * @utype_insn: pointer to the utype instruction of the pair
- * @itype_insn: pointer to the itype instruction of the pair
- * @imm: the immediate to insert into the two instructions
- */
-static inline void riscv_insn_insert_utype_itype_imm(u32 *utype_insn, u32 *itype_insn, s32 imm)
-{
- /* drop possible old IMM values */
- *utype_insn &= ~(RV_U_IMM_31_12_MASK);
- *itype_insn &= ~(RV_I_IMM_11_0_MASK << RV_I_IMM_11_0_OPOFF);
-
- /* add the adapted IMMs */
- *utype_insn |= (imm & RV_U_IMM_31_12_MASK) + ((imm & BIT(11)) << 1);
- *itype_insn |= ((imm & RV_I_IMM_11_0_MASK) << RV_I_IMM_11_0_OPOFF);
-}
#endif /* _ASM_RISCV_INSN_H */
diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c
index 7642704c7f18..b26a90eb65cc 100644
--- a/arch/riscv/kernel/alternative.c
+++ b/arch/riscv/kernel/alternative.c
@@ -11,6 +11,7 @@
#include <linux/cpu.h>
#include <linux/uaccess.h>
#include <asm/alternative.h>
+#include <asm/insn.h>
#include <asm/module.h>
#include <asm/sections.h>
#include <asm/vdso.h>
@@ -78,14 +79,24 @@ static void riscv_alternative_fix_auipc_jalr(void *ptr, u32 auipc_insn,
u32 jalr_insn, int patch_offset)
{
u32 call[2] = { auipc_insn, jalr_insn };
+ u32 auipc_imm;
s32 imm;
/* get and adjust new target address */
- imm = riscv_insn_extract_utype_itype_imm(auipc_insn, jalr_insn);
+ imm = riscv_insn_auipc_extract_imm(auipc_insn) + riscv_insn_jalr_extract_imm(jalr_insn);
imm -= patch_offset;
+ /*
+ * When the 32-bit immediate is split across auipc and jalr, the
+ * constructed immediates need to be treated as individually sign
+ * extended numbers. Add the sign bit of the lower 12 bits to the upper
+ * 20 bits to undo the bleeding of the sign.
+ */
+ auipc_imm = imm + (BIT(11) << 1);
+
/* update instructions */
- riscv_insn_insert_utype_itype_imm(&call[0], &call[1], imm);
+ riscv_insn_auipc_insert_imm(&call[0], auipc_imm);
+ riscv_insn_jalr_insert_imm(&call[1], imm);
/* patch the call place again */
patch_text_nosync(ptr, call, sizeof(u32) * 2);
@@ -96,11 +107,11 @@ static void riscv_alternative_fix_jal(void *ptr, u32 jal_insn, int patch_offset)
s32 imm;
/* get and adjust new target address */
- imm = riscv_insn_extract_jtype_imm(jal_insn);
+ imm = riscv_insn_jal_extract_imm(jal_insn);
imm -= patch_offset;
/* update instruction */
- riscv_insn_insert_jtype_imm(&jal_insn, imm);
+ riscv_insn_jal_insert_imm(&jal_insn, imm);
/* patch the call place again */
patch_text_nosync(ptr, &jal_insn, sizeof(u32));
@@ -127,7 +138,7 @@ void riscv_alternative_fix_offsets(void *alt_ptr, unsigned int len,
continue;
/* if instruction pair is a call, it will use the ra register */
- if (RV_EXTRACT_RD_REG(insn) != 1)
+ if (riscv_insn_jalr_extract_xd(insn) != 1)
continue;
riscv_alternative_fix_auipc_jalr(alt_ptr + i * sizeof(u32),
@@ -136,7 +147,7 @@ void riscv_alternative_fix_offsets(void *alt_ptr, unsigned int len,
}
if (riscv_insn_is_jal(insn)) {
- s32 imm = riscv_insn_extract_jtype_imm(insn);
+ s32 imm = riscv_insn_jal_extract_imm(insn);
/* Don't modify jumps inside the alternative block */
if ((alt_ptr + i * sizeof(u32) + imm) >= alt_ptr &&
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 03/16] riscv: kgdb: Use generated instruction headers
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 01/16] riscv: Introduce instruction table generation Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 02/16] riscv: alternatives: Use generated instruction headers for patching code Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 04/16] riscv: Add kprobes instruction simulation KUnit Charlie Jenkins via B4 Relay
` (12 subsequent siblings)
15 siblings, 0 replies; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Migrate the code that is decoding instructions for the use of kgdb
single stepping to use the generated instruction headers instead of the
hand-written instruction functions.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
I tested this again by comparing the original get_step_address()
function with this new version and input all possible 32 bit numbers and
checked that the next_addr was the same in every case.
This is the code I used:
void check_step()
{
for (unsigned long opcode = 0; opcode < ((1ULL << 32) - 1); opcode++) {
unsigned long next_addr, next_addr2;
get_step_address(opcode, &next_addr);
get_step_address2(opcode, &next_addr2);
if (next_addr != next_addr2) {
printf("opcode: %lu -> %lu != %lu\n", opcode, next_addr, next_addr2);
}
}
}
---
arch/riscv/include/asm/insn.h | 21 +++++++++
arch/riscv/kernel/kgdb.c | 102 ++++++++++++++++--------------------------
2 files changed, 60 insertions(+), 63 deletions(-)
diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h
index d0e137f9bcd7..b92c71896c00 100644
--- a/arch/riscv/include/asm/insn.h
+++ b/arch/riscv/include/asm/insn.h
@@ -514,4 +514,25 @@ static __always_inline bool riscv_insn_is_branch(u32 code)
#define RVV_EXTRACT_VL_VS_WIDTH(x) RVFDQ_EXTRACT_FL_FS_WIDTH(x)
+static inline unsigned long riscv_insn_reg_get_val(unsigned long *regs, u32 index)
+{
+ /* register 0 is always 0 and not stored in the register struct */
+ return index ? *(regs + index) : 0;
+}
+
+#define riscv_insn_branch(_insn, regs_ptr, _opcode, _pc, _comparison, type) \
+ ({ \
+ unsigned long _ret; \
+ if ((type)riscv_insn_reg_get_val( \
+ regs_ptr, \
+ riscv_insn_##_insn##_extract_xs1(_opcode)) \
+ _comparison(type) riscv_insn_reg_get_val( \
+ regs_ptr, \
+ riscv_insn_##_insn##_extract_xs2(_opcode))) \
+ _ret = _pc + riscv_insn_##_insn##_extract_imm(_opcode); \
+ else \
+ _ret = _pc + 4; \
+ _ret; \
+ })
+
#endif /* _ASM_RISCV_INSN_H */
diff --git a/arch/riscv/kernel/kgdb.c b/arch/riscv/kernel/kgdb.c
index 0bf629204c76..fcf7cda3cc33 100644
--- a/arch/riscv/kernel/kgdb.c
+++ b/arch/riscv/kernel/kgdb.c
@@ -23,97 +23,73 @@ enum {
static unsigned long stepped_address;
static unsigned int stepped_opcode;
-static int decode_register_index(unsigned long opcode, int offset)
-{
- return (opcode >> offset) & 0x1F;
-}
-
-static int decode_register_index_short(unsigned long opcode, int offset)
-{
- return ((opcode >> offset) & 0x7) + 8;
-}
-
-/* Calculate the new address for after a step */
static int get_step_address(struct pt_regs *regs, unsigned long *next_addr)
{
unsigned long pc = regs->epc;
unsigned long *regs_ptr = (unsigned long *)regs;
- unsigned int rs1_num, rs2_num;
+ unsigned int rs1_num;
int op_code;
if (get_kernel_nofault(op_code, (void *)pc))
return -EINVAL;
+
if ((op_code & __INSN_LENGTH_MASK) != __INSN_LENGTH_GE_32) {
- if (riscv_insn_is_c_jalr(op_code) ||
- riscv_insn_is_c_jr(op_code)) {
- rs1_num = decode_register_index(op_code, RVC_C2_RS1_OPOFF);
- *next_addr = regs_ptr[rs1_num];
- } else if (riscv_insn_is_c_j(op_code) ||
- riscv_insn_is_c_jal(op_code)) {
- *next_addr = RVC_EXTRACT_JTYPE_IMM(op_code) + pc;
+ if (riscv_insn_is_c_jalr(op_code)) {
+ *next_addr = regs_ptr[riscv_insn_c_jalr_extract_xs1(op_code)];
+ } else if (riscv_insn_is_c_jr(op_code)) {
+ *next_addr = regs_ptr[riscv_insn_c_jr_extract_xs1(op_code)];
+ } else if (riscv_insn_is_c_j(op_code)) {
+ *next_addr = riscv_insn_c_j_extract_imm(op_code) + pc;
+ } else if (riscv_insn_is_c_jal(op_code)) {
+ *next_addr = riscv_insn_c_jal_extract_imm(op_code) + pc;
} else if (riscv_insn_is_c_beqz(op_code)) {
- rs1_num = decode_register_index_short(op_code,
- RVC_C1_RS1_OPOFF);
- if (!rs1_num || regs_ptr[rs1_num] == 0)
- *next_addr = RVC_EXTRACT_BTYPE_IMM(op_code) + pc;
+ rs1_num = riscv_insn_c_beqz_extract_xs1(op_code);
+ if (regs_ptr[8 + rs1_num] == 0)
+ *next_addr = riscv_insn_c_beqz_extract_imm(op_code) + pc;
else
*next_addr = pc + 2;
} else if (riscv_insn_is_c_bnez(op_code)) {
- rs1_num =
- decode_register_index_short(op_code, RVC_C1_RS1_OPOFF);
- if (rs1_num && regs_ptr[rs1_num] != 0)
- *next_addr = RVC_EXTRACT_BTYPE_IMM(op_code) + pc;
+ rs1_num = riscv_insn_c_bnez_extract_xs1(op_code);
+ if (regs_ptr[8 + rs1_num] != 0)
+ *next_addr = riscv_insn_c_bnez_extract_imm(op_code) + pc;
else
*next_addr = pc + 2;
} else {
*next_addr = pc + 2;
}
} else {
- if ((op_code & __INSN_OPCODE_MASK) == __INSN_BRANCH_OPCODE) {
- bool result = false;
- long imm = RV_EXTRACT_BTYPE_IMM(op_code);
- unsigned long rs1_val = 0, rs2_val = 0;
-
- rs1_num = decode_register_index(op_code, RVG_RS1_OPOFF);
- rs2_num = decode_register_index(op_code, RVG_RS2_OPOFF);
- if (rs1_num)
- rs1_val = regs_ptr[rs1_num];
- if (rs2_num)
- rs2_val = regs_ptr[rs2_num];
-
- if (riscv_insn_is_beq(op_code))
- result = (rs1_val == rs2_val) ? true : false;
- else if (riscv_insn_is_bne(op_code))
- result = (rs1_val != rs2_val) ? true : false;
- else if (riscv_insn_is_blt(op_code))
- result =
- ((long)rs1_val <
- (long)rs2_val) ? true : false;
- else if (riscv_insn_is_bge(op_code))
- result =
- ((long)rs1_val >=
- (long)rs2_val) ? true : false;
- else if (riscv_insn_is_bltu(op_code))
- result = (rs1_val < rs2_val) ? true : false;
- else if (riscv_insn_is_bgeu(op_code))
- result = (rs1_val >= rs2_val) ? true : false;
- if (result)
- *next_addr = imm + pc;
- else
- *next_addr = pc + 4;
+ if (riscv_insn_is_beq(op_code)) {
+ *next_addr = riscv_insn_branch(beq, regs_ptr, op_code,
+ pc, ==, unsigned long);
+ } else if (riscv_insn_is_bne(op_code)) {
+ *next_addr = riscv_insn_branch(bne, regs_ptr, op_code,
+ pc, !=, unsigned long);
+ } else if (riscv_insn_is_blt(op_code)) {
+ *next_addr = riscv_insn_branch(blt, regs_ptr, op_code,
+ pc, <, long);
+ } else if (riscv_insn_is_bge(op_code)) {
+ *next_addr = riscv_insn_branch(bge, regs_ptr, op_code,
+ pc, >=, long);
+ } else if (riscv_insn_is_bltu(op_code)) {
+ *next_addr = riscv_insn_branch(bltu, regs_ptr, op_code,
+ pc, <, unsigned long);
+ } else if (riscv_insn_is_bgeu(op_code)) {
+ *next_addr = riscv_insn_branch(bgeu, regs_ptr, op_code,
+ pc, >=, unsigned long);
} else if (riscv_insn_is_jal(op_code)) {
- *next_addr = RV_EXTRACT_JTYPE_IMM(op_code) + pc;
+ *next_addr = riscv_insn_jal_extract_imm(op_code) + pc;
} else if (riscv_insn_is_jalr(op_code)) {
- rs1_num = decode_register_index(op_code, RVG_RS1_OPOFF);
+ rs1_num = riscv_insn_jalr_extract_xs1(op_code);
if (rs1_num)
- *next_addr = ((unsigned long *)regs)[rs1_num];
- *next_addr += RV_EXTRACT_ITYPE_IMM(op_code);
+ *next_addr = regs_ptr[rs1_num];
+ *next_addr += riscv_insn_jalr_extract_imm(op_code);
} else if (riscv_insn_is_sret(op_code)) {
*next_addr = pc;
} else {
*next_addr = pc + 4;
}
}
+
return 0;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 04/16] riscv: Add kprobes instruction simulation KUnit
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (2 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 03/16] riscv: kgdb: Use generated instruction headers Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:19 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 05/16] riscv: kprobes: Use generated instruction headers Charlie Jenkins via B4 Relay
` (11 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
This KUnit iterates through all 32-bit integers and validates that the
simulation code for kprobes simulates properly. These tests are very
slow so they are gated behind a new kconfig option
CONFIG_RISCV_KPROBES_SIMULATE_KUNIT.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
arch/riscv/kernel/tests/Kconfig.debug | 13 ++
arch/riscv/kernel/tests/kprobes/Makefile | 2 +
.../kernel/tests/kprobes/test-kprobes-simulate.c | 250 +++++++++++++++++++++
arch/riscv/kernel/tests/kprobes/test-kprobes.h | 6 +
4 files changed, 271 insertions(+)
diff --git a/arch/riscv/kernel/tests/Kconfig.debug b/arch/riscv/kernel/tests/Kconfig.debug
index 40f8dafffa0a..9eda8938ec15 100644
--- a/arch/riscv/kernel/tests/Kconfig.debug
+++ b/arch/riscv/kernel/tests/Kconfig.debug
@@ -42,6 +42,19 @@ config RISCV_KPROBES_KUNIT
If unsure, say N.
+config RISCV_KPROBES_SIMULATE_KUNIT
+ tristate "KUnit test for riscv kprobes instruction simulation" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ depends on KPROBES
+ default KUNIT_ALL_TESTS
+ help
+ Enable testing for riscv kprobes instruction simulation. Useful for
+ riscv and/or kprobes development. The test verifies that kprobes
+ instruction simulation properly simulates the instructions. These tests
+ are very slow.
+
+ If unsure, say N.
+
endif # RUNTIME_TESTING_MENU
endmenu # "arch/riscv/kernel runtime Testing"
diff --git a/arch/riscv/kernel/tests/kprobes/Makefile b/arch/riscv/kernel/tests/kprobes/Makefile
index df7256f62313..34db6044e87f 100644
--- a/arch/riscv/kernel/tests/kprobes/Makefile
+++ b/arch/riscv/kernel/tests/kprobes/Makefile
@@ -1,3 +1,5 @@
obj-$(CONFIG_RISCV_KPROBES_KUNIT) += kprobes_riscv_kunit.o
+obj-$(CONFIG_RISCV_KPROBES_SIMULATE_KUNIT) += kprobes_simulate_riscv_kunit.o
kprobes_riscv_kunit-objs := test-kprobes.o test-kprobes-asm.o
+kprobes_simulate_riscv_kunit-objs := test-kprobes-simulate.o
diff --git a/arch/riscv/kernel/tests/kprobes/test-kprobes-simulate.c b/arch/riscv/kernel/tests/kprobes/test-kprobes-simulate.c
new file mode 100644
index 000000000000..d82706685823
--- /dev/null
+++ b/arch/riscv/kernel/tests/kprobes/test-kprobes-simulate.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <kunit/test.h>
+
+#include "../../probes/simulate-insn.h"
+
+#include <asm/insn.h>
+#include <asm/text-patching.h>
+
+static void test_kprobe_simulate_riscv(struct kunit *test)
+{
+ unsigned int addr = 0xdeadbeef;
+ unsigned int i = 0;
+
+ do {
+ struct pt_regs regs = { 0 };
+
+ if (riscv_insn_is_jal(i)) {
+ s32 offset = riscv_insn_jal_extract_imm(i);
+ u32 xd_index = riscv_insn_jal_extract_xd(i);
+
+ simulate_jal(i, addr, ®s);
+
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + offset,
+ "jal instruction (0x%x) incorrectly simulated", i);
+
+ if (xd_index)
+ KUNIT_EXPECT_EQ_MSG(
+ test,
+ riscv_insn_reg_get_val((unsigned long *)®s, xd_index),
+ addr + 4, "jal instruction (0x%x) incorrectly simulated",
+ i);
+ }
+ if (riscv_insn_is_jalr(i)) {
+ unsigned long reg_addr = 0xffff;
+ s32 offset = riscv_insn_jalr_extract_imm(i);
+ u32 rd_index = riscv_insn_jalr_extract_xd(i);
+ u32 rs1_index = riscv_insn_jalr_extract_xs1(i);
+
+ if (rs1_index)
+ riscv_insn_reg_set_val((unsigned long *)®s, rs1_index, reg_addr);
+ else
+ reg_addr = 0;
+
+ simulate_jalr(i, addr, ®s);
+
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, (reg_addr + offset) & ~1,
+ "jalr instruction (0x%x) incorrectly simulated", i);
+
+ if (rd_index)
+ KUNIT_EXPECT_EQ_MSG(
+ test,
+ riscv_insn_reg_get_val((unsigned long *)®s, rd_index),
+ addr + 4, "jalr instruction (0x%x) incorrectly simulated",
+ i);
+ } else if (riscv_insn_is_auipc(i)) {
+ s32 offset = riscv_insn_auipc_extract_imm(i);
+ u32 rd_index = riscv_insn_auipc_extract_xd(i);
+
+ simulate_auipc(i, addr, ®s);
+
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + 4,
+ "auipc instruction (0x%x) incorrectly simulated", i);
+
+ if (rd_index)
+ KUNIT_EXPECT_EQ_MSG(
+ test,
+ riscv_insn_reg_get_val((unsigned long *)®s, rd_index),
+ (unsigned long)addr + offset,
+ "auipc instruction (0x%x) incorrectly simulated", i);
+ } else if (riscv_insn_is_beq(i)) {
+ s32 offset = riscv_insn_beq_extract_imm(i);
+ u32 rs1_index = riscv_insn_beq_extract_xs1(i);
+ u32 rs2_index = riscv_insn_beq_extract_xs2(i);
+
+ simulate_beq(i, addr, ®s);
+
+ if (riscv_insn_reg_get_val((unsigned long *)®s, rs1_index) ==
+ riscv_insn_reg_get_val((unsigned long *)®s, rs2_index)) {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + offset,
+ "beq instruction (0x%x) incorrectly simulated",
+ i);
+ } else {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + 4,
+ "beq instruction (0x%x) incorrectly simulated",
+ i);
+ }
+ } else if (riscv_insn_is_bne(i)) {
+ s32 offset = riscv_insn_bne_extract_imm(i);
+ u32 rs1_index = riscv_insn_bne_extract_xs1(i);
+ u32 rs2_index = riscv_insn_bne_extract_xs2(i);
+
+ simulate_bne(i, addr, ®s);
+
+ if (riscv_insn_reg_get_val((unsigned long *)®s, rs1_index) !=
+ riscv_insn_reg_get_val((unsigned long *)®s, rs2_index)) {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + offset,
+ "bne instruction (0x%x) incorrectly simulated",
+ i);
+ } else {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + 4,
+ "bne instruction (0x%x) incorrectly simulated",
+ i);
+ }
+ } else if (riscv_insn_is_blt(i)) {
+ s32 offset = riscv_insn_blt_extract_imm(i);
+ u32 rs1_index = riscv_insn_blt_extract_xs1(i);
+ u32 rs2_index = riscv_insn_blt_extract_xs2(i);
+
+ simulate_blt(i, addr, ®s);
+
+ if ((long)riscv_insn_reg_get_val((unsigned long *)®s, rs1_index) <
+ (long)riscv_insn_reg_get_val((unsigned long *)®s, rs2_index)) {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + offset,
+ "blt instruction (0x%x) incorrectly simulated",
+ i);
+ } else {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + 4,
+ "blt instruction (0x%x) incorrectly simulated",
+ i);
+ }
+ } else if (riscv_insn_is_bge(i)) {
+ s32 offset = riscv_insn_bge_extract_imm(i);
+ u32 rs1_index = riscv_insn_bge_extract_xs1(i);
+ u32 rs2_index = riscv_insn_bge_extract_xs2(i);
+
+ simulate_bge(i, addr, ®s);
+
+ if ((long)riscv_insn_reg_get_val((unsigned long *)®s, rs1_index) >=
+ (long)riscv_insn_reg_get_val((unsigned long *)®s, rs2_index)) {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + offset,
+ "bge instruction (0x%x) incorrectly simulated",
+ i);
+ } else {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + 4,
+ "bge instruction (0x%x) incorrectly simulated",
+ i);
+ }
+ } else if (riscv_insn_is_bltu(i)) {
+ s32 offset = riscv_insn_bltu_extract_imm(i);
+ u32 rs1_index = riscv_insn_bltu_extract_xs1(i);
+ u32 rs2_index = riscv_insn_bltu_extract_xs2(i);
+
+ simulate_bltu(i, addr, ®s);
+
+ if (riscv_insn_reg_get_val((unsigned long *)®s, rs1_index) <
+ riscv_insn_reg_get_val((unsigned long *)®s, rs2_index)) {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + offset,
+ "bltu instruction (0x%x) incorrectly simulated",
+ i);
+ } else {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + 4,
+ "bltu instruction (0x%x) incorrectly simulated",
+ i);
+ }
+ } else if (riscv_insn_is_bgeu(i)) {
+ s32 offset = riscv_insn_bgeu_extract_imm(i);
+ u32 rs1_index = riscv_insn_bgeu_extract_xs1(i);
+ u32 rs2_index = riscv_insn_bgeu_extract_xs2(i);
+
+ simulate_bgeu(i, addr, ®s);
+
+ if (riscv_insn_reg_get_val((unsigned long *)®s, rs1_index) >=
+ riscv_insn_reg_get_val((unsigned long *)®s, rs2_index)) {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + offset,
+ "bgeu instruction (0x%x) incorrectly simulated",
+ i);
+ } else {
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + 4,
+ "bgeu instruction (0x%x) incorrectly simulated",
+ i);
+ }
+ } else if (riscv_insn_is_c_j(i)) {
+ s32 offset = riscv_insn_c_j_extract_imm(i);
+
+ simulate_c_j(i, addr, ®s);
+
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + offset,
+ "c.j instruction (0x%x) incorrectly simulated", i);
+ } else if (riscv_insn_is_c_jr(i)) {
+ u32 rs1_index = riscv_insn_c_jr_extract_xs1(i);
+
+ simulate_c_jr(i, addr, ®s);
+
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc,
+ riscv_insn_reg_get_val((unsigned long *)®s,
+ rs1_index),
+ "c.jr instruction (0x%x) incorrectly simulated", i);
+ } else if (riscv_insn_is_c_jalr(i)) {
+ unsigned long reg_addr = 0xffff;
+ u32 rs1_index = riscv_insn_c_jalr_extract_xs1(i);
+
+ if (rs1_index)
+ riscv_insn_reg_set_val((unsigned long *)®s, rs1_index, reg_addr);
+ else
+ reg_addr = 0;
+
+ simulate_c_jalr(i, addr, ®s);
+
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, reg_addr,
+ "c.jalr instruction (0x%x) incorrectly simulated", i);
+
+ KUNIT_EXPECT_EQ_MSG(test, regs.ra, addr + 2,
+ "c.jalr instruction (0x%x) incorrectly simulated", i);
+ } else if (riscv_insn_is_c_bnez(i)) {
+ u32 offset;
+ u32 rs1_index = riscv_insn_c_bnez_extract_xs1(i);
+
+ simulate_c_bnez(i, addr, ®s);
+
+ if (riscv_insn_reg_get_val((unsigned long *)®s, rs1_index + 8) != 0)
+ offset = riscv_insn_c_bnez_extract_imm(i);
+ else
+ offset = 2;
+
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + offset,
+ "c.bnez instruction (0x%x) incorrectly simulated", i);
+ } else if (riscv_insn_is_c_beqz(i)) {
+ u32 offset;
+ u32 rs1_index = riscv_insn_c_beqz_extract_xs1(i);
+
+ simulate_c_beqz(i, addr, ®s);
+
+ if (riscv_insn_reg_get_val((unsigned long *)®s, rs1_index + 8) == 0)
+ offset = riscv_insn_c_beqz_extract_imm(i);
+ else
+ offset = 2;
+
+ KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + offset,
+ "c.beqz instruction (0x%x) incorrectly simulated", i);
+ }
+ } while (++i > 0);
+}
+
+static struct kunit_case kprobes_simulate_testcases[] = {
+ KUNIT_CASE_SLOW(test_kprobe_simulate_riscv),
+ {}
+};
+
+static struct kunit_suite kprobes_simulate_test_suite = {
+ .name = "kprobes_simulate_riscv",
+ .test_cases = kprobes_simulate_testcases,
+};
+
+kunit_test_suites(&kprobes_simulate_test_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("KUnit test for riscv kprobes instruction simulatation");
diff --git a/arch/riscv/kernel/tests/kprobes/test-kprobes.h b/arch/riscv/kernel/tests/kprobes/test-kprobes.h
index 537f44aa9d3f..7a672de8f130 100644
--- a/arch/riscv/kernel/tests/kprobes/test-kprobes.h
+++ b/arch/riscv/kernel/tests/kprobes/test-kprobes.h
@@ -19,6 +19,12 @@ extern void *test_kprobes_addresses[];
/* array of functions that return KPROBE_TEST_MAGIC */
extern long (*test_kprobes_functions[])(void);
+void test_kprobes_arbitrary(void);
+
+extern unsigned int *test_kprobes_arbitrary_addr;
+
+extern unsigned int *test_kprobes_c_bnez_addr1;
+
#endif /* __ASSEMBLER__ */
#endif /* TEST_KPROBES_H */
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 05/16] riscv: kprobes: Use generated instruction headers
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (3 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 04/16] riscv: Add kprobes instruction simulation KUnit Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 06/16] riscv: cfi: " Charlie Jenkins via B4 Relay
` (10 subsequent siblings)
15 siblings, 0 replies; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Migrate the code that is decoding instruction for the use of kprobes to
use the generated instruction headers instead of the hand-written
instruction functions.
With the more granular instruction support, split the decoding of branches into
their own functions.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
Tested using CONFIG_RISCV_KPROBES_KUNIT
---
arch/riscv/include/asm/insn.h | 7 +
arch/riscv/kernel/probes/decode-insn.c | 7 +-
arch/riscv/kernel/probes/simulate-insn.c | 253 ++++++++++++-------------------
arch/riscv/kernel/probes/simulate-insn.h | 7 +-
4 files changed, 114 insertions(+), 160 deletions(-)
diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h
index b92c71896c00..bf6f5d530491 100644
--- a/arch/riscv/include/asm/insn.h
+++ b/arch/riscv/include/asm/insn.h
@@ -520,6 +520,13 @@ static inline unsigned long riscv_insn_reg_get_val(unsigned long *regs, u32 inde
return index ? *(regs + index) : 0;
}
+static inline void riscv_insn_reg_set_val(unsigned long *regs, u32 index, unsigned long val)
+{
+ /* register 0 is always 0 and not stored in the register struct */
+ if (index != 0)
+ *(regs + index) = val;
+}
+
#define riscv_insn_branch(_insn, regs_ptr, _opcode, _pc, _comparison, type) \
({ \
unsigned long _ret; \
diff --git a/arch/riscv/kernel/probes/decode-insn.c b/arch/riscv/kernel/probes/decode-insn.c
index 65d9590bfb9f..0d70c8301a45 100644
--- a/arch/riscv/kernel/probes/decode-insn.c
+++ b/arch/riscv/kernel/probes/decode-insn.c
@@ -42,7 +42,12 @@ riscv_probe_decode_insn(probe_opcode_t *addr, struct arch_probe_insn *api)
RISCV_INSN_SET_SIMULATE(jal, insn);
RISCV_INSN_SET_SIMULATE(jalr, insn);
RISCV_INSN_SET_SIMULATE(auipc, insn);
- RISCV_INSN_SET_SIMULATE(branch, insn);
+ RISCV_INSN_SET_SIMULATE(beq, insn);
+ RISCV_INSN_SET_SIMULATE(bne, insn);
+ RISCV_INSN_SET_SIMULATE(blt, insn);
+ RISCV_INSN_SET_SIMULATE(bge, insn);
+ RISCV_INSN_SET_SIMULATE(bltu, insn);
+ RISCV_INSN_SET_SIMULATE(bgeu, insn);
return INSN_GOOD;
}
diff --git a/arch/riscv/kernel/probes/simulate-insn.c b/arch/riscv/kernel/probes/simulate-insn.c
index fa581590c1f8..a443883c3237 100644
--- a/arch/riscv/kernel/probes/simulate-insn.c
+++ b/arch/riscv/kernel/probes/simulate-insn.c
@@ -4,222 +4,152 @@
#include <linux/kernel.h>
#include <linux/kprobes.h>
-#include "decode-insn.h"
+#include <asm/insn.h>
#include "simulate-insn.h"
-static inline bool rv_insn_reg_get_val(struct pt_regs *regs, u32 index,
- unsigned long *ptr)
+bool __kprobes simulate_jal(u32 opcode, unsigned long addr, struct pt_regs *regs)
{
- if (index == 0)
- *ptr = 0;
- else if (index <= 31)
- *ptr = *((unsigned long *)regs + index);
- else
- return false;
+ s32 imm = riscv_insn_jal_extract_imm(opcode);
+ u32 index = riscv_insn_jal_extract_xd(opcode);
- return true;
-}
+ riscv_insn_reg_set_val((unsigned long *)regs, index, addr + 4);
-static inline bool rv_insn_reg_set_val(struct pt_regs *regs, u32 index,
- unsigned long val)
-{
- if (index == 0)
- return true;
- else if (index <= 31)
- *((unsigned long *)regs + index) = val;
- else
- return false;
+ instruction_pointer_set(regs, addr + imm);
return true;
}
-bool __kprobes simulate_jal(u32 opcode, unsigned long addr, struct pt_regs *regs)
+bool __kprobes simulate_jalr(u32 opcode, unsigned long addr, struct pt_regs *regs)
{
- /*
- * 31 30 21 20 19 12 11 7 6 0
- * imm [20] | imm[10:1] | imm[11] | imm[19:12] | rd | opcode
- * 1 10 1 8 5 JAL/J
- */
- bool ret;
- s32 imm;
- u32 index = RV_EXTRACT_RD_REG(opcode);
+ unsigned long base_addr;
+ s32 imm = riscv_insn_jalr_extract_imm(opcode);
+ u32 rd_index = riscv_insn_jalr_extract_xd(opcode);
+ u32 rs1_index = riscv_insn_jalr_extract_xs1(opcode);
- ret = rv_insn_reg_set_val(regs, index, addr + 4);
- if (!ret)
- return ret;
+ base_addr = riscv_insn_reg_get_val((unsigned long *)regs, rs1_index);
- imm = RV_EXTRACT_JTYPE_IMM(opcode);
+ riscv_insn_reg_set_val((unsigned long *)regs, rd_index, addr + 4);
- instruction_pointer_set(regs, addr + imm);
+ instruction_pointer_set(regs, (base_addr + imm) & ~1);
- return ret;
+ return true;
}
-bool __kprobes simulate_jalr(u32 opcode, unsigned long addr, struct pt_regs *regs)
+bool __kprobes simulate_auipc(u32 opcode, unsigned long addr, struct pt_regs *regs)
{
- /*
- * 31 20 19 15 14 12 11 7 6 0
- * offset[11:0] | rs1 | 010 | rd | opcode
- * 12 5 3 5 JALR/JR
- */
- bool ret;
- unsigned long base_addr;
- u32 imm = RV_EXTRACT_ITYPE_IMM(opcode);
- u32 rd_index = RV_EXTRACT_RD_REG(opcode);
- u32 rs1_index = RV_EXTRACT_RS1_REG(opcode);
+ u32 rd_index = riscv_insn_auipc_extract_xd(opcode);
+ unsigned long rd_val = addr + (s32)riscv_insn_auipc_extract_imm(opcode);
- ret = rv_insn_reg_get_val(regs, rs1_index, &base_addr);
- if (!ret)
- return ret;
+ riscv_insn_reg_set_val((unsigned long *)regs, rd_index, rd_val);
- ret = rv_insn_reg_set_val(regs, rd_index, addr + 4);
- if (!ret)
- return ret;
-
- instruction_pointer_set(regs, (base_addr + sign_extend32((imm), 11))&~1);
+ instruction_pointer_set(regs, addr + 4);
- return ret;
+ return true;
}
-bool __kprobes simulate_auipc(u32 opcode, unsigned long addr, struct pt_regs *regs)
+bool __kprobes simulate_beq(u32 opcode, unsigned long addr, struct pt_regs *regs)
{
- /*
- * auipc instruction:
- * 31 12 11 7 6 0
- * | imm[31:12] | rd | opcode |
- * 20 5 7
- */
+ unsigned long next_addr;
- u32 rd_idx = RV_EXTRACT_RD_REG(opcode);
- unsigned long rd_val = addr + (s32)RV_EXTRACT_UTYPE_IMM(opcode);
+ next_addr = riscv_insn_branch(beq, (unsigned long *)regs, opcode, addr, ==, unsigned long);
+ instruction_pointer_set(regs, next_addr);
- if (!rv_insn_reg_set_val(regs, rd_idx, rd_val))
- return false;
+ return true;
+}
- instruction_pointer_set(regs, addr + 4);
+bool __kprobes simulate_bne(u32 opcode, unsigned long addr, struct pt_regs *regs)
+{
+ unsigned long next_addr;
+
+ next_addr = riscv_insn_branch(bne, (unsigned long *)regs, opcode, addr, !=, unsigned long);
+ instruction_pointer_set(regs, next_addr);
return true;
}
-bool __kprobes simulate_branch(u32 opcode, unsigned long addr, struct pt_regs *regs)
+bool __kprobes simulate_blt(u32 opcode, unsigned long addr, struct pt_regs *regs)
{
- /*
- * branch instructions:
- * 31 30 25 24 20 19 15 14 12 11 8 7 6 0
- * | imm[12] | imm[10:5] | rs2 | rs1 | funct3 | imm[4:1] | imm[11] | opcode |
- * 1 6 5 5 3 4 1 7
- * imm[12|10:5] rs2 rs1 000 imm[4:1|11] 1100011 BEQ
- * imm[12|10:5] rs2 rs1 001 imm[4:1|11] 1100011 BNE
- * imm[12|10:5] rs2 rs1 100 imm[4:1|11] 1100011 BLT
- * imm[12|10:5] rs2 rs1 101 imm[4:1|11] 1100011 BGE
- * imm[12|10:5] rs2 rs1 110 imm[4:1|11] 1100011 BLTU
- * imm[12|10:5] rs2 rs1 111 imm[4:1|11] 1100011 BGEU
- */
-
- s32 offset;
- s32 offset_tmp;
- unsigned long rs1_val;
- unsigned long rs2_val;
-
- if (!rv_insn_reg_get_val(regs, RV_EXTRACT_RS1_REG(opcode), &rs1_val) ||
- !rv_insn_reg_get_val(regs, RV_EXTRACT_RS2_REG(opcode), &rs2_val))
- return false;
-
- offset_tmp = RV_EXTRACT_BTYPE_IMM(opcode);
- switch (RV_EXTRACT_FUNCT3(opcode)) {
- case RVG_FUNCT3_BEQ:
- offset = (rs1_val == rs2_val) ? offset_tmp : 4;
- break;
- case RVG_FUNCT3_BNE:
- offset = (rs1_val != rs2_val) ? offset_tmp : 4;
- break;
- case RVG_FUNCT3_BLT:
- offset = ((long)rs1_val < (long)rs2_val) ? offset_tmp : 4;
- break;
- case RVG_FUNCT3_BGE:
- offset = ((long)rs1_val >= (long)rs2_val) ? offset_tmp : 4;
- break;
- case RVG_FUNCT3_BLTU:
- offset = (rs1_val < rs2_val) ? offset_tmp : 4;
- break;
- case RVG_FUNCT3_BGEU:
- offset = (rs1_val >= rs2_val) ? offset_tmp : 4;
- break;
- default:
- return false;
- }
+ unsigned long next_addr;
- instruction_pointer_set(regs, addr + offset);
+ next_addr = riscv_insn_branch(blt, (unsigned long *)regs, opcode, addr, <, long);
+ instruction_pointer_set(regs, next_addr);
return true;
}
-bool __kprobes simulate_c_j(u32 opcode, unsigned long addr, struct pt_regs *regs)
+bool __kprobes simulate_bge(u32 opcode, unsigned long addr, struct pt_regs *regs)
{
- s32 offset = RVC_EXTRACT_JTYPE_IMM(opcode);
+ unsigned long next_addr;
- instruction_pointer_set(regs, addr + offset);
+ next_addr = riscv_insn_branch(bge, (unsigned long *)regs, opcode, addr, >=, long);
+ instruction_pointer_set(regs, next_addr);
return true;
}
-static bool __kprobes simulate_c_jr_jalr(u32 opcode, unsigned long addr, struct pt_regs *regs,
- bool is_jalr)
+bool __kprobes simulate_bltu(u32 opcode, unsigned long addr, struct pt_regs *regs)
{
- /*
- * 15 12 11 7 6 2 1 0
- * | funct4 | rs1 | rs2 | op |
- * 4 5 5 2
- */
+ unsigned long next_addr;
+
+ next_addr = riscv_insn_branch(bltu, (unsigned long *)regs, opcode, addr, <, unsigned long);
+ instruction_pointer_set(regs, next_addr);
- unsigned long jump_addr;
+ return true;
+}
- u32 rs1 = RVC_EXTRACT_C2_RS1_REG(opcode);
+bool __kprobes simulate_bgeu(u32 opcode, unsigned long addr, struct pt_regs *regs)
+{
+ unsigned long next_addr;
- if (rs1 == 0) /* C.JR is only valid when rs1 != x0 */
- return false;
+ next_addr = riscv_insn_branch(bgeu, (unsigned long *)regs, opcode, addr, >=, unsigned long);
+ instruction_pointer_set(regs, next_addr);
- if (!rv_insn_reg_get_val(regs, rs1, &jump_addr))
- return false;
+ return true;
+}
- if (is_jalr && !rv_insn_reg_set_val(regs, 1, addr + 2))
- return false;
+bool __kprobes simulate_c_j(u32 opcode, unsigned long addr, struct pt_regs *regs)
+{
+ s32 offset = riscv_insn_c_j_extract_imm(opcode);
- instruction_pointer_set(regs, jump_addr);
+ instruction_pointer_set(regs, addr + offset);
return true;
}
bool __kprobes simulate_c_jr(u32 opcode, unsigned long addr, struct pt_regs *regs)
{
- return simulate_c_jr_jalr(opcode, addr, regs, false);
+ unsigned long next_addr;
+ unsigned long *regs_ptr = (unsigned long *)regs;
+
+ /* xs1 == 0 is invalid so riscv_insn_reg_get_val() isn't needed */
+ next_addr = regs_ptr[riscv_insn_c_jr_extract_xs1(opcode)];
+ instruction_pointer_set(regs, next_addr);
+
+ return true;
}
bool __kprobes simulate_c_jalr(u32 opcode, unsigned long addr, struct pt_regs *regs)
{
- return simulate_c_jr_jalr(opcode, addr, regs, true);
+ unsigned long next_addr;
+ unsigned long *regs_ptr = (unsigned long *)regs;
+
+ /* xs1 == 0 is invalid so riscv_insn_reg_get_val() isn't needed */
+ next_addr = regs_ptr[riscv_insn_c_jalr_extract_xs1(opcode)];
+ instruction_pointer_set(regs, next_addr);
+
+ regs->ra = addr + 2;
+ return true;
}
-static bool __kprobes simulate_c_bnez_beqz(u32 opcode, unsigned long addr, struct pt_regs *regs,
- bool is_bnez)
+bool __kprobes simulate_c_bnez(u32 opcode, unsigned long addr, struct pt_regs *regs)
{
- /*
- * 15 13 12 10 9 7 6 2 1 0
- * | funct3 | offset[8|4:3] | rs1' | offset[7:6|2:1|5] | op |
- * 3 3 3 5 2
- */
-
- s32 offset;
u32 rs1;
- unsigned long rs1_val;
+ unsigned long offset;
+ unsigned long *regs_ptr = (unsigned long *)regs;
- rs1 = 0x8 | ((opcode >> 7) & 0x7);
-
- if (!rv_insn_reg_get_val(regs, rs1, &rs1_val))
- return false;
-
- if ((rs1_val != 0 && is_bnez) || (rs1_val == 0 && !is_bnez))
- offset = RVC_EXTRACT_BTYPE_IMM(opcode);
+ rs1 = riscv_insn_c_bnez_extract_xs1(opcode);
+ if (regs_ptr[8 + rs1] != 0)
+ offset = riscv_insn_c_bnez_extract_imm(opcode);
else
offset = 2;
@@ -228,12 +158,19 @@ static bool __kprobes simulate_c_bnez_beqz(u32 opcode, unsigned long addr, struc
return true;
}
-bool __kprobes simulate_c_bnez(u32 opcode, unsigned long addr, struct pt_regs *regs)
-{
- return simulate_c_bnez_beqz(opcode, addr, regs, true);
-}
-
bool __kprobes simulate_c_beqz(u32 opcode, unsigned long addr, struct pt_regs *regs)
{
- return simulate_c_bnez_beqz(opcode, addr, regs, false);
+ u32 rs1;
+ unsigned long offset;
+ unsigned long *regs_ptr = (unsigned long *)regs;
+
+ rs1 = riscv_insn_c_beqz_extract_xs1(opcode);
+ if (regs_ptr[8 + rs1] == 0)
+ offset = riscv_insn_c_beqz_extract_imm(opcode);
+ else
+ offset = 2;
+
+ instruction_pointer_set(regs, addr + offset);
+
+ return true;
}
diff --git a/arch/riscv/kernel/probes/simulate-insn.h b/arch/riscv/kernel/probes/simulate-insn.h
index 44ebbc444db9..f2f707e92dee 100644
--- a/arch/riscv/kernel/probes/simulate-insn.h
+++ b/arch/riscv/kernel/probes/simulate-insn.h
@@ -21,7 +21,12 @@
} while (0)
bool simulate_auipc(u32 opcode, unsigned long addr, struct pt_regs *regs);
-bool simulate_branch(u32 opcode, unsigned long addr, struct pt_regs *regs);
+bool simulate_beq(u32 opcode, unsigned long addr, struct pt_regs *regs);
+bool simulate_bne(u32 opcode, unsigned long addr, struct pt_regs *regs);
+bool simulate_blt(u32 opcode, unsigned long addr, struct pt_regs *regs);
+bool simulate_bge(u32 opcode, unsigned long addr, struct pt_regs *regs);
+bool simulate_bltu(u32 opcode, unsigned long addr, struct pt_regs *regs);
+bool simulate_bgeu(u32 opcode, unsigned long addr, struct pt_regs *regs);
bool simulate_jal(u32 opcode, unsigned long addr, struct pt_regs *regs);
bool simulate_jalr(u32 opcode, unsigned long addr, struct pt_regs *regs);
bool simulate_c_j(u32 opcode, unsigned long addr, struct pt_regs *regs);
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 06/16] riscv: cfi: Use generated instruction headers
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (4 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 05/16] riscv: kprobes: Use generated instruction headers Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:35 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 07/16] riscv: Use generated instruction headers for misaligned loads/stores Charlie Jenkins via B4 Relay
` (9 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Migrate the code that is decoding cfi instructions to use the generated
instruction headers.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
This function generates the same assembly as before.
---
arch/riscv/kernel/cfi.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/riscv/kernel/cfi.c b/arch/riscv/kernel/cfi.c
index 6ec9dbd7292e..e38d5f863747 100644
--- a/arch/riscv/kernel/cfi.c
+++ b/arch/riscv/kernel/cfi.c
@@ -40,16 +40,16 @@ static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target,
if (!riscv_insn_is_beq(insn))
return false;
- *type = (u32)regs_ptr[RV_EXTRACT_RS1_REG(insn)];
+ *type = (u32)regs_ptr[riscv_insn_beq_extract_xs1(insn)];
if (get_kernel_nofault(insn, (void *)regs->epc) ||
get_kernel_nofault(insn, (void *)regs->epc + GET_INSN_LENGTH(insn)))
return false;
if (riscv_insn_is_jalr(insn))
- rs1_num = RV_EXTRACT_RS1_REG(insn);
+ rs1_num = riscv_insn_jalr_extract_xs1(insn);
else if (riscv_insn_is_c_jalr(insn))
- rs1_num = RVC_EXTRACT_C2_RS1_REG(insn);
+ rs1_num = riscv_insn_c_jalr_extract_xs1(insn);
else
return false;
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 07/16] riscv: Use generated instruction headers for misaligned loads/stores
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (5 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 06/16] riscv: cfi: " Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:18 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 08/16] riscv: kvm: Use generated instruction headers for csr code Charlie Jenkins via B4 Relay
` (8 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Migrate the misaligned loads/store code to use the generated instruction
headers instead of the hand-written instruction composition functions.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
Similar to the other patches of this series, I extracted out the logic
of this function and brute forced all possible inputs to validate that
the outputs are the same. To verify this change in the kernel, I booted
on Spike and used the misaligned access checker which does some
misaligned accesses.
---
arch/riscv/kernel/traps_misaligned.c | 183 ++++++++++++++++-------------------
1 file changed, 83 insertions(+), 100 deletions(-)
diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
index 81b7682e6c6d..4d2a2432e0c4 100644
--- a/arch/riscv/kernel/traps_misaligned.c
+++ b/arch/riscv/kernel/traps_misaligned.c
@@ -22,15 +22,11 @@
#ifdef CONFIG_FPU
-#define FP_GET_RD(insn) (insn >> 7 & 0x1F)
-
extern void put_f32_reg(unsigned long fp_reg, unsigned long value);
-static int set_f32_rd(unsigned long insn, struct pt_regs *regs,
+static int set_f32_rd(unsigned long fp_reg, struct pt_regs *regs,
unsigned long val)
{
- unsigned long fp_reg = FP_GET_RD(insn);
-
put_f32_reg(fp_reg, val);
regs->status |= SR_FS_DIRTY;
@@ -39,9 +35,8 @@ static int set_f32_rd(unsigned long insn, struct pt_regs *regs,
extern void put_f64_reg(unsigned long fp_reg, unsigned long value);
-static int set_f64_rd(unsigned long insn, struct pt_regs *regs, u64 val)
+static int set_f64_rd(unsigned long fp_reg, struct pt_regs *regs, u64 val)
{
- unsigned long fp_reg = FP_GET_RD(insn);
unsigned long value;
#if __riscv_xlen == 32
@@ -58,10 +53,8 @@ static int set_f64_rd(unsigned long insn, struct pt_regs *regs, u64 val)
#if __riscv_xlen == 32
extern void get_f64_reg(unsigned long fp_reg, u64 *value);
-static u64 get_f64_rs(unsigned long insn, u8 fp_reg_offset,
- struct pt_regs *regs)
+static u64 get_f64_rs(unsigned long fp_reg, struct pt_regs *regs)
{
- unsigned long fp_reg = (insn >> fp_reg_offset) & 0x1F;
u64 val;
get_f64_reg(fp_reg, &val);
@@ -73,10 +66,8 @@ static u64 get_f64_rs(unsigned long insn, u8 fp_reg_offset,
extern unsigned long get_f64_reg(unsigned long fp_reg);
-static unsigned long get_f64_rs(unsigned long insn, u8 fp_reg_offset,
- struct pt_regs *regs)
+static unsigned long get_f64_rs(unsigned long fp_reg, struct pt_regs *regs)
{
- unsigned long fp_reg = (insn >> fp_reg_offset) & 0x1F;
unsigned long val;
val = get_f64_reg(fp_reg);
@@ -89,10 +80,8 @@ static unsigned long get_f64_rs(unsigned long insn, u8 fp_reg_offset,
extern unsigned long get_f32_reg(unsigned long fp_reg);
-static unsigned long get_f32_rs(unsigned long insn, u8 fp_reg_offset,
- struct pt_regs *regs)
+static unsigned long get_f32_rs(unsigned long fp_reg, struct pt_regs *regs)
{
- unsigned long fp_reg = (insn >> fp_reg_offset) & 0x1F;
unsigned long val;
val = get_f32_reg(fp_reg);
@@ -107,28 +96,18 @@ static void set_f32_rd(unsigned long insn, struct pt_regs *regs,
static void set_f64_rd(unsigned long insn, struct pt_regs *regs, u64 val) {}
-static unsigned long get_f64_rs(unsigned long insn, u8 fp_reg_offset,
- struct pt_regs *regs)
+static unsigned long get_f64_rs(unsigned long fp_reg, struct pt_regs *regs)
{
return 0;
}
-static unsigned long get_f32_rs(unsigned long insn, u8 fp_reg_offset,
- struct pt_regs *regs)
+static unsigned long get_f32_rs(unsigned long fp_reg, struct pt_regs *regs)
{
return 0;
}
#endif
-#define GET_F64_RS2(insn, regs) (get_f64_rs(insn, 20, regs))
-#define GET_F64_RS2C(insn, regs) (get_f64_rs(insn, 2, regs))
-#define GET_F64_RS2S(insn, regs) (get_f64_rs(RVC_RS2S(insn), 0, regs))
-
-#define GET_F32_RS2(insn, regs) (get_f32_rs(insn, 20, regs))
-#define GET_F32_RS2C(insn, regs) (get_f32_rs(insn, 2, regs))
-#define GET_F32_RS2S(insn, regs) (get_f32_rs(RVC_RS2S(insn), 0, regs))
-
#define __read_insn(regs, insn, insn_addr, type) \
({ \
int __ret; \
@@ -217,13 +196,13 @@ static int handle_vector_misaligned_load(struct pt_regs *regs)
}
#endif
-static int handle_scalar_misaligned_load(struct pt_regs *regs)
+static noinline int handle_scalar_misaligned_load(struct pt_regs *regs)
{
union reg_data val;
unsigned long epc = regs->epc;
unsigned long insn;
unsigned long addr = regs->badaddr;
- int fp = 0, shift = 0, len = 0;
+ int fp = 0, shift = 0, len = 0, rd = 0;
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
@@ -240,68 +219,71 @@ static int handle_scalar_misaligned_load(struct pt_regs *regs)
regs->epc = 0;
- if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
+ if (riscv_insn_is_lw(insn)) {
len = 4;
shift = 8 * (sizeof(unsigned long) - len);
-#if defined(CONFIG_64BIT)
- } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
+ rd = riscv_insn_lw_extract_xd(insn);
+ } else if (riscv_insn_is_ld(insn)) {
len = 8;
shift = 8 * (sizeof(unsigned long) - len);
- } else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
+ rd = riscv_insn_ld_extract_xd(insn);
+ } else if (riscv_insn_is_lwu(insn)) {
len = 4;
-#endif
- } else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) {
+ rd = riscv_insn_lwu_extract_xd(insn);
+ } else if (riscv_insn_is_fld(insn)) {
fp = 1;
len = 8;
- } else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) {
+ rd = riscv_insn_fld_extract_fd(insn);
+ } else if (riscv_insn_is_flw(insn)) {
fp = 1;
len = 4;
- } else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
+ rd = riscv_insn_flw_extract_fd(insn);
+ } else if (riscv_insn_is_lh(insn)) {
len = 2;
shift = 8 * (sizeof(unsigned long) - len);
- } else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
+ rd = riscv_insn_lh_extract_xd(insn);
+ } else if (riscv_insn_is_lhu(insn)) {
len = 2;
-#if defined(CONFIG_64BIT)
- } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
+ rd = riscv_insn_lhu_extract_xd(insn);
+ } else if (riscv_insn_is_c_ld(insn)) {
len = 8;
shift = 8 * (sizeof(unsigned long) - len);
- insn = RVC_RS2S(insn) << SH_RD;
- } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP &&
- ((insn >> SH_RD) & 0x1f)) {
+ rd = (8 + riscv_insn_c_ld_extract_xd(insn));
+ } else if (riscv_insn_is_c_ldsp(insn)) {
len = 8;
shift = 8 * (sizeof(unsigned long) - len);
-#endif
- } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
+ rd = riscv_insn_c_ldsp_extract_xd(insn);
+ } else if (riscv_insn_is_c_lw(insn)) {
len = 4;
shift = 8 * (sizeof(unsigned long) - len);
- insn = RVC_RS2S(insn) << SH_RD;
- } else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP &&
- ((insn >> SH_RD) & 0x1f)) {
+ rd = (8 + riscv_insn_c_lw_extract_xd(insn));
+ } else if (riscv_insn_is_c_lwsp(insn)) {
len = 4;
shift = 8 * (sizeof(unsigned long) - len);
- } else if ((insn & INSN_MASK_C_FLD) == INSN_MATCH_C_FLD) {
+ rd = riscv_insn_c_lwsp_extract_xd(insn);
+ } else if (riscv_insn_is_c_fld(insn)) {
fp = 1;
len = 8;
- insn = RVC_RS2S(insn) << SH_RD;
- } else if ((insn & INSN_MASK_C_FLDSP) == INSN_MATCH_C_FLDSP) {
+ rd = (8 + riscv_insn_c_fld_extract_fd(insn));
+ } else if (riscv_insn_is_c_fldsp(insn)) {
fp = 1;
len = 8;
-#if defined(CONFIG_32BIT)
- } else if ((insn & INSN_MASK_C_FLW) == INSN_MATCH_C_FLW) {
+ rd = riscv_insn_c_fldsp_extract_fd(insn);
+ } else if (riscv_insn_is_c_flw(insn)) {
fp = 1;
len = 4;
- insn = RVC_RS2S(insn) << SH_RD;
- } else if ((insn & INSN_MASK_C_FLWSP) == INSN_MATCH_C_FLWSP) {
+ rd = (8 + riscv_insn_c_flw_extract_fd(insn));
+ } else if (riscv_insn_is_c_flwsp(insn)) {
fp = 1;
len = 4;
-#endif
- } else if ((insn & INSN_MASK_C_LHU) == INSN_MATCH_C_LHU) {
+ rd = riscv_insn_c_flwsp_extract_fd(insn);
+ } else if (riscv_insn_is_c_lhu(insn)) {
len = 2;
- insn = RVC_RS2S(insn) << SH_RD;
- } else if ((insn & INSN_MASK_C_LH) == INSN_MATCH_C_LH) {
+ rd = (8 + riscv_insn_c_lhu_extract_xd(insn));
+ } else if (riscv_insn_is_c_lh(insn)) {
len = 2;
- shift = 8 * (sizeof(ulong) - len);
- insn = RVC_RS2S(insn) << SH_RD;
+ shift = 8 * (sizeof(unsigned long) - len);
+ rd = (8 + riscv_insn_c_lh_extract_xd(insn));
} else {
regs->epc = epc;
return -1;
@@ -319,11 +301,11 @@ static int handle_scalar_misaligned_load(struct pt_regs *regs)
}
if (!fp)
- SET_RD(insn, regs, (long)(val.data_ulong << shift) >> shift);
+ *(unsigned long *)((unsigned long *)regs + rd) = val.data_ulong << shift;
else if (len == 8)
- set_f64_rd(insn, regs, val.data_u64);
+ set_f64_rd(rd, regs, val.data_u64);
else
- set_f32_rd(insn, regs, val.data_ulong);
+ set_f32_rd(rd, regs, val.data_ulong);
regs->epc = epc + INSN_LEN(insn);
@@ -336,7 +318,7 @@ static int handle_scalar_misaligned_store(struct pt_regs *regs)
unsigned long epc = regs->epc;
unsigned long insn;
unsigned long addr = regs->badaddr;
- int len = 0, fp = 0;
+ int fp = 0, len = 0, rd = 0;
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, addr);
@@ -351,67 +333,68 @@ static int handle_scalar_misaligned_store(struct pt_regs *regs)
regs->epc = 0;
- val.data_ulong = GET_RS2(insn, regs);
-
- if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
+ if (riscv_insn_is_sw(insn)) {
len = 4;
-#if defined(CONFIG_64BIT)
- } else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
+ rd = riscv_insn_sw_extract_xs2(insn);
+ } else if (riscv_insn_is_sd(insn)) {
len = 8;
-#endif
- } else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) {
+ rd = riscv_insn_sd_extract_xs2(insn);
+ } else if (riscv_insn_is_fsd(insn)) {
fp = 1;
len = 8;
- val.data_u64 = GET_F64_RS2(insn, regs);
- } else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) {
+ rd = riscv_insn_fsd_extract_fs2(insn);
+ } else if (riscv_insn_is_fsw(insn)) {
fp = 1;
len = 4;
- val.data_ulong = GET_F32_RS2(insn, regs);
- } else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
+ rd = riscv_insn_fsw_extract_fs2(insn);
+ } else if (riscv_insn_is_sh(insn)) {
len = 2;
-#if defined(CONFIG_64BIT)
- } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
+ rd = riscv_insn_sh_extract_xs2(insn);
+ } else if (riscv_insn_is_c_sd(insn)) {
len = 8;
- val.data_ulong = GET_RS2S(insn, regs);
- } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP) {
+ rd = riscv_insn_c_sd_extract_xs2(insn);
+ } else if (riscv_insn_is_c_sdsp(insn)) {
len = 8;
- val.data_ulong = GET_RS2C(insn, regs);
-#endif
- } else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
+ rd = riscv_insn_c_sdsp_extract_xs2(insn);
+ } else if (riscv_insn_is_c_sw(insn)) {
len = 4;
- val.data_ulong = GET_RS2S(insn, regs);
- } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP) {
+ rd = riscv_insn_c_sw_extract_xs2(insn);
+ } else if (riscv_insn_is_c_swsp(insn)) {
len = 4;
- val.data_ulong = GET_RS2C(insn, regs);
- } else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) {
+ rd = riscv_insn_c_swsp_extract_xs2(insn);
+ } else if (riscv_insn_is_c_fsd(insn)) {
fp = 1;
len = 8;
- val.data_u64 = GET_F64_RS2S(insn, regs);
- } else if ((insn & INSN_MASK_C_FSDSP) == INSN_MATCH_C_FSDSP) {
+ rd = riscv_insn_c_fsd_extract_fs2(insn);
+ } else if (riscv_insn_is_c_fsdsp(insn)) {
fp = 1;
len = 8;
- val.data_u64 = GET_F64_RS2C(insn, regs);
-#if !defined(CONFIG_64BIT)
- } else if ((insn & INSN_MASK_C_FSW) == INSN_MATCH_C_FSW) {
+ rd = riscv_insn_c_fsdsp_extract_fs2(insn);
+ } else if (riscv_insn_is_c_fsw(insn)) {
fp = 1;
len = 4;
- val.data_ulong = GET_F32_RS2S(insn, regs);
- } else if ((insn & INSN_MASK_C_FSWSP) == INSN_MATCH_C_FSWSP) {
+ rd = riscv_insn_c_fsw_extract_fs2(insn);
+ } else if (riscv_insn_is_c_fswsp(insn)) {
fp = 1;
len = 4;
- val.data_ulong = GET_F32_RS2C(insn, regs);
-#endif
- } else if ((insn & INSN_MASK_C_SH) == INSN_MATCH_C_SH) {
+ rd = riscv_insn_c_fswsp_extract_fs2(insn);
+ } else if (riscv_insn_is_c_sh(insn)) {
len = 2;
- val.data_ulong = GET_RS2S(insn, regs);
+ rd = riscv_insn_c_sh_extract_xs2(insn);
} else {
- regs->epc = epc;
return -1;
}
if (!IS_ENABLED(CONFIG_FPU) && fp)
return -EOPNOTSUPP;
+ if (!fp)
+ val.data_ulong = *(unsigned long *)((unsigned long *)regs + rd);
+ else if (len == 8)
+ val.data_u64 = get_f64_rs(rd, regs);
+ else
+ val.data_ulong = get_f32_rs(rd, regs);
+
if (user_mode(regs)) {
if (copy_to_user((u8 __user *)addr, &val, len))
return -1;
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 08/16] riscv: kvm: Use generated instruction headers for csr code
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (6 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 07/16] riscv: Use generated instruction headers for misaligned loads/stores Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:18 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 09/16] KVM: device: Add test device Charlie Jenkins via B4 Relay
` (7 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Migrate the csr parsing code to use the generated instruction headers
instead of the hand-written instruction composition functions.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
This is a simple transformation that I have again validated through
brute force.
---
arch/riscv/kvm/vcpu_insn.c | 47 +++++++++++++++++++++++-----------------------
1 file changed, 24 insertions(+), 23 deletions(-)
diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c
index f09f9251d1f0..8ccf6ec722f0 100644
--- a/arch/riscv/kvm/vcpu_insn.c
+++ b/arch/riscv/kvm/vcpu_insn.c
@@ -146,43 +146,44 @@ int kvm_riscv_vcpu_csr_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
static int csr_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn)
{
+ #define GET_REG(_rd) (*((unsigned long *)(&vcpu->arch.guest_context) + _rd))
+
int i, rc = KVM_INSN_ILLEGAL_TRAP;
- unsigned int csr_num = insn >> SH_RS2;
- unsigned int rs1_num = (insn >> SH_RS1) & MASK_RX;
- ulong rs1_val = GET_RS1(insn, &vcpu->arch.guest_context);
+ unsigned int csr_num;
const struct csr_func *tcfn, *cfn = NULL;
ulong val = 0, wr_mask = 0, new_val = 0;
/* Decode the CSR instruction */
- switch (GET_FUNCT3(insn)) {
- case GET_FUNCT3(INSN_MATCH_CSRRW):
+ if (riscv_insn_is_csrrw(insn)) {
wr_mask = -1UL;
- new_val = rs1_val;
- break;
- case GET_FUNCT3(INSN_MATCH_CSRRS):
- wr_mask = rs1_val;
+ new_val = GET_REG(riscv_insn_csrrw_extract_xs1(insn));
+ csr_num = riscv_insn_csrrw_extract_csr(insn);
+ } else if (riscv_insn_is_csrrs(insn)) {
+ wr_mask = GET_REG(riscv_insn_csrrs_extract_xs1(insn));
new_val = -1UL;
- break;
- case GET_FUNCT3(INSN_MATCH_CSRRC):
- wr_mask = rs1_val;
+ csr_num = riscv_insn_csrrs_extract_csr(insn);
+ } else if (riscv_insn_is_csrrc(insn)) {
+ wr_mask = GET_REG(riscv_insn_csrrs_extract_xs1(insn));
new_val = 0;
- break;
- case GET_FUNCT3(INSN_MATCH_CSRRWI):
+ csr_num = riscv_insn_csrrc_extract_csr(insn);
+ } else if (riscv_insn_is_csrrwi(insn)) {
wr_mask = -1UL;
- new_val = rs1_num;
- break;
- case GET_FUNCT3(INSN_MATCH_CSRRSI):
- wr_mask = rs1_num;
+ new_val = riscv_insn_csrrwi_extract_imm(insn);
+ csr_num = riscv_insn_csrrwi_extract_csr(insn);
+ } else if (riscv_insn_is_csrrsi(insn)) {
+ wr_mask = riscv_insn_csrrwi_extract_imm(insn);
new_val = -1UL;
- break;
- case GET_FUNCT3(INSN_MATCH_CSRRCI):
- wr_mask = rs1_num;
+ csr_num = riscv_insn_csrrsi_extract_csr(insn);
+ } else if (riscv_insn_is_csrrci(insn)) {
+ wr_mask = GET_REG(riscv_insn_csrrwi_extract_imm(insn));
new_val = 0;
- break;
- default:
+ csr_num = riscv_insn_csrrwi_extract_csr(insn);
+ } else {
return rc;
}
+ #undef GET_REG
+
/* Save instruction decode info */
vcpu->arch.csr_decode.insn = insn;
vcpu->arch.csr_decode.return_handled = 0;
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 09/16] KVM: device: Add test device
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (7 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 08/16] riscv: kvm: Use generated instruction headers for csr code Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:13 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 10/16] KVM: riscv: selftests: Add mmio test Charlie Jenkins via B4 Relay
` (6 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Create a KVM test device to help verify mmio reads and write emulation.
This is a simple device that will store the data in a buffer on writes
and echo back that stored data on a read.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
include/uapi/linux/kvm.h | 2 +
lib/Kconfig.debug | 6 +++
virt/kvm/Kconfig.debug | 16 ++++++++
virt/kvm/Makefile.kvm | 1 +
virt/kvm/kvm_main.c | 8 ++++
virt/kvm/mmio_test.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++
virt/kvm/mmio_test.h | 18 +++++++++
7 files changed, 146 insertions(+)
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 6c8afa2047bf..abbbf74627a2 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1235,6 +1235,8 @@ enum kvm_device_type {
#define KVM_DEV_TYPE_LOONGARCH_DMSINTC KVM_DEV_TYPE_LOONGARCH_DMSINTC
KVM_DEV_TYPE_ARM_VGIC_V5,
#define KVM_DEV_TYPE_ARM_VGIC_V5 KVM_DEV_TYPE_ARM_VGIC_V5
+ KVM_DEV_TYPE_TEST,
+#define KVM_DEV_TYPE_TEST KVM_DEV_TYPE_TEST
KVM_DEV_TYPE_MAX,
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 8ff5adcfe1e0..0d235bdc94ec 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -754,6 +754,12 @@ source "net/Kconfig.debug"
endmenu # "Networking Debugging"
+menu "KVM Debugging"
+
+source "virt/kvm/Kconfig.debug"
+
+endmenu # "KVM Debugging"
+
menu "Memory Debugging"
source "mm/Kconfig.debug"
diff --git a/virt/kvm/Kconfig.debug b/virt/kvm/Kconfig.debug
new file mode 100644
index 000000000000..d24709f5bcbf
--- /dev/null
+++ b/virt/kvm/Kconfig.debug
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config KVM_MMIO_TEST
+ bool "Enable kvm mmio testing"
+ depends on KVM
+ depends on KVM_MMIO
+ default n
+ help
+ Enable testing for kvm mmio. This is a test-only mmio device that
+ stores writes in a buffer and returns the buffered data on a read.
+
+ This is useful for testing the kvm mmio emulation code. Enabling
+ this does not run any tests, just builds in the support for the test
+ device into the kernel.
+
+ If unsure, say N.
diff --git a/virt/kvm/Makefile.kvm b/virt/kvm/Makefile.kvm
index d047d4cf58c9..bd4da8c23923 100644
--- a/virt/kvm/Makefile.kvm
+++ b/virt/kvm/Makefile.kvm
@@ -8,6 +8,7 @@ KVM ?= ../../../virt/kvm
kvm-y := $(KVM)/kvm_main.o $(KVM)/eventfd.o $(KVM)/binary_stats.o
kvm-$(CONFIG_KVM_VFIO) += $(KVM)/vfio.o
kvm-$(CONFIG_KVM_MMIO) += $(KVM)/coalesced_mmio.o
+kvm-$(CONFIG_KVM_MMIO_TEST) += $(KVM)/mmio_test.o
kvm-$(CONFIG_KVM_ASYNC_PF) += $(KVM)/async_pf.o
kvm-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(KVM)/irqchip.o
kvm-$(CONFIG_HAVE_KVM_DIRTY_RING) += $(KVM)/dirty_ring.o
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 881f92d7a469..d9bbe570eddd 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -58,6 +58,7 @@
#include "async_pf.h"
#include "kvm_mm.h"
#include "vfio.h"
+#include "mmio_test.h"
#include <trace/events/ipi.h>
@@ -6532,6 +6533,10 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
if (WARN_ON_ONCE(r))
goto err_vfio;
+ r = kvm_mmio_test_ops_init();
+ if (WARN_ON_ONCE(r))
+ goto err_mmio_test;
+
r = kvm_gmem_init(module);
if (r)
goto err_gmem;
@@ -6559,6 +6564,8 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
err_gmem:
kvm_vfio_ops_exit();
err_vfio:
+ kvm_mmio_test_ops_exit();
+err_mmio_test:
kvm_async_pf_deinit();
err_async_pf:
kvm_irqfd_exit();
@@ -6589,6 +6596,7 @@ void kvm_exit(void)
free_cpumask_var(per_cpu(cpu_kick_mask, cpu));
kmem_cache_destroy(kvm_vcpu_cache);
kvm_gmem_exit();
+ kvm_mmio_test_ops_exit();
kvm_vfio_ops_exit();
kvm_async_pf_deinit();
kvm_irqfd_exit();
diff --git a/virt/kvm/mmio_test.c b/virt/kvm/mmio_test.c
new file mode 100644
index 000000000000..fa84c2b4c5fc
--- /dev/null
+++ b/virt/kvm/mmio_test.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * mmio_test.c - Kernel module side for testing the KVM riscv mmio functionality.
+ */
+
+#include <linux/kvm_host.h>
+
+#include <kvm/iodev.h>
+#include "mmio_test.h"
+
+struct mmio_test {
+ struct kvm *kvm;
+ struct kvm_io_device dev;
+ unsigned long start;
+ unsigned long size;
+ char cache[16];
+};
+
+static struct mmio_test *kvm_to_mmio_test_dev(const struct kvm_io_device *dev)
+{
+ return container_of(dev, struct mmio_test, dev);
+}
+
+static int mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ struct mmio_test *mmio_test = kvm_to_mmio_test_dev(dev);
+
+ if ((addr - mmio_test->start) >= mmio_test->size)
+ return -1;
+
+ /* Write back cached value */
+ memcpy(val, &mmio_test->cache[(addr - mmio_test->start)], len);
+ return 0;
+}
+
+static int mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ struct mmio_test *mmio_test = kvm_to_mmio_test_dev(dev);
+
+ if ((addr - mmio_test->start) >= mmio_test->size)
+ return -1;
+
+ /* Cache value */
+ memcpy(&mmio_test->cache[(addr - mmio_test->start)], val, len);
+ return 0;
+}
+
+static const struct kvm_io_device_ops mmio_ops = {
+ .read = mmio_read,
+ .write = mmio_write,
+};
+
+static int mmio_test_create(struct kvm_device *dev, u32 type)
+{
+ struct mmio_test *mmio_test;
+
+ mmio_test = kzalloc(sizeof(*mmio_test), GFP_KERNEL);
+ if (!mmio_test)
+ return -ENOMEM;
+
+ mmio_test->start = 0x20000000;
+ mmio_test->size = 0x16;
+
+ dev->private = mmio_test;
+
+ kvm_iodevice_init(&mmio_test->dev, &mmio_ops);
+ kvm_io_bus_register_dev(dev->kvm, KVM_MMIO_BUS, mmio_test->start,
+ mmio_test->size, &mmio_test->dev);
+
+ return 0;
+}
+
+static void mmio_test_release(struct kvm_device *dev)
+{
+ kfree(dev->private);
+}
+
+struct kvm_device_ops kvm_riscv_mmio_test_device_ops = {
+ .name = "kvm-riscv-mmio_test",
+ .create = mmio_test_create,
+ .release = mmio_test_release,
+};
+
+int kvm_mmio_test_ops_init(void)
+{
+ return kvm_register_device_ops(&kvm_riscv_mmio_test_device_ops,
+ KVM_DEV_TYPE_TEST);
+}
+
+void kvm_mmio_test_ops_exit(void)
+{
+ kvm_unregister_device_ops(KVM_DEV_TYPE_TEST);
+}
diff --git a/virt/kvm/mmio_test.h b/virt/kvm/mmio_test.h
new file mode 100644
index 000000000000..49a6e900eec9
--- /dev/null
+++ b/virt/kvm/mmio_test.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KVM_MMIO_TEST_H
+#define __KVM_MMIO_TEST_H
+
+#ifdef CONFIG_KVM_MMIO_TEST
+int kvm_mmio_test_ops_init(void);
+void kvm_mmio_test_ops_exit(void);
+#else
+static inline int kvm_mmio_test_ops_init(void)
+{
+ return 0;
+}
+static inline void kvm_mmio_test_ops_exit(void)
+{
+}
+#endif
+
+#endif
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 10/16] KVM: riscv: selftests: Add mmio test
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (8 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 09/16] KVM: device: Add test device Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:18 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 11/16] riscv: kvm: Use generated instruction headers for mmio emulation Charlie Jenkins via B4 Relay
` (5 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Use the test KVM device to validate that reads and writes to a device
are properly emulated by KVM. This test checks all load and store
instructions that are emulated by KVM.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
tools/testing/selftests/kvm/Makefile.kvm | 1 +
tools/testing/selftests/kvm/riscv/mmio_test.c | 184 ++++++++++++++++++++++++++
2 files changed, 185 insertions(+)
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 9118a5a51b89..07a5fc2bf67c 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -214,6 +214,7 @@ TEST_GEN_PROGS_s390 += mmu_stress_test
TEST_GEN_PROGS_riscv = $(TEST_GEN_PROGS_COMMON)
TEST_GEN_PROGS_riscv += riscv/sbi_pmu_test
TEST_GEN_PROGS_riscv += riscv/ebreak_test
+TEST_GEN_PROGS_riscv += riscv/mmio_test
TEST_GEN_PROGS_riscv += access_tracking_perf_test
TEST_GEN_PROGS_riscv += arch_timer
TEST_GEN_PROGS_riscv += coalesced_io_test
diff --git a/tools/testing/selftests/kvm/riscv/mmio_test.c b/tools/testing/selftests/kvm/riscv/mmio_test.c
new file mode 100644
index 000000000000..9726860a269a
--- /dev/null
+++ b/tools/testing/selftests/kvm/riscv/mmio_test.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * mmio_test.c - Tests the mmio functionality.
+ */
+#include "kvm_util.h"
+#include "ucall_common.h"
+
+#define MMIO_TEST_REGION 0x20000000
+
+#define test_standard_read(len, instruction, name, options) \
+static void test_##name(void) \
+{ \
+ unsigned long mmio_result, reference_result; \
+ /* Configure the MMIO to return 0xff for each byte to check sign extension */ \
+ unsigned long reference = ((unsigned long)-1 >> ((sizeof(long) - len) * 8)); \
+ *((unsigned long *)MMIO_TEST_REGION) = reference; \
+ /* Check that reads through MMIO are equivalent to standard reads. */ \
+ asm volatile ( \
+ ".option push\n" \
+ options \
+ #instruction " %[mmio_res], 0(%[region])\n" \
+ #instruction " %[ref_res], 0(%[ref])\n" \
+ ".option pop\n" \
+ : [mmio_res] "=&cr" (mmio_result), [ref_res] "=&cr" (reference_result) \
+ : [region] "cr" (MMIO_TEST_REGION), [ref] "cr" (&reference) \
+ ); \
+ GUEST_ASSERT_EQ(mmio_result, reference_result); \
+ GUEST_DONE(); \
+}
+
+#define test_sp_read(len, instruction, name) \
+static void test_##name(void) \
+{ \
+ unsigned long mmio_result, reference_result; \
+ unsigned long tmp; \
+ /* Configure the MMIO to return 0xff for each byte to check sign extension */ \
+ unsigned long reference = ((unsigned long)-1 >> ((sizeof(long) - len) * 8)); \
+ *(((unsigned long *)MMIO_TEST_REGION)) = reference; \
+ /* Check that reads through MMIO are equivalent to standard reads. */ \
+ asm volatile ( \
+ "mv %[tmp], sp\n" \
+ "mv sp, %[region]\n" \
+ ".option push\n" \
+ ".option arch,+c\n" \
+ #instruction " %[mmio_res], 0(sp)\n" \
+ "mv sp, %[ref]\n" \
+ #instruction " %[ref_res], 0(sp)\n" \
+ ".option pop\n" \
+ "mv sp, %[tmp]\n" \
+ : [mmio_res] "=&cr" (mmio_result), [ref_res] "=&cr" (reference_result), \
+ [tmp] "=&r" (tmp) \
+ : [region] "r" (MMIO_TEST_REGION), [ref] "cr" (&reference) \
+ ); \
+ GUEST_ASSERT_EQ(mmio_result, reference_result); \
+ GUEST_DONE(); \
+}
+
+test_standard_read(1, lb, lb, "")
+test_standard_read(1, lbu, lbu, "")
+test_standard_read(4, lw, lw, "")
+test_standard_read(4, c.lw, c_lw, ".option arch,+c\n")
+test_sp_read(4, c.lwsp, c_lwsp)
+
+#if __riscv_xlen == 64
+test_standard_read(2, lh, lh, "")
+test_standard_read(2, lhu, lhu, "")
+test_standard_read(4, lwu, lwu, "")
+test_standard_read(8, ld, ld, "")
+test_standard_read(8, c.ld, c_ld, ".option arch,+c\n")
+test_sp_read(8, c.ldsp, c_ldsp)
+#endif
+
+#define test_standard_write(len, write, read, name, options) \
+static void test_##name(void) \
+{ \
+ unsigned long result; \
+ unsigned long reference = (0x55555555UL >> ((sizeof(long) - len) * 8)); \
+ /* Check that we can write and then read the same value. */ \
+ asm volatile ( \
+ ".option push\n" \
+ options \
+ #write " %[ref], 0(%[region])\n" \
+ #read " %[res], 0(%[region])\n" \
+ ".option pop\n" \
+ : [res] "=&cr" (result) \
+ : [region] "cr" (MMIO_TEST_REGION), [ref] "cr" (reference) \
+ ); \
+ GUEST_ASSERT_EQ(result, reference); \
+ GUEST_DONE(); \
+}
+
+#define test_sp_write(len, write, read, name) \
+static void test_##name(void) \
+{ \
+ unsigned long result; \
+ unsigned long tmp; \
+ unsigned long reference = (0x55555555UL >> ((sizeof(long) - len) * 8)); \
+ /* Check that we can write and then read the same value. */ \
+ asm volatile ( \
+ "mv %[tmp], sp\n" \
+ "mv sp, %[region]\n" \
+ ".option push\n" \
+ ".option arch,+c\n" \
+ #write " %[ref], 0(sp)\n" \
+ #read " %[res], 0(sp)\n" \
+ ".option pop\n" \
+ "mv sp, %[tmp]\n" \
+ : [res] "=&cr" (result), [tmp] "=&r" (tmp) \
+ : [region] "cr" (MMIO_TEST_REGION), [ref] "cr" (reference) \
+ ); \
+ GUEST_ASSERT_EQ(result, reference); \
+ GUEST_DONE(); \
+}
+
+test_standard_write(1, sb, lb, sb, "")
+test_standard_write(2, sh, lh, sh, "")
+test_standard_write(4, sw, lw, sw, "")
+test_standard_write(4, c.sw, c.lw, c_sw, ".option arch,+c\n")
+test_sp_write(4, c.swsp, c.lwsp, c_swsp)
+
+#if __riscv_xlen == 64
+test_standard_write(8, sd, ld, sd, "")
+test_standard_write(8, c.sd, c.ld, c_sd, ".option arch,+c\n")
+#endif
+
+static void run(void *guest_code, char *instruction)
+{
+ struct ucall uc;
+ struct kvm_vm *vm;
+ struct kvm_vcpu *vcpu;
+
+ vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+ kvm_create_device(vm, KVM_DEV_TYPE_TEST);
+
+ virt_map(vm, (unsigned long)MMIO_TEST_REGION, MMIO_TEST_REGION, 1);
+
+ vcpu_run(vcpu);
+
+ TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_DONE,
+ "MMIO with instruction '%s' failed: '%s'", instruction,
+ uc.buffer);
+
+ kvm_vm_free(vm);
+}
+
+void test_mmio_read_sign_extension(void)
+{
+ run(test_lb, "lb");
+ run(test_lbu, "lbu");
+ run(test_lw, "lw");
+ run(test_c_lw, "c.lw");
+ run(test_c_lwsp, "c.lwsp");
+
+#if __riscv_xlen == 64
+ run(test_lh, "lh");
+ run(test_lhu, "lhu");
+ run(test_lwu, "lwu");
+ run(test_ld, "ld");
+ run(test_c_ld, "c.ld");
+ run(test_c_ldsp, "c.ldsp");
+#endif
+}
+
+void test_mmio_write(void)
+{
+ run(test_sb, "sb");
+ run(test_sh, "sh");
+ run(test_sw, "sw");
+ run(test_c_sw, "c.sw");
+ run(test_c_swsp, "c.swsp");
+
+#if __riscv_xlen == 64
+ run(test_sd, "sd");
+ run(test_c_sd, "c.sd");
+#endif
+}
+
+int main(void)
+{
+ test_mmio_read_sign_extension();
+ test_mmio_write();
+
+ return 0;
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 11/16] riscv: kvm: Use generated instruction headers for mmio emulation
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (9 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 10/16] KVM: riscv: selftests: Add mmio test Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:27 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 12/16] riscv: kvm: Add emulated test csr Charlie Jenkins via B4 Relay
` (4 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Migrate the mmio emulation code to use the generated instruction headers
instead of the hand-written instruction composition functions.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
arch/riscv/include/asm/kvm_vcpu_insn.h | 2 +-
arch/riscv/kvm/vcpu_insn.c | 127 ++++++++++++++-------------------
2 files changed, 55 insertions(+), 74 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_vcpu_insn.h b/arch/riscv/include/asm/kvm_vcpu_insn.h
index 350011c83581..106fb4c45108 100644
--- a/arch/riscv/include/asm/kvm_vcpu_insn.h
+++ b/arch/riscv/include/asm/kvm_vcpu_insn.h
@@ -11,7 +11,7 @@ struct kvm_run;
struct kvm_cpu_trap;
struct kvm_mmio_decode {
- unsigned long insn;
+ unsigned long rd;
int insn_len;
int len;
int shift;
diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c
index 8ccf6ec722f0..1d8741d02242 100644
--- a/arch/riscv/kvm/vcpu_insn.c
+++ b/arch/riscv/kvm/vcpu_insn.c
@@ -376,7 +376,7 @@ int kvm_riscv_vcpu_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run,
unsigned long htinst)
{
u8 data_buf[8];
- unsigned long insn;
+ unsigned long insn, rd;
int shift = 0, len = 0, insn_len = 0;
struct kvm_cpu_trap utrap = { 0 };
struct kvm_cpu_context *ct = &vcpu->arch.guest_context;
@@ -408,44 +408,47 @@ int kvm_riscv_vcpu_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run,
}
/* Decode length of MMIO and shift */
- if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
+ if (riscv_insn_is_lw(insn)) {
len = 4;
shift = 8 * (sizeof(ulong) - len);
- } else if ((insn & INSN_MASK_LB) == INSN_MATCH_LB) {
+ rd = riscv_insn_lw_extract_xd(insn);
+ } else if (riscv_insn_is_lb(insn)) {
len = 1;
shift = 8 * (sizeof(ulong) - len);
- } else if ((insn & INSN_MASK_LBU) == INSN_MATCH_LBU) {
+ rd = riscv_insn_lb_extract_xd(insn);
+ } else if (riscv_insn_is_lbu(insn)) {
len = 1;
-#ifdef CONFIG_64BIT
- } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
+ rd = riscv_insn_lbu_extract_xd(insn);
+ } else if (riscv_insn_is_ld(insn)) {
len = 8;
shift = 8 * (sizeof(ulong) - len);
- } else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
+ rd = riscv_insn_ld_extract_xd(insn);
+ } else if (riscv_insn_is_lwu(insn)) {
len = 4;
-#endif
- } else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
+ rd = riscv_insn_lwu_extract_xd(insn);
+ } else if (riscv_insn_is_lh(insn)) {
len = 2;
shift = 8 * (sizeof(ulong) - len);
- } else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
+ rd = riscv_insn_lh_extract_xd(insn);
+ } else if (riscv_insn_is_lhu(insn)) {
len = 2;
-#ifdef CONFIG_64BIT
- } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
+ rd = riscv_insn_lhu_extract_xd(insn);
+ } else if (riscv_insn_is_c_ld(insn)) {
len = 8;
shift = 8 * (sizeof(ulong) - len);
- insn = RVC_RS2S(insn) << SH_RD;
- } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP &&
- ((insn >> SH_RD) & 0x1f)) {
+ rd = riscv_insn_c_ld_extract_xd(insn);
+ } else if (riscv_insn_is_c_ldsp(insn)) {
len = 8;
shift = 8 * (sizeof(ulong) - len);
-#endif
- } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
+ rd = riscv_insn_c_ldsp_extract_xd(insn);
+ } else if (riscv_insn_is_c_lw(insn)) {
len = 4;
shift = 8 * (sizeof(ulong) - len);
- insn = RVC_RS2S(insn) << SH_RD;
- } else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP &&
- ((insn >> SH_RD) & 0x1f)) {
+ rd = riscv_insn_c_lw_extract_xd(insn);
+ } else if (riscv_insn_is_c_lwsp(insn)) {
len = 4;
shift = 8 * (sizeof(ulong) - len);
+ rd = riscv_insn_c_lwsp_extract_xd(insn);
} else {
return -EOPNOTSUPP;
}
@@ -455,7 +458,7 @@ int kvm_riscv_vcpu_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run,
return -EIO;
/* Save instruction decode info */
- vcpu->arch.mmio_decode.insn = insn;
+ vcpu->arch.mmio_decode.rd = rd;
vcpu->arch.mmio_decode.insn_len = insn_len;
vcpu->arch.mmio_decode.shift = shift;
vcpu->arch.mmio_decode.len = len;
@@ -498,11 +501,7 @@ int kvm_riscv_vcpu_mmio_store(struct kvm_vcpu *vcpu, struct kvm_run *run,
unsigned long fault_addr,
unsigned long htinst)
{
- u8 data8;
- u16 data16;
- u32 data32;
- u64 data64;
- ulong data;
+ ulong data, rs2;
unsigned long insn;
int len = 0, insn_len = 0;
struct kvm_cpu_trap utrap = { 0 };
@@ -534,35 +533,30 @@ int kvm_riscv_vcpu_mmio_store(struct kvm_vcpu *vcpu, struct kvm_run *run,
insn_len = INSN_LEN(insn);
}
- data = GET_RS2(insn, &vcpu->arch.guest_context);
- data8 = data16 = data32 = data64 = data;
-
- if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
+ if (riscv_insn_is_sw(insn)) {
len = 4;
- } else if ((insn & INSN_MASK_SB) == INSN_MATCH_SB) {
+ rs2 = riscv_insn_sw_extract_xs2(insn);
+ } else if (riscv_insn_is_sb(insn)) {
len = 1;
-#ifdef CONFIG_64BIT
- } else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
+ rs2 = riscv_insn_sb_extract_xs2(insn);
+ } else if (riscv_insn_is_sd(insn)) {
len = 8;
-#endif
- } else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
+ rs2 = riscv_insn_sd_extract_xs2(insn);
+ } else if (riscv_insn_is_sh(insn)) {
len = 2;
-#ifdef CONFIG_64BIT
- } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
+ rs2 = riscv_insn_sh_extract_xs2(insn);
+ } else if (riscv_insn_is_c_sd(insn)) {
len = 8;
- data64 = GET_RS2S(insn, &vcpu->arch.guest_context);
- } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP &&
- ((insn >> SH_RD) & 0x1f)) {
+ rs2 = riscv_insn_c_sd_extract_xs2(insn);
+ } else if (riscv_insn_is_c_sdsp(insn)) {
len = 8;
- data64 = GET_RS2C(insn, &vcpu->arch.guest_context);
-#endif
- } else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
+ rs2 = riscv_insn_c_sdsp_extract_xs2(insn);
+ } else if (riscv_insn_is_c_sw(insn)) {
len = 4;
- data32 = GET_RS2S(insn, &vcpu->arch.guest_context);
- } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP &&
- ((insn >> SH_RD) & 0x1f)) {
+ rs2 = riscv_insn_c_sw_extract_xs2(insn);
+ } else if (riscv_insn_is_c_swsp(insn)) {
len = 4;
- data32 = GET_RS2C(insn, &vcpu->arch.guest_context);
+ rs2 = riscv_insn_c_swsp_extract_xs2(insn);
} else {
return -EOPNOTSUPP;
}
@@ -571,26 +565,24 @@ int kvm_riscv_vcpu_mmio_store(struct kvm_vcpu *vcpu, struct kvm_run *run,
if (fault_addr & (len - 1))
return -EIO;
- /* Save instruction decode info */
- vcpu->arch.mmio_decode.insn = insn;
vcpu->arch.mmio_decode.insn_len = insn_len;
- vcpu->arch.mmio_decode.shift = 0;
- vcpu->arch.mmio_decode.len = len;
vcpu->arch.mmio_decode.return_handled = 0;
+ data = *((ulong *)(&vcpu->arch.guest_context) + rs2);
+
/* Copy data to kvm_run instance */
switch (len) {
case 1:
- *((u8 *)run->mmio.data) = data8;
+ *((u8 *)run->mmio.data) = data;
break;
case 2:
- *((u16 *)run->mmio.data) = data16;
+ *((u16 *)run->mmio.data) = data;
break;
case 4:
- *((u32 *)run->mmio.data) = data32;
+ *((u32 *)run->mmio.data) = data;
break;
case 8:
- *((u64 *)run->mmio.data) = data64;
+ *((u64 *)run->mmio.data) = data;
break;
default:
return -EOPNOTSUPP;
@@ -626,18 +618,13 @@ int kvm_riscv_vcpu_mmio_store(struct kvm_vcpu *vcpu, struct kvm_run *run,
*/
int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
- u8 data8;
- u16 data16;
- u32 data32;
- u64 data64;
- ulong insn;
int len, shift;
+ unsigned long data;
if (vcpu->arch.mmio_decode.return_handled)
return 0;
vcpu->arch.mmio_decode.return_handled = 1;
- insn = vcpu->arch.mmio_decode.insn;
if (run->mmio.is_write)
goto done;
@@ -647,29 +634,23 @@ int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
switch (len) {
case 1:
- data8 = *((u8 *)run->mmio.data);
- SET_RD(insn, &vcpu->arch.guest_context,
- (long)((ulong)data8 << shift) >> shift);
+ data = *((u8 *)run->mmio.data);
break;
case 2:
- data16 = *((u16 *)run->mmio.data);
- SET_RD(insn, &vcpu->arch.guest_context,
- (long)((ulong)data16 << shift) >> shift);
+ data = *((u16 *)run->mmio.data);
break;
case 4:
- data32 = *((u32 *)run->mmio.data);
- SET_RD(insn, &vcpu->arch.guest_context,
- (long)((ulong)data32 << shift) >> shift);
+ data = *((u32 *)run->mmio.data);
break;
case 8:
- data64 = *((u64 *)run->mmio.data);
- SET_RD(insn, &vcpu->arch.guest_context,
- (long)((ulong)data64 << shift) >> shift);
+ data = *((u64 *)run->mmio.data);
break;
default:
return -EOPNOTSUPP;
}
+ *((ulong *)(&vcpu->arch.guest_context) + vcpu->arch.mmio_decode.rd) =
+ (long)data << shift >> shift;
done:
/* Move to next instruction */
vcpu->arch.guest_context.sepc += vcpu->arch.mmio_decode.insn_len;
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 12/16] riscv: kvm: Add emulated test csr
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (10 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 11/16] riscv: kvm: Use generated instruction headers for mmio emulation Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:23 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 13/16] KVM: riscv: selftests: Add csr emulation test Charlie Jenkins via B4 Relay
` (3 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
To test the riscv kvm implementation of emulated CSRs, add support to
emulate the vsscratch csr when CONFIG_RISCV_KVM_TEST_CSR is set.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
arch/riscv/Kconfig.debug | 1 +
arch/riscv/include/asm/kvm_host.h | 10 ++++++++++
arch/riscv/include/asm/kvm_vcpu_test_csr.h | 15 +++++++++++++++
arch/riscv/kvm/Kconfig.debug | 16 ++++++++++++++++
arch/riscv/kvm/Makefile | 1 +
arch/riscv/kvm/vcpu_insn.c | 5 +++++
arch/riscv/kvm/vcpu_test_csr.c | 21 +++++++++++++++++++++
7 files changed, 69 insertions(+)
diff --git a/arch/riscv/Kconfig.debug b/arch/riscv/Kconfig.debug
index eafe17ebf710..be202267da6d 100644
--- a/arch/riscv/Kconfig.debug
+++ b/arch/riscv/Kconfig.debug
@@ -1 +1,2 @@
source "arch/riscv/kernel/tests/Kconfig.debug"
+source "arch/riscv/kvm/Kconfig.debug"
diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index 75b0a951c1bc..4d30d30ebefc 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -167,6 +167,12 @@ struct kvm_vcpu_reset_state {
unsigned long a1;
};
+#ifdef CONFIG_RISCV_KVM_TEST_CSR
+struct kvm_test_csr {
+ unsigned long val;
+};
+#endif
+
struct kvm_vcpu_arch {
/* VCPU ran at least once */
bool ran_atleast_once;
@@ -265,6 +271,10 @@ struct kvm_vcpu_arch {
gpa_t shmem;
u64 last_steal;
} sta;
+
+#ifdef CONFIG_RISCV_KVM_TEST_CSR
+ struct kvm_test_csr test_csr;
+#endif
};
/*
diff --git a/arch/riscv/include/asm/kvm_vcpu_test_csr.h b/arch/riscv/include/asm/kvm_vcpu_test_csr.h
new file mode 100644
index 000000000000..a844fccaafc3
--- /dev/null
+++ b/arch/riscv/include/asm/kvm_vcpu_test_csr.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __KVM_VCPU_RISCV_TEST_CSR_H
+#define __KVM_VCPU_RISCV_TEST_CSR_H
+
+#include <asm/kvm_vcpu_insn.h>
+
+#define KVM_RISCV_VCPU_TEST_CSR_FUNCS \
+ {.base = CSR_VSSCRATCH, .count = 1, .func = kvm_riscv_vcpu_test_csr },
+
+int kvm_riscv_vcpu_test_csr(struct kvm_vcpu *vcpu, unsigned int csr_num,
+ unsigned long *val, unsigned long new_val,
+ unsigned long wr_mask);
+
+#endif /* !__KVM_VCPU_RISCV_TEST_CSR_H */
diff --git a/arch/riscv/kvm/Kconfig.debug b/arch/riscv/kvm/Kconfig.debug
new file mode 100644
index 000000000000..dc76e02120a3
--- /dev/null
+++ b/arch/riscv/kvm/Kconfig.debug
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-only
+menu "arch/riscv/kvm testing"
+
+config RISCV_KVM_TEST_CSR
+ bool "Test KVM CSR emulation"
+ depends on KVM
+ default n
+ help
+ Enable this option to enable the emulation of a test hypervisor csr.
+ The KVM test csr is the vsscratch register. Once this is enabled,
+ reading/writing to the vsscratch register will trap into the host
+ supervisor and reflect the change.
+
+ If unsure, say N.
+
+endmenu # "arch/riscv/kvm testing"
diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile
index 296c2ba05089..5092b86751c4 100644
--- a/arch/riscv/kvm/Makefile
+++ b/arch/riscv/kvm/Makefile
@@ -38,6 +38,7 @@ kvm-y += vcpu_sbi_sta.o
kvm-y += vcpu_sbi_system.o
kvm-$(CONFIG_RISCV_SBI_V01) += vcpu_sbi_v01.o
kvm-y += vcpu_switch.o
+kvm-$(CONFIG_RISCV_KVM_TEST_CSR) += vcpu_test_csr.o
kvm-y += vcpu_timer.o
kvm-y += vcpu_vector.o
kvm-y += vm.o
diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c
index 1d8741d02242..c5a70de4a579 100644
--- a/arch/riscv/kvm/vcpu_insn.c
+++ b/arch/riscv/kvm/vcpu_insn.c
@@ -10,6 +10,8 @@
#include <asm/cpufeature.h>
#include <asm/insn.h>
+#include <asm/kvm_vcpu_test_csr.h>
+
struct insn_func {
unsigned long mask;
unsigned long match;
@@ -112,6 +114,9 @@ static int seed_csr_rmw(struct kvm_vcpu *vcpu, unsigned int csr_num,
static const struct csr_func csr_funcs[] = {
KVM_RISCV_VCPU_AIA_CSR_FUNCS
KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS
+#ifdef CONFIG_RISCV_KVM_TEST_CSR
+ KVM_RISCV_VCPU_TEST_CSR_FUNCS
+#endif
{ .base = CSR_SEED, .count = 1, .func = seed_csr_rmw },
};
diff --git a/arch/riscv/kvm/vcpu_test_csr.c b/arch/riscv/kvm/vcpu_test_csr.c
new file mode 100644
index 000000000000..b8aa503cdaba
--- /dev/null
+++ b/arch/riscv/kvm/vcpu_test_csr.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_vcpu_insn.h>
+#include <asm/kvm_vcpu_test_csr.h>
+
+#define vcpu_to_test_csr(vcpu) (&(vcpu)->arch.test_csr)
+
+int kvm_riscv_vcpu_test_csr(struct kvm_vcpu *vcpu, unsigned int csr_num,
+ unsigned long *val, unsigned long new_val,
+ unsigned long wr_mask)
+{
+ struct kvm_test_csr *test_csr = vcpu_to_test_csr(vcpu);
+
+ *val = test_csr->val;
+
+ if (wr_mask)
+ test_csr->val = (test_csr->val & ~wr_mask) | (new_val & wr_mask);
+
+ return KVM_INSN_CONTINUE_NEXT_SEPC;
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 13/16] KVM: riscv: selftests: Add csr emulation test
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (11 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 12/16] riscv: kvm: Add emulated test csr Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:24 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 14/16] riscv: kvm: Use generated instruction headers for csr emulation Charlie Jenkins via B4 Relay
` (2 subsequent siblings)
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Introduce a kvm test that uses the emulated test csr to validate that
all emulated reads/writes to csrs function as expected.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
tools/testing/selftests/kvm/Makefile.kvm | 1 +
tools/testing/selftests/kvm/riscv/csr_test.c | 126 +++++++++++++++++++++++++++
2 files changed, 127 insertions(+)
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 07a5fc2bf67c..88ccd15e8f94 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -212,6 +212,7 @@ TEST_GEN_PROGS_s390 += s390/irq_routing
TEST_GEN_PROGS_s390 += mmu_stress_test
TEST_GEN_PROGS_riscv = $(TEST_GEN_PROGS_COMMON)
+TEST_GEN_PROGS_riscv += riscv/csr_test
TEST_GEN_PROGS_riscv += riscv/sbi_pmu_test
TEST_GEN_PROGS_riscv += riscv/ebreak_test
TEST_GEN_PROGS_riscv += riscv/mmio_test
diff --git a/tools/testing/selftests/kvm/riscv/csr_test.c b/tools/testing/selftests/kvm/riscv/csr_test.c
new file mode 100644
index 000000000000..b3e8b99b6e92
--- /dev/null
+++ b/tools/testing/selftests/kvm/riscv/csr_test.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * csr_test.c - Tests the csr functionality.
+ */
+#include "kvm_util.h"
+#include "ucall_common.h"
+
+#define CSR_TEST 0x240
+#define FP 0x00006000
+
+/*
+ * Use the fcsr as a U-mode accesible csr and compare against the custom 'test'
+ * hypervisor csr (currently using vsscratch)
+ */
+#define test_csr(write, initial, mode) \
+static void test_##write(void) \
+{ \
+ unsigned long hypervisor_result, reference_result, old_hypervisor; \
+ unsigned long mask = 0x15; \
+ asm volatile ( \
+ "csrs sstatus, %[enable_fp]\n" \
+ "csrw fcsr, %[init]\n" \
+ #write" zero, fcsr, %[mask]\n" \
+ "csrr %[ref_res], fcsr\n" \
+ : [ref_res] "=&r" (reference_result) \
+ : [enable_fp] "r" (FP), [mask] #mode(mask), [init] "r" (initial) \
+ : "memory" \
+ ); \
+ asm volatile ( \
+ "csrw %[test_csr], %[init]\n" \
+ #write" %[old], %[test_csr], %[mask]\n" \
+ "csrr %[hyp_res], %[test_csr]\n" \
+ : [hyp_res] "=&r" (hypervisor_result), [old] "=&r" (old_hypervisor) \
+ : [test_csr] "i"(CSR_TEST), [mask] #mode(mask), [init] "r" (initial) \
+ : "memory" \
+ ); \
+ /* Check that writing works */ \
+ GUEST_ASSERT_EQ(reference_result, hypervisor_result); \
+ /* Check that reading works */ \
+ GUEST_ASSERT_EQ(old_hypervisor, initial); \
+ GUEST_DONE(); \
+}
+
+test_csr(csrrw, 0x0, r)
+test_csr(csrrs, 0x0, r)
+test_csr(csrrc, 0x15, r)
+test_csr(csrrwi, 0x0, i)
+test_csr(csrrsi, 0x0, i)
+test_csr(csrrci, 0x15, i)
+
+static void run(void *guest_code, char *instruction)
+{
+ struct ucall uc;
+ struct kvm_vm *vm;
+ struct kvm_vcpu *vcpu;
+
+ vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+
+ kvm_create_device(vm, KVM_DEV_TYPE_TEST);
+
+ vcpu_run(vcpu);
+
+ TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_DONE,
+ "CSR instruction '%s' failed: '%s'", instruction,
+ uc.buffer);
+
+ kvm_vm_free(vm);
+}
+
+static void check_test_csr_guest(void)
+{
+ unsigned long scause, stvec;
+
+ asm volatile(
+ "la %[stvec], 1f\n"
+ "csrw stvec, %[stvec]\n"
+ "csrwi %[test_csr], 0x0\n"
+ "1:\n"
+ "csrr %[scause], scause\n"
+ : [scause] "=&r" (scause), [stvec] "=&r" (stvec)
+ : [test_csr] "i" (CSR_TEST)
+ );
+
+ /* An illegal instruction will be generated if CONFIG_RISCV_KVM_TEST_CSR is not enabled. */
+ if (scause == 2)
+ GUEST_FAIL("CONFIG_RISCV_KVM_TEST_CSR not enabled.\n");
+ GUEST_DONE();
+}
+
+static int check_test_csr(void)
+{
+ struct ucall uc;
+ struct kvm_vm *vm;
+ struct kvm_vcpu *vcpu;
+ int success;
+
+ vm = vm_create_with_one_vcpu(&vcpu, check_test_csr_guest);
+
+ /* Skip if CONFIG_KVM_MMIO_TEST not enabled */
+ if (!kvm_create_device(vm, KVM_DEV_TYPE_TEST))
+ exit(KSFT_SKIP);
+
+ vcpu_run(vcpu);
+
+ success = get_ucall(vcpu, &uc) == UCALL_DONE;
+
+ kvm_vm_free(vm);
+
+ return success;
+}
+
+int main(void)
+{
+ /* Skip if CONFIG_RISCV_KVM_TEST_CSR not enabled */
+ if (!check_test_csr())
+ exit(KSFT_SKIP);
+
+ run(test_csrrw, "csrrw");
+ run(test_csrrs, "csrrs");
+ run(test_csrrc, "csrrc");
+ run(test_csrrwi, "csrrwi");
+ run(test_csrrsi, "csrrsi");
+ run(test_csrrci, "csrrci");
+
+ return 0;
+}
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 14/16] riscv: kvm: Use generated instruction headers for csr emulation
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (12 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 13/16] KVM: riscv: selftests: Add csr emulation test Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:30 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 15/16] riscv: kexec: Use generated instruction headers for kexec relocations Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 16/16] riscv: Remove unused instruction headers Charlie Jenkins via B4 Relay
15 siblings, 1 reply; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Migrate the csr emulation code to use the generated instruction headers
instead of the hand-written instruction composition functions.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
This can be tested with the introduced csr_test selftest.
---
arch/riscv/include/asm/kvm_vcpu_insn.h | 3 +-
arch/riscv/kvm/vcpu_insn.c | 61 +++++++++++++++++-----------------
2 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/arch/riscv/include/asm/kvm_vcpu_insn.h b/arch/riscv/include/asm/kvm_vcpu_insn.h
index 106fb4c45108..01efdaaede21 100644
--- a/arch/riscv/include/asm/kvm_vcpu_insn.h
+++ b/arch/riscv/include/asm/kvm_vcpu_insn.h
@@ -19,7 +19,8 @@ struct kvm_mmio_decode {
};
struct kvm_csr_decode {
- unsigned long insn;
+ unsigned long rd;
+ unsigned long insn_len;
int return_handled;
};
diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c
index c5a70de4a579..d666cd24f8c0 100644
--- a/arch/riscv/kvm/vcpu_insn.c
+++ b/arch/riscv/kvm/vcpu_insn.c
@@ -13,8 +13,7 @@
#include <asm/kvm_vcpu_test_csr.h>
struct insn_func {
- unsigned long mask;
- unsigned long match;
+ bool (*cmp)(u32 insn);
/*
* Possible return values are as follows:
* 1) Returns < 0 for error case
@@ -131,20 +130,17 @@ static const struct csr_func csr_funcs[] = {
*/
int kvm_riscv_vcpu_csr_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
- ulong insn;
-
if (vcpu->arch.csr_decode.return_handled)
return 0;
vcpu->arch.csr_decode.return_handled = 1;
/* Update destination register for CSR reads */
- insn = vcpu->arch.csr_decode.insn;
- if ((insn >> SH_RD) & MASK_RX)
- SET_RD(insn, &vcpu->arch.guest_context,
- run->riscv_csr.ret_value);
+ if (vcpu->arch.csr_decode.rd)
+ *((ulong *)&vcpu->arch.guest_context +
+ vcpu->arch.csr_decode.rd) = run->riscv_csr.ret_value;
/* Move to next instruction */
- vcpu->arch.guest_context.sepc += INSN_LEN(insn);
+ vcpu->arch.guest_context.sepc += vcpu->arch.csr_decode.insn_len;
return 0;
}
@@ -154,7 +150,7 @@ static int csr_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn)
#define GET_REG(_rd) (*((unsigned long *)(&vcpu->arch.guest_context) + _rd))
int i, rc = KVM_INSN_ILLEGAL_TRAP;
- unsigned int csr_num;
+ unsigned int csr_num, rd;
const struct csr_func *tcfn, *cfn = NULL;
ulong val = 0, wr_mask = 0, new_val = 0;
@@ -163,26 +159,32 @@ static int csr_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn)
wr_mask = -1UL;
new_val = GET_REG(riscv_insn_csrrw_extract_xs1(insn));
csr_num = riscv_insn_csrrw_extract_csr(insn);
+ rd = riscv_insn_csrrw_extract_xd(insn);
} else if (riscv_insn_is_csrrs(insn)) {
wr_mask = GET_REG(riscv_insn_csrrs_extract_xs1(insn));
new_val = -1UL;
csr_num = riscv_insn_csrrs_extract_csr(insn);
+ rd = riscv_insn_csrrs_extract_xd(insn);
} else if (riscv_insn_is_csrrc(insn)) {
- wr_mask = GET_REG(riscv_insn_csrrs_extract_xs1(insn));
+ wr_mask = GET_REG(riscv_insn_csrrc_extract_xs1(insn));
new_val = 0;
csr_num = riscv_insn_csrrc_extract_csr(insn);
+ rd = riscv_insn_csrrc_extract_xd(insn);
} else if (riscv_insn_is_csrrwi(insn)) {
wr_mask = -1UL;
new_val = riscv_insn_csrrwi_extract_imm(insn);
csr_num = riscv_insn_csrrwi_extract_csr(insn);
+ rd = riscv_insn_csrrwi_extract_xd(insn);
} else if (riscv_insn_is_csrrsi(insn)) {
wr_mask = riscv_insn_csrrwi_extract_imm(insn);
new_val = -1UL;
csr_num = riscv_insn_csrrsi_extract_csr(insn);
+ rd = riscv_insn_csrrsi_extract_xd(insn);
} else if (riscv_insn_is_csrrci(insn)) {
- wr_mask = GET_REG(riscv_insn_csrrwi_extract_imm(insn));
+ wr_mask = riscv_insn_csrrci_extract_imm(insn);
new_val = 0;
- csr_num = riscv_insn_csrrwi_extract_csr(insn);
+ csr_num = riscv_insn_csrrci_extract_csr(insn);
+ rd = riscv_insn_csrrci_extract_xd(insn);
} else {
return rc;
}
@@ -190,7 +192,8 @@ static int csr_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn)
#undef GET_REG
/* Save instruction decode info */
- vcpu->arch.csr_decode.insn = insn;
+ vcpu->arch.csr_decode.rd = rd;
+ vcpu->arch.csr_decode.insn_len = INSN_LEN(insn);
vcpu->arch.csr_decode.return_handled = 0;
/* Update CSR details in kvm_run struct */
@@ -234,43 +237,39 @@ static int csr_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn)
static const struct insn_func system_opcode_funcs[] = {
{
- .mask = INSN_MASK_CSRRW,
- .match = INSN_MATCH_CSRRW,
+ .cmp = riscv_insn_is_csrrw,
.func = csr_insn,
},
{
- .mask = INSN_MASK_CSRRS,
- .match = INSN_MATCH_CSRRS,
+ .cmp = riscv_insn_is_csrrs,
.func = csr_insn,
},
{
- .mask = INSN_MASK_CSRRC,
- .match = INSN_MATCH_CSRRC,
+ .cmp = riscv_insn_is_csrrc,
.func = csr_insn,
},
{
- .mask = INSN_MASK_CSRRWI,
- .match = INSN_MATCH_CSRRWI,
+ .cmp = riscv_insn_is_csrrwi,
.func = csr_insn,
},
{
- .mask = INSN_MASK_CSRRSI,
- .match = INSN_MATCH_CSRRSI,
+ .cmp = riscv_insn_is_csrrsi,
.func = csr_insn,
},
{
- .mask = INSN_MASK_CSRRCI,
- .match = INSN_MATCH_CSRRCI,
+ .cmp = riscv_insn_is_csrrci,
.func = csr_insn,
},
{
- .mask = INSN_MASK_WFI,
- .match = INSN_MATCH_WFI,
+ .cmp = riscv_insn_is_wfi,
.func = wfi_insn,
},
{
- .mask = INSN_MASK_WRS,
- .match = INSN_MATCH_WRS,
+ .cmp = riscv_insn_is_wrs_nto,
+ .func = wrs_insn,
+ },
+ {
+ .cmp = riscv_insn_is_wrs_sto,
.func = wrs_insn,
},
};
@@ -283,7 +282,7 @@ static int system_opcode_insn(struct kvm_vcpu *vcpu, struct kvm_run *run,
for (i = 0; i < ARRAY_SIZE(system_opcode_funcs); i++) {
ifn = &system_opcode_funcs[i];
- if ((insn & ifn->mask) == ifn->match) {
+ if (ifn->cmp(insn)) {
rc = ifn->func(vcpu, run, insn);
break;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 15/16] riscv: kexec: Use generated instruction headers for kexec relocations
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (13 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 14/16] riscv: kvm: Use generated instruction headers for csr emulation Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 16/16] riscv: Remove unused instruction headers Charlie Jenkins via B4 Relay
15 siblings, 0 replies; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
Migrate the kexec relocation code to use the generated instruction
headers instead of the hand-written instruction composition functions.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
This was again tested by brute forcing all possible inputs to the value
fed into the immediates.
---
arch/riscv/kernel/machine_kexec_file.c | 55 ++++++++++++----------------------
1 file changed, 19 insertions(+), 36 deletions(-)
diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
index 54e2d9552e93..cad40e4afd86 100644
--- a/arch/riscv/kernel/machine_kexec_file.c
+++ b/arch/riscv/kernel/machine_kexec_file.c
@@ -116,32 +116,6 @@ static char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
(((x) + (RISCV_IMM_REACH >> 1)) & ~(RISCV_IMM_REACH - 1))
#define RISCV_CONST_LOW_PART(x) ((x) - RISCV_CONST_HIGH_PART(x))
-#define ENCODE_ITYPE_IMM(x) \
- (RV_X(x, 0, 12) << 20)
-#define ENCODE_BTYPE_IMM(x) \
- ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | \
- (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31))
-#define ENCODE_UTYPE_IMM(x) \
- (RV_X(x, 12, 20) << 12)
-#define ENCODE_JTYPE_IMM(x) \
- ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | \
- (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31))
-#define ENCODE_CBTYPE_IMM(x) \
- ((RV_X(x, 1, 2) << 3) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 5, 1) << 2) | \
- (RV_X(x, 6, 2) << 5) | (RV_X(x, 8, 1) << 12))
-#define ENCODE_CJTYPE_IMM(x) \
- ((RV_X(x, 1, 3) << 3) | (RV_X(x, 4, 1) << 11) | (RV_X(x, 5, 1) << 2) | \
- (RV_X(x, 6, 1) << 7) | (RV_X(x, 7, 1) << 6) | (RV_X(x, 8, 2) << 9) | \
- (RV_X(x, 10, 1) << 8) | (RV_X(x, 11, 1) << 12))
-#define ENCODE_UJTYPE_IMM(x) \
- (ENCODE_UTYPE_IMM(RISCV_CONST_HIGH_PART(x)) | \
- (ENCODE_ITYPE_IMM(RISCV_CONST_LOW_PART(x)) << 32))
-#define ENCODE_UITYPE_IMM(x) \
- (ENCODE_UTYPE_IMM(x) | (ENCODE_ITYPE_IMM(x) << 32))
-
-#define CLEAN_IMM(type, x) \
- ((~ENCODE_##type##_IMM((uint64_t)(-1))) & (x))
-
int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
Elf_Shdr *section,
const Elf_Shdr *relsec,
@@ -197,12 +171,14 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
switch (r_type) {
case R_RISCV_BRANCH:
- *(u32 *)loc = CLEAN_IMM(BTYPE, *(u32 *)loc) |
- ENCODE_BTYPE_IMM(val - addr);
+ /*
+ * For simplicity, use beq as represenative of all
+ * branches (they all have the same imm encoding)
+ */
+ riscv_insn_beq_insert_imm((u32 *)loc, val - addr);
break;
case R_RISCV_JAL:
- *(u32 *)loc = CLEAN_IMM(JTYPE, *(u32 *)loc) |
- ENCODE_JTYPE_IMM(val - addr);
+ riscv_insn_jal_insert_imm((u32 *)loc, val - addr);
break;
/*
* With no R_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_I
@@ -213,16 +189,23 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
case R_RISCV_PCREL_HI20:
case R_RISCV_CALL_PLT:
case R_RISCV_CALL:
- *(u64 *)loc = CLEAN_IMM(UITYPE, *(u64 *)loc) |
- ENCODE_UJTYPE_IMM(val - addr);
+ riscv_insn_auipc_insert_imm((u32 *)loc, RISCV_CONST_HIGH_PART(val - addr));
+ riscv_insn_jalr_insert_imm((u32 *)loc + 1,
+ RISCV_CONST_LOW_PART(val - addr));
break;
case R_RISCV_RVC_BRANCH:
- *(u32 *)loc = CLEAN_IMM(CBTYPE, *(u32 *)loc) |
- ENCODE_CBTYPE_IMM(val - addr);
+ /*
+ * For simplicity, use c.beqz as represenative of all
+ * compressed branches (they all have the same imm encoding)
+ */
+ riscv_insn_c_beqz_insert_imm((u16 *)loc, val - addr);
break;
case R_RISCV_RVC_JUMP:
- *(u32 *)loc = CLEAN_IMM(CJTYPE, *(u32 *)loc) |
- ENCODE_CJTYPE_IMM(val - addr);
+ /*
+ * For simplicity, use c.j as represenative of all
+ * compressed jumps (they all have the same imm encoding)
+ */
+ riscv_insn_c_j_insert_imm((u16 *)loc, val - addr);
break;
case R_RISCV_ADD16:
*(u16 *)loc += val;
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH v2 16/16] riscv: Remove unused instruction headers
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
` (14 preceding siblings ...)
2026-06-22 4:01 ` [PATCH v2 15/16] riscv: kexec: Use generated instruction headers for kexec relocations Charlie Jenkins via B4 Relay
@ 2026-06-22 4:01 ` Charlie Jenkins via B4 Relay
15 siblings, 0 replies; 29+ messages in thread
From: Charlie Jenkins via B4 Relay @ 2026-06-22 4:01 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Nam Cao, Alexandre Ghiti,
Anup Patel, Atish Patra, Conor Dooley, Paolo Bonzini,
Andrew Morton, Shuah Khan, Radim Krčmář
Cc: linux-riscv, linux-kernel, kvm, kvm-riscv, linux-kselftest,
Charlie Jenkins
From: Charlie Jenkins <thecharlesjenkins@gmail.com>
All usages of hard-coded riscv instruction have been migrated over to
the generated instruction headers so the old macros can be deleted.
Signed-off-by: Charlie Jenkins <thecharlesjenkins@gmail.com>
---
arch/riscv/include/asm/insn.h | 413 +-----------------------------------------
1 file changed, 4 insertions(+), 409 deletions(-)
diff --git a/arch/riscv/include/asm/insn.h b/arch/riscv/include/asm/insn.h
index bf6f5d530491..ea1f139d6d90 100644
--- a/arch/riscv/include/asm/insn.h
+++ b/arch/riscv/include/asm/insn.h
@@ -38,151 +38,22 @@ static __always_inline bool riscv_insn_is_##name(u32 _insn) \
#include <asm/insn_gen.h>
-#define RV_INSN_FUNCT3_MASK GENMASK(14, 12)
-#define RV_INSN_FUNCT3_OPOFF 12
#define RV_INSN_OPCODE_MASK GENMASK(6, 0)
-#define RV_INSN_OPCODE_OPOFF 0
-#define RV_INSN_FUNCT12_OPOFF 20
-
-#define RV_ENCODE_FUNCT3(f_) (RVG_FUNCT3_##f_ << RV_INSN_FUNCT3_OPOFF)
-#define RV_ENCODE_FUNCT12(f_) (RVG_FUNCT12_##f_ << RV_INSN_FUNCT12_OPOFF)
-
-/* The bit field of immediate value in I-type instruction */
-#define RV_I_IMM_SIGN_OPOFF 31
-#define RV_I_IMM_11_0_OPOFF 20
-#define RV_I_IMM_SIGN_OFF 12
-#define RV_I_IMM_11_0_OFF 0
-#define RV_I_IMM_11_0_MASK GENMASK(11, 0)
-
-/* The bit field of immediate value in J-type instruction */
-#define RV_J_IMM_SIGN_OPOFF 31
-#define RV_J_IMM_10_1_OPOFF 21
-#define RV_J_IMM_11_OPOFF 20
-#define RV_J_IMM_19_12_OPOFF 12
-#define RV_J_IMM_SIGN_OFF 20
-#define RV_J_IMM_10_1_OFF 1
-#define RV_J_IMM_11_OFF 11
-#define RV_J_IMM_19_12_OFF 12
-#define RV_J_IMM_10_1_MASK GENMASK(9, 0)
-#define RV_J_IMM_11_MASK GENMASK(0, 0)
-#define RV_J_IMM_19_12_MASK GENMASK(7, 0)
-
-/*
- * U-type IMMs contain the upper 20bits [31:20] of an immediate with
- * the rest filled in by zeros, so no shifting required. Similarly,
- * bit31 contains the signed state, so no sign extension necessary.
- */
-#define RV_U_IMM_SIGN_OPOFF 31
-#define RV_U_IMM_31_12_OPOFF 0
-#define RV_U_IMM_31_12_MASK GENMASK(31, 12)
-
-/* The bit field of immediate value in B-type instruction */
-#define RV_B_IMM_SIGN_OPOFF 31
-#define RV_B_IMM_10_5_OPOFF 25
-#define RV_B_IMM_4_1_OPOFF 8
-#define RV_B_IMM_11_OPOFF 7
-#define RV_B_IMM_SIGN_OFF 12
-#define RV_B_IMM_10_5_OFF 5
-#define RV_B_IMM_4_1_OFF 1
-#define RV_B_IMM_11_OFF 11
-#define RV_B_IMM_10_5_MASK GENMASK(5, 0)
-#define RV_B_IMM_4_1_MASK GENMASK(3, 0)
-#define RV_B_IMM_11_MASK GENMASK(0, 0)
-
-/* The register offset in RVG instruction */
-#define RVG_RS1_OPOFF 15
-#define RVG_RS2_OPOFF 20
-#define RVG_RD_OPOFF 7
-#define RVG_RS1_MASK GENMASK(4, 0)
-#define RVG_RS2_MASK GENMASK(4, 0)
-#define RVG_RD_MASK GENMASK(4, 0)
-
-/* The bit field of immediate value in RVC J instruction */
-#define RVC_J_IMM_SIGN_OPOFF 12
-#define RVC_J_IMM_4_OPOFF 11
-#define RVC_J_IMM_9_8_OPOFF 9
-#define RVC_J_IMM_10_OPOFF 8
-#define RVC_J_IMM_6_OPOFF 7
-#define RVC_J_IMM_7_OPOFF 6
-#define RVC_J_IMM_3_1_OPOFF 3
-#define RVC_J_IMM_5_OPOFF 2
-#define RVC_J_IMM_SIGN_OFF 11
-#define RVC_J_IMM_4_OFF 4
-#define RVC_J_IMM_9_8_OFF 8
-#define RVC_J_IMM_10_OFF 10
-#define RVC_J_IMM_6_OFF 6
-#define RVC_J_IMM_7_OFF 7
-#define RVC_J_IMM_3_1_OFF 1
-#define RVC_J_IMM_5_OFF 5
-#define RVC_J_IMM_4_MASK GENMASK(0, 0)
-#define RVC_J_IMM_9_8_MASK GENMASK(1, 0)
-#define RVC_J_IMM_10_MASK GENMASK(0, 0)
-#define RVC_J_IMM_6_MASK GENMASK(0, 0)
-#define RVC_J_IMM_7_MASK GENMASK(0, 0)
-#define RVC_J_IMM_3_1_MASK GENMASK(2, 0)
-#define RVC_J_IMM_5_MASK GENMASK(0, 0)
-
-/* The bit field of immediate value in RVC B instruction */
-#define RVC_B_IMM_SIGN_OPOFF 12
-#define RVC_B_IMM_4_3_OPOFF 10
-#define RVC_B_IMM_7_6_OPOFF 5
-#define RVC_B_IMM_2_1_OPOFF 3
-#define RVC_B_IMM_5_OPOFF 2
-#define RVC_B_IMM_SIGN_OFF 8
-#define RVC_B_IMM_4_3_OFF 3
-#define RVC_B_IMM_7_6_OFF 6
-#define RVC_B_IMM_2_1_OFF 1
-#define RVC_B_IMM_5_OFF 5
-#define RVC_B_IMM_4_3_MASK GENMASK(1, 0)
-#define RVC_B_IMM_7_6_MASK GENMASK(1, 0)
-#define RVC_B_IMM_2_1_MASK GENMASK(1, 0)
-#define RVC_B_IMM_5_MASK GENMASK(0, 0)
-
-#define RVC_INSN_FUNCT4_MASK GENMASK(15, 12)
-#define RVC_INSN_FUNCT4_OPOFF 12
-#define RVC_INSN_FUNCT3_MASK GENMASK(15, 13)
-#define RVC_INSN_FUNCT3_OPOFF 13
-#define RVC_INSN_J_RS1_MASK GENMASK(11, 7)
-#define RVC_INSN_J_RS2_MASK GENMASK(6, 2)
-#define RVC_INSN_OPCODE_MASK GENMASK(1, 0)
-#define RVC_ENCODE_FUNCT3(f_) (RVC_FUNCT3_##f_ << RVC_INSN_FUNCT3_OPOFF)
-#define RVC_ENCODE_FUNCT4(f_) (RVC_FUNCT4_##f_ << RVC_INSN_FUNCT4_OPOFF)
-
-/* The register offset in RVC op=C0 instruction */
-#define RVC_C0_RS1_OPOFF 7
-#define RVC_C0_RS2_OPOFF 2
-#define RVC_C0_RD_OPOFF 2
-
-/* The register offset in RVC op=C1 instruction */
-#define RVC_C1_RS1_OPOFF 7
-#define RVC_C1_RS2_OPOFF 2
-#define RVC_C1_RD_OPOFF 7
-
-/* The register offset in RVC op=C2 instruction */
-#define RVC_C2_RS1_OPOFF 7
-#define RVC_C2_RS2_OPOFF 2
-#define RVC_C2_RD_OPOFF 7
-#define RVC_C2_RS1_MASK GENMASK(4, 0)
/* parts of opcode for RVG*/
-#define RVG_OPCODE_FENCE 0x0f
-#define RVG_OPCODE_AUIPC 0x17
#define RVG_OPCODE_BRANCH 0x63
-#define RVG_OPCODE_JALR 0x67
-#define RVG_OPCODE_JAL 0x6f
#define RVG_OPCODE_SYSTEM 0x73
#define RVG_SYSTEM_CSR_OFF 20
#define RVG_SYSTEM_CSR_MASK GENMASK(12, 0)
+// THESE ARE ALL ACTUALLY USED
/* parts of opcode for RVF, RVD and RVQ */
#define RVFDQ_FL_FS_WIDTH_OFF 12
#define RVFDQ_FL_FS_WIDTH_MASK GENMASK(2, 0)
-#define RVFDQ_FL_FS_WIDTH_W 2
-#define RVFDQ_FL_FS_WIDTH_D 3
-#define RVFDQ_LS_FS_WIDTH_Q 4
#define RVFDQ_OPCODE_FL 0x07
#define RVFDQ_OPCODE_FS 0x27
+// THESE ARE ALL ACTUALLY USED
/* parts of opcode for RVV */
#define RVV_OPCODE_VECTOR 0x57
#define RVV_VL_VS_WIDTH_8 0
@@ -192,72 +63,6 @@ static __always_inline bool riscv_insn_is_##name(u32 _insn) \
#define RVV_OPCODE_VL RVFDQ_OPCODE_FL
#define RVV_OPCODE_VS RVFDQ_OPCODE_FS
-/* parts of opcode for RVC*/
-#define RVC_OPCODE_C0 0x0
-#define RVC_OPCODE_C1 0x1
-#define RVC_OPCODE_C2 0x2
-
-/* parts of funct3 code for I, M, A extension*/
-#define RVG_FUNCT3_JALR 0x0
-#define RVG_FUNCT3_BEQ 0x0
-#define RVG_FUNCT3_BNE 0x1
-#define RVG_FUNCT3_BLT 0x4
-#define RVG_FUNCT3_BGE 0x5
-#define RVG_FUNCT3_BLTU 0x6
-#define RVG_FUNCT3_BGEU 0x7
-
-/* parts of funct3 code for C extension*/
-#define RVC_FUNCT3_C_BEQZ 0x6
-#define RVC_FUNCT3_C_BNEZ 0x7
-#define RVC_FUNCT3_C_J 0x5
-#define RVC_FUNCT3_C_JAL 0x1
-#define RVC_FUNCT4_C_JR 0x8
-#define RVC_FUNCT4_C_JALR 0x9
-#define RVC_FUNCT4_C_EBREAK 0x9
-
-#define RVG_FUNCT12_EBREAK 0x1
-#define RVG_FUNCT12_SRET 0x102
-
-#define RVG_MATCH_AUIPC (RVG_OPCODE_AUIPC)
-#define RVG_MATCH_JALR (RV_ENCODE_FUNCT3(JALR) | RVG_OPCODE_JALR)
-#define RVG_MATCH_JAL (RVG_OPCODE_JAL)
-#define RVG_MATCH_FENCE (RVG_OPCODE_FENCE)
-#define RVG_MATCH_BEQ (RV_ENCODE_FUNCT3(BEQ) | RVG_OPCODE_BRANCH)
-#define RVG_MATCH_BNE (RV_ENCODE_FUNCT3(BNE) | RVG_OPCODE_BRANCH)
-#define RVG_MATCH_BLT (RV_ENCODE_FUNCT3(BLT) | RVG_OPCODE_BRANCH)
-#define RVG_MATCH_BGE (RV_ENCODE_FUNCT3(BGE) | RVG_OPCODE_BRANCH)
-#define RVG_MATCH_BLTU (RV_ENCODE_FUNCT3(BLTU) | RVG_OPCODE_BRANCH)
-#define RVG_MATCH_BGEU (RV_ENCODE_FUNCT3(BGEU) | RVG_OPCODE_BRANCH)
-#define RVG_MATCH_EBREAK (RV_ENCODE_FUNCT12(EBREAK) | RVG_OPCODE_SYSTEM)
-#define RVG_MATCH_SRET (RV_ENCODE_FUNCT12(SRET) | RVG_OPCODE_SYSTEM)
-#define RVC_MATCH_C_BEQZ (RVC_ENCODE_FUNCT3(C_BEQZ) | RVC_OPCODE_C1)
-#define RVC_MATCH_C_BNEZ (RVC_ENCODE_FUNCT3(C_BNEZ) | RVC_OPCODE_C1)
-#define RVC_MATCH_C_J (RVC_ENCODE_FUNCT3(C_J) | RVC_OPCODE_C1)
-#define RVC_MATCH_C_JAL (RVC_ENCODE_FUNCT3(C_JAL) | RVC_OPCODE_C1)
-#define RVC_MATCH_C_JR (RVC_ENCODE_FUNCT4(C_JR) | RVC_OPCODE_C2)
-#define RVC_MATCH_C_JALR (RVC_ENCODE_FUNCT4(C_JALR) | RVC_OPCODE_C2)
-#define RVC_MATCH_C_EBREAK (RVC_ENCODE_FUNCT4(C_EBREAK) | RVC_OPCODE_C2)
-
-#define RVG_MASK_AUIPC (RV_INSN_OPCODE_MASK)
-#define RVG_MASK_JALR (RV_INSN_FUNCT3_MASK | RV_INSN_OPCODE_MASK)
-#define RVG_MASK_JAL (RV_INSN_OPCODE_MASK)
-#define RVG_MASK_FENCE (RV_INSN_OPCODE_MASK)
-#define RVC_MASK_C_JALR (RVC_INSN_FUNCT4_MASK | RVC_INSN_J_RS2_MASK | RVC_INSN_OPCODE_MASK)
-#define RVC_MASK_C_JR (RVC_INSN_FUNCT4_MASK | RVC_INSN_J_RS2_MASK | RVC_INSN_OPCODE_MASK)
-#define RVC_MASK_C_JAL (RVC_INSN_FUNCT3_MASK | RVC_INSN_OPCODE_MASK)
-#define RVC_MASK_C_J (RVC_INSN_FUNCT3_MASK | RVC_INSN_OPCODE_MASK)
-#define RVG_MASK_BEQ (RV_INSN_FUNCT3_MASK | RV_INSN_OPCODE_MASK)
-#define RVG_MASK_BNE (RV_INSN_FUNCT3_MASK | RV_INSN_OPCODE_MASK)
-#define RVG_MASK_BLT (RV_INSN_FUNCT3_MASK | RV_INSN_OPCODE_MASK)
-#define RVG_MASK_BGE (RV_INSN_FUNCT3_MASK | RV_INSN_OPCODE_MASK)
-#define RVG_MASK_BLTU (RV_INSN_FUNCT3_MASK | RV_INSN_OPCODE_MASK)
-#define RVG_MASK_BGEU (RV_INSN_FUNCT3_MASK | RV_INSN_OPCODE_MASK)
-#define RVC_MASK_C_BEQZ (RVC_INSN_FUNCT3_MASK | RVC_INSN_OPCODE_MASK)
-#define RVC_MASK_C_BNEZ (RVC_INSN_FUNCT3_MASK | RVC_INSN_OPCODE_MASK)
-#define RVC_MASK_C_EBREAK 0xffff
-#define RVG_MASK_EBREAK 0xffffffff
-#define RVG_MASK_SRET 0xffffffff
-
#define __INSN_LENGTH_MASK _UL(0x3)
#define __INSN_LENGTH_GE_32 _UL(0x3)
#define __INSN_OPCODE_MASK _UL(0x7F)
@@ -275,236 +80,26 @@ static __always_inline bool riscv_insn_is_branch(u32 code)
return (code & RV_INSN_OPCODE_MASK) == RVG_OPCODE_BRANCH;
}
-#define INSN_MATCH_LB 0x3
-#define INSN_MASK_LB 0x707f
-#define INSN_MATCH_LH 0x1003
-#define INSN_MASK_LH 0x707f
-#define INSN_MATCH_LW 0x2003
-#define INSN_MASK_LW 0x707f
-#define INSN_MATCH_LD 0x3003
-#define INSN_MASK_LD 0x707f
-#define INSN_MATCH_LBU 0x4003
-#define INSN_MASK_LBU 0x707f
-#define INSN_MATCH_LHU 0x5003
-#define INSN_MASK_LHU 0x707f
-#define INSN_MATCH_LWU 0x6003
-#define INSN_MASK_LWU 0x707f
-#define INSN_MATCH_SB 0x23
-#define INSN_MASK_SB 0x707f
-#define INSN_MATCH_SH 0x1023
-#define INSN_MASK_SH 0x707f
-#define INSN_MATCH_SW 0x2023
-#define INSN_MASK_SW 0x707f
-#define INSN_MATCH_SD 0x3023
-#define INSN_MASK_SD 0x707f
-
-#define INSN_MATCH_C_LD 0x6000
-#define INSN_MASK_C_LD 0xe003
-#define INSN_MATCH_C_SD 0xe000
-#define INSN_MASK_C_SD 0xe003
-#define INSN_MATCH_C_LW 0x4000
-#define INSN_MASK_C_LW 0xe003
-#define INSN_MATCH_C_SW 0xc000
-#define INSN_MASK_C_SW 0xe003
-#define INSN_MATCH_C_LDSP 0x6002
-#define INSN_MASK_C_LDSP 0xe003
-#define INSN_MATCH_C_SDSP 0xe002
-#define INSN_MASK_C_SDSP 0xe003
-#define INSN_MATCH_C_LWSP 0x4002
-#define INSN_MASK_C_LWSP 0xe003
-#define INSN_MATCH_C_SWSP 0xc002
-#define INSN_MASK_C_SWSP 0xe003
-
#define INSN_OPCODE_MASK 0x007c
#define INSN_OPCODE_SHIFT 2
#define INSN_OPCODE_SYSTEM 28
-#define INSN_MASK_WFI 0xffffffff
-#define INSN_MATCH_WFI 0x10500073
-
-#define INSN_MASK_WRS 0xffffffff
-#define INSN_MATCH_WRS 0x00d00073
-
-#define INSN_MATCH_CSRRW 0x1073
-#define INSN_MASK_CSRRW 0x707f
-#define INSN_MATCH_CSRRS 0x2073
-#define INSN_MASK_CSRRS 0x707f
-#define INSN_MATCH_CSRRC 0x3073
-#define INSN_MASK_CSRRC 0x707f
-#define INSN_MATCH_CSRRWI 0x5073
-#define INSN_MASK_CSRRWI 0x707f
-#define INSN_MATCH_CSRRSI 0x6073
-#define INSN_MASK_CSRRSI 0x707f
-#define INSN_MATCH_CSRRCI 0x7073
-#define INSN_MASK_CSRRCI 0x707f
-
-#define INSN_MATCH_FLW 0x2007
-#define INSN_MASK_FLW 0x707f
-#define INSN_MATCH_FLD 0x3007
-#define INSN_MASK_FLD 0x707f
-#define INSN_MATCH_FLQ 0x4007
-#define INSN_MASK_FLQ 0x707f
-#define INSN_MATCH_FSW 0x2027
-#define INSN_MASK_FSW 0x707f
-#define INSN_MATCH_FSD 0x3027
-#define INSN_MASK_FSD 0x707f
-#define INSN_MATCH_FSQ 0x4027
-#define INSN_MASK_FSQ 0x707f
-
-#define INSN_MATCH_C_FLD 0x2000
-#define INSN_MASK_C_FLD 0xe003
-#define INSN_MATCH_C_FLW 0x6000
-#define INSN_MASK_C_FLW 0xe003
-#define INSN_MATCH_C_FSD 0xa000
-#define INSN_MASK_C_FSD 0xe003
-#define INSN_MATCH_C_FSW 0xe000
-#define INSN_MASK_C_FSW 0xe003
-#define INSN_MATCH_C_FLDSP 0x2002
-#define INSN_MASK_C_FLDSP 0xe003
-#define INSN_MATCH_C_FSDSP 0xa002
-#define INSN_MASK_C_FSDSP 0xe003
-#define INSN_MATCH_C_FLWSP 0x6002
-#define INSN_MASK_C_FLWSP 0xe003
-#define INSN_MATCH_C_FSWSP 0xe002
-#define INSN_MASK_C_FSWSP 0xe003
-
-#define INSN_MATCH_C_LHU 0x8400
-#define INSN_MASK_C_LHU 0xfc43
-#define INSN_MATCH_C_LH 0x8440
-#define INSN_MASK_C_LH 0xfc43
-#define INSN_MATCH_C_SH 0x8c00
-#define INSN_MASK_C_SH 0xfc43
-
#define INSN_16BIT_MASK 0x3
#define INSN_IS_16BIT(insn) (((insn) & INSN_16BIT_MASK) != INSN_16BIT_MASK)
#define INSN_LEN(insn) (INSN_IS_16BIT(insn) ? 2 : 4)
-#define SHIFT_RIGHT(x, y) \
- ((y) < 0 ? ((x) << -(y)) : ((x) >> (y)))
-
#define REG_MASK \
((1 << (5 + LOG_REGBYTES)) - (1 << LOG_REGBYTES))
-#define REG_OFFSET(insn, pos) \
- (SHIFT_RIGHT((insn), (pos) - LOG_REGBYTES) & REG_MASK)
-
-#define REG_PTR(insn, pos, regs) \
- ((ulong *)((ulong)(regs) + REG_OFFSET(insn, pos)))
-
-#define GET_RS1(insn, regs) (*REG_PTR(insn, SH_RS1, regs))
-#define GET_RS2(insn, regs) (*REG_PTR(insn, SH_RS2, regs))
-#define GET_RS1S(insn, regs) (*REG_PTR(RVC_RS1S(insn), 0, regs))
-#define GET_RS2S(insn, regs) (*REG_PTR(RVC_RS2S(insn), 0, regs))
-#define GET_RS2C(insn, regs) (*REG_PTR(insn, SH_RS2C, regs))
-#define GET_SP(regs) (*REG_PTR(2, 0, regs))
-#define SET_RD(insn, regs, val) (*REG_PTR(insn, SH_RD, regs) = (val))
-#define IMM_I(insn) ((s32)(insn) >> 20)
-#define IMM_S(insn) (((s32)(insn) >> 25 << 5) | \
- (s32)(((insn) >> 7) & 0x1f))
-
-#define SH_RD 7
-#define SH_RS1 15
-#define SH_RS2 20
-#define SH_RS2C 2
-#define MASK_RX 0x1f
-
#if defined(CONFIG_64BIT)
#define LOG_REGBYTES 3
#else
#define LOG_REGBYTES 2
#endif
-#define MASK_FUNCT3 0x7000
-
-#define GET_FUNCT3(insn) (((insn) >> 12) & 7)
-
-#define RV_IMM_SIGN(x) (-(((x) >> 31) & 1))
-#define RVC_IMM_SIGN(x) (-(((x) >> 12) & 1))
-#define RV_X_MASK(X, s, mask) (((X) >> (s)) & (mask))
-#define RV_X(X, s, n) RV_X_MASK(X, s, ((1 << (n)) - 1))
-#define RVC_LW_IMM(x) ((RV_X(x, 6, 1) << 2) | \
- (RV_X(x, 10, 3) << 3) | \
- (RV_X(x, 5, 1) << 6))
-#define RVC_LD_IMM(x) ((RV_X(x, 10, 3) << 3) | \
- (RV_X(x, 5, 2) << 6))
-#define RVC_LWSP_IMM(x) ((RV_X(x, 4, 3) << 2) | \
- (RV_X(x, 12, 1) << 5) | \
- (RV_X(x, 2, 2) << 6))
-#define RVC_LDSP_IMM(x) ((RV_X(x, 5, 2) << 3) | \
- (RV_X(x, 12, 1) << 5) | \
- (RV_X(x, 2, 3) << 6))
-#define RVC_SWSP_IMM(x) ((RV_X(x, 9, 4) << 2) | \
- (RV_X(x, 7, 2) << 6))
-#define RVC_SDSP_IMM(x) ((RV_X(x, 10, 3) << 3) | \
- (RV_X(x, 7, 3) << 6))
-#define RVC_RS1S(insn) (8 + RV_X(insn, SH_RD, 3))
-#define RVC_RS2S(insn) (8 + RV_X(insn, SH_RS2C, 3))
-#define RVC_RS2(insn) RV_X(insn, SH_RS2C, 5)
-#define RVC_X(X, s, mask) RV_X_MASK(X, s, mask)
-
-#define RV_EXTRACT_FUNCT3(x) \
- ({typeof(x) x_ = (x); \
- (RV_X_MASK(x_, RV_INSN_FUNCT3_OPOFF, \
- RV_INSN_FUNCT3_MASK >> RV_INSN_FUNCT3_OPOFF)); })
-
-#define RV_EXTRACT_RS1_REG(x) \
- ({typeof(x) x_ = (x); \
- (RV_X_MASK(x_, RVG_RS1_OPOFF, RVG_RS1_MASK)); })
-
-#define RV_EXTRACT_RS2_REG(x) \
- ({typeof(x) x_ = (x); \
- (RV_X_MASK(x_, RVG_RS2_OPOFF, RVG_RS2_MASK)); })
-
-#define RV_EXTRACT_RD_REG(x) \
- ({typeof(x) x_ = (x); \
- (RV_X_MASK(x_, RVG_RD_OPOFF, RVG_RD_MASK)); })
-
-#define RV_EXTRACT_UTYPE_IMM(x) \
- ({typeof(x) x_ = (x); \
- (RV_X_MASK(x_, RV_U_IMM_31_12_OPOFF, RV_U_IMM_31_12_MASK)); })
-
-#define RV_EXTRACT_JTYPE_IMM(x) \
- ({typeof(x) x_ = (x); \
- (RV_X_MASK(x_, RV_J_IMM_10_1_OPOFF, RV_J_IMM_10_1_MASK) << RV_J_IMM_10_1_OFF) | \
- (RV_X_MASK(x_, RV_J_IMM_11_OPOFF, RV_J_IMM_11_MASK) << RV_J_IMM_11_OFF) | \
- (RV_X_MASK(x_, RV_J_IMM_19_12_OPOFF, RV_J_IMM_19_12_MASK) << RV_J_IMM_19_12_OFF) | \
- (RV_IMM_SIGN(x_) << RV_J_IMM_SIGN_OFF); })
-
-#define RV_EXTRACT_ITYPE_IMM(x) \
- ({typeof(x) x_ = (x); \
- (RV_X_MASK(x_, RV_I_IMM_11_0_OPOFF, RV_I_IMM_11_0_MASK)) | \
- (RV_IMM_SIGN(x_) << RV_I_IMM_SIGN_OFF); })
-
-#define RV_EXTRACT_BTYPE_IMM(x) \
- ({typeof(x) x_ = (x); \
- (RV_X_MASK(x_, RV_B_IMM_4_1_OPOFF, RV_B_IMM_4_1_MASK) << RV_B_IMM_4_1_OFF) | \
- (RV_X_MASK(x_, RV_B_IMM_10_5_OPOFF, RV_B_IMM_10_5_MASK) << RV_B_IMM_10_5_OFF) | \
- (RV_X_MASK(x_, RV_B_IMM_11_OPOFF, RV_B_IMM_11_MASK) << RV_B_IMM_11_OFF) | \
- (RV_IMM_SIGN(x_) << RV_B_IMM_SIGN_OFF); })
-
-#define RVC_EXTRACT_C2_RS1_REG(x) \
- ({typeof(x) x_ = (x); \
- (RV_X_MASK(x_, RVC_C2_RS1_OPOFF, RVC_C2_RS1_MASK)); })
-
-#define RVC_EXTRACT_JTYPE_IMM(x) \
- ({typeof(x) x_ = (x); \
- (RVC_X(x_, RVC_J_IMM_3_1_OPOFF, RVC_J_IMM_3_1_MASK) << RVC_J_IMM_3_1_OFF) | \
- (RVC_X(x_, RVC_J_IMM_4_OPOFF, RVC_J_IMM_4_MASK) << RVC_J_IMM_4_OFF) | \
- (RVC_X(x_, RVC_J_IMM_5_OPOFF, RVC_J_IMM_5_MASK) << RVC_J_IMM_5_OFF) | \
- (RVC_X(x_, RVC_J_IMM_6_OPOFF, RVC_J_IMM_6_MASK) << RVC_J_IMM_6_OFF) | \
- (RVC_X(x_, RVC_J_IMM_7_OPOFF, RVC_J_IMM_7_MASK) << RVC_J_IMM_7_OFF) | \
- (RVC_X(x_, RVC_J_IMM_9_8_OPOFF, RVC_J_IMM_9_8_MASK) << RVC_J_IMM_9_8_OFF) | \
- (RVC_X(x_, RVC_J_IMM_10_OPOFF, RVC_J_IMM_10_MASK) << RVC_J_IMM_10_OFF) | \
- (RVC_IMM_SIGN(x_) << RVC_J_IMM_SIGN_OFF); })
-
-#define RVC_EXTRACT_BTYPE_IMM(x) \
- ({typeof(x) x_ = (x); \
- (RVC_X(x_, RVC_B_IMM_2_1_OPOFF, RVC_B_IMM_2_1_MASK) << RVC_B_IMM_2_1_OFF) | \
- (RVC_X(x_, RVC_B_IMM_4_3_OPOFF, RVC_B_IMM_4_3_MASK) << RVC_B_IMM_4_3_OFF) | \
- (RVC_X(x_, RVC_B_IMM_5_OPOFF, RVC_B_IMM_5_MASK) << RVC_B_IMM_5_OFF) | \
- (RVC_X(x_, RVC_B_IMM_7_6_OPOFF, RVC_B_IMM_7_6_MASK) << RVC_B_IMM_7_6_OFF) | \
- (RVC_IMM_SIGN(x_) << RVC_B_IMM_SIGN_OFF); })
+#define RV_X_MASK(X, s, mask) (((X) >> (s)) & (mask))
+// These three are used by vector stuff
#define RVG_EXTRACT_SYSTEM_CSR(x) \
({typeof(x) x_ = (x); RV_X_MASK(x_, RVG_SYSTEM_CSR_OFF, RVG_SYSTEM_CSR_MASK); })
--
2.54.0
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH v2 01/16] riscv: Introduce instruction table generation
2026-06-22 4:01 ` [PATCH v2 01/16] riscv: Introduce instruction table generation Charlie Jenkins via B4 Relay
@ 2026-06-22 4:13 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:13 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] The shell script incorrectly truncates multiple instruction constraints during bash parameter expansion, causing generated matchers to drop all but the first constraint.
- [High] Extracted immediate values for compressed instructions are incorrectly truncated to 16 bits, corrupting instructions with large shifted immediates like c.lui.
- [Low] The generated header relies on `sign_extend32` but fails to include `<linux/bitops.h>`.
- [Low] Signed integer shift overflow when generating instruction masks and matches.
--
commit 2e4d01f18f465b8609784ae2ae57f5539bddd357
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
riscv: Introduce instruction table generation
Eliminate the need to hand-write riscv instructions by using a shell
script to autogenerate a header from an instruction table. This is modeled
after the syscall table infrastructure. The table is generated externally
by riscv-unified-db.
Link: https://github.com/riscv-software-src/riscv-unified-db
> diff --git a/arch/riscv/tools/insn_tbl.sh b/arch/riscv/tools/insn_tbl.sh
> new file mode 100755
> index 0000000000000..aede14c80146f
> --- /dev/null
> +++ b/arch/riscv/tools/insn_tbl.sh
> @@ -0,0 +1,256 @@
[ ... ]
> +echo "#ifndef RISCV_INSN_GEN_H" >> $outfile
> +echo "#define RISCV_INSN_GEN_H" >> $outfile
> +echo >> $outfile
> +
> +printf "#include <linux/bits.h>" >> $outfile
> +echo >> $outfile
[Severity: Low]
The generated header relies on sign_extend32() for signed fields, but only
includes <linux/bits.h>. Could this missing <linux/bitops.h> inclusion cause
compilation failures for future standalone inclusions of the generated header?
[ ... ]
> + if [ ${offset} -gt 0 ]; then
> + s=" << ${offset}"
> + else
> + s=""
> + fi
> +
> + mask="${mask}${s}"
> +
> + match="${match} | 0b${bits}${s}"
[Severity: Low]
Does this code trigger signed integer shift overflow warnings? The script
generates macros using signed binary literals shifted by large amounts
(e.g., 0b111000100000 << 20 for fclass.d). Even with -fno-strict-overflow,
this can cause compiler warnings if -Wshift-overflow is enabled. Would it be
better to append a U suffix to these binary literals to ensure unsigned
shifts?
[ ... ]
> + if [ "${variable}" != "${variable#*!}" ]; then
> + raw_constraints="${variable#*!}"
> + raw_constraints="${raw_constraints%%[=<~!]**}"
[Severity: High]
Does this parameter expansion inadvertently truncate multiple constraints?
Because the ! character is included in the character class [=<~!], the
%% operator greedily matches the longest suffix starting with the first !
it encounters.
For example, with c.ldsp which has constraints like xd!0!1!3!5!7=11-7, it
looks like this strips everything after the first !, leaving only 0. This
would cause the generated matcher to only verify that xd != 0 and fail to
enforce the rest of the constraints.
[ ... ]
> + if [ ${sign_extend} ]; then
> + extract="sign_extend32(${extract}, $((offset + left_shift - 1)))"
> + type="s"
> + else
> + type="u"
> + fi
> +
> + printf "static __always_inline ${type}${size} riscv_insn_${formatted_inst_name}_extract_${variable_name}(u${size} ${insn})\n"
[Severity: High]
Does this return type cause unintended truncation for compressed instructions
with large immediates?
The script deduces the return type as s16 or u16 for compressed instructions.
However, instructions like c.lui encode a 6-bit immediate shifted left by 12,
resulting in an 18-bit signed value. It appears the generated function correctly
computes the 32-bit signed value, but returning it as s16 silently truncates
the upper 16 bits (including the sign bit). Could this cause data corruption
when decoding such instructions?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=1
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 09/16] KVM: device: Add test device
2026-06-22 4:01 ` [PATCH v2 09/16] KVM: device: Add test device Charlie Jenkins via B4 Relay
@ 2026-06-22 4:13 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:13 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [Critical] Guest-triggerable out-of-bounds memory access in mmio_read and mmio_write due to invalid size constraints and missing length validation.
- [Critical] Use-after-free vulnerability due to missing IO bus unregistration during device release.
- [High] Registering the KVM IO device without holding `kvm->slots_lock`.
- [High] Memory leak of the parent `struct kvm_device` in the device release callback.
- [High] Ignoring the return value of `kvm_io_bus_register_dev()` leaves the device silently non-functional on failure.
- [High] Incorrect error handling sequence in `kvm_init()` leads to a resource leak of VFIO ops or uninitialized teardown.
--
commit 9fe1265e6415d3c7d4c794808d6fc306d06a4e0e
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
KVM: device: Add test device
Create a KVM test device to help verify mmio reads and write emulation.
This is a simple device that will store the data in a buffer on writes
and echo back that stored data on a read.
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 881f92d7a469e..d9bbe570eddd5 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
[ ... ]
> @@ -6559,6 +6564,8 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module)
> err_gmem:
> kvm_vfio_ops_exit();
> err_vfio:
> + kvm_mmio_test_ops_exit();
> +err_mmio_test:
> kvm_async_pf_deinit();
[Severity: High]
Does this error handling sequence leak VFIO ops or tear down uninitialized
state?
If kvm_mmio_test_ops_init() fails, the code jumps to err_mmio_test, which
only executes kvm_async_pf_deinit() and skips kvm_vfio_ops_exit().
Conversely, if kvm_vfio_ops_init() fails, the code jumps to err_vfio and
executes kvm_mmio_test_ops_exit() before it was initialized. Should the labels
reverse the initialization sequence perfectly?
> diff --git a/virt/kvm/mmio_test.c b/virt/kvm/mmio_test.c
> new file mode 100644
> index 0000000000000..fa84c2b4c5fcf
> --- /dev/null
> +++ b/virt/kvm/mmio_test.c
[ ... ]
> +struct mmio_test {
> + struct kvm *kvm;
> + struct kvm_io_device dev;
> + unsigned long start;
> + unsigned long size;
> + char cache[16];
> +};
[ ... ]
> +static int mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
> + gpa_t addr, int len, void *val)
> +{
> + struct mmio_test *mmio_test = kvm_to_mmio_test_dev(dev);
> +
> + if ((addr - mmio_test->start) >= mmio_test->size)
> + return -1;
> +
> + /* Write back cached value */
> + memcpy(val, &mmio_test->cache[(addr - mmio_test->start)], len);
[Severity: Critical]
Can a guest trigger an out-of-bounds read of host memory here?
The cache array is 16 bytes long, but mmio_test->size is configured to 0x16
(22 bytes) in mmio_test_create(). The boundary check permits accesses up to
offset 21.
Furthermore, is there a check to ensure that the access offset plus len
does not exceed the bounds of the array?
> + return 0;
> +}
> +
> +static int mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
> + gpa_t addr, int len, const void *val)
> +{
> + struct mmio_test *mmio_test = kvm_to_mmio_test_dev(dev);
> +
> + if ((addr - mmio_test->start) >= mmio_test->size)
> + return -1;
> +
> + /* Cache value */
> + memcpy(&mmio_test->cache[(addr - mmio_test->start)], val, len);
[Severity: Critical]
Similarly, can this allow a malicious guest to trigger a heap buffer overflow?
Without a check verifying that the access length fits within the remaining
space in the cache array, a large or offset write could overwrite adjacent
host kernel memory.
> + return 0;
> +}
[ ... ]
> +static int mmio_test_create(struct kvm_device *dev, u32 type)
> +{
> + struct mmio_test *mmio_test;
> +
> + mmio_test = kzalloc(sizeof(*mmio_test), GFP_KERNEL);
> + if (!mmio_test)
> + return -ENOMEM;
> +
> + mmio_test->start = 0x20000000;
> + mmio_test->size = 0x16;
> +
> + dev->private = mmio_test;
> +
> + kvm_iodevice_init(&mmio_test->dev, &mmio_ops);
> + kvm_io_bus_register_dev(dev->kvm, KVM_MMIO_BUS, mmio_test->start,
> + mmio_test->size, &mmio_test->dev);
[Severity: High]
Does kvm_io_bus_register_dev() require kvm->slots_lock to be held?
The function modifies RCU-protected bus arrays and has a lockdep assertion
for kvm->slots_lock. This is called under kvm->lock but appears to be missing
the slots_lock acquisition.
[Severity: High]
What happens if kvm_io_bus_register_dev() fails here?
The function could return -ENOMEM or -ENOSPC, but its return value is not
checked. Could this leave the test device reported as fully instantiated
without being able to receive MMIO traps?
> +
> + return 0;
> +}
> +
> +static void mmio_test_release(struct kvm_device *dev)
> +{
> + kfree(dev->private);
[Severity: Critical]
Does freeing dev->private without unregistering the io device create a
use-after-free?
When the file descriptor is closed, the device state is freed, but the
embedded kvm_io_device remains registered on the KVM MMIO bus. Any subsequent
guest MMIO access to that region would route the request to this freed memory.
Should this call kvm_io_bus_unregister_dev() first?
[Severity: High]
Is the parent kvm_device leaked here?
When a KVM device implements the release callback instead of destroy, it is
responsible for freeing the core kvm_device object allocated by KVM core.
Should there be a call to kfree(dev) before returning?
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=9
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 07/16] riscv: Use generated instruction headers for misaligned loads/stores
2026-06-22 4:01 ` [PATCH v2 07/16] riscv: Use generated instruction headers for misaligned loads/stores Charlie Jenkins via B4 Relay
@ 2026-06-22 4:18 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:18 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
New issues:
- [Critical] Missing arithmetic right shift and sign-extension in emulated scalar misaligned loads corrupts returned data.
- [Critical] Missing +8 register index offset for compressed C-extension store instructions reads from incorrect registers.
- [High] Removal of CONFIG_64BIT guards causes overlapping RV32 floating-point and RV64 integer compressed instructions to be incorrectly decoded.
- [High] Instruction pointer (`regs->epc`) is left as 0 on unhandled store instructions.
- [Medium] Missing validation for reserved encodings in compressed SP-relative loads allows reserved instructions to be emulated.
Pre-existing issues:
- [High] Emulating misaligned stores with the zero register (x0) leaks the instruction pointer (epc) to memory.
- [High] Instruction pointer (`regs->epc`) is not restored when user memory copy fails.
--
commit ebbff49ec30db1d18deced4c1343cfcdd49aef84
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
riscv: Use generated instruction headers for misaligned loads/stores
This commit migrates the misaligned loads/store code to use the generated
instruction headers instead of the hand-written instruction composition
functions.
> diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c
> index 81b7682e6c6db..4d2a2432e0c45 100644
> --- a/arch/riscv/kernel/traps_misaligned.c
> +++ b/arch/riscv/kernel/traps_misaligned.c
[ ... ]
> @@ -240,68 +219,71 @@ static int handle_scalar_misaligned_load(struct pt_regs *regs)
>
> regs->epc = 0;
>
> - if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
> + if (riscv_insn_is_lw(insn)) {
> len = 4;
[ ... ]
> -#if defined(CONFIG_64BIT)
> - } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
> + rd = riscv_insn_lw_extract_xd(insn);
> + } else if (riscv_insn_is_ld(insn)) {
> len = 8;
[ ... ]
> - } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
> + rd = riscv_insn_lhu_extract_xd(insn);
> + } else if (riscv_insn_is_c_ld(insn)) {
> len = 8;
> shift = 8 * (sizeof(unsigned long) - len);
> - insn = RVC_RS2S(insn) << SH_RD;
[Severity: High]
Could this incorrectly decode a compressed floating point instruction as an
integer load on 32-bit systems? Since RV64 compressed integer instructions
and RV32 compressed floating-point instructions share the same encoding
bitmasks, removing the bitness guards and checking for RV64 instructions
first might result in a negative shift amount in
handle_scalar_misaligned_load(), leading to an invalid memory read.
> - } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP &&
> - ((insn >> SH_RD) & 0x1f)) {
> + } else if (riscv_insn_is_c_ldsp(insn)) {
> len = 8;
> shift = 8 * (sizeof(unsigned long) - len);
> -#endif
> - } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
> + rd = riscv_insn_c_ldsp_extract_xd(insn);
[Severity: Medium]
Does this bypass validation for reserved encodings? The specification
dictates that compressed SP-relative loads must have a non-zero destination
register. The previous code enforced this, but the new branch seems to allow
processing reserved instructions as valid loads if the destination register
is zero.
[ ... ]
> @@ -319,11 +301,11 @@ static int handle_scalar_misaligned_load(struct pt_regs *regs)
> }
>
> if (!fp)
> - SET_RD(insn, regs, (long)(val.data_ulong << shift) >> shift);
> + *(unsigned long *)((unsigned long *)regs + rd) = val.data_ulong << shift;
[Severity: Critical]
Does this code miss an arithmetic right shift? For loads smaller than the
native register width in handle_scalar_misaligned_load(), left-shifting the
loaded data into the most significant bits of the register without
arithmetically right-shifting it back leaves the lower bits zeroed out and
fails to sign-extend the value.
[ ... ]
> @@ -351,67 +333,68 @@ static int handle_scalar_misaligned_store(struct pt_regs *regs)
>
> regs->epc = 0;
>
> - val.data_ulong = GET_RS2(insn, regs);
> -
> - if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
> + if (riscv_insn_is_sw(insn)) {
> len = 4;
[ ... ]
> -#if defined(CONFIG_64BIT)
> - } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
> + rd = riscv_insn_sh_extract_xs2(insn);
> + } else if (riscv_insn_is_c_sd(insn)) {
> len = 8;
> - val.data_ulong = GET_RS2S(insn, regs);
> - } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP) {
> + rd = riscv_insn_c_sd_extract_xs2(insn);
[Severity: Critical]
Could this read from the wrong registers? The load handler adds the required
offset of 8 for compressed instructions, but it appears missing here in
handle_scalar_misaligned_store() for all compressed stores.
[ ... ]
> - } else if ((insn & INSN_MASK_C_SH) == INSN_MATCH_C_SH) {
> + } else if (riscv_insn_is_c_sh(insn)) {
> len = 2;
> - val.data_ulong = GET_RS2S(insn, regs);
> + rd = riscv_insn_c_sh_extract_xs2(insn);
> } else {
> - regs->epc = epc;
> return -1;
> }
[Severity: High]
Is it intentional to return without restoring regs->epc here? Since regs->epc
is temporarily set to 0 during instruction evaluation, returning -1 without
restoring it might cause the task's instruction pointer in the signal context
to be incorrectly reported as 0 when a SIGBUS is delivered.
> if (!IS_ENABLED(CONFIG_FPU) && fp)
> return -EOPNOTSUPP;
>
> + if (!fp)
> + val.data_ulong = *(unsigned long *)((unsigned long *)regs + rd);
[Severity: High]
This isn't a bug introduced by this patch, but does this leak the instruction
pointer to memory? When a misaligned store uses the hardwired zero register,
the extracted register index is 0. Since struct pt_regs stores the epc at
index 0, the emulator writes the epc value to memory instead of 0.
Also, due to the missing offset for compressed stores mentioned earlier,
reading without the offset might cause the handler to read from kernel state
pointers like epc in pt_regs instead of the correct user registers.
[ ... ]
[Severity: High]
This is a pre-existing issue, but should we restore regs->epc when the user
memory copy fails?
In handle_scalar_misaligned_load() and handle_scalar_misaligned_store():
if (user_mode(regs)) {
if (copy_from_user(&val, (u8 __user *)addr, len))
return -1;
}
Returning -1 on memory copy failure while regs->epc is still set to 0 breaks
user-space signal handlers because the program counter in the signal context
will be 0.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=7
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 08/16] riscv: kvm: Use generated instruction headers for csr code
2026-06-22 4:01 ` [PATCH v2 08/16] riscv: kvm: Use generated instruction headers for csr code Charlie Jenkins via B4 Relay
@ 2026-06-22 4:18 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:18 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] KVM's `guest_context.zero` can be overwritten by MMIO reads with `rd=x0`, corrupting subsequent emulated instructions that read `x0`.
--
commit 6e0c9adf0592e2c6310d9a0a01fa605f82581d3e
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
riscv: kvm: Use generated instruction headers for csr code
Migrate the csr parsing code to use the generated instruction headers
instead of the hand-written instruction composition functions.
> diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c
> index f09f9251d1f0a..8ccf6ec722f03 100644
> --- a/arch/riscv/kvm/vcpu_insn.c
> +++ b/arch/riscv/kvm/vcpu_insn.c
> @@ -146,43 +146,44 @@ int kvm_riscv_vcpu_csr_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
>
> static int csr_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn)
> {
> + #define GET_REG(_rd) (*((unsigned long *)(&vcpu->arch.guest_context) + _rd))
[Severity: High]
This isn't a bug introduced by this patch, but KVM's software copy of the
zero register (which this GET_REG macro can read) can be permanently
corrupted by a pre-existing issue in MMIO emulation.
When an MMIO load uses x0 as the destination register (e.g., lw x0, (a0)),
kvm_riscv_vcpu_mmio_return() in arch/riscv/kvm/vcpu_insn.c unconditionally
stores the result:
*((ulong *)(&vcpu->arch.guest_context) + vcpu->arch.mmio_decode.rd) =
(long)data << shift >> shift;
Because rd is 0, this overwrites guest_context.zero at index 0.
Unlike kvm_riscv_vcpu_csr_return() which checks if (vcpu->arch.csr_decode.rd)
before writing, the MMIO return path lacks this guard.
Since instruction emulation like the CSR emulation here uses x0 as an
operand and reads from guest_context via GET_REG(), could the corrupted
non-zero value be used instead of the hardware-mandated 0, leading to
incorrect guest execution?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=8
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 10/16] KVM: riscv: selftests: Add mmio test
2026-06-22 4:01 ` [PATCH v2 10/16] KVM: riscv: selftests: Add mmio test Charlie Jenkins via B4 Relay
@ 2026-06-22 4:18 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:18 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 11 potential issue(s) to consider:
New issues:
- [High] The test pattern for MMIO writes uses a 32-bit literal, causing it to evaluate to 0 when shifted on 64-bit architectures.
- [Medium] The compressed store instruction `c.sdsp` is entirely omitted from the test suite.
- [Medium] Standard 16-bit loads (`lh` and `lhu`) are erroneously restricted to 64-bit RISC-V builds.
- [Medium] The KVM device file descriptor returned by `kvm_create_device` is leaked, which also leaks the KVM VM.
- [Medium] The selftest fails to gracefully skip when KVM_DEV_TYPE_TEST is not supported by the kernel.
Pre-existing issues:
- [Critical] The KVM MMIO test device contains a heap buffer overflow and out-of-bounds read vulnerability due to a mismatch between the registered device size and its internal cache array capacity.
- [Critical] The mmio_test device fails to unregister itself from the KVM MMIO bus upon release, leading to a Use-After-Free vulnerability.
- [High] `mmio_test_create()` registers the device to the KVM IO bus without holding the required `kvm->slots_lock`.
- [High] The error cleanup path in `kvm_init()` unwinds initializations in the wrong order.
- [High] The return value of `kvm_io_bus_register_dev()` is ignored, potentially leaking an unregistered device.
- [High] The `struct kvm_device` allocated for the test device is permanently leaked.
--
commit 91109e879d023e4a9b60888f79545187037508bf
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
KVM: riscv: selftests: Add mmio test
This commit adds a new MMIO selftest for KVM on RISC-V. It introduces test
cases for various read and write instructions, including compressed
instructions, to ensure KVM properly emulates MMIO accesses.
> diff --git a/tools/testing/selftests/kvm/riscv/mmio_test.c b/tools/testing/selftests/kvm/riscv/mmio_test.c
> new file mode 100644
> index 0000000000000..9726860a269a3
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/riscv/mmio_test.c
> @@ -0,0 +1,184 @@
[ ... ]
> +test_standard_read(4, lw, lw, "")
> +test_standard_read(4, c.lw, c_lw, ".option arch,+c\n")
> +test_sp_read(4, c.lwsp, c_lwsp)
> +
> +#if __riscv_xlen == 64
> +test_standard_read(2, lh, lh, "")
> +test_standard_read(2, lhu, lhu, "")
[Severity: Medium]
Are lh and lhu intentionally restricted to 64-bit architectures here?
Since these are standard 16-bit loads in the RV32I base instruction set,
should they be moved outside the __riscv_xlen == 64 check so they are also
tested on 32-bit platforms?
> +test_standard_read(4, lwu, lwu, "")
> +test_standard_read(8, ld, ld, "")
[ ... ]
> +#define test_standard_write(len, write, read, name, options) \
> +static void test_##name(void) \
> +{ \
> + unsigned long result; \
> + unsigned long reference = (0x55555555UL >> ((sizeof(long) - len) * 8)); \
[Severity: High]
Does this bitwise shift evaluate to 0 on 64-bit systems?
When __riscv_xlen == 64, sizeof(long) is 8. For a 32-bit store (len=4),
this shifts 0x55555555UL right by 32 bits, resulting in 0.
For len=1 and len=2, it shifts by 56 and 48 bits, also resulting in 0.
Could this mask sign-extension or truncation issues by only ever verifying
a value of 0?
Should this use a 64-bit literal like 0x5555555555555555ULL instead?
> + /* Check that we can write and then read the same value. */ \
> + asm volatile ( \
[ ... ]
> +#define test_sp_write(len, write, read, name) \
> +static void test_##name(void) \
> +{ \
> + unsigned long result; \
> + unsigned long tmp; \
> + unsigned long reference = (0x55555555UL >> ((sizeof(long) - len) * 8)); \
[Severity: High]
Similar to test_standard_write, does this shift evaluate to 0 on 64-bit
systems for compressed stack-pointer relative writes?
> + /* Check that we can write and then read the same value. */ \
[ ... ]
> +static void run(void *guest_code, char *instruction)
> +{
> + struct ucall uc;
> + struct kvm_vm *vm;
> + struct kvm_vcpu *vcpu;
> +
> + vm = vm_create_with_one_vcpu(&vcpu, guest_code);
> + kvm_create_device(vm, KVM_DEV_TYPE_TEST);
[Severity: Medium]
Does this test need to gracefully skip if KVM_DEV_TYPE_TEST is unavailable?
kvm_create_device() uses TEST_ASSERT internally and will abort the test
if the kernel lacks support.
Would it be safer to check support with __kvm_create_device() and use
TEST_REQUIRE() to exit with a skip code in CI environments running older
kernels?
[Severity: Medium]
Does this leak the KVM device file descriptor returned by kvm_create_device()?
Since the file descriptor holds a reference to the KVM VM (kvm_get_kvm),
failing to close it will prevent the VM from being destroyed when
kvm_vm_free(vm) is called.
Since run() iterates for multiple instructions, will this accumulate file
descriptor and kernel memory leaks?
> +
> + virt_map(vm, (unsigned long)MMIO_TEST_REGION, MMIO_TEST_REGION, 1);
[ ... ]
> +void test_mmio_read_sign_extension(void)
> +{
> + run(test_lb, "lb");
[ ... ]
> + run(test_c_lwsp, "c.lwsp");
> +
> +#if __riscv_xlen == 64
> + run(test_lh, "lh");
> + run(test_lhu, "lhu");
[Severity: Medium]
Are the executions for lh and lhu also intentionally restricted to 64-bit
builds here?
> + run(test_lwu, "lwu");
[ ... ]
> +void test_mmio_write(void)
> +{
> + run(test_sb, "sb");
> + run(test_sh, "sh");
> + run(test_sw, "sw");
> + run(test_c_sw, "c.sw");
> + run(test_c_swsp, "c.swsp");
> +
> +#if __riscv_xlen == 64
> + run(test_sd, "sd");
> + run(test_c_sd, "c.sd");
[Severity: Medium]
Is the compressed store instruction c.sdsp omitted from the 64-bit write
tests?
The commit message notes that all emulated load and store instructions are
checked, but c.sdsp appears to be missing an instantiation via
test_sp_write and execution via run(test_c_sdsp, "c.sdsp").
> +#endif
> +}
While reviewing how this selftest interacts with KVM_DEV_TYPE_TEST, I
noticed several pre-existing issues in the test device implementation itself
(virt/kvm/mmio_test.c and virt/kvm/kvm_main.c). I have included them here
for completeness:
virt/kvm/mmio_test.c:mmio_test_create():
mmio_test->size = 0x16;
[Severity: Critical]
This is a pre-existing issue, but does mmio_test->size exceed the capacity
of the internal cache array?
The internal cache array is sized at 16 bytes (char cache[16];), but the
size field is initialized to 0x16 (22 bytes).
When a guest accesses an MMIO address near the end of the registered region,
the addr - start + len calculation inside mmio_write() and mmio_read()
can exceed 16.
Can this allow an unprivileged guest to trigger an out-of-bounds memcpy(),
leading to host heap corruption or information leaks?
virt/kvm/mmio_test.c:mmio_test_release():
static void mmio_test_release(struct kvm_device *dev)
{
kfree(dev->private);
}
[Severity: Critical]
This is a pre-existing issue, but is there a use-after-free vulnerability here?
The release callback frees the backing dev->private structure, but it does
not call kvm_io_bus_unregister_dev().
The KVM MMIO bus retains a dangling pointer to the freed structure.
Will any subsequent MMIO access to the registered range by an active vCPU
dereference this freed pointer?
[Severity: High]
This is a pre-existing issue, but does mmio_test_release() leak the
struct kvm_device?
kvm_ioctl_create_device() dynamically allocates the struct kvm_device
using kzalloc().
The device implementation's .release or .destroy callback is responsible
for freeing this memory, but it appears to be omitted here.
Does this cause a permanent leak every time a test device is closed?
virt/kvm/mmio_test.c:mmio_test_create():
kvm_io_bus_register_dev(dev->kvm, KVM_MMIO_BUS, mmio_test->start,
mmio_test->size, &mmio_test->dev);
[Severity: High]
This is a pre-existing issue, but is kvm_io_bus_register_dev() called
without holding the required kvm->slots_lock?
mmio_test_create() is invoked via kvm_ioctl_create_device(), which only
holds kvm->lock.
kvm_io_bus_register_dev() strictly requires kvm->slots_lock and enforces
it via lockdep.
Will this cause an immediate lockdep splat and a data race against concurrent
MMIO bus updates?
[Severity: High]
This is a pre-existing issue, but is the return value of
kvm_io_bus_register_dev() safely ignored?
The function can fail (e.g., due to -ENOMEM or hitting NR_IOBUS_DEVS).
Since mmio_test_create() ignores the return value and unconditionally
returns 0, will userspace receive a valid fd for a device that was never
actually attached to the MMIO bus?
virt/kvm/kvm_main.c:kvm_init():
err_gmem:
kvm_vfio_ops_exit();
err_vfio:
kvm_mmio_test_ops_exit();
err_mmio_test:
kvm_async_pf_deinit();
[Severity: High]
This is a pre-existing issue, but are the error unwinding labels interleaved
incorrectly?
kvm_init() initializes components in the order: VFIO, MMIO_TEST, and GMEM.
If kvm_gmem_init() fails, it jumps to err_gmem which executes
kvm_vfio_ops_exit() followed by kvm_mmio_test_ops_exit(), which is the
reverse of the correct unwinding order.
Furthermore, if kvm_vfio_ops_init() fails, it jumps to err_vfio and
attempts to exit mmio_test (which hasn't been initialized yet).
If kvm_mmio_test_ops_init() fails, it skips unwinding VFIO entirely.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=10
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 04/16] riscv: Add kprobes instruction simulation KUnit
2026-06-22 4:01 ` [PATCH v2 04/16] riscv: Add kprobes instruction simulation KUnit Charlie Jenkins via B4 Relay
@ 2026-06-22 4:19 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:19 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The KUnit test executes an uninterruptible 4.29 billion iteration loop, guaranteeing kernel soft lockups and breaking CI.
- [Medium] The KUnit test logic is tautological and its state initialization masks branch outcomes, halving test coverage.
--
commit 0b416648ab5f17f7e140c671781502c76b641895
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
riscv: Add kprobes instruction simulation KUnit
This commit introduces a KUnit test that iterates through all 32-bit
integers to validate kprobes instruction simulation. The tests are gated
behind a new CONFIG_RISCV_KPROBES_SIMULATE_KUNIT kconfig option.
diff --git a/arch/riscv/kernel/tests/Kconfig.debug b/arch/riscv/kernel/tests/Kconfig.debug
index 40f8dafffa0ab..9eda8938ec15b 100644
--- a/arch/riscv/kernel/tests/Kconfig.debug
+++ b/arch/riscv/kernel/tests/Kconfig.debug
@@ -42,6 +42,19 @@ config RISCV_KPROBES_KUNIT
If unsure, say N.
> +config RISCV_KPROBES_SIMULATE_KUNIT
> + tristate "KUnit test for riscv kprobes instruction simulation" if !KUNIT_ALL_TESTS
> + depends on KUNIT
> + depends on KPROBES
> + default KUNIT_ALL_TESTS
[Severity: High]
Will this default KUNIT_ALL_TESTS cause CI pipelines to break?
Since the test iterates through all 32-bit integers, it appears it could
cause standard testing environments to timeout or lockup when they enable
all tests.
> + help
> + Enable testing for riscv kprobes instruction simulation. Useful for
[ ... ]
diff --git a/arch/riscv/kernel/tests/kprobes/test-kprobes-simulate.c b/arch/riscv/kernel/tests/kprobes/test-kprobes-simulate.c
new file mode 100644
index 0000000000000..d82706685823d
--- /dev/null
+++ b/arch/riscv/kernel/tests/kprobes/test-kprobes-simulate.c
@@ -0,0 +1,250 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +#include <linux/kernel.h>
[ ... ]
> +static void test_kprobe_simulate_riscv(struct kunit *test)
> +{
> + unsigned int addr = 0xdeadbeef;
> + unsigned int i = 0;
> +
> + do {
> + struct pt_regs regs = { 0 };
[Severity: High]
Is it safe to run a 4.29 billion iteration loop inside the kernel without
yielding the CPU?
Looking at test_kprobe_simulate_riscv(), there doesn't appear to be any
mechanism like cond_resched() inside the loop or the simulated functions.
Won't this monopolize the CPU and reliably trigger the soft lockup watchdog
or RCU stall detectors?
[Severity: Medium]
Does initializing the registers to zero on every iteration reduce the coverage
of conditional branches?
If source registers like rs1 and rs2 are never populated with non-zero values,
won't the branch conditions evaluate to a single static outcome? For example,
a beq (0 == 0) will always be true, and bne (0 != 0) will always be false.
This seems to skip testing the alternate branch paths.
> +
> + if (riscv_insn_is_jal(i)) {
[ ... ]
> + } else if (riscv_insn_is_auipc(i)) {
> + s32 offset = riscv_insn_auipc_extract_imm(i);
> + u32 rd_index = riscv_insn_auipc_extract_xd(i);
> +
> + simulate_auipc(i, addr, ®s);
> +
> + KUNIT_EXPECT_EQ_MSG(test, regs.epc, addr + 4,
> + "auipc instruction (0x%x) incorrectly simulated", i);
> +
> + if (rd_index)
> + KUNIT_EXPECT_EQ_MSG(
> + test,
> + riscv_insn_reg_get_val((unsigned long *)®s, rd_index),
> + (unsigned long)addr + offset,
> + "auipc instruction (0x%x) incorrectly simulated", i);
[Severity: Medium]
Does extracting the expected values using the same macros as the implementation
make the test tautological?
If a macro like riscv_insn_auipc_extract_imm() is flawed, both the test and
the implementation will compute the identical incorrect value, causing the
test to spuriously pass.
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=4
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH v2 12/16] riscv: kvm: Add emulated test csr
2026-06-22 4:01 ` [PATCH v2 12/16] riscv: kvm: Add emulated test csr Charlie Jenkins via B4 Relay
@ 2026-06-22 4:23 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:23 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] The `vsscratch` test CSR emulation handler is structurally unreachable, rendering the feature dead code because accesses to VS-level CSRs from VS-mode do not trap to KVM.
- [High] The emulated test CSR unconditionally introduces a silently-on guest-visible feature and unmigratable state, violating KVM API invariants.
- [High] The patch hijacks the architectural `vsscratch` CSR, backing it with disconnected software state and causing split-brain register semantics.
- [Medium] The emulated test CSR state is not cleared during VCPU reset, leaking state across warm resets.
--
commit 783cfef4904ebb8469e4e71c63a55936a9c8e148
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
riscv: kvm: Add emulated test csr
This commit adds support to emulate the vsscratch CSR when
CONFIG_RISCV_KVM_TEST_CSR is set. It introduces a new kvm_test_csr
struct and hooks into the CSR instruction handling to reflect changes
when the vsscratch register is accessed.
> diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
> index 75b0a951c1bc6..4d30d30ebefc7 100644
> --- a/arch/riscv/include/asm/kvm_host.h
> +++ b/arch/riscv/include/asm/kvm_host.h
[ ... ]
> @@ -265,6 +271,10 @@ struct kvm_vcpu_arch {
> gpa_t shmem;
> u64 last_steal;
> } sta;
> +
> +#ifdef CONFIG_RISCV_KVM_TEST_CSR
> + struct kvm_test_csr test_csr;
> +#endif
> };
[Severity: High]
Does this new guest-visible state need to be explicitly enabled by userspace
with a runtime capability check rather than just a compile-time config?
Also, since this state isn't exposed via the KVM_GET_ONE_REG or KVM_SET_ONE_REG
API, will it break live migration because it is completely invisible to
userspace?
[Severity: Medium]
Is this test_csr state cleared during a VCPU reset? It looks like it is missing
from the architecture-specific reset path kvm_riscv_vcpu_context_reset(),
which might allow the modified value to leak across warm resets.
> diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c
> index 1d8741d022425..c5a70de4a5790 100644
> --- a/arch/riscv/kvm/vcpu_insn.c
> +++ b/arch/riscv/kvm/vcpu_insn.c
[ ... ]
> @@ -112,6 +114,9 @@ static int seed_csr_rmw(struct kvm_vcpu *vcpu, unsigned int csr_num,
> static const struct csr_func csr_funcs[] = {
> KVM_RISCV_VCPU_AIA_CSR_FUNCS
> KVM_RISCV_VCPU_HPMCOUNTER_CSR_FUNCS
> +#ifdef CONFIG_RISCV_KVM_TEST_CSR
> + KVM_RISCV_VCPU_TEST_CSR_FUNCS
> +#endif
> { .base = CSR_SEED, .count = 1, .func = seed_csr_rmw },
> };
[Severity: High]
Will this CSR emulation handler ever be reached?
KVM's CSR emulation path kvm_riscv_vcpu_virtual_insn() is only invoked for
Virtual Instruction exceptions (EXC_VIRTUAL_INST_FAULT, cause 22). However,
accessing an HS-level CSR like vsscratch from VS-mode natively generates an
Illegal Instruction exception (EXC_INST_ILLEGAL, cause 2).
Since KVM explicitly delegates these exceptions directly to the guest's
VS-mode exception handler, it seems this handler gets bypassed entirely.
> diff --git a/arch/riscv/kvm/vcpu_test_csr.c b/arch/riscv/kvm/vcpu_test_csr.c
> new file mode 100644
> index 0000000000000..b8aa503cdaba7
> --- /dev/null
> +++ b/arch/riscv/kvm/vcpu_test_csr.c
> @@ -0,0 +1,21 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/kvm_host.h>
> +#include <asm/kvm_vcpu_insn.h>
> +#include <asm/kvm_vcpu_test_csr.h>
> +
> +#define vcpu_to_test_csr(vcpu) (&(vcpu)->arch.test_csr)
> +
> +int kvm_riscv_vcpu_test_csr(struct kvm_vcpu *vcpu, unsigned int csr_num,
> + unsigned long *val, unsigned long new_val,
> + unsigned long wr_mask)
> +{
> + struct kvm_test_csr *test_csr = vcpu_to_test_csr(vcpu);
> +
> + *val = test_csr->val;
> +
> + if (wr_mask)
> + test_csr->val = (test_csr->val & ~wr_mask) | (new_val & wr_mask);
> +
> + return KVM_INSN_CONTINUE_NEXT_SEPC;
> +}
[Severity: High]
Does using the architectural vsscratch CSR for this test cause a split-brain
state?
In a RISC-V guest, accessing sscratch implicitly accesses the hardware
vsscratch register, which KVM context-switches via its standard guest context
structures.
By intercepting explicit guest accesses to the vsscratch address and directing
them to this disjoint test_csr.val variable, the guest will see different
values depending on whether it accesses the register implicitly via sscratch
or explicitly via vsscratch. Would it be safer for a test CSR to use a
reserved or custom CSR address?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=12
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 13/16] KVM: riscv: selftests: Add csr emulation test
2026-06-22 4:01 ` [PATCH v2 13/16] KVM: riscv: selftests: Add csr emulation test Charlie Jenkins via B4 Relay
@ 2026-06-22 4:24 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:24 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] The `kvm_create_device` wrapper is incorrectly used for feature probing, which turns an intended graceful skip into a hard assertion failure.
- [Medium] The test unconditionally manipulates the floating-point CSR (`fcsr`) and `sstatus.FS` without checking if the F (Floating-Point) extension is supported.
- [Medium] File descriptors returned by `kvm_create_device()` are leaked on every successful execution.
- [Medium] Missing `.align 2` directive for the `stvec` target label risks creating an infinite exception loop.
- [Low] A local C variable is passed to an inline assembly block using the `"i"` (immediate) constraint, violating C compiler requirements and causing build failures.
--
commit 9c090464385301d04ee38fa944d2379ab3dfd21a
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
KVM: riscv: selftests: Add csr emulation test
Introduce a kvm test that uses the emulated test csr to validate that
all emulated reads/writes to csrs function as expected.
> diff --git a/tools/testing/selftests/kvm/riscv/csr_test.c b/tools/testing/selftests/kvm/riscv/csr_test.c
> new file mode 100644
> index 0000000000000..b3e8b99b6e923
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/riscv/csr_test.c
[ ... ]
> +/*
> + * Use the fcsr as a U-mode accesible csr and compare against the custom 'test'
> + * hypervisor csr (currently using vsscratch)
> + */
> +#define test_csr(write, initial, mode) \
> +static void test_##write(void) \
> +{ \
> + unsigned long hypervisor_result, reference_result, old_hypervisor; \
> + unsigned long mask = 0x15; \
> + asm volatile ( \
> + "csrs sstatus, %[enable_fp]\n" \
> + "csrw fcsr, %[init]\n" \
[Severity: Medium]
Does this code unconditionally manipulate the floating-point CSR (fcsr) and
sstatus.FS without checking if the F (Floating-Point) extension is supported?
On RISC-V targets lacking the F extension, accessing fcsr will raise an
illegal instruction exception and crash the test. Should there be a probe for
the F extension (e.g., via KVM_RISCV_ISA_EXT_F) before proceeding?
> + #write" zero, fcsr, %[mask]\n" \
> + "csrr %[ref_res], fcsr\n" \
> + : [ref_res] "=&r" (reference_result) \
> + : [enable_fp] "r" (FP), [mask] #mode(mask), [init] "r" (initial) \
[Severity: Low]
Is it safe to pass the local variable mask using the "i" (immediate)
constraint?
For tests like test_csrrwi, #mode(mask) expands to an "i" constraint, but
compilers like GCC and Clang require the operand for an "i" constraint to be
a compile-time constant expression. Does this cause an 'impossible constraint
in asm' build error with -O0 or when using Clang?
> + : "memory" \
> + ); \
[ ... ]
> +static void run(void *guest_code, char *instruction)
> +{
> + struct ucall uc;
> + struct kvm_vm *vm;
> + struct kvm_vcpu *vcpu;
> +
> + vm = vm_create_with_one_vcpu(&vcpu, guest_code);
> +
> + kvm_create_device(vm, KVM_DEV_TYPE_TEST);
[Severity: Medium]
Does this leak the file descriptor returned by kvm_create_device()?
The function returns a new file descriptor which is ignored here and never
explicitly closed. kvm_vm_free() only cleans up VM and vCPU file descriptors.
> +
> + vcpu_run(vcpu);
> +
> + TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_DONE,
> + "CSR instruction '%s' failed: '%s'", instruction,
> + uc.buffer);
> +
> + kvm_vm_free(vm);
> +}
> +
> +static void check_test_csr_guest(void)
> +{
> + unsigned long scause, stvec;
> +
> + asm volatile(
> + "la %[stvec], 1f\n"
> + "csrw stvec, %[stvec]\n"
> + "csrwi %[test_csr], 0x0\n"
> + "1:\n"
[Severity: Medium]
Could the lack of an .align 2 directive before the 1: label create an
infinite exception loop?
The RISC-V specification requires the stvec BASE address to be 4-byte
aligned. If the test is compiled with the Compressed extension, the 1: label
might reside at a 2-byte aligned boundary. When the hardware jumps to stvec,
it masks out the lower bits, potentially resuming execution at an invalid
offset.
> + "csrr %[scause], scause\n"
> + : [scause] "=&r" (scause), [stvec] "=&r" (stvec)
> + : [test_csr] "i" (CSR_TEST)
> + );
> +
> + /* An illegal instruction will be generated if CONFIG_RISCV_KVM_TEST_CSR is not enabled. */
> + if (scause == 2)
> + GUEST_FAIL("CONFIG_RISCV_KVM_TEST_CSR not enabled.\n");
> + GUEST_DONE();
> +}
> +
> +static int check_test_csr(void)
> +{
> + struct ucall uc;
> + struct kvm_vm *vm;
> + struct kvm_vcpu *vcpu;
> + int success;
> +
> + vm = vm_create_with_one_vcpu(&vcpu, check_test_csr_guest);
> +
> + /* Skip if CONFIG_KVM_MMIO_TEST not enabled */
> + if (!kvm_create_device(vm, KVM_DEV_TYPE_TEST))
> + exit(KSFT_SKIP);
[Severity: High]
Will this check crash with an assertion failure instead of gracefully
skipping?
The selftests wrapper kvm_create_device() internally asserts
TEST_ASSERT(fd >= 0, ...). If the host kernel does not support
KVM_DEV_TYPE_TEST, the ioctl returns a negative error code, triggering the
assertion rather than reaching the exit(KSFT_SKIP) path.
Also, on success, it returns a valid file descriptor (fd > 0), which
evaluates to true and bypasses the skip. Shouldn't we use
__kvm_test_create_device() or __kvm_create_device() to probe safely without
asserting?
[Severity: Medium]
Similar to the call in run(), does this also leak the file descriptor returned
by kvm_create_device() if the device creation is successful?
> +
> + vcpu_run(vcpu);
> +
> + success = get_ucall(vcpu, &uc) == UCALL_DONE;
> +
> + kvm_vm_free(vm);
> +
> + return success;
> +}
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=13
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 11/16] riscv: kvm: Use generated instruction headers for mmio emulation
2026-06-22 4:01 ` [PATCH v2 11/16] riscv: kvm: Use generated instruction headers for mmio emulation Charlie Jenkins via B4 Relay
@ 2026-06-22 4:27 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:27 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The migration to generated instruction headers missed the required '+8' offset for compressed instructions that use 3-bit register fields, causing KVM to access the wrong architectural registers.
- [High] Removal of `#ifdef CONFIG_64BIT` guards exposes 32-bit KVM hosts to Undefined Behavior (negative bit shift) when a guest triggers 64-bit instruction emulation.
--
commit 5795a15cde75d07e7edad3d6b52a93e9aa4d9d86
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
riscv: kvm: Use generated instruction headers for mmio emulation
Migrate the mmio emulation code to use the generated instruction headers
instead of the hand-written instruction composition functions.
> diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c
> index 8ccf6ec722f03..1d8741d022425 100644
> --- a/arch/riscv/kvm/vcpu_insn.c
> +++ b/arch/riscv/kvm/vcpu_insn.c
[ ... ]
> @@ -408,44 +408,47 @@ int kvm_riscv_vcpu_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run,
[ ... ]
> -#ifdef CONFIG_64BIT
> - } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
> + } else if (riscv_insn_is_ld(insn)) {
> len = 8;
> shift = 8 * (sizeof(ulong) - len);
> - } else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
[Severity: High]
By removing these CONFIG_64BIT guards, does this expose 32-bit KVM hosts
to undefined behavior?
If a guest triggers emulation of a 64-bit load, len becomes 8, and shift
is calculated as 8 * (sizeof(ulong) - len). On a 32-bit host where
sizeof(ulong) is 4, shift becomes -32.
This would result in a negative bit shift when kvm_riscv_vcpu_mmio_return()
later evaluates (long)data << shift >> shift.
> + rd = riscv_insn_ld_extract_xd(insn);
> + } else if (riscv_insn_is_lwu(insn)) {
> len = 4;
> -#endif
[ ... ]
> - } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
> + } else if (riscv_insn_is_c_lw(insn)) {
> len = 4;
> shift = 8 * (sizeof(ulong) - len);
> - insn = RVC_RS2S(insn) << SH_RD;
> - } else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP &&
> - ((insn >> SH_RD) & 0x1f)) {
> + rd = riscv_insn_c_lw_extract_xd(insn);
[Severity: High]
Does this code read or write to the wrong guest register?
Compressed instructions like c.lw and c.sw use 3-bit register fields
corresponding to general purpose registers x8 through x15. The generated
extraction macros (like riscv_insn_c_lw_extract_xd) return the raw 0-7
value.
Without an explicit +8 offset mapping, won't KVM incorrectly use registers
x0-x7 as the index into the guest_context array?
> + } else if (riscv_insn_is_c_lwsp(insn)) {
> len = 4;
> shift = 8 * (sizeof(ulong) - len);
> + rd = riscv_insn_c_lwsp_extract_xd(insn);
> } else {
> return -EOPNOTSUPP;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=11
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 02/16] riscv: alternatives: Use generated instruction headers for patching code
2026-06-22 4:01 ` [PATCH v2 02/16] riscv: alternatives: Use generated instruction headers for patching code Charlie Jenkins via B4 Relay
@ 2026-06-22 4:28 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:28 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Incorrect immediate calculation for auipc unconditionally adds 4096, breaking alternative patching for jumps where bit 11 is 0.
- [Low] Using a jalr-specific extraction function on an auipc instruction.
--
commit 67f209569c2cc2afe918708c4cf86d391c4abcd2
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
Subject: riscv: alternatives: Use generated instruction headers for patching code
This commit migrates the alternative patching code to use generated
instruction headers instead of hand-written composition functions.
> diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c
> --- a/arch/riscv/kernel/alternative.c
> +++ b/arch/riscv/kernel/alternative.c
[ ... ]
> @@ -78,14 +79,24 @@ static void riscv_alternative_fix_auipc_jalr(void *ptr, u32 auipc_insn,
> u32 jalr_insn, int patch_offset)
> {
> u32 call[2] = { auipc_insn, jalr_insn };
> + u32 auipc_imm;
> s32 imm;
>
> /* get and adjust new target address */
> - imm = riscv_insn_extract_utype_itype_imm(auipc_insn, jalr_insn);
> + imm = riscv_insn_auipc_extract_imm(auipc_insn) + riscv_insn_jalr_extract_imm(jalr_insn);
> imm -= patch_offset;
>
> + /*
> + * When the 32-bit immediate is split across auipc and jalr, the
> + * constructed immediates need to be treated as individually sign
> + * extended numbers. Add the sign bit of the lower 12 bits to the upper
> + * 20 bits to undo the bleeding of the sign.
> + */
> + auipc_imm = imm + (BIT(11) << 1);
[Severity: High]
Does this unconditionally add 4096 to the immediate?
The original code conditionally added the offset using (imm & BIT(11)) << 1,
but the new code appears to evaluate to a constant BIT(11) << 1. If imm
has bit 11 set to 0, won't this corrupt the target jump address by 4096 bytes?
> +
> /* update instructions */
> - riscv_insn_insert_utype_itype_imm(&call[0], &call[1], imm);
> + riscv_insn_auipc_insert_imm(&call[0], auipc_imm);
> + riscv_insn_jalr_insert_imm(&call[1], imm);
[ ... ]
> @@ -127,7 +138,7 @@ void riscv_alternative_fix_offsets(void *alt_ptr, unsigned int len,
> continue;
>
> /* if instruction pair is a call, it will use the ra register */
> - if (RV_EXTRACT_RD_REG(insn) != 1)
> + if (riscv_insn_jalr_extract_xd(insn) != 1)
[Severity: Low]
Since insn is verified to be an auipc instruction just above this block,
should this be using riscv_insn_auipc_extract_xd(insn) instead?
While they both extract the destination register at bits 11:7 and work
mathematically, using the jalr helper on an auipc instruction seems
to break the abstraction provided by the new headers.
> continue;
>
> riscv_alternative_fix_auipc_jalr(alt_ptr + i * sizeof(u32),
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=2
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 14/16] riscv: kvm: Use generated instruction headers for csr emulation
2026-06-22 4:01 ` [PATCH v2 14/16] riscv: kvm: Use generated instruction headers for csr emulation Charlie Jenkins via B4 Relay
@ 2026-06-22 4:30 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:30 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] KVM's MMIO emulation unconditionally overwrites the hardwired `x0` register within the guest's context, causing subsequent KVM-emulated instructions to use non-zero garbage values for `x0`.
--
commit 7feea165a4c11a607fc4f7aca428cb92288c4147
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
riscv: kvm: Use generated instruction headers for csr emulation
Migrate the csr emulation code to use the generated instruction headers
instead of the hand-written instruction composition functions.
> diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c
> index c5a70de4a5790..d666cd24f8c0e 100644
> --- a/arch/riscv/kvm/vcpu_insn.c
> +++ b/arch/riscv/kvm/vcpu_insn.c
[ ... ]
> @@ -154,7 +150,7 @@ static int csr_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn)
> #define GET_REG(_rd) (*((unsigned long *)(&vcpu->arch.guest_context) + _rd))
>
> int i, rc = KVM_INSN_ILLEGAL_TRAP;
> - unsigned int csr_num;
> + unsigned int csr_num, rd;
> const struct csr_func *tcfn, *cfn = NULL;
> ulong val = 0, wr_mask = 0, new_val = 0;
>
> @@ -163,26 +159,32 @@ static int csr_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn)
> wr_mask = -1UL;
> new_val = GET_REG(riscv_insn_csrrw_extract_xs1(insn));
[Severity: High]
This isn't a bug introduced by this patch, but does the newly introduced
GET_REG macro expose a pre-existing corruption of guest_context.zero?
In RISC-V, the x0 register is hardwired to 0. If a guest executes an MMIO
load with destination register x0, KVM unconditionally writes the loaded data
to guest_context.zero:
arch/riscv/kvm/vcpu_insn.c:kvm_riscv_vcpu_mmio_return() {
...
*((ulong *)(&vcpu->arch.guest_context) + vcpu->arch.mmio_decode.rd) =
(long)data << shift >> shift;
...
}
This patch changes csr_insn() to unconditionally read the source register
using GET_REG() without verifying if the register is x0.
If a guest triggers an MMIO load to x0, and then executes a CSR instruction
such as csrrw x0, sscratch, x0, will KVM read the corrupted non-zero value
from guest_context.zero and write it into the guest's CSR?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=14
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH v2 06/16] riscv: cfi: Use generated instruction headers
2026-06-22 4:01 ` [PATCH v2 06/16] riscv: cfi: " Charlie Jenkins via B4 Relay
@ 2026-06-22 4:35 ` sashiko-bot
0 siblings, 0 replies; 29+ messages in thread
From: sashiko-bot @ 2026-06-22 4:35 UTC (permalink / raw)
To: Charlie Jenkins via B4 Relay; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [Critical] Incorrect target address calculation for auipc+jalr pairs during alternative patching.
Pre-existing issues:
- [High] KCFI failure handler extracts the actual type instead of the expected type, leading to a misleading log and a potential arbitrary kernel memory leak.
--
commit fc627870b9c3f0a09b99b862169f28fa7f3bcda2
Author: Charlie Jenkins <thecharlesjenkins@gmail.com>
riscv: cfi: Use generated instruction headers
Migrate the code that is decoding cfi instructions to use the generated
instruction headers. This is part of a broader series that updates
instruction decoding and patching across alternative, kprobe, kgdb, and
cfi subsystems to use the newly generated instruction tables.
> diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c
> index 7642704c7f184..b26a90eb65cca 100644
> --- a/arch/riscv/kernel/alternative.c
> +++ b/arch/riscv/kernel/alternative.c
[ ... ]
> @@ -78,14 +79,24 @@ static void riscv_alternative_fix_auipc_jalr(void *ptr, u32 auipc_insn,
> u32 jalr_insn, int patch_offset)
> {
> u32 call[2] = { auipc_insn, jalr_insn };
> + u32 auipc_imm;
> s32 imm;
>
> /* get and adjust new target address */
> - imm = riscv_insn_extract_utype_itype_imm(auipc_insn, jalr_insn);
> + imm = riscv_insn_auipc_extract_imm(auipc_insn) + riscv_insn_jalr_extract_imm(jalr_insn);
> imm -= patch_offset;
>
> + /*
> + * When the 32-bit immediate is split across auipc and jalr, the
> + * constructed immediates need to be treated as individually sign
> + * extended numbers. Add the sign bit of the lower 12 bits to the upper
> + * 20 bits to undo the bleeding of the sign.
> + */
> + auipc_imm = imm + (BIT(11) << 1);
[Severity: Critical]
Does this calculation unconditionally add 4096 to the immediate?
Since BIT(11) << 1 evaluates to a constant 4096 (0x1000), it looks like
this regression adds 4096 regardless of whether bit 11 is actually set
in the immediate.
For any jump where bit 11 of the offset is 0, won't the auipc instruction
be patched with a value that is 0x1000 too large, causing the execution to
jump to an unintended address?
> +
> /* update instructions */
> - riscv_insn_insert_utype_itype_imm(&call[0], &call[1], imm);
> + riscv_insn_auipc_insert_imm(&call[0], auipc_imm);
> + riscv_insn_jalr_insert_imm(&call[1], imm);
>
> /* patch the call place again */
> patch_text_nosync(ptr, call, sizeof(u32) * 2);
> diff --git a/arch/riscv/kernel/cfi.c b/arch/riscv/kernel/cfi.c
> index 6ec9dbd7292ee..e38d5f863747a 100644
> --- a/arch/riscv/kernel/cfi.c
> +++ b/arch/riscv/kernel/cfi.c
> @@ -40,16 +40,16 @@ static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target,
> if (!riscv_insn_is_beq(insn))
> return false;
>
> - *type = (u32)regs_ptr[RV_EXTRACT_RS1_REG(insn)];
> + *type = (u32)regs_ptr[riscv_insn_beq_extract_xs1(insn)];
[Severity: High]
This is a pre-existing issue, but does this extract the actual type
instead of the expected type?
The compiler sequence for indirect call checks places the actual type in
t1 (rs1) and the expected type in t2 (rs2). By extracting xs1 here, the
KCFI failure handler appears to retrieve the actual type loaded from memory.
Since the actual type is read from -4(<reg>) where <reg> could be an
attacker-controlled function pointer, could this allow leaking arbitrary
kernel memory if CONFIG_CFI_PERMISSIVE is enabled and the warning is printed
to dmesg?
Should this extract xs2 instead to get the expected type?
>
> if (get_kernel_nofault(insn, (void *)regs->epc) ||
> get_kernel_nofault(insn, (void *)regs->epc + GET_INSN_LENGTH(insn)))
> return false;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com?part=6
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2026-06-22 4:35 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-22 4:01 [PATCH v2 00/16] riscv: Generate riscv instruction functions Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 01/16] riscv: Introduce instruction table generation Charlie Jenkins via B4 Relay
2026-06-22 4:13 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 02/16] riscv: alternatives: Use generated instruction headers for patching code Charlie Jenkins via B4 Relay
2026-06-22 4:28 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 03/16] riscv: kgdb: Use generated instruction headers Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 04/16] riscv: Add kprobes instruction simulation KUnit Charlie Jenkins via B4 Relay
2026-06-22 4:19 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 05/16] riscv: kprobes: Use generated instruction headers Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 06/16] riscv: cfi: " Charlie Jenkins via B4 Relay
2026-06-22 4:35 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 07/16] riscv: Use generated instruction headers for misaligned loads/stores Charlie Jenkins via B4 Relay
2026-06-22 4:18 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 08/16] riscv: kvm: Use generated instruction headers for csr code Charlie Jenkins via B4 Relay
2026-06-22 4:18 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 09/16] KVM: device: Add test device Charlie Jenkins via B4 Relay
2026-06-22 4:13 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 10/16] KVM: riscv: selftests: Add mmio test Charlie Jenkins via B4 Relay
2026-06-22 4:18 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 11/16] riscv: kvm: Use generated instruction headers for mmio emulation Charlie Jenkins via B4 Relay
2026-06-22 4:27 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 12/16] riscv: kvm: Add emulated test csr Charlie Jenkins via B4 Relay
2026-06-22 4:23 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 13/16] KVM: riscv: selftests: Add csr emulation test Charlie Jenkins via B4 Relay
2026-06-22 4:24 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 14/16] riscv: kvm: Use generated instruction headers for csr emulation Charlie Jenkins via B4 Relay
2026-06-22 4:30 ` sashiko-bot
2026-06-22 4:01 ` [PATCH v2 15/16] riscv: kexec: Use generated instruction headers for kexec relocations Charlie Jenkins via B4 Relay
2026-06-22 4:01 ` [PATCH v2 16/16] riscv: Remove unused instruction headers Charlie Jenkins via B4 Relay
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox