diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c index 2eab15339694f6..dde6e39aab5e9a 100644 --- a/arch/riscv/kvm/vcpu_sbi_fwft.c +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c @@ -35,6 +35,16 @@ struct kvm_sbi_fwft_feature { */ bool (*supported)(struct kvm_vcpu *vcpu); + /** + * @init: Probe and initialize the feature on the vcpu + * + * This callback is optional. If provided, it will be called during + * vcpu initialization to probe the feature availability and perform + * any necessary initialization. Returns true if the feature is supported + * and initialized successfully, false otherwise. + */ + bool (*init)(struct kvm_vcpu *vcpu); + /** * @reset: Reset the feature value irrespective whether feature is supported or not * @@ -137,10 +147,12 @@ static bool try_to_set_pmm(unsigned long value) static bool kvm_sbi_fwft_pointer_masking_pmlen_supported(struct kvm_vcpu *vcpu) { - struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + return riscv_isa_extension_available(vcpu->arch.isa, SMNPM); +} - if (!riscv_isa_extension_available(vcpu->arch.isa, SMNPM)) - return false; +static bool kvm_sbi_fwft_pointer_masking_pmlen_init(struct kvm_vcpu *vcpu) +{ + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); fwft->have_vs_pmlen_7 = try_to_set_pmm(ENVCFG_PMM_PMLEN_7); fwft->have_vs_pmlen_16 = try_to_set_pmm(ENVCFG_PMM_PMLEN_16); @@ -231,6 +243,7 @@ static const struct kvm_sbi_fwft_feature features[] = { .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pointer_masking.enable) / sizeof(unsigned long), .supported = kvm_sbi_fwft_pointer_masking_pmlen_supported, + .init = kvm_sbi_fwft_pointer_masking_pmlen_init, .reset = kvm_sbi_fwft_reset_pointer_masking_pmlen, .set = kvm_sbi_fwft_set_pointer_masking_pmlen, .get = kvm_sbi_fwft_get_pointer_masking_pmlen, @@ -281,6 +294,8 @@ static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, u32 feature, if (!tconf->supported || !tconf->enabled) return SBI_ERR_NOT_SUPPORTED; + else if (tconf->feature->supported && !tconf->feature->supported(vcpu)) + return SBI_ERR_NOT_SUPPORTED; *conf = tconf; @@ -365,6 +380,9 @@ static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu) else conf->supported = true; + if (conf->supported && feature->init) + conf->supported = feature->init(vcpu); + conf->enabled = conf->supported; conf->feature = feature; } @@ -408,6 +426,8 @@ static unsigned long kvm_sbi_ext_fwft_get_reg_count(struct kvm_vcpu *vcpu) conf = kvm_sbi_fwft_get_config(vcpu, feature->id); if (!conf || !conf->supported) continue; + else if (conf->feature->supported && !conf->feature->supported(vcpu)) + continue; ret++; } @@ -430,6 +450,8 @@ static int kvm_sbi_ext_fwft_get_reg_id(struct kvm_vcpu *vcpu, int index, u64 *re conf = kvm_sbi_fwft_get_config(vcpu, feature->id); if (!conf || !conf->supported) continue; + else if (conf->feature->supported && !conf->feature->supported(vcpu)) + continue; if (index == idx) { *reg_id = KVM_REG_RISCV | @@ -465,6 +487,8 @@ static int kvm_sbi_ext_fwft_get_reg(struct kvm_vcpu *vcpu, unsigned long reg_num conf = kvm_sbi_fwft_get_config(vcpu, feature->id); if (!conf || !conf->supported) return -ENOENT; + else if (conf->feature->supported && !conf->feature->supported(vcpu)) + return -ENOENT; switch (reg_num - feature->first_reg_num) { case 0: @@ -502,6 +526,8 @@ static int kvm_sbi_ext_fwft_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num conf = kvm_sbi_fwft_get_config(vcpu, feature->id); if (!conf || !conf->supported) return -ENOENT; + else if (conf->feature->supported && !conf->feature->supported(vcpu)) + return -ENOENT; switch (reg_num - feature->first_reg_num) { case 0: diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c index 8d6fdb5d38b89e..7ae55fbad29aaf 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), @@ -1013,7 +1072,7 @@ static __u64 fp_d_regs[] = { }; /* Define a default vector registers with length. This will be overwritten at runtime */ -static __u64 vector_regs[] = { +static __u64 v_regs[] = { KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vstart), KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vl), KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vtype), @@ -1057,37 +1116,17 @@ static __u64 vector_regs[] = { #define SUBLIST_BASE \ {"base", .regs = base_regs, .regs_n = ARRAY_SIZE(base_regs), \ .skips_set = base_skips_set, .skips_set_n = ARRAY_SIZE(base_skips_set),} -#define SUBLIST_SBI_BASE \ - {"sbi-base", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_V01, \ - .regs = sbi_base_regs, .regs_n = ARRAY_SIZE(sbi_base_regs),} -#define SUBLIST_SBI_STA \ - {"sbi-sta", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_STA, \ - .regs = sbi_sta_regs, .regs_n = ARRAY_SIZE(sbi_sta_regs),} -#define SUBLIST_SBI_FWFT \ - {"sbi-fwft", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_FWFT, \ - .regs = sbi_fwft_regs, .regs_n = ARRAY_SIZE(sbi_fwft_regs),} -#define SUBLIST_ZICBOM \ - {"zicbom", .feature = KVM_RISCV_ISA_EXT_ZICBOM, .regs = zicbom_regs, .regs_n = ARRAY_SIZE(zicbom_regs),} -#define SUBLIST_ZICBOP \ - {"zicbop", .feature = KVM_RISCV_ISA_EXT_ZICBOP, .regs = zicbop_regs, .regs_n = ARRAY_SIZE(zicbop_regs),} -#define SUBLIST_ZICBOZ \ - {"zicboz", .feature = KVM_RISCV_ISA_EXT_ZICBOZ, .regs = zicboz_regs, .regs_n = ARRAY_SIZE(zicboz_regs),} -#define SUBLIST_AIA \ - {"aia", .feature = KVM_RISCV_ISA_EXT_SSAIA, .regs = aia_regs, .regs_n = ARRAY_SIZE(aia_regs),} -#define SUBLIST_SMSTATEEN \ - {"smstateen", .feature = KVM_RISCV_ISA_EXT_SMSTATEEN, .regs = smstateen_regs, .regs_n = ARRAY_SIZE(smstateen_regs),} -#define SUBLIST_FP_F \ - {"fp_f", .feature = KVM_RISCV_ISA_EXT_F, .regs = fp_f_regs, \ - .regs_n = ARRAY_SIZE(fp_f_regs),} -#define SUBLIST_FP_D \ - {"fp_d", .feature = KVM_RISCV_ISA_EXT_D, .regs = fp_d_regs, \ - .regs_n = ARRAY_SIZE(fp_d_regs),} - -#define SUBLIST_V \ - {"v", .feature = KVM_RISCV_ISA_EXT_V, .regs = vector_regs, .regs_n = ARRAY_SIZE(vector_regs),} + +#define SUBLIST_ISA(ext, extu) \ + { \ + .name = #ext, \ + .feature = KVM_RISCV_ISA_EXT_##extu, \ + .regs = ext##_regs, \ + .regs_n = ARRAY_SIZE(ext##_regs), \ + } #define KVM_ISA_EXT_SIMPLE_CONFIG(ext, extu) \ -static __u64 regs_##ext[] = { \ +static __u64 ext##_regs[] = { \ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | \ KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | \ KVM_RISCV_ISA_EXT_##extu, \ @@ -1095,18 +1134,22 @@ static __u64 regs_##ext[] = { \ static struct vcpu_reg_list config_##ext = { \ .sublists = { \ SUBLIST_BASE, \ - { \ - .name = #ext, \ - .feature = KVM_RISCV_ISA_EXT_##extu, \ - .regs = regs_##ext, \ - .regs_n = ARRAY_SIZE(regs_##ext), \ - }, \ + SUBLIST_ISA(ext, extu), \ {0}, \ }, \ } \ +#define SUBLIST_SBI(ext, extu) \ + { \ + .name = "sbi-"#ext, \ + .feature_type = VCPU_FEATURE_SBI_EXT, \ + .feature = KVM_RISCV_SBI_EXT_##extu, \ + .regs = sbi_##ext##_regs, \ + .regs_n = ARRAY_SIZE(sbi_##ext##_regs), \ + } + #define KVM_SBI_EXT_SIMPLE_CONFIG(ext, extu) \ -static __u64 regs_sbi_##ext[] = { \ +static __u64 sbi_##ext##_regs[] = { \ KVM_REG_RISCV | KVM_REG_SIZE_ULONG | \ KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | \ KVM_RISCV_SBI_EXT_##extu, \ @@ -1114,13 +1157,7 @@ static __u64 regs_sbi_##ext[] = { \ static struct vcpu_reg_list config_sbi_##ext = { \ .sublists = { \ SUBLIST_BASE, \ - { \ - .name = "sbi-"#ext, \ - .feature_type = VCPU_FEATURE_SBI_EXT, \ - .feature = KVM_RISCV_SBI_EXT_##extu, \ - .regs = regs_sbi_##ext, \ - .regs_n = ARRAY_SIZE(regs_sbi_##ext), \ - }, \ + SUBLIST_SBI(ext, extu), \ {0}, \ }, \ } \ @@ -1129,7 +1166,7 @@ static struct vcpu_reg_list config_sbi_##ext = { \ static struct vcpu_reg_list config_##ext = { \ .sublists = { \ SUBLIST_BASE, \ - SUBLIST_##extu, \ + SUBLIST_ISA(ext, extu), \ {0}, \ }, \ } \ @@ -1138,24 +1175,23 @@ static struct vcpu_reg_list config_##ext = { \ static struct vcpu_reg_list config_sbi_##ext = { \ .sublists = { \ SUBLIST_BASE, \ - SUBLIST_SBI_##extu, \ + SUBLIST_SBI(ext, extu), \ {0}, \ }, \ } \ /* Note: The below list is alphabetically sorted. */ -KVM_SBI_EXT_SUBLIST_CONFIG(base, BASE); +KVM_SBI_EXT_SUBLIST_CONFIG(base, V01); KVM_SBI_EXT_SUBLIST_CONFIG(sta, STA); 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, AIA); -KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, FP_F); -KVM_ISA_EXT_SUBLIST_CONFIG(fp_d, FP_D); +KVM_ISA_EXT_SUBLIST_CONFIG(aia, SSAIA); +KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, F); +KVM_ISA_EXT_SUBLIST_CONFIG(fp_d, D); KVM_ISA_EXT_SUBLIST_CONFIG(v, V); KVM_ISA_EXT_SIMPLE_CONFIG(h, H); KVM_ISA_EXT_SIMPLE_CONFIG(smnpm, SMNPM); @@ -1228,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, @@ -1235,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,