]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
RISC-V: KVM: Add SBI system suspend support
authorAndrew Jones <ajones@ventanamicro.com>
Thu, 17 Oct 2024 07:45:40 +0000 (09:45 +0200)
committerAnup Patel <anup@brainfault.org>
Mon, 30 Dec 2024 08:31:01 +0000 (14:01 +0530)
Implement a KVM SBI SUSP extension handler. The handler only
validates the system suspend entry criteria and prepares for resuming
in the appropriate state at the resume_addr (as specified by the SBI
spec), but then it forwards the call to the VMM where any system
suspend behavior may be implemented. Since VMM support is needed, KVM
disables the extension by default.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Link: https://lore.kernel.org/r/20241017074538.18867-5-ajones@ventanamicro.com
Signed-off-by: Anup Patel <anup@brainfault.org>
arch/riscv/include/asm/kvm_vcpu_sbi.h
arch/riscv/include/uapi/asm/kvm.h
arch/riscv/kvm/Makefile
arch/riscv/kvm/vcpu_sbi.c
arch/riscv/kvm/vcpu_sbi_system.c [new file with mode: 0644]

index b96705258cf9641fbc43810cda7c01f970db1f58..4ed6203cdd3079006fb9e22ba8eb8aee37d9d951 100644 (file)
@@ -85,6 +85,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn;
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_susp;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor;
index 3482c9a73d1b644385182436192914f34b50b997..24e22f6e3a477259dfc25f34e1953640200d2822 100644 (file)
@@ -198,6 +198,7 @@ enum KVM_RISCV_SBI_EXT_ID {
        KVM_RISCV_SBI_EXT_VENDOR,
        KVM_RISCV_SBI_EXT_DBCN,
        KVM_RISCV_SBI_EXT_STA,
+       KVM_RISCV_SBI_EXT_SUSP,
        KVM_RISCV_SBI_EXT_MAX,
 };
 
index 0fb1840c3e0ad47f8b2d5e5a1a5b4f7eeb0b7b27..4e0bba91d2841d4ec44c5e06b047a7b2d0a9f7a5 100644 (file)
@@ -30,6 +30,7 @@ kvm-y += vcpu_sbi_hsm.o
 kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_sbi_pmu.o
 kvm-y += vcpu_sbi_replace.o
 kvm-y += vcpu_sbi_sta.o
+kvm-y += vcpu_sbi_system.o
 kvm-$(CONFIG_RISCV_SBI_V01) += vcpu_sbi_v01.o
 kvm-y += vcpu_switch.o
 kvm-y += vcpu_timer.o
index 6e704ed86a83a9c4f610d6836073c80e9b7620cc..d1c83a77735e059d2e9daf2c52b8b35f66c4b4ad 100644 (file)
@@ -70,6 +70,10 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = {
                .ext_idx = KVM_RISCV_SBI_EXT_DBCN,
                .ext_ptr = &vcpu_sbi_ext_dbcn,
        },
+       {
+               .ext_idx = KVM_RISCV_SBI_EXT_SUSP,
+               .ext_ptr = &vcpu_sbi_ext_susp,
+       },
        {
                .ext_idx = KVM_RISCV_SBI_EXT_STA,
                .ext_ptr = &vcpu_sbi_ext_sta,
diff --git a/arch/riscv/kvm/vcpu_sbi_system.c b/arch/riscv/kvm/vcpu_sbi_system.c
new file mode 100644 (file)
index 0000000..5d55e08
--- /dev/null
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 Ventana Micro Systems Inc.
+ */
+
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_vcpu_sbi.h>
+#include <asm/sbi.h>
+
+static int kvm_sbi_ext_susp_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
+                                   struct kvm_vcpu_sbi_return *retdata)
+{
+       struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
+       struct kvm_cpu_context *reset_cntx;
+       unsigned long funcid = cp->a6;
+       unsigned long hva, i;
+       struct kvm_vcpu *tmp;
+
+       switch (funcid) {
+       case SBI_EXT_SUSP_SYSTEM_SUSPEND:
+               if (cp->a0 != SBI_SUSP_SLEEP_TYPE_SUSPEND_TO_RAM) {
+                       retdata->err_val = SBI_ERR_INVALID_PARAM;
+                       return 0;
+               }
+
+               if (!(cp->sstatus & SR_SPP)) {
+                       retdata->err_val = SBI_ERR_FAILURE;
+                       return 0;
+               }
+
+               hva = kvm_vcpu_gfn_to_hva_prot(vcpu, cp->a1 >> PAGE_SHIFT, NULL);
+               if (kvm_is_error_hva(hva)) {
+                       retdata->err_val = SBI_ERR_INVALID_ADDRESS;
+                       return 0;
+               }
+
+               kvm_for_each_vcpu(i, tmp, vcpu->kvm) {
+                       if (tmp == vcpu)
+                               continue;
+                       if (!kvm_riscv_vcpu_stopped(tmp)) {
+                               retdata->err_val = SBI_ERR_DENIED;
+                               return 0;
+                       }
+               }
+
+               spin_lock(&vcpu->arch.reset_cntx_lock);
+               reset_cntx = &vcpu->arch.guest_reset_context;
+               reset_cntx->sepc = cp->a1;
+               reset_cntx->a0 = vcpu->vcpu_id;
+               reset_cntx->a1 = cp->a2;
+               spin_unlock(&vcpu->arch.reset_cntx_lock);
+
+               kvm_make_request(KVM_REQ_VCPU_RESET, vcpu);
+
+               /* userspace provides the suspend implementation */
+               kvm_riscv_vcpu_sbi_forward(vcpu, run);
+               retdata->uexit = true;
+               break;
+       default:
+               retdata->err_val = SBI_ERR_NOT_SUPPORTED;
+               break;
+       }
+
+       return 0;
+}
+
+const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_susp = {
+       .extid_start = SBI_EXT_SUSP,
+       .extid_end = SBI_EXT_SUSP,
+       .default_disabled = true,
+       .handler = kvm_sbi_ext_susp_handler,
+};