linux/arch/riscv/kvm/vcpu_sbi_hsm.c
<<
>>
Prefs
   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
  16static 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
  43static 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
  53static 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_STATE_STARTED;
  64        else if (vcpu->stat.generic.blocking)
  65                return SBI_HSM_STATE_SUSPENDED;
  66        else
  67                return SBI_HSM_STATE_STOPPED;
  68}
  69
  70static int kvm_sbi_ext_hsm_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
  71                                   unsigned long *out_val,
  72                                   struct kvm_cpu_trap *utrap,
  73                                   bool *exit)
  74{
  75        int ret = 0;
  76        struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
  77        struct kvm *kvm = vcpu->kvm;
  78        unsigned long funcid = cp->a6;
  79
  80        switch (funcid) {
  81        case SBI_EXT_HSM_HART_START:
  82                mutex_lock(&kvm->lock);
  83                ret = kvm_sbi_hsm_vcpu_start(vcpu);
  84                mutex_unlock(&kvm->lock);
  85                break;
  86        case SBI_EXT_HSM_HART_STOP:
  87                ret = kvm_sbi_hsm_vcpu_stop(vcpu);
  88                break;
  89        case SBI_EXT_HSM_HART_STATUS:
  90                ret = kvm_sbi_hsm_vcpu_get_status(vcpu);
  91                if (ret >= 0) {
  92                        *out_val = ret;
  93                        ret = 0;
  94                }
  95                break;
  96        case SBI_EXT_HSM_HART_SUSPEND:
  97                switch (cp->a0) {
  98                case SBI_HSM_SUSPEND_RET_DEFAULT:
  99                        kvm_riscv_vcpu_wfi(vcpu);
 100                        break;
 101                case SBI_HSM_SUSPEND_NON_RET_DEFAULT:
 102                        ret = -EOPNOTSUPP;
 103                        break;
 104                default:
 105                        ret = -EINVAL;
 106                }
 107                break;
 108        default:
 109                ret = -EOPNOTSUPP;
 110        }
 111
 112        return ret;
 113}
 114
 115const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm = {
 116        .extid_start = SBI_EXT_HSM,
 117        .extid_end = SBI_EXT_HSM,
 118        .handler = kvm_sbi_ext_hsm_handler,
 119};
 120