1 1.18 bouyer /* $NetBSD: xen_shm_machdep.c,v 1.18 2022/09/01 12:29:00 bouyer Exp $ */ 2 1.2 bouyer 3 1.2 bouyer /* 4 1.2 bouyer * Copyright (c) 2006 Manuel Bouyer. 5 1.2 bouyer * 6 1.2 bouyer * Redistribution and use in source and binary forms, with or without 7 1.2 bouyer * modification, are permitted provided that the following conditions 8 1.2 bouyer * are met: 9 1.2 bouyer * 1. Redistributions of source code must retain the above copyright 10 1.2 bouyer * notice, this list of conditions and the following disclaimer. 11 1.2 bouyer * 2. Redistributions in binary form must reproduce the above copyright 12 1.2 bouyer * notice, this list of conditions and the following disclaimer in the 13 1.2 bouyer * documentation and/or other materials provided with the distribution. 14 1.2 bouyer * 15 1.2 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.2 bouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.2 bouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.2 bouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.2 bouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 1.2 bouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 1.2 bouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 1.2 bouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 1.2 bouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 1.2 bouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 1.2 bouyer */ 26 1.2 bouyer 27 1.3 bouyer #include <sys/cdefs.h> 28 1.18 bouyer __KERNEL_RCSID(0, "$NetBSD: xen_shm_machdep.c,v 1.18 2022/09/01 12:29:00 bouyer Exp $"); 29 1.18 bouyer 30 1.18 bouyer #include "opt_xen.h" 31 1.3 bouyer 32 1.2 bouyer #include <sys/types.h> 33 1.2 bouyer #include <sys/param.h> 34 1.2 bouyer #include <sys/systm.h> 35 1.2 bouyer #include <sys/queue.h> 36 1.2 bouyer #include <sys/vmem.h> 37 1.2 bouyer #include <sys/kernel.h> 38 1.2 bouyer #include <uvm/uvm.h> 39 1.2 bouyer 40 1.2 bouyer #include <machine/pmap.h> 41 1.2 bouyer #include <xen/hypervisor.h> 42 1.2 bouyer #include <xen/xen.h> 43 1.2 bouyer #include <xen/evtchn.h> 44 1.18 bouyer #include <xen/xenmem.h> 45 1.2 bouyer #include <xen/xen_shm.h> 46 1.2 bouyer 47 1.2 bouyer /* 48 1.12 maxv * Helper routines for the backend drivers. This implements the necessary 49 1.12 maxv * functions to map a bunch of pages from foreign domains into our kernel VM 50 1.2 bouyer * space, do I/O to it, and unmap it. 51 1.2 bouyer */ 52 1.2 bouyer 53 1.17 jdolecek /* 54 1.17 jdolecek * Map the memory referenced via grefp to supplied VA space. 55 1.17 jdolecek * If there is a failure for particular gref, no memory is mapped 56 1.17 jdolecek * and error is returned. 57 1.17 jdolecek */ 58 1.2 bouyer int 59 1.15 jdolecek xen_shm_map(int nentries, int domid, grant_ref_t *grefp, vaddr_t va, 60 1.2 bouyer grant_handle_t *handlep, int flags) 61 1.2 bouyer { 62 1.12 maxv gnttab_map_grant_ref_t op[XENSHM_MAX_PAGES_PER_REQUEST]; 63 1.15 jdolecek int ret, i; 64 1.18 bouyer #ifndef XENPV 65 1.18 bouyer paddr_t base_paddr; 66 1.18 bouyer #endif 67 1.18 bouyer 68 1.2 bouyer 69 1.2 bouyer #ifdef DIAGNOSTIC 70 1.2 bouyer if (nentries > XENSHM_MAX_PAGES_PER_REQUEST) { 71 1.12 maxv panic("xen_shm_map: %d entries", nentries); 72 1.2 bouyer } 73 1.2 bouyer #endif 74 1.18 bouyer #ifndef XENPV 75 1.18 bouyer base_paddr = xenmem_alloc_pa(nentries * PAGE_SIZE, PAGE_SIZE, false); 76 1.18 bouyer if (base_paddr == 0) 77 1.18 bouyer return ENOMEM; 78 1.18 bouyer #endif 79 1.12 maxv 80 1.2 bouyer for (i = 0; i < nentries; i++) { 81 1.18 bouyer #ifndef XENPV 82 1.18 bouyer op[i].host_addr = base_paddr + i * PAGE_SIZE; 83 1.18 bouyer #else 84 1.15 jdolecek op[i].host_addr = va + i * PAGE_SIZE; 85 1.18 bouyer #endif 86 1.2 bouyer op[i].dom = domid; 87 1.2 bouyer op[i].ref = grefp[i]; 88 1.2 bouyer op[i].flags = GNTMAP_host_map | 89 1.2 bouyer ((flags & XSHM_RO) ? GNTMAP_readonly : 0); 90 1.2 bouyer } 91 1.12 maxv 92 1.12 maxv ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, op, nentries); 93 1.17 jdolecek if (__predict_false(ret < 0)) { 94 1.17 jdolecek #ifdef DIAGNOSTIC 95 1.17 jdolecek printf("%s: HYPERVISOR_grant_table_op failed %d\n", __func__, 96 1.17 jdolecek ret); 97 1.17 jdolecek #endif 98 1.18 bouyer ret = EINVAL; 99 1.18 bouyer goto err1; 100 1.12 maxv } 101 1.12 maxv 102 1.17 jdolecek /* 103 1.17 jdolecek * If ret is positive, it means there was an error in processing, 104 1.17 jdolecek * and only first ret entries were actually handled. If it's zero, 105 1.17 jdolecek * it only means all entries were processed, but there could still 106 1.17 jdolecek * be failure. 107 1.17 jdolecek */ 108 1.17 jdolecek if (__predict_false(ret > 0 && ret < nentries)) { 109 1.17 jdolecek nentries = ret; 110 1.17 jdolecek } 111 1.17 jdolecek 112 1.2 bouyer for (i = 0; i < nentries; i++) { 113 1.17 jdolecek if (__predict_false(op[i].status)) { 114 1.15 jdolecek #ifdef DIAGNOSTIC 115 1.17 jdolecek printf("%s: op[%d] bad status %d gref %u\n", __func__, 116 1.17 jdolecek i, op[i].status, grefp[i]); 117 1.15 jdolecek #endif 118 1.17 jdolecek ret = 1; 119 1.17 jdolecek continue; 120 1.17 jdolecek } 121 1.2 bouyer handlep[i] = op[i].handle; 122 1.2 bouyer } 123 1.12 maxv 124 1.17 jdolecek if (__predict_false(ret > 0)) { 125 1.17 jdolecek int uncnt = 0; 126 1.17 jdolecek gnttab_unmap_grant_ref_t unop[XENSHM_MAX_PAGES_PER_REQUEST]; 127 1.17 jdolecek 128 1.17 jdolecek /* 129 1.17 jdolecek * When returning error, make sure the successfully mapped 130 1.17 jdolecek * entries are unmapped before returning the error. 131 1.17 jdolecek * xen_shm_unmap() can't be used, it assumes 132 1.17 jdolecek * linear consecutive space. 133 1.17 jdolecek */ 134 1.17 jdolecek for (i = uncnt = 0; i < nentries; i++) { 135 1.17 jdolecek if (op[i].status == 0) { 136 1.18 bouyer #ifndef XENPV 137 1.18 bouyer unop[uncnt].host_addr = 138 1.18 bouyer base_paddr + i * PAGE_SIZE; 139 1.18 bouyer #else 140 1.17 jdolecek unop[uncnt].host_addr = va + i * PAGE_SIZE; 141 1.18 bouyer #endif 142 1.17 jdolecek unop[uncnt].dev_bus_addr = 0; 143 1.17 jdolecek unop[uncnt].handle = handlep[i]; 144 1.17 jdolecek uncnt++; 145 1.17 jdolecek } 146 1.17 jdolecek } 147 1.17 jdolecek if (uncnt > 0) { 148 1.17 jdolecek ret = HYPERVISOR_grant_table_op( 149 1.17 jdolecek GNTTABOP_unmap_grant_ref, unop, uncnt); 150 1.17 jdolecek if (ret != 0) { 151 1.17 jdolecek panic("%s: unmap on error recovery failed" 152 1.17 jdolecek " %d", __func__, ret); 153 1.17 jdolecek } 154 1.17 jdolecek } 155 1.17 jdolecek #ifdef DIAGNOSTIC 156 1.17 jdolecek printf("%s: HYPERVISOR_grant_table_op bad entry\n", 157 1.17 jdolecek __func__); 158 1.17 jdolecek #endif 159 1.18 bouyer ret = EINVAL; 160 1.18 bouyer goto err1; 161 1.18 bouyer } 162 1.18 bouyer #ifndef XENPV 163 1.18 bouyer for (i = 0; i < nentries; i++) { 164 1.18 bouyer pmap_kenter_pa(va + i * PAGE_SIZE, 165 1.18 bouyer base_paddr + i * PAGE_SIZE, 166 1.18 bouyer VM_PROT_READ | VM_PROT_WRITE, 0); 167 1.17 jdolecek } 168 1.18 bouyer #endif 169 1.17 jdolecek 170 1.2 bouyer return 0; 171 1.18 bouyer err1: 172 1.18 bouyer #ifndef XENPV 173 1.18 bouyer xenmem_free_pa(base_paddr, nentries * PAGE_SIZE); 174 1.18 bouyer #endif 175 1.18 bouyer return ret; 176 1.2 bouyer } 177 1.2 bouyer 178 1.2 bouyer void 179 1.2 bouyer xen_shm_unmap(vaddr_t va, int nentries, grant_handle_t *handlep) 180 1.2 bouyer { 181 1.2 bouyer gnttab_unmap_grant_ref_t op[XENSHM_MAX_PAGES_PER_REQUEST]; 182 1.15 jdolecek int ret, i; 183 1.18 bouyer #ifndef XENPV 184 1.18 bouyer paddr_t base_paddr; 185 1.18 bouyer if (pmap_extract(pmap_kernel(), va, &base_paddr) != true) 186 1.18 bouyer panic("xen_shm_unmap: unmapped va"); 187 1.18 bouyer #endif 188 1.2 bouyer 189 1.2 bouyer #ifdef DIAGNOSTIC 190 1.2 bouyer if (nentries > XENSHM_MAX_PAGES_PER_REQUEST) { 191 1.12 maxv panic("xen_shm_unmap: %d entries", nentries); 192 1.2 bouyer } 193 1.2 bouyer #endif 194 1.2 bouyer 195 1.2 bouyer for (i = 0; i < nentries; i++) { 196 1.18 bouyer #ifndef XENPV 197 1.18 bouyer pmap_kremove(va + i * PAGE_SIZE, PAGE_SIZE); 198 1.18 bouyer op[i].host_addr = base_paddr + i * PAGE_SIZE; 199 1.18 bouyer #else 200 1.2 bouyer op[i].host_addr = va + i * PAGE_SIZE; 201 1.18 bouyer #endif 202 1.2 bouyer op[i].dev_bus_addr = 0; 203 1.2 bouyer op[i].handle = handlep[i]; 204 1.2 bouyer } 205 1.12 maxv 206 1.2 bouyer ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, 207 1.2 bouyer op, nentries); 208 1.12 maxv if (__predict_false(ret)) { 209 1.2 bouyer panic("xen_shm_unmap: unmap failed"); 210 1.12 maxv } 211 1.18 bouyer #ifndef XENPV 212 1.18 bouyer xenmem_free_pa(base_paddr, PAGE_SIZE * nentries); 213 1.18 bouyer #endif 214 1.2 bouyer } 215