@@ -30,6 +30,8 @@ struct kvm_sbi_fwft_config {
/* FWFT data structure per vcpu */
struct kvm_sbi_fwft {
struct kvm_sbi_fwft_config *configs;
+ bool have_vs_pmlen_7;
+ bool have_vs_pmlen_16;
};
#define vcpu_to_fwft(vcpu) (&(vcpu)->arch.fwft_context)
@@ -168,7 +168,6 @@ static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext)
case KVM_RISCV_ISA_EXT_C:
case KVM_RISCV_ISA_EXT_I:
case KVM_RISCV_ISA_EXT_M:
- case KVM_RISCV_ISA_EXT_SMNPM:
/* There is not architectural config bit to disable sscofpmf completely */
case KVM_RISCV_ISA_EXT_SSCOFPMF:
case KVM_RISCV_ISA_EXT_SSNPM:
@@ -68,13 +68,81 @@ static int kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu,
return SBI_SUCCESS;
}
+static bool try_to_set_pmm(unsigned long value)
+{
+ csr_set(CSR_HENVCFG, value);
+ return (csr_read_clear(CSR_HENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value;
+}
+
+static bool kvm_sbi_fwft_pointer_masking_pmlen_supported(struct kvm_vcpu *vcpu)
+{
+ struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
+
+ if (!riscv_isa_extension_available(vcpu->arch.isa, SMNPM))
+ return false;
+
+ 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);
+
+ return fwft->have_vs_pmlen_7 || fwft->have_vs_pmlen_16;
+}
+
+static int kvm_sbi_fwft_set_pointer_masking_pmlen(struct kvm_vcpu *vcpu,
+ struct kvm_sbi_fwft_config *conf,
+ unsigned long value)
+{
+ struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
+ unsigned long pmm;
+
+ if (value == 0)
+ pmm = ENVCFG_PMM_PMLEN_0;
+ else if (value <= 7 && fwft->have_vs_pmlen_7)
+ pmm = ENVCFG_PMM_PMLEN_7;
+ else if (value <= 16 && fwft->have_vs_pmlen_16)
+ pmm = ENVCFG_PMM_PMLEN_16;
+ else
+ return SBI_ERR_INVALID_PARAM;
+
+ vcpu->arch.cfg.henvcfg &= ~ENVCFG_PMM;
+ vcpu->arch.cfg.henvcfg |= pmm;
+
+ return SBI_SUCCESS;
+}
+
+static int kvm_sbi_fwft_get_pointer_masking_pmlen(struct kvm_vcpu *vcpu,
+ struct kvm_sbi_fwft_config *conf,
+ unsigned long *value)
+{
+ switch (vcpu->arch.cfg.henvcfg & ENVCFG_PMM) {
+ case ENVCFG_PMM_PMLEN_0:
+ *value = 0;
+ break;
+ case ENVCFG_PMM_PMLEN_7:
+ *value = 7;
+ break;
+ case ENVCFG_PMM_PMLEN_16:
+ *value = 16;
+ break;
+ default:
+ return SBI_ERR_FAILURE;
+ }
+
+ return SBI_SUCCESS;
+}
+
static const struct kvm_sbi_fwft_feature features[] = {
{
.id = SBI_FWFT_MISALIGNED_EXC_DELEG,
.supported = kvm_sbi_fwft_misaligned_delegation_supported,
.set = kvm_sbi_fwft_set_misaligned_delegation,
.get = kvm_sbi_fwft_get_misaligned_delegation,
- }
+ },
+ {
+ .id = SBI_FWFT_POINTER_MASKING_PMLEN,
+ .supported = kvm_sbi_fwft_pointer_masking_pmlen_supported,
+ .set = kvm_sbi_fwft_set_pointer_masking_pmlen,
+ .get = kvm_sbi_fwft_get_pointer_masking_pmlen,
+ },
};
static struct kvm_sbi_fwft_config *
Pointer masking is controlled through a WARL field in henvcfg. Expose the feature only if at least one PMLEN value is supported for VS-mode. Allow the VMM to block access to the feature by disabling the Smnpm ISA extension in the guest. Signed-off-by: Samuel Holland <samuel.holland@sifive.com> --- arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h | 2 + arch/riscv/kvm/vcpu_onereg.c | 1 - arch/riscv/kvm/vcpu_sbi_fwft.c | 70 +++++++++++++++++++++- 3 files changed, 71 insertions(+), 2 deletions(-)