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> 1240327154SAnup Patel #include <linux/version.h> 13c62a7685SAtish Patra #include <asm/sbi.h> 14c62a7685SAtish Patra #include <asm/kvm_vcpu_sbi.h> 15c62a7685SAtish Patra 16c62a7685SAtish Patra static int kvm_sbi_ext_base_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, 17bae0dfd7SAtish Patra struct kvm_vcpu_sbi_return *retdata) 18c62a7685SAtish Patra { 19c62a7685SAtish Patra struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 20026bac45SAtish Patra const struct kvm_vcpu_sbi_extension *sbi_ext; 21bae0dfd7SAtish Patra unsigned long *out_val = &retdata->out_val; 22c62a7685SAtish Patra 23c62a7685SAtish Patra switch (cp->a6) { 24c62a7685SAtish Patra case SBI_EXT_BASE_GET_SPEC_VERSION: 25c62a7685SAtish Patra *out_val = (KVM_SBI_VERSION_MAJOR << 26c62a7685SAtish Patra SBI_SPEC_VERSION_MAJOR_SHIFT) | 27c62a7685SAtish Patra KVM_SBI_VERSION_MINOR; 28c62a7685SAtish Patra break; 29c62a7685SAtish Patra case SBI_EXT_BASE_GET_IMP_ID: 30c62a7685SAtish Patra *out_val = KVM_SBI_IMPID; 31c62a7685SAtish Patra break; 32c62a7685SAtish Patra case SBI_EXT_BASE_GET_IMP_VERSION: 3340327154SAnup Patel *out_val = LINUX_VERSION_CODE; 34c62a7685SAtish Patra break; 35c62a7685SAtish Patra case SBI_EXT_BASE_PROBE_EXT: 36c62a7685SAtish Patra if ((cp->a0 >= SBI_EXT_EXPERIMENTAL_START && 37c62a7685SAtish Patra cp->a0 <= SBI_EXT_EXPERIMENTAL_END) || 38c62a7685SAtish Patra (cp->a0 >= SBI_EXT_VENDOR_START && 39c62a7685SAtish Patra cp->a0 <= SBI_EXT_VENDOR_END)) { 40c62a7685SAtish Patra /* 41c62a7685SAtish Patra * For experimental/vendor extensions 42c62a7685SAtish Patra * forward it to the userspace 43c62a7685SAtish Patra */ 44c62a7685SAtish Patra kvm_riscv_vcpu_sbi_forward(vcpu, run); 45bae0dfd7SAtish Patra retdata->uexit = true; 46026bac45SAtish Patra } else { 47*96b3d4bdSAnup Patel sbi_ext = kvm_vcpu_sbi_find_ext(vcpu, cp->a0); 48026bac45SAtish Patra *out_val = sbi_ext && sbi_ext->probe ? 49026bac45SAtish Patra sbi_ext->probe(vcpu) : !!sbi_ext; 50026bac45SAtish Patra } 51c62a7685SAtish Patra break; 52c62a7685SAtish Patra case SBI_EXT_BASE_GET_MVENDORID: 5352ec4b69SAnup Patel *out_val = vcpu->arch.mvendorid; 5452ec4b69SAnup Patel break; 55c62a7685SAtish Patra case SBI_EXT_BASE_GET_MARCHID: 5652ec4b69SAnup Patel *out_val = vcpu->arch.marchid; 5752ec4b69SAnup Patel break; 58c62a7685SAtish Patra case SBI_EXT_BASE_GET_MIMPID: 5952ec4b69SAnup Patel *out_val = vcpu->arch.mimpid; 60c62a7685SAtish Patra break; 61c62a7685SAtish Patra default: 62bae0dfd7SAtish Patra retdata->err_val = SBI_ERR_NOT_SUPPORTED; 63c62a7685SAtish Patra break; 64c62a7685SAtish Patra } 65c62a7685SAtish Patra 66bae0dfd7SAtish Patra return 0; 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, 77bae0dfd7SAtish Patra struct kvm_vcpu_sbi_return *retdata) 78ef8949a9SAnup Patel { 79ef8949a9SAnup Patel /* 80ef8949a9SAnup Patel * Both SBI experimental and vendor extensions are 81ef8949a9SAnup Patel * unconditionally forwarded to userspace. 82ef8949a9SAnup Patel */ 83ef8949a9SAnup Patel kvm_riscv_vcpu_sbi_forward(vcpu, run); 84bae0dfd7SAtish Patra retdata->uexit = true; 85ef8949a9SAnup Patel return 0; 86ef8949a9SAnup Patel } 87ef8949a9SAnup Patel 88ef8949a9SAnup Patel const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental = { 89ef8949a9SAnup Patel .extid_start = SBI_EXT_EXPERIMENTAL_START, 90ef8949a9SAnup Patel .extid_end = SBI_EXT_EXPERIMENTAL_END, 91ef8949a9SAnup Patel .handler = kvm_sbi_ext_forward_handler, 92ef8949a9SAnup Patel }; 93ef8949a9SAnup Patel 94ef8949a9SAnup Patel const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor = { 95ef8949a9SAnup Patel .extid_start = SBI_EXT_VENDOR_START, 96ef8949a9SAnup Patel .extid_end = SBI_EXT_VENDOR_END, 97ef8949a9SAnup Patel .handler = kvm_sbi_ext_forward_handler, 98ef8949a9SAnup Patel }; 99