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_timer.h> 15 #include <asm/kvm_vcpu_sbi.h> 16 17 static int kvm_sbi_ext_base_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, 18 unsigned long *out_val, 19 struct kvm_cpu_trap *trap, bool *exit) 20 { 21 int ret = 0; 22 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 23 struct sbiret ecall_ret; 24 25 switch (cp->a6) { 26 case SBI_EXT_BASE_GET_SPEC_VERSION: 27 *out_val = (KVM_SBI_VERSION_MAJOR << 28 SBI_SPEC_VERSION_MAJOR_SHIFT) | 29 KVM_SBI_VERSION_MINOR; 30 break; 31 case SBI_EXT_BASE_GET_IMP_ID: 32 *out_val = KVM_SBI_IMPID; 33 break; 34 case SBI_EXT_BASE_GET_IMP_VERSION: 35 *out_val = 0; 36 break; 37 case SBI_EXT_BASE_PROBE_EXT: 38 if ((cp->a0 >= SBI_EXT_EXPERIMENTAL_START && 39 cp->a0 <= SBI_EXT_EXPERIMENTAL_END) || 40 (cp->a0 >= SBI_EXT_VENDOR_START && 41 cp->a0 <= SBI_EXT_VENDOR_END)) { 42 /* 43 * For experimental/vendor extensions 44 * forward it to the userspace 45 */ 46 kvm_riscv_vcpu_sbi_forward(vcpu, run); 47 *exit = true; 48 } else 49 *out_val = kvm_vcpu_sbi_find_ext(cp->a0) ? 1 : 0; 50 break; 51 case SBI_EXT_BASE_GET_MVENDORID: 52 case SBI_EXT_BASE_GET_MARCHID: 53 case SBI_EXT_BASE_GET_MIMPID: 54 ecall_ret = sbi_ecall(SBI_EXT_BASE, cp->a6, 0, 0, 0, 0, 0, 0); 55 if (!ecall_ret.error) 56 *out_val = ecall_ret.value; 57 /*TODO: We are unnecessarily converting the error twice */ 58 ret = sbi_err_map_linux_errno(ecall_ret.error); 59 break; 60 default: 61 ret = -EOPNOTSUPP; 62 break; 63 } 64 65 return ret; 66 } 67 68 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_base = { 69 .extid_start = SBI_EXT_BASE, 70 .extid_end = SBI_EXT_BASE, 71 .handler = kvm_sbi_ext_base_handler, 72 }; 73 74 static int kvm_sbi_ext_forward_handler(struct kvm_vcpu *vcpu, 75 struct kvm_run *run, 76 unsigned long *out_val, 77 struct kvm_cpu_trap *utrap, 78 bool *exit) 79 { 80 /* 81 * Both SBI experimental and vendor extensions are 82 * unconditionally forwarded to userspace. 83 */ 84 kvm_riscv_vcpu_sbi_forward(vcpu, run); 85 *exit = true; 86 return 0; 87 } 88 89 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental = { 90 .extid_start = SBI_EXT_EXPERIMENTAL_START, 91 .extid_end = SBI_EXT_EXPERIMENTAL_END, 92 .handler = kvm_sbi_ext_forward_handler, 93 }; 94 95 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor = { 96 .extid_start = SBI_EXT_VENDOR_START, 97 .extid_end = SBI_EXT_VENDOR_END, 98 .handler = kvm_sbi_ext_forward_handler, 99 }; 100