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