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/sbi.h> 13 #include <asm/kvm_vcpu_timer.h> 14 #include <asm/kvm_vcpu_pmu.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 struct kvm_vcpu_sbi_return *retdata) 19 { 20 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 21 u64 next_cycle; 22 23 if (cp->a6 != SBI_EXT_TIME_SET_TIMER) { 24 retdata->err_val = SBI_ERR_NOT_SUPPORTED; 25 return 0; 26 } 27 28 kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_SET_TIMER); 29 #if __riscv_xlen == 32 30 next_cycle = ((u64)cp->a1 << 32) | (u64)cp->a0; 31 #else 32 next_cycle = (u64)cp->a0; 33 #endif 34 kvm_riscv_vcpu_timer_next_event(vcpu, next_cycle); 35 36 return 0; 37 } 38 39 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_time = { 40 .extid_start = SBI_EXT_TIME, 41 .extid_end = SBI_EXT_TIME, 42 .handler = kvm_sbi_ext_time_handler, 43 }; 44 45 static int kvm_sbi_ext_ipi_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, 46 struct kvm_vcpu_sbi_return *retdata) 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 unsigned long hart_bit = 0, sentmask = 0; 55 56 if (cp->a6 != SBI_EXT_IPI_SEND_IPI) { 57 retdata->err_val = SBI_ERR_NOT_SUPPORTED; 58 return 0; 59 } 60 61 kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_IPI_SENT); 62 kvm_for_each_vcpu(i, tmp, vcpu->kvm) { 63 if (hbase != -1UL) { 64 if (tmp->vcpu_id < hbase) 65 continue; 66 hart_bit = tmp->vcpu_id - hbase; 67 /* 68 * kvm_for_each_vcpu() walks kvm->vcpus[] by 69 * vcpu_idx, i.e. the creation order, which has 70 * nothing to do with the vcpu_id (hart id) space 71 * that the SBI IPI operates on. vcpu_ids need not 72 * increase along the iteration, so harts outside 73 * the hart_mask window must be skipped instead of 74 * aborting the loop. 75 */ 76 if (hart_bit >= __riscv_xlen) 77 continue; 78 if (!(hmask & (1UL << hart_bit))) 79 continue; 80 } 81 ret = kvm_riscv_vcpu_set_interrupt(tmp, IRQ_VS_SOFT); 82 if (ret < 0) 83 break; 84 sentmask |= 1UL << hart_bit; 85 kvm_riscv_vcpu_pmu_incr_fw(tmp, SBI_PMU_FW_IPI_RCVD); 86 } 87 88 if (hbase != -1UL && (hmask ^ sentmask)) 89 retdata->err_val = SBI_ERR_INVALID_PARAM; 90 91 return ret; 92 } 93 94 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_ipi = { 95 .extid_start = SBI_EXT_IPI, 96 .extid_end = SBI_EXT_IPI, 97 .handler = kvm_sbi_ext_ipi_handler, 98 }; 99 100 static int kvm_sbi_ext_rfence_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, 101 struct kvm_vcpu_sbi_return *retdata) 102 { 103 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 104 unsigned long hmask = cp->a0; 105 unsigned long hbase = cp->a1; 106 unsigned long funcid = cp->a6; 107 unsigned long vmid; 108 109 switch (funcid) { 110 case SBI_EXT_RFENCE_REMOTE_FENCE_I: 111 kvm_riscv_fence_i(vcpu->kvm, hbase, hmask); 112 kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_FENCE_I_SENT); 113 break; 114 case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA: 115 vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid); 116 if ((cp->a2 == 0 && cp->a3 == 0) || cp->a3 == -1UL) 117 kvm_riscv_hfence_vvma_all(vcpu->kvm, hbase, hmask, vmid); 118 else 119 kvm_riscv_hfence_vvma_gva(vcpu->kvm, hbase, hmask, 120 cp->a2, cp->a3, PAGE_SHIFT, vmid); 121 kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_HFENCE_VVMA_SENT); 122 break; 123 case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID: 124 vmid = READ_ONCE(vcpu->kvm->arch.vmid.vmid); 125 if ((cp->a2 == 0 && cp->a3 == 0) || cp->a3 == -1UL) 126 kvm_riscv_hfence_vvma_asid_all(vcpu->kvm, hbase, hmask, 127 cp->a4, vmid); 128 else 129 kvm_riscv_hfence_vvma_asid_gva(vcpu->kvm, hbase, hmask, cp->a2, 130 cp->a3, PAGE_SHIFT, cp->a4, vmid); 131 kvm_riscv_vcpu_pmu_incr_fw(vcpu, SBI_PMU_FW_HFENCE_VVMA_ASID_SENT); 132 break; 133 case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA: 134 case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID: 135 case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA: 136 case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID: 137 /* 138 * Until nested virtualization is implemented, the 139 * SBI HFENCE calls should return not supported 140 * hence fallthrough. 141 */ 142 default: 143 retdata->err_val = SBI_ERR_NOT_SUPPORTED; 144 } 145 146 return 0; 147 } 148 149 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence = { 150 .extid_start = SBI_EXT_RFENCE, 151 .extid_end = SBI_EXT_RFENCE, 152 .handler = kvm_sbi_ext_rfence_handler, 153 }; 154 155 static int kvm_sbi_ext_srst_handler(struct kvm_vcpu *vcpu, 156 struct kvm_run *run, 157 struct kvm_vcpu_sbi_return *retdata) 158 { 159 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 160 unsigned long funcid = cp->a6; 161 u32 reason = cp->a1; 162 u32 type = cp->a0; 163 164 switch (funcid) { 165 case SBI_EXT_SRST_RESET: 166 switch (type) { 167 case SBI_SRST_RESET_TYPE_SHUTDOWN: 168 kvm_riscv_vcpu_sbi_system_reset(vcpu, run, 169 KVM_SYSTEM_EVENT_SHUTDOWN, 170 reason); 171 retdata->uexit = true; 172 break; 173 case SBI_SRST_RESET_TYPE_COLD_REBOOT: 174 case SBI_SRST_RESET_TYPE_WARM_REBOOT: 175 kvm_riscv_vcpu_sbi_system_reset(vcpu, run, 176 KVM_SYSTEM_EVENT_RESET, 177 reason); 178 retdata->uexit = true; 179 break; 180 default: 181 retdata->err_val = SBI_ERR_NOT_SUPPORTED; 182 } 183 break; 184 default: 185 retdata->err_val = SBI_ERR_NOT_SUPPORTED; 186 } 187 188 return 0; 189 } 190 191 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst = { 192 .extid_start = SBI_EXT_SRST, 193 .extid_end = SBI_EXT_SRST, 194 .handler = kvm_sbi_ext_srst_handler, 195 }; 196