1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2024 Ruslan Bukin <br@bsdpad.com> 5 * 6 * This software was developed by the University of Cambridge Computer 7 * Laboratory (Department of Computer Science and Technology) under Innovate 8 * UK project 105694, "Digital Security by Design (DSbD) Technology Platform 9 * Prototype". 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/kernel.h> 35 #include <sys/jail.h> 36 #include <sys/queue.h> 37 #include <sys/lock.h> 38 #include <sys/mutex.h> 39 #include <sys/malloc.h> 40 #include <sys/conf.h> 41 #include <sys/sysctl.h> 42 #include <sys/libkern.h> 43 #include <sys/ioccom.h> 44 #include <sys/mman.h> 45 #include <sys/uio.h> 46 #include <sys/proc.h> 47 48 #include <vm/vm.h> 49 #include <vm/pmap.h> 50 #include <vm/vm_map.h> 51 #include <vm/vm_object.h> 52 53 #include <machine/machdep.h> 54 #include <machine/vmparam.h> 55 #include <machine/vmm.h> 56 #include <machine/vmm_dev.h> 57 #include <machine/md_var.h> 58 #include <machine/sbi.h> 59 60 #include "riscv.h" 61 #include "vmm_fence.h" 62 63 static int 64 vmm_sbi_handle_rfnc(struct vcpu *vcpu, struct hypctx *hypctx) 65 { 66 struct vmm_fence fence; 67 uint64_t hart_mask; 68 uint64_t hart_mask_base; 69 uint64_t func_id; 70 struct hyp *hyp; 71 uint16_t maxcpus; 72 cpuset_t cpus; 73 int vcpu_id; 74 int i; 75 76 func_id = hypctx->guest_regs.hyp_a[6]; 77 hart_mask = hypctx->guest_regs.hyp_a[0]; 78 hart_mask_base = hypctx->guest_regs.hyp_a[1]; 79 80 /* Construct vma_fence. */ 81 82 fence.start = hypctx->guest_regs.hyp_a[2]; 83 fence.size = hypctx->guest_regs.hyp_a[3]; 84 fence.asid = hypctx->guest_regs.hyp_a[4]; 85 86 switch (func_id) { 87 case SBI_RFNC_REMOTE_FENCE_I: 88 fence.type = VMM_RISCV_FENCE_I; 89 break; 90 case SBI_RFNC_REMOTE_SFENCE_VMA: 91 fence.type = VMM_RISCV_FENCE_VMA; 92 break; 93 case SBI_RFNC_REMOTE_SFENCE_VMA_ASID: 94 fence.type = VMM_RISCV_FENCE_VMA_ASID; 95 break; 96 default: 97 return (-1); 98 } 99 100 /* Construct cpuset_t from the mask supplied. */ 101 102 CPU_ZERO(&cpus); 103 hyp = hypctx->hyp; 104 maxcpus = vm_get_maxcpus(hyp->vm); 105 for (i = 0; i < maxcpus; i++) { 106 vcpu = vm_vcpu(hyp->vm, i); 107 if (vcpu == NULL) 108 continue; 109 vcpu_id = vcpu_vcpuid(vcpu); 110 if (hart_mask_base != -1UL) { 111 if (vcpu_id < hart_mask_base) 112 continue; 113 if (!(hart_mask & (1UL << (vcpu_id - hart_mask_base)))) 114 continue; 115 } 116 CPU_SET(i, &cpus); 117 } 118 119 vmm_fence_add(hyp->vm, &cpus, &fence); 120 121 return (0); 122 } 123 124 static int 125 vmm_sbi_handle_time(struct vcpu *vcpu, struct hypctx *hypctx) 126 { 127 uint64_t func_id; 128 uint64_t next_val; 129 int ret; 130 131 func_id = hypctx->guest_regs.hyp_a[6]; 132 next_val = hypctx->guest_regs.hyp_a[0]; 133 134 switch (func_id) { 135 case SBI_TIME_SET_TIMER: 136 vtimer_set_timer(hypctx, next_val); 137 ret = 0; 138 break; 139 default: 140 ret = -1; 141 break; 142 } 143 144 hypctx->guest_regs.hyp_a[0] = ret; 145 146 return (0); 147 } 148 149 static int 150 vmm_sbi_handle_ipi(struct vcpu *vcpu, struct hypctx *hypctx) 151 { 152 struct hypctx *target_hypctx; 153 struct vcpu *target_vcpu __unused; 154 cpuset_t active_cpus; 155 struct hyp *hyp; 156 uint64_t hart_mask; 157 uint64_t func_id; 158 int hart_id; 159 int bit; 160 int ret; 161 162 func_id = hypctx->guest_regs.hyp_a[6]; 163 hart_mask = hypctx->guest_regs.hyp_a[0]; 164 165 dprintf("%s: hart_mask %lx\n", __func__, hart_mask); 166 167 hyp = hypctx->hyp; 168 169 active_cpus = vm_active_cpus(hyp->vm); 170 171 switch (func_id) { 172 case SBI_IPI_SEND_IPI: 173 while ((bit = ffs(hart_mask))) { 174 hart_id = (bit - 1); 175 hart_mask &= ~(1u << hart_id); 176 if (CPU_ISSET(hart_id, &active_cpus)) { 177 /* TODO. */ 178 target_vcpu = vm_vcpu(hyp->vm, hart_id); 179 target_hypctx = hypctx->hyp->ctx[hart_id]; 180 riscv_send_ipi(target_hypctx, hart_id); 181 } 182 } 183 ret = 0; 184 break; 185 default: 186 printf("%s: unknown func %ld\n", __func__, func_id); 187 ret = -1; 188 break; 189 } 190 191 hypctx->guest_regs.hyp_a[0] = ret; 192 193 return (0); 194 } 195 196 int 197 vmm_sbi_ecall(struct vcpu *vcpu, bool *retu) 198 { 199 int sbi_extension_id __unused; 200 struct hypctx *hypctx; 201 int error; 202 203 hypctx = riscv_get_active_vcpu(); 204 sbi_extension_id = hypctx->guest_regs.hyp_a[7]; 205 206 dprintf("%s: args %lx %lx %lx %lx %lx %lx %lx %lx\n", __func__, 207 hypctx->guest_regs.hyp_a[0], 208 hypctx->guest_regs.hyp_a[1], 209 hypctx->guest_regs.hyp_a[2], 210 hypctx->guest_regs.hyp_a[3], 211 hypctx->guest_regs.hyp_a[4], 212 hypctx->guest_regs.hyp_a[5], 213 hypctx->guest_regs.hyp_a[6], 214 hypctx->guest_regs.hyp_a[7]); 215 216 switch (sbi_extension_id) { 217 case SBI_EXT_ID_RFNC: 218 error = vmm_sbi_handle_rfnc(vcpu, hypctx); 219 hypctx->guest_regs.hyp_a[0] = error; 220 break; 221 case SBI_EXT_ID_TIME: 222 vmm_sbi_handle_time(vcpu, hypctx); 223 break; 224 case SBI_EXT_ID_IPI: 225 vmm_sbi_handle_ipi(vcpu, hypctx); 226 break; 227 default: 228 *retu = true; 229 break; 230 } 231 232 return (0); 233 } 234