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