[PATCH v3 3/3] KVM: riscv: selftests: Split SBI FWFT into separate feature-specific sublists
Yong-Xuan Wang
yongxuan.wang at sifive.com
Thu May 28 23:28:29 PDT 2026
Divide the monolithic SBI FWFT (Firmware Features) register list into
separate sublists, each testing a specific FWFT feature independently
with proper dependency checking.
Previously, all FWFT features were tested together in a single sublist.
This caused issues because:
1. Not all FWFT features are available on all platforms
2. Some features depend on specific ISA extensions (e.g., pointer_masking
requires Smnpm)
3. Tests would fail if any single feature was unavailable
Add the feature-specific SBI FWFT sublists with the following
improvements:
- Add check_supported_reg() function to validate register availability
based on required ISA extensions and SBI extensions
- Add check_fwft_feature() helper to verify FWFT feature availability
at runtime
- Update filter_reg() to handle per-feature FWFT register filtering
Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
---
tools/testing/selftests/kvm/riscv/get-reg-list.c | 90 ++++++++++++++++++++++--
1 file changed, 83 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
index 5033c09201ef..7ae55fbad29a 100644
--- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
+++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
@@ -27,6 +27,23 @@ enum {
};
static bool isa_ext_cant_disable[KVM_RISCV_ISA_EXT_MAX];
+static bool isa_ext_enabled[KVM_RISCV_ISA_EXT_MAX];
+static bool sbi_ext_enabled[KVM_RISCV_SBI_EXT_MAX];
+
+bool check_supported_reg(struct kvm_vcpu *vcpu, __u64 reg)
+{
+ switch (reg & ~REG_MASK) {
+ case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable):
+ case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags):
+ case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value):
+ return sbi_ext_enabled[KVM_RISCV_SBI_EXT_FWFT] &&
+ isa_ext_enabled[KVM_RISCV_ISA_EXT_SMNPM];
+ default:
+ break;
+ }
+
+ return true;
+}
bool filter_reg(__u64 reg)
{
@@ -149,6 +166,14 @@ bool filter_reg(__u64 reg)
case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio1h):
case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio2h):
return isa_ext_cant_disable[KVM_RISCV_ISA_EXT_SSAIA];
+ /*
+ * FWFT misaligned delegation registers are always visible when the SBI FWFT
+ * extension is enable and the host supports the misaligned delegation.
+ */
+ case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable):
+ case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags):
+ case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value):
+ return sbi_ext_enabled[KVM_RISCV_SBI_EXT_FWFT];
default:
break;
}
@@ -193,15 +218,39 @@ static int override_vector_reg_size(struct kvm_vcpu *vcpu, struct vcpu_reg_subli
return 0;
}
+void check_fwft_feature(struct kvm_vcpu *vcpu, struct vcpu_reg_sublist *s, u64 feature)
+{
+ unsigned long value;
+ int rc;
+
+ /* Enable SBI FWFT extension so that we can check the supported register */
+ rc = __vcpu_set_reg(vcpu, feature, 1);
+ if (rc)
+ return;
+
+ for (int i = 0; i < s->regs_n; i++) {
+ if ((s->regs[i] & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_SBI_STATE) {
+ rc = __vcpu_get_reg(vcpu, s->regs[i], &value);
+ __TEST_REQUIRE(!rc, "%s not available, skipping tests", s->name);
+ }
+ }
+
+ /* We should assert if disabling failed here while enabling succeeded before */
+ vcpu_set_reg(vcpu, feature, 0);
+}
+
void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
{
- unsigned long isa_ext_state[KVM_RISCV_ISA_EXT_MAX] = { 0 };
+ unsigned long isa_ext_state;
struct vcpu_reg_sublist *s;
u64 feature;
int rc;
- for (int i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++)
- __vcpu_get_reg(vcpu, RISCV_ISA_EXT_REG(i), &isa_ext_state[i]);
+ for (int i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++) {
+ rc = __vcpu_get_reg(vcpu, RISCV_ISA_EXT_REG(i), &isa_ext_state);
+ if (!rc)
+ isa_ext_enabled[i] = !!isa_ext_state;
+ }
/*
* Disable all extensions which were enabled by default
@@ -209,8 +258,10 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
*/
for (int i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++) {
rc = __vcpu_set_reg(vcpu, RISCV_ISA_EXT_REG(i), 0);
- if (rc && isa_ext_state[i])
+ if (rc && isa_ext_enabled[i])
isa_ext_cant_disable[i] = true;
+ else
+ isa_ext_enabled[i] = false;
}
for (int i = 0; i < KVM_RISCV_SBI_EXT_MAX; i++) {
@@ -232,9 +283,13 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
switch (s->feature_type) {
case VCPU_FEATURE_ISA_EXT:
feature = RISCV_ISA_EXT_REG(s->feature);
+ isa_ext_enabled[s->feature] = true;
break;
case VCPU_FEATURE_SBI_EXT:
feature = RISCV_SBI_EXT_REG(s->feature);
+ if (s->feature == KVM_RISCV_SBI_EXT_FWFT)
+ check_fwft_feature(vcpu, s, feature);
+ sbi_ext_enabled[s->feature] = true;
break;
default:
TEST_FAIL("Unknown feature type");
@@ -897,11 +952,15 @@ static __u64 sbi_sta_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_STA | KVM_REG_RISCV_SBI_STA_REG(shmem_hi),
};
-static __u64 sbi_fwft_regs[] = {
+static __u64 sbi_fwft_misaligned_deleg_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT,
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value),
+};
+
+static __u64 sbi_fwft_pointer_masking_regs[] = {
+ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT,
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value),
@@ -1129,7 +1188,6 @@ KVM_SBI_EXT_SIMPLE_CONFIG(pmu, PMU);
KVM_SBI_EXT_SIMPLE_CONFIG(dbcn, DBCN);
KVM_SBI_EXT_SIMPLE_CONFIG(susp, SUSP);
KVM_SBI_EXT_SIMPLE_CONFIG(mpxy, MPXY);
-KVM_SBI_EXT_SUBLIST_CONFIG(fwft, FWFT);
KVM_ISA_EXT_SUBLIST_CONFIG(aia, SSAIA);
KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, F);
@@ -1206,6 +1264,23 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zvksed, ZVKSED);
KVM_ISA_EXT_SIMPLE_CONFIG(zvksh, ZVKSH);
KVM_ISA_EXT_SIMPLE_CONFIG(zvkt, ZVKT);
+static struct vcpu_reg_list config_sbi_fwft_misaligned_deleg = {
+ .sublists = {
+ SUBLIST_BASE,
+ SUBLIST_SBI(fwft_misaligned_deleg, FWFT),
+ {0},
+ },
+};
+
+static struct vcpu_reg_list config_sbi_fwft_pointer_masking = {
+ .sublists = {
+ SUBLIST_BASE,
+ SUBLIST_ISA(smnpm, SMNPM),
+ SUBLIST_SBI(fwft_pointer_masking, FWFT),
+ {0},
+ },
+};
+
struct vcpu_reg_list *vcpu_configs[] = {
&config_sbi_base,
&config_sbi_sta,
@@ -1213,7 +1288,8 @@ struct vcpu_reg_list *vcpu_configs[] = {
&config_sbi_dbcn,
&config_sbi_susp,
&config_sbi_mpxy,
- &config_sbi_fwft,
+ &config_sbi_fwft_misaligned_deleg,
+ &config_sbi_fwft_pointer_masking,
&config_aia,
&config_fp_f,
&config_fp_d,
--
2.43.7
More information about the kvm-riscv
mailing list