Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2024 Ventana Micro Systems Inc.
4 */
5
6#include <linux/kvm_host.h>
7#include <linux/wordpart.h>
8
9#include <asm/kvm_vcpu_sbi.h>
10#include <asm/sbi.h>
11
12static int kvm_sbi_ext_susp_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
13 struct kvm_vcpu_sbi_return *retdata)
14{
15 struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
16 unsigned long funcid = cp->a6;
17 unsigned long hva, i;
18 struct kvm_vcpu *tmp;
19
20 switch (funcid) {
21 case SBI_EXT_SUSP_SYSTEM_SUSPEND:
22 if (lower_32_bits(cp->a0) != SBI_SUSP_SLEEP_TYPE_SUSPEND_TO_RAM) {
23 retdata->err_val = SBI_ERR_INVALID_PARAM;
24 return 0;
25 }
26
27 if (!(cp->sstatus & SR_SPP)) {
28 retdata->err_val = SBI_ERR_FAILURE;
29 return 0;
30 }
31
32 hva = kvm_vcpu_gfn_to_hva_prot(vcpu, cp->a1 >> PAGE_SHIFT, NULL);
33 if (kvm_is_error_hva(hva)) {
34 retdata->err_val = SBI_ERR_INVALID_ADDRESS;
35 return 0;
36 }
37
38 kvm_for_each_vcpu(i, tmp, vcpu->kvm) {
39 if (tmp == vcpu)
40 continue;
41 if (!kvm_riscv_vcpu_stopped(tmp)) {
42 retdata->err_val = SBI_ERR_DENIED;
43 return 0;
44 }
45 }
46
47 kvm_riscv_vcpu_sbi_request_reset(vcpu, cp->a1, cp->a2);
48
49 /* userspace provides the suspend implementation */
50 return kvm_riscv_vcpu_sbi_forward_handler(vcpu, run, retdata);
51 default:
52 retdata->err_val = SBI_ERR_NOT_SUPPORTED;
53 break;
54 }
55
56 return 0;
57}
58
59const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_susp = {
60 .extid_start = SBI_EXT_SUSP,
61 .extid_end = SBI_EXT_SUSP,
62 .default_disabled = true,
63 .handler = kvm_sbi_ext_susp_handler,
64};