vcpu_sbi_hsm.c 2.7 KB

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