[kvm-unit-tests PATCH 7/7] riscv: Add BRS SBI requirement tests

Xiang W wangxiang at iscas.ac.cn
Wed Sep 23 20:39:45 PDT 2026


Add a riscv-brs unit test for the SBI rules in the RISC-V Boot and
Runtime Services specification:

  SBI_010  spec version must be v2.0 or later
  SBI_020  HSM must be implemented
  SBI_030  TIME is required unless Sstc is present
  SBI_040  IPI is required unless Ssaia is present
  SBI_050  RFENCE is required unless Ssaia is present
  SBI_060  PMU is required unless Smcsrind, Sscsrind, Smcdeleg
           and Ssccfg are all present
  SBI_070  DBCN is required when ACPI SPCR Interface Type is 0x15

Parse the extra ISA names used as skip conditions, and add the RFNC
and PMU extension IDs needed to probe those extensions.

Signed-off-by: Xiang W <wangxiang at iscas.ac.cn>
---
 lib/riscv/asm/isa.h |   5 ++
 lib/riscv/asm/sbi.h |   2 +
 lib/riscv/isa.c     |  14 +++-
 riscv/Makefile      |   1 +
 riscv/riscv-brs.c   | 171 ++++++++++++++++++++++++++++++++++++++++++++
 riscv/unittests.cfg |   4 ++
 6 files changed, 195 insertions(+), 2 deletions(-)
 create mode 100644 riscv/riscv-brs.c

diff --git a/lib/riscv/asm/isa.h b/lib/riscv/asm/isa.h
index fb3af67d..8a124881 100644
--- a/lib/riscv/asm/isa.h
+++ b/lib/riscv/asm/isa.h
@@ -13,7 +13,12 @@
  * by name not tracked here with cpu_has_extension_name()
  */
 enum {
+	ISA_SMCDELEG,
+	ISA_SMCSRIND,
+	ISA_SSAIA,
+	ISA_SSCCFG,
 	ISA_SSTC,
+	ISA_SSCSRIND,
 	ISA_MAX,
 };
 __static_assert(ISA_MAX <= __riscv_xlen, "Need to increase thread_info.isa");
diff --git a/lib/riscv/asm/sbi.h b/lib/riscv/asm/sbi.h
index 289a6a24..c92a66dc 100644
--- a/lib/riscv/asm/sbi.h
+++ b/lib/riscv/asm/sbi.h
@@ -45,8 +45,10 @@ enum sbi_ext_id {
 	SBI_EXT_BASE = 0x10,
 	SBI_EXT_TIME = 0x54494d45,
 	SBI_EXT_IPI = 0x735049,
+	SBI_EXT_RFNC = 0x52464E43,
 	SBI_EXT_HSM = 0x48534d,
 	SBI_EXT_SRST = 0x53525354,
+	SBI_EXT_PMU = 0x504D55,
 	SBI_EXT_DBCN = 0x4442434E,
 	SBI_EXT_SUSP = 0x53555350,
 	SBI_EXT_FWFT = 0x46574654,
diff --git a/lib/riscv/isa.c b/lib/riscv/isa.c
index b0257979..f5e2a61b 100644
--- a/lib/riscv/isa.c
+++ b/lib/riscv/isa.c
@@ -39,8 +39,18 @@ static void isa_bit(const char *name, int len, void *data)
 {
 	struct thread_info *info = (struct thread_info *)data;
 
-	if (isa_match("sstc", name, len))
-		set_bit(ISA_SSTC, info->isa);
+#define ISA_MATCH_AND_SET(ext) \
+	if (isa_match(#ext, name, len)) \
+		set_bit(ISA_##ext, info->isa)
+
+	ISA_MATCH_AND_SET(SMCDELEG);
+	ISA_MATCH_AND_SET(SMCSRIND);
+	ISA_MATCH_AND_SET(SSAIA);
+	ISA_MATCH_AND_SET(SSCCFG);
+	ISA_MATCH_AND_SET(SSCSRIND);
+	ISA_MATCH_AND_SET(SSTC);
+
+#undef ISA_MATCH_AND_SET
 }
 
 static void isa_parse(const char *isa_string, int len, struct isa_info *info)
diff --git a/riscv/Makefile b/riscv/Makefile
index 348a30a7..7da7526f 100644
--- a/riscv/Makefile
+++ b/riscv/Makefile
@@ -15,6 +15,7 @@ tests += $(TEST_DIR)/sbi.$(exe)
 tests += $(TEST_DIR)/selftest.$(exe)
 tests += $(TEST_DIR)/sieve.$(exe)
 tests += $(TEST_DIR)/isa-dbltrp.$(exe)
+tests += $(TEST_DIR)/riscv-brs.$(exe)
 
 all: $(tests)
 
diff --git a/riscv/riscv-brs.c b/riscv/riscv-brs.c
new file mode 100644
index 00000000..0d4a8f47
--- /dev/null
+++ b/riscv/riscv-brs.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  RISC-V BRS SBI requirement tests
+ *
+ * Copyright (C) 2026, Institute of Software, CAS., Xiang W <wangxiang at iscas.ac.cn>
+ */
+
+#include <libcflat.h>
+#include <devicetree.h>
+#include <asm/sbi.h>
+#include <asm/isa.h>
+#include <asm/smp.h>
+
+#ifdef CONFIG_EFI
+#include <acpi.h>
+#endif
+
+static void check_sbi_010(void)
+{
+	struct sbiret ret;
+
+	report_prefix_push("SBI_010");
+
+	ret = sbi_get_spec_version();
+	if (ret.error) {
+		report_fail("sbi_get_spec_version failed with %ld", ret.error);
+		report_prefix_pop();
+		return;
+	}
+
+	report_info("SBI spec version %lu.%lu",
+		    (ret.value >> SBI_SPEC_VERSION_MAJOR_SHIFT) &
+		    SBI_SPEC_VERSION_MAJOR_MASK,
+		    ret.value & SBI_SPEC_VERSION_MINOR_MASK);
+
+	report(ret.value >= sbi_mk_version(2, 0),
+	       "SBI spec version is v2.0 or later");
+
+	report_prefix_pop();
+}
+
+static void check_sbi_020(void)
+{
+	report_prefix_push("SBI_020");
+	report(sbi_probe(SBI_EXT_HSM), "HSM extension is implemented");
+	report_prefix_pop();
+}
+
+static void check_sbi_030(void)
+{
+	report_prefix_push("SBI_030");
+
+	if (cpu_has_extension(smp_processor_id(), ISA_SSTC)) {
+		report_skip("Sstc is present, TIME is not mandated");
+		report_prefix_pop();
+		return;
+	}
+
+	report(sbi_probe(SBI_EXT_TIME), "TIME extension is implemented");
+	report_prefix_pop();
+}
+
+static void check_sbi_040(void)
+{
+	report_prefix_push("SBI_040");
+
+	if (cpu_has_extension(smp_processor_id(), ISA_SSAIA)) {
+		report_skip("Ssaia is present, IPI is not mandated");
+		report_prefix_pop();
+		return;
+	}
+
+	report(sbi_probe(SBI_EXT_IPI), "IPI extension is implemented");
+	report_prefix_pop();
+}
+
+static void check_sbi_050(void)
+{
+	report_prefix_push("SBI_050");
+
+	if (cpu_has_extension(smp_processor_id(), ISA_SSAIA)) {
+		report_skip("Ssaia is present, RFENCE is not mandated");
+		report_prefix_pop();
+		return;
+	}
+
+	report(sbi_probe(SBI_EXT_RFNC), "RFENCE extension is implemented");
+	report_prefix_pop();
+}
+
+static void check_sbi_060(void)
+{
+	int cpu = smp_processor_id();
+	bool skip = true;
+	bool has_ext;
+
+	report_prefix_push("SBI_060");
+
+	has_ext = cpu_has_extension(cpu, ISA_SMCSRIND);
+	if (!has_ext)
+		report_info("Smcsrind is not present");
+	skip &= has_ext;
+
+	has_ext = cpu_has_extension(cpu, ISA_SSCSRIND);
+	if (!has_ext)
+		report_info("Sscsrind is not present");
+	skip &= has_ext;
+
+	has_ext = cpu_has_extension(cpu, ISA_SMCDELEG);
+	if (!has_ext)
+		report_info("Smcdeleg is not present");
+	skip &= has_ext;
+
+	has_ext = cpu_has_extension(cpu, ISA_SSCCFG);
+	if (!has_ext)
+		report_info("Ssccfg is not present");
+	skip &= has_ext;
+
+	if (skip) {
+		report_skip("Smcsrind, Sscsrind, Smcdeleg and Ssccfg are present, PMU is not mandated");
+		report_prefix_pop();
+		return;
+	}
+
+	report(sbi_probe(SBI_EXT_PMU), "PMU extension is implemented");
+	report_prefix_pop();
+}
+
+static void check_sbi_070(void)
+{
+	report_prefix_push("SBI_070");
+
+#ifdef CONFIG_EFI
+	if (!dt_available()) {
+		struct spcr_descriptor *spcr;
+
+		spcr = find_acpi_table_addr(SPCR_SIGNATURE);
+		if (spcr) {
+			report_info("SPCR interface type is %#x", spcr->interface_type);
+			if (spcr->interface_type == 0x15) {
+				report(sbi_probe(SBI_EXT_DBCN), "DBCN extension is implemented");
+				report_prefix_pop();
+				return;
+			}
+			report_skip("SPCR interface type is not 0x15, DBCN is not mandated");
+			report_prefix_pop();
+			return;
+		}
+		report_skip("SPCR is not present, DBCN is not mandated");
+		report_prefix_pop();
+		return;
+	}
+#endif
+	report_skip("ACPI not available, DBCN is not mandated");
+	report_prefix_pop();
+}
+
+int main(int argc, char **argv)
+{
+	report_prefix_push("riscv-brs");
+
+	check_sbi_010();
+	check_sbi_020();
+	check_sbi_030();
+	check_sbi_040();
+	check_sbi_050();
+	check_sbi_060();
+	check_sbi_070();
+
+	return report_summary();
+}
diff --git a/riscv/unittests.cfg b/riscv/unittests.cfg
index 9e9f58d9..990f03db 100644
--- a/riscv/unittests.cfg
+++ b/riscv/unittests.cfg
@@ -22,3 +22,7 @@ groups = sbi
 [dbltrp]
 file = isa-dbltrp.flat
 groups = isa sbi
+
+[riscv-brs]
+file = riscv-brs.flat
+groups = riscv-brs nodefault
-- 
2.47.3




More information about the kvm-riscv mailing list