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_time_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, 18 unsigned long *out_val, 19 struct kvm_cpu_trap *utrap, bool *exit) 20 { 21 int ret = 0; 22 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 23 u64 next_cycle; 24 25 if (cp->a6 != SBI_EXT_TIME_SET_TIMER) 26 return -EINVAL; 27 28 #if __riscv_xlen == 32 29 next_cycle = ((u64)cp->a1 << 32) | (u64)cp->a0; 30 #else 31 next_cycle = (u64)cp->a0; 32 #endif 33 kvm_riscv_vcpu_timer_next_event(vcpu, next_cycle); 34 35 return ret; 36 } 37 38 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_time = { 39 .extid_start = SBI_EXT_TIME, 40 .extid_end = SBI_EXT_TIME, 41 .handler = kvm_sbi_ext_time_handler, 42 }; 43 44 static int kvm_sbi_ext_ipi_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, 45 unsigned long *out_val, 46 struct kvm_cpu_trap *utrap, bool *exit) 47 { 48 int ret = 0; 49 unsigned long i; 50 struct kvm_vcpu *tmp; 51 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 52 unsigned long hmask = cp->a0; 53 unsigned long hbase = cp->a1; 54 55 if (cp->a6 != SBI_EXT_IPI_SEND_IPI) 56 return -EINVAL; 57 58 kvm_for_each_vcpu(i, tmp, vcpu->kvm) { 59 if (hbase != -1UL) { 60 if (tmp->vcpu_id < hbase) 61 continue; 62 if (!(hmask & (1UL << (tmp->vcpu_id - hbase)))) 63 continue; 64 } 65 ret = kvm_riscv_vcpu_set_interrupt(tmp, IRQ_VS_SOFT); 66 if (ret < 0) 67 break; 68 } 69 70 return ret; 71 } 72 73 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_ipi = { 74 .extid_start = SBI_EXT_IPI, 75 .extid_end = SBI_EXT_IPI, 76 .handler = kvm_sbi_ext_ipi_handler, 77 }; 78 79 static int kvm_sbi_ext_rfence_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, 80 unsigned long *out_val, 81 struct kvm_cpu_trap *utrap, bool *exit) 82 { 83 int ret = 0; 84 unsigned long i; 85 struct cpumask cm, hm; 86 struct kvm_vcpu *tmp; 87 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 88 unsigned long hmask = cp->a0; 89 unsigned long hbase = cp->a1; 90 unsigned long funcid = cp->a6; 91 92 cpumask_clear(&cm); 93 cpumask_clear(&hm); 94 kvm_for_each_vcpu(i, tmp, vcpu->kvm) { 95 if (hbase != -1UL) { 96 if (tmp->vcpu_id < hbase) 97 continue; 98 if (!(hmask & (1UL << (tmp->vcpu_id - hbase)))) 99 continue; 100 } 101 if (tmp->cpu < 0) 102 continue; 103 cpumask_set_cpu(tmp->cpu, &cm); 104 } 105 106 riscv_cpuid_to_hartid_mask(&cm, &hm); 107 108 switch (funcid) { 109 case SBI_EXT_RFENCE_REMOTE_FENCE_I: 110 ret = sbi_remote_fence_i(cpumask_bits(&hm)); 111 break; 112 case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA: 113 ret = sbi_remote_hfence_vvma(cpumask_bits(&hm), cp->a2, cp->a3); 114 break; 115 case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID: 116 ret = sbi_remote_hfence_vvma_asid(cpumask_bits(&hm), cp->a2, 117 cp->a3, cp->a4); 118 break; 119 case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA: 120 case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID: 121 case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA: 122 case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID: 123 /* TODO: implement for nested hypervisor case */ 124 default: 125 ret = -EOPNOTSUPP; 126 } 127 128 return ret; 129 } 130 131 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence = { 132 .extid_start = SBI_EXT_RFENCE, 133 .extid_end = SBI_EXT_RFENCE, 134 .handler = kvm_sbi_ext_rfence_handler, 135 }; 136