Commit 023c1515 authored by Andrew Jones's avatar Andrew Jones Committed by Anup Patel
Browse files

RISC-V: KVM: Add SBI system suspend support



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: default avatarAndrew Jones <ajones@ventanamicro.com>
Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
Link: https://lore.kernel.org/r/20241017074538.18867-5-ajones@ventanamicro.com


Signed-off-by: default avatarAnup Patel <anup@brainfault.org>
parent fc033cf2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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,
};

+1 −0
Original line number Diff line number Diff line
@@ -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
+4 −0
Original line number Diff line number Diff line
@@ -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,
+73 −0
Original line number Diff line number Diff line
// 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,
};