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
- 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 <[email protected]>
---
 tools/testing/selftests/kvm/riscv/get-reg-list.c | 92 +++++++++++++++++++++---
 1 file changed, 82 insertions(+), 10 deletions(-)

diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c 
b/tools/testing/selftests/kvm/riscv/get-reg-list.c
index cb16c638ce1a..6a34320be78c 100644
--- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
+++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
@@ -26,7 +26,21 @@ enum {
        KVM_RISC_V_REG_OFFSET_MAX,
 };
 
-static bool isa_ext_cant_disable[KVM_RISCV_ISA_EXT_MAX];
+static bool isa_ext_enabled[KVM_RISCV_ISA_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 isa_ext_enabled[KVM_RISCV_ISA_EXT_SMNPM];
+       default:
+               break;
+       }
+
+       return true;
+}
 
 bool filter_reg(__u64 reg)
 {
@@ -148,7 +162,12 @@ bool filter_reg(__u64 reg)
        case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | 
KVM_REG_RISCV_CSR_AIA_REG(siph):
        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];
+               return isa_ext_enabled[KVM_RISCV_ISA_EXT_SSAIA];
+       /* KVM misaligned delegation registers are always visible when the host 
supports it */
+       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 true;
        default:
                break;
        }
@@ -193,15 +212,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 +252,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])
-                       isa_ext_cant_disable[i] = true;
+               if (rc && isa_ext_enabled[i])
+                       isa_ext_enabled[i] = true;
+               else
+                       isa_ext_enabled[i] = false;
        }
 
        for (int i = 0; i < KVM_RISCV_SBI_EXT_MAX; i++) {
@@ -229,9 +274,15 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct 
vcpu_reg_list *c)
                                goto skip;
                }
 
+               if (s->feature == KVM_RISCV_SBI_EXT_FWFT) {
+                       feature = RISCV_SBI_EXT_REG(KVM_RISCV_SBI_EXT_FWFT);
+                       check_fwft_feature(vcpu, s, feature);
+               }
+
                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);
@@ -897,11 +948,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 +1184,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 +1260,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 +1284,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


Reply via email to