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; 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 kvm_for_each_vcpu(i, tmp, vcpu->kvm) { 94 if (hbase != -1UL) { 95 if (tmp->vcpu_id < hbase) 96 continue; 97 if (!(hmask & (1UL << (tmp->vcpu_id - hbase)))) 98 continue; 99 } 100 if (tmp->cpu < 0) 101 continue; 102 cpumask_set_cpu(tmp->cpu, &cm); 103 } 104 105 switch (funcid) { 106 case SBI_EXT_RFENCE_REMOTE_FENCE_I: 107 ret = sbi_remote_fence_i(&cm); 108 break; 109 case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA: 110 ret = sbi_remote_hfence_vvma(&cm, cp->a2, cp->a3); 111 break; 112 case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID: 113 ret = sbi_remote_hfence_vvma_asid(&cm, cp->a2, 114 cp->a3, cp->a4); 115 break; 116 case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA: 117 case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID: 118 case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA: 119 case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID: 120 /* TODO: implement for nested hypervisor case */ 121 default: 122 ret = -EOPNOTSUPP; 123 } 124 125 return ret; 126 } 127 128 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence = { 129 .extid_start = SBI_EXT_RFENCE, 130 .extid_end = SBI_EXT_RFENCE, 131 .handler = kvm_sbi_ext_rfence_handler, 132 }; 133 134 static int kvm_sbi_ext_srst_handler(struct kvm_vcpu *vcpu, 135 struct kvm_run *run, 136 unsigned long *out_val, 137 struct kvm_cpu_trap *utrap, bool *exit) 138 { 139 struct kvm_cpu_context *cp = &vcpu->arch.guest_context; 140 unsigned long funcid = cp->a6; 141 u32 reason = cp->a1; 142 u32 type = cp->a0; 143 int ret = 0; 144 145 switch (funcid) { 146 case SBI_EXT_SRST_RESET: 147 switch (type) { 148 case SBI_SRST_RESET_TYPE_SHUTDOWN: 149 kvm_riscv_vcpu_sbi_system_reset(vcpu, run, 150 KVM_SYSTEM_EVENT_SHUTDOWN, 151 reason); 152 *exit = true; 153 break; 154 case SBI_SRST_RESET_TYPE_COLD_REBOOT: 155 case SBI_SRST_RESET_TYPE_WARM_REBOOT: 156 kvm_riscv_vcpu_sbi_system_reset(vcpu, run, 157 KVM_SYSTEM_EVENT_RESET, 158 reason); 159 *exit = true; 160 break; 161 default: 162 ret = -EOPNOTSUPP; 163 } 164 break; 165 default: 166 ret = -EOPNOTSUPP; 167 } 168 169 return ret; 170 } 171 172 const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst = { 173 .extid_start = SBI_EXT_SRST, 174 .extid_end = SBI_EXT_SRST, 175 .handler = kvm_sbi_ext_srst_handler, 176 }; 177