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 12 static 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 kvm_riscv_vcpu_sbi_forward(vcpu, run); 51 retdata->uexit = true; 52 break; 53 default: 54 retdata->err_val = SBI_ERR_NOT_SUPPORTED; 55 break; 56 } 57 58 return 0; 59 } 60 61 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_susp = { 62 .extid_start = SBI_EXT_SUSP, 63 .extid_end = SBI_EXT_SUSP, 64 .default_disabled = true, 65 .handler = kvm_sbi_ext_susp_handler, 66 }; 67