1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2021 Western Digital Corporation or its affiliates. 4 * 5 * Authors: 6 * Atish Patra <atish.patra@wdc.com> 7 */ 8 9 #include <linux/errno.h> 10 #include <linux/err.h> 11 #include <linux/kvm_host.h> 12 #include <asm/csr.h> 13 #include <asm/sbi.h> 14 #include <asm/kvm_vcpu_sbi.h> 15 16 static int kvm_sbi_hsm_vcpu_start(struct kvm_vcpu *vcpu) 17 { 18 struct kvm_cpu_context *reset_cntx; 19 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 20 struct kvm_vcpu *target_vcpu; 21 unsigned long target_vcpuid = cp->a0; 22 23 target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid); 24 if (!target_vcpu) 25 return -EINVAL; 26 if (!target_vcpu->arch.power_off) 27 return -EALREADY; 28 29 reset_cntx = &target_vcpu->arch.guest_reset_context; 30 /* start address */ 31 reset_cntx->sepc = cp->a1; 32 /* target vcpu id to start */ 33 reset_cntx->a0 = target_vcpuid; 34 /* private data passed from kernel */ 35 reset_cntx->a1 = cp->a2; 36 kvm_make_request(KVM_REQ_VCPU_RESET, target_vcpu); 37 38 kvm_riscv_vcpu_power_on(target_vcpu); 39 40 return 0; 41 } 42 43 static int kvm_sbi_hsm_vcpu_stop(struct kvm_vcpu *vcpu) 44 { 45 if (vcpu->arch.power_off) 46 return -EINVAL; 47 48 kvm_riscv_vcpu_power_off(vcpu); 49 50 return 0; 51 } 52 53 static int kvm_sbi_hsm_vcpu_get_status(struct kvm_vcpu *vcpu) 54 { 55 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 56 unsigned long target_vcpuid = cp->a0; 57 struct kvm_vcpu *target_vcpu; 58 59 target_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, target_vcpuid); 60 if (!target_vcpu) 61 return -EINVAL; 62 if (!target_vcpu->arch.power_off) 63 return SBI_HSM_HART_STATUS_STARTED; 64 else 65 return SBI_HSM_HART_STATUS_STOPPED; 66 } 67 68 static int kvm_sbi_ext_hsm_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, 69 unsigned long *out_val, 70 struct kvm_cpu_trap *utrap, 71 bool *exit) 72 { 73 int ret = 0; 74 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 75 struct kvm *kvm = vcpu->kvm; 76 unsigned long funcid = cp->a6; 77 78 switch (funcid) { 79 case SBI_EXT_HSM_HART_START: 80 mutex_lock(&kvm->lock); 81 ret = kvm_sbi_hsm_vcpu_start(vcpu); 82 mutex_unlock(&kvm->lock); 83 break; 84 case SBI_EXT_HSM_HART_STOP: 85 ret = kvm_sbi_hsm_vcpu_stop(vcpu); 86 break; 87 case SBI_EXT_HSM_HART_STATUS: 88 ret = kvm_sbi_hsm_vcpu_get_status(vcpu); 89 if (ret >= 0) { 90 *out_val = ret; 91 ret = 0; 92 } 93 break; 94 default: 95 ret = -EOPNOTSUPP; 96 } 97 98 return ret; 99 } 100 101 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm = { 102 .extid_start = SBI_EXT_HSM, 103 .extid_end = SBI_EXT_HSM, 104 .handler = kvm_sbi_ext_hsm_handler, 105 }; 106