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 62 static int 63 vmm_sbi_handle_rfnc(struct vcpu *vcpu, struct hypctx *hypctx) 64 { 65 uint64_t hart_mask __unused; 66 uint64_t start __unused; 67 uint64_t size __unused; 68 uint64_t asid __unused; 69 uint64_t func_id; 70 71 func_id = hypctx->guest_regs.hyp_a[6]; 72 hart_mask = hypctx->guest_regs.hyp_a[0]; 73 start = hypctx->guest_regs.hyp_a[2]; 74 size = hypctx->guest_regs.hyp_a[3]; 75 asid = hypctx->guest_regs.hyp_a[4]; 76 77 dprintf("%s: %ld hart_mask %lx start %lx size %lx\n", __func__, 78 func_id, hart_mask, start, size); 79 80 /* TODO: implement remote sfence. */ 81 82 switch (func_id) { 83 case SBI_RFNC_REMOTE_FENCE_I: 84 break; 85 case SBI_RFNC_REMOTE_SFENCE_VMA: 86 break; 87 case SBI_RFNC_REMOTE_SFENCE_VMA_ASID: 88 break; 89 default: 90 break; 91 } 92 93 hypctx->guest_regs.hyp_a[0] = 0; 94 95 return (0); 96 } 97 98 static int 99 vmm_sbi_handle_time(struct vcpu *vcpu, struct hypctx *hypctx) 100 { 101 uint64_t func_id; 102 uint64_t next_val; 103 int ret; 104 105 func_id = hypctx->guest_regs.hyp_a[6]; 106 next_val = hypctx->guest_regs.hyp_a[0]; 107 108 switch (func_id) { 109 case SBI_TIME_SET_TIMER: 110 vtimer_set_timer(hypctx, next_val); 111 ret = 0; 112 break; 113 default: 114 ret = -1; 115 break; 116 } 117 118 hypctx->guest_regs.hyp_a[0] = ret; 119 120 return (0); 121 } 122 123 static int 124 vmm_sbi_handle_ipi(struct vcpu *vcpu, struct hypctx *hypctx) 125 { 126 struct hypctx *target_hypctx; 127 struct vcpu *target_vcpu __unused; 128 cpuset_t active_cpus; 129 struct hyp *hyp; 130 uint64_t hart_mask; 131 uint64_t func_id; 132 int hart_id; 133 int bit; 134 int ret; 135 136 func_id = hypctx->guest_regs.hyp_a[6]; 137 hart_mask = hypctx->guest_regs.hyp_a[0]; 138 139 dprintf("%s: hart_mask %lx\n", __func__, hart_mask); 140 141 hyp = hypctx->hyp; 142 143 active_cpus = vm_active_cpus(hyp->vm); 144 145 switch (func_id) { 146 case SBI_IPI_SEND_IPI: 147 while ((bit = ffs(hart_mask))) { 148 hart_id = (bit - 1); 149 hart_mask &= ~(1u << hart_id); 150 if (CPU_ISSET(hart_id, &active_cpus)) { 151 /* TODO. */ 152 target_vcpu = vm_vcpu(hyp->vm, hart_id); 153 target_hypctx = hypctx->hyp->ctx[hart_id]; 154 riscv_send_ipi(target_hypctx, hart_id); 155 } 156 } 157 ret = 0; 158 break; 159 default: 160 printf("%s: unknown func %ld\n", __func__, func_id); 161 ret = -1; 162 break; 163 } 164 165 hypctx->guest_regs.hyp_a[0] = ret; 166 167 return (0); 168 } 169 170 int 171 vmm_sbi_ecall(struct vcpu *vcpu, bool *retu) 172 { 173 int sbi_extension_id __unused; 174 struct hypctx *hypctx; 175 176 hypctx = riscv_get_active_vcpu(); 177 sbi_extension_id = hypctx->guest_regs.hyp_a[7]; 178 179 dprintf("%s: args %lx %lx %lx %lx %lx %lx %lx %lx\n", __func__, 180 hypctx->guest_regs.hyp_a[0], 181 hypctx->guest_regs.hyp_a[1], 182 hypctx->guest_regs.hyp_a[2], 183 hypctx->guest_regs.hyp_a[3], 184 hypctx->guest_regs.hyp_a[4], 185 hypctx->guest_regs.hyp_a[5], 186 hypctx->guest_regs.hyp_a[6], 187 hypctx->guest_regs.hyp_a[7]); 188 189 switch (sbi_extension_id) { 190 case SBI_EXT_ID_RFNC: 191 vmm_sbi_handle_rfnc(vcpu, hypctx); 192 break; 193 case SBI_EXT_ID_TIME: 194 vmm_sbi_handle_time(vcpu, hypctx); 195 break; 196 case SBI_EXT_ID_IPI: 197 vmm_sbi_handle_ipi(vcpu, hypctx); 198 break; 199 default: 200 *retu = true; 201 break; 202 } 203 204 return (0); 205 } 206