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