]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
RISC-V: KVM: Add support for SBI_FWFT_POINTER_MASKING_PMLEN
authorSamuel Holland <samuel.holland@sifive.com>
Sat, 11 Jan 2025 00:46:59 +0000 (16:46 -0800)
committerAnup Patel <anup@brainfault.org>
Tue, 16 Sep 2025 05:23:03 +0000 (10:53 +0530)
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>
Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Link: https://lore.kernel.org/r/20250111004702.2813013-3-samuel.holland@sifive.com
Signed-off-by: Anup Patel <anup@brainfault.org>
arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h
arch/riscv/kvm/vcpu_onereg.c
arch/riscv/kvm/vcpu_sbi_fwft.c

index 9ba841355758701f18a411c19be5227d5345695e..afb6305e46bbff161eed8de32bfb02ac1ba96947 100644 (file)
@@ -22,6 +22,10 @@ struct kvm_sbi_fwft_config {
 /* FWFT data structure per vcpu */
 struct kvm_sbi_fwft {
        struct kvm_sbi_fwft_config *configs;
+#ifndef CONFIG_32BIT
+       bool have_vs_pmlen_7;
+       bool have_vs_pmlen_16;
+#endif
 };
 
 #define vcpu_to_fwft(vcpu) (&(vcpu)->arch.fwft_context)
index cce6a38ea54f2a39bbc075a10314101c43f3f428..b77748a56a594779fdc8da76cab78796b6ab59be 100644 (file)
@@ -173,7 +173,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:
index 6770c043bbcb358f56747a1917c8d154e2b9cea6..93bcc8fb45d66634dc6355f011d4d2891a105f06 100644 (file)
@@ -103,6 +103,88 @@ static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu,
        return SBI_SUCCESS;
 }
 
+#ifndef CONFIG_32BIT
+
+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 long 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;
+
+       switch (value) {
+       case 0:
+               pmm = ENVCFG_PMM_PMLEN_0;
+               break;
+       case 7:
+               if (!fwft->have_vs_pmlen_7)
+                       return SBI_ERR_INVALID_PARAM;
+               pmm = ENVCFG_PMM_PMLEN_7;
+               break;
+       case 16:
+               if (!fwft->have_vs_pmlen_16)
+                       return SBI_ERR_INVALID_PARAM;
+               pmm = ENVCFG_PMM_PMLEN_16;
+               break;
+       default:
+               return SBI_ERR_INVALID_PARAM;
+       }
+
+       vcpu->arch.cfg.henvcfg &= ~ENVCFG_PMM;
+       vcpu->arch.cfg.henvcfg |= pmm;
+
+       /*
+        * Instead of waiting for vcpu_load/put() to update HENVCFG CSR,
+        * update here so that VCPU see's pointer masking mode change
+        * immediately.
+        */
+       csr_write(CSR_HENVCFG, vcpu->arch.cfg.henvcfg);
+
+       return SBI_SUCCESS;
+}
+
+static long 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;
+}
+
+#endif
+
 static const struct kvm_sbi_fwft_feature features[] = {
        {
                .id = SBI_FWFT_MISALIGNED_EXC_DELEG,
@@ -110,6 +192,14 @@ static const struct kvm_sbi_fwft_feature features[] = {
                .set = kvm_sbi_fwft_set_misaligned_delegation,
                .get = kvm_sbi_fwft_get_misaligned_delegation,
        },
+#ifndef CONFIG_32BIT
+       {
+               .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,
+       },
+#endif
 };
 
 static struct kvm_sbi_fwft_config *