---
docs/system/target-riscv.rst | 14 ++++-
target/riscv/cpu.c | 69 +++++++++++++++++++++++
target/riscv/cpu.h | 1 +
target/riscv/tcg/tcg-cpu.c | 7 ++-
tests/functional/riscv32/test_cpu_arch.py | 12 ++++
tests/functional/riscv64/test_cpu_arch.py | 25 ++++++++
6 files changed, 124 insertions(+), 4 deletions(-)
diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
index 3ec53dbf9e5..9acc51fbc2b 100644
--- a/docs/system/target-riscv.rst
+++ b/docs/system/target-riscv.rst
@@ -90,8 +90,18 @@ Individual ISA extensions can be enabled or disabled using boolean properties::
The ``arch`` property
^^^^^^^^^^^^^^^^^^^^^
-The ``arch`` property provides a convenient way to inspect the current ISA
-configuration:
+The ``arch`` property provides convenient ways to discover and inspect ISA
+extensions:
+
+* ``arch=help``
+
+ Print a list of all supported ISA extensions and exit::
+
+ $ qemu-system-riscv64 -M virt -cpu rv64,arch=help
+ $ qemu-riscv64 -cpu rv64,arch=help /bin/true
+
+ This lists standard single-letter extensions (with descriptions), multi-letter
+ extensions, vendor extensions, and experimental extensions.
* ``arch=dump``
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 2886b7ebcdd..b1d8438cd14 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -896,6 +896,23 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
}
#endif
+/*
+ * Helper function to print single-letter extensions for arch=help.
+ */
+static void riscv_cpu_help_misa_exts(void)
+{
+ qemu_printf("Standard Extensions (single-letter):\n");
+
+ for (int i = 0; misa_bits[i] != 0; i++) {
+ uint32_t bit = misa_bits[i];
+ const char *name = riscv_get_misa_ext_name(bit);
+ const char *desc = riscv_get_misa_ext_description(bit);
+
+ qemu_printf(" %-4s %s\n", name, desc);
+ }
+ qemu_printf("\n");
+}
+
static inline const char *riscv_ext_status_str(bool enabled)
{
return enabled ? "enabled" : "disabled";
@@ -965,6 +982,58 @@ static void riscv_cpu_dump_priv_implied_exts(RISCVCPU *cpu)
qemu_printf("\n");
}
+/*
+ * Helper function to print multi-letter extension names for arch=help.
+ * Does not print section header.
+ */
+static void riscv_cpu_help_multiext_entries(const RISCVCPUMultiExtConfig *exts)
+{
+ for (const RISCVCPUMultiExtConfig *prop = exts;
+ prop && prop->name; prop++) {
+ qemu_printf(" %s\n", prop->name);
+ }
+}
+
+/*
+ * Helper function to print multi-letter extensions for arch=help.
+ */
+static void riscv_cpu_help_multiext(const char *title,
+ const RISCVCPUMultiExtConfig *exts)
+{
+ qemu_printf("%s:\n", title);
+
+ riscv_cpu_help_multiext_entries(exts);
+ qemu_printf("\n");
+}
+
+/*
+ * Print list of supported ISA extensions and exit.
+ * Called when arch=help is specified.
+ */
+G_NORETURN void riscv_cpu_list_supported_extensions(void)
+{
+ qemu_printf("\n");
+ qemu_printf("Supported RISC-V ISA Extensions\n");
+ qemu_printf("================================\n\n");
+
+ riscv_cpu_help_misa_exts();
+
+ /* Print multi-letter standard extensions (including named features) */
+ qemu_printf("Standard Extensions (multi-letter):\n");
+ riscv_cpu_help_multiext_entries(riscv_cpu_extensions);
+ riscv_cpu_help_multiext_entries(riscv_cpu_named_features);
+ qemu_printf("\n");
+
+ riscv_cpu_help_multiext("Vendor Extensions", riscv_cpu_vendor_exts);
+ riscv_cpu_help_multiext("Experimental Extensions",
+ riscv_cpu_experimental_exts);
+
+ qemu_printf("Use '-cpu <cpu>,<ext>=true' to enable an extension.\n");
+ qemu_printf("Use '-cpu <cpu>,arch=dump' to show current configuration.\n");
+
+ exit(0);
+}
+
/*
* Print detailed ISA configuration and exit.
* Called when arch=dump is specified.
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 90b3e951053..5c08c2ca4d6 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -986,4 +986,5 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit);
extern const RISCVCSR th_csr_list[];
const char *priv_spec_to_str(int priv_version);
+G_NORETURN void riscv_cpu_list_supported_extensions(void);
#endif /* RISCV_CPU_H */
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index f7187472cd2..c9600a52e1c 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -1567,9 +1567,11 @@ static void cpu_set_arch(Object *obj, Visitor *v, const char *name,
if (g_strcmp0(value, "dump") == 0) {
cpu->cfg.arch_dump_requested = true;
+ } else if (g_strcmp0(value, "help") == 0) {
+ riscv_cpu_list_supported_extensions();
} else {
error_setg(errp, "unknown arch option '%s'. "
- "Supported options: dump", value);
+ "Supported options: dump, help", value);
}
}
@@ -1579,7 +1581,8 @@ static void riscv_cpu_add_arch_property(Object *obj)
NULL, cpu_set_arch,
NULL, NULL);
object_property_set_description(obj, "arch",
- "ISA configuration string (write-only). Use 'dump' to print ISA config.");
+ "ISA configuration (write-only). "
+ "Use 'help' to list extensions, 'dump' to show current config.");
}
/*
diff --git a/tests/functional/riscv32/test_cpu_arch.py b/tests/functional/riscv32/test_cpu_arch.py
index 7b2f87cad88..b2042f1e5d8 100644
--- a/tests/functional/riscv32/test_cpu_arch.py
+++ b/tests/functional/riscv32/test_cpu_arch.py
@@ -47,6 +47,18 @@ def test_arch_dump_shows_enabled_extensions(self):
self.assertRegex(res.stdout, r'd\s+enabled')
self.assertRegex(res.stdout, r'c\s+enabled')
+ def test_arch_help(self):
+ """Test arch=help prints list of supported extensions and exits"""
+ res = self.run_qemu('rv32,arch=help')
+
+ self.assertEqual(res.returncode, 0,
+ f"arch=help should exit with 0, got {res.returncode}")
+
+ # Check for expected output sections
+ self.assertIn('Supported RISC-V ISA Extensions', res.stdout)
+ self.assertIn('Standard Extensions (single-letter):', res.stdout)
+ self.assertIn('Standard Extensions (multi-letter):', res.stdout)
+
def test_arch_invalid_option(self):
"""Test invalid arch= option shows error with supported options"""
res = self.run_qemu('rv32,arch=invalid')
diff --git a/tests/functional/riscv64/test_cpu_arch.py b/tests/functional/riscv64/test_cpu_arch.py
index b0af8991397..4ec807b7276 100644
--- a/tests/functional/riscv64/test_cpu_arch.py
+++ b/tests/functional/riscv64/test_cpu_arch.py
@@ -66,6 +66,31 @@ def test_arch_dump_position_independence(self):
self.assertRegex(res1.stdout, r'v\s+enabled')
self.assertRegex(res2.stdout, r'v\s+enabled')
+ def test_arch_help(self):
+ """Test arch=help prints list of supported extensions and exits"""
+ res = self.run_qemu('rv64,arch=help')
+
+ self.assertEqual(res.returncode, 0,
+ f"arch=help should exit with 0, got {res.returncode}")
+
+ # Check for expected output sections
+ self.assertIn('Supported RISC-V ISA Extensions', res.stdout)
+ self.assertIn('Standard Extensions (single-letter):', res.stdout)
+ self.assertIn('Standard Extensions (multi-letter):', res.stdout)
+ self.assertIn('Vendor Extensions:', res.stdout)
+
+ def test_arch_help_shows_extensions(self):
+ """Test arch=help lists common extensions"""
+ res = self.run_qemu('rv64,arch=help')
+
+ # Check single-letter extensions with descriptions
+ self.assertIn('Base integer instruction set', res.stdout)
+ self.assertIn('Vector operations', res.stdout)
+
+ # Check multi-letter extensions are listed
+ self.assertIn('zba', res.stdout)
+ self.assertIn('zbb', res.stdout)
+
def test_arch_invalid_option(self):
"""Test invalid arch= option shows error with supported options"""
res = self.run_qemu('rv64,arch=invalid')
--
2.52.0
© 2016 - 2026 Red Hat, Inc.