*/
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
*
static bool try_to_set_pmm(unsigned long value)
{
+ unsigned long prev;
+ bool ret;
+
+ prev = csr_read_clear(CSR_HENVCFG, ENVCFG_PMM);
csr_set(CSR_HENVCFG, value);
- return (csr_read_clear(CSR_HENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value;
+ ret = (csr_read_clear(CSR_HENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value;
+ csr_write(CSR_HENVCFG, prev);
+
+ return ret;
}
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);
+ preempt_disable();
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);
+ preempt_enable();
return fwft->have_vs_pmlen_7 || fwft->have_vs_pmlen_16;
}
.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,
else
conf->supported = true;
+ if (conf->supported && feature->init)
+ conf->supported = feature->init(vcpu);
+
conf->enabled = conf->supported;
conf->feature = feature;
}