1 /* $NetBSD: xengnt.c,v 1.2 2006/03/19 00:28:02 bouyer 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 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Manuel Bouyer. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33 #include <sys/types.h> 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/malloc.h> 37 #include <sys/queue.h> 38 #include <sys/extent.h> 39 #include <sys/kernel.h> 40 #include <uvm/uvm.h> 41 42 #include <machine/hypervisor.h> 43 #include <machine/xen.h> 44 #include <machine/granttables.h> 45 46 #undef XENDEBUG 47 #ifdef XENDEBUG 48 #define DPRINTF(x) printf x 49 #else 50 #define DPRINTF(x) 51 #endif 52 53 #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t)) 54 55 /* bitmask of free grant entries. 1 = entrie is free */ 56 #define NR_BITMASK_ENTRIES ((NR_GRANT_ENTRIES + 31) / 32) 57 u_int32_t gnt_entries_bitmask[NR_BITMASK_ENTRIES]; 58 59 /* VM address of the grant table */ 60 grant_entry_t *grant_table; 61 62 static grant_ref_t xengnt_get_entry(void); 63 #define XENGNT_NO_ENTRY 0xffffffff 64 static void xengnt_free_entry(grant_ref_t); 65 static void xengnt_resume(void); 66 67 void 68 xengnt_init() 69 { 70 grant_table = (void *)uvm_km_alloc(kernel_map, 71 NR_GRANT_FRAMES * PAGE_SIZE, 0, UVM_KMF_VAONLY); 72 if (grant_table == NULL) 73 panic("xengnt_init() no VM space"); 74 75 xengnt_resume(); 76 77 memset(gnt_entries_bitmask, 0xff, sizeof(gnt_entries_bitmask)); 78 } 79 80 static void 81 xengnt_resume() 82 { 83 gnttab_setup_table_t setup; 84 unsigned long pages[NR_GRANT_FRAMES]; 85 int i = 0; 86 87 setup.dom = DOMID_SELF; 88 setup.nr_frames = NR_GRANT_FRAMES; 89 setup.frame_list = pages; 90 91 if (HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1) != 0) 92 panic("xengnt_resume: setup table failed"); 93 if (setup.status != 0) 94 panic("xengnt_resume: setup table returned %d", setup.status); 95 96 for (i = 0; i < NR_GRANT_FRAMES; i++) { 97 DPRINTF(("xengnt_resume: map 0x%lx -> %p\n", 98 pages[i], (char *)grant_table + i * PAGE_SIZE)); 99 100 pmap_kenter_ma(((vaddr_t)grant_table) + i * PAGE_SIZE, 101 pages[i] << PAGE_SHIFT, VM_PROT_WRITE); 102 } 103 } 104 105 static grant_ref_t 106 xengnt_get_entry() 107 { 108 int i; 109 grant_ref_t entry; 110 int s = splvm(); 111 112 for (i = 0; i < NR_BITMASK_ENTRIES; i++) { 113 entry = ffs(gnt_entries_bitmask[i]); 114 if (entry != 0) { 115 entry--; 116 gnt_entries_bitmask[i] &= ~(1 << (entry & 0x1f)); 117 splx(s); 118 return ((i << 5) + entry); 119 } 120 } 121 splx(s); 122 return XENGNT_NO_ENTRY; 123 } 124 125 static void 126 xengnt_free_entry(grant_ref_t entry) 127 { 128 int s = splvm(); 129 KASSERT((entry >> 5) < NR_BITMASK_ENTRIES); 130 gnt_entries_bitmask[entry >> 5] |= (1 << (entry & 0x1f)); 131 splx(s); 132 } 133 134 int 135 xengnt_grant_access(domid_t dom, paddr_t ma, int ro, grant_ref_t *entryp) 136 { 137 *entryp = xengnt_get_entry(); 138 if (__predict_false(*entryp == XENGNT_NO_ENTRY)) 139 return ENOMEM; 140 141 grant_table[*entryp].frame = ma >> PAGE_SHIFT; 142 grant_table[*entryp].domid = dom; 143 x86_lfence(); 144 grant_table[*entryp].flags = 145 GTF_permit_access | (ro ? GTF_readonly : 0); 146 return 0; 147 } 148 149 void 150 xengnt_revoke_access(grant_ref_t entry) 151 { 152 uint16_t flags, nflags; 153 154 nflags = grant_table[entry].flags; 155 156 do { 157 if ((flags = nflags) & (GTF_reading|GTF_writing)) 158 panic("xengnt_revoke_access: still in use"); 159 nflags = xen_atomic_cmpxchg16(&grant_table[entry].flags, 160 flags, 0); 161 } while (nflags != flags); 162 xengnt_free_entry(entry); 163 } 164 165 int 166 xengnt_grant_transfer(domid_t dom, grant_ref_t *entryp) 167 { 168 *entryp = xengnt_get_entry(); 169 if (__predict_false(*entryp == XENGNT_NO_ENTRY)) 170 return ENOMEM; 171 172 grant_table[*entryp].frame = 0; 173 grant_table[*entryp].domid =dom; 174 x86_lfence(); 175 grant_table[*entryp].flags = GTF_accept_transfer; 176 return 0; 177 } 178 179 paddr_t 180 xengnt_revoke_transfer(grant_ref_t entry) 181 { 182 paddr_t page; 183 uint16_t flags; 184 185 /* if the transfer has not started, free the entry and return 0 */ 186 while (!((flags = grant_table[entry].flags) & GTF_transfer_committed)) { 187 if (xen_atomic_cmpxchg16(&grant_table[entry].flags, 188 flags, 0) == flags ) { 189 xengnt_free_entry(entry); 190 return 0; 191 } 192 HYPERVISOR_yield(); 193 } 194 195 /* If transfer in progress, wait for completion */ 196 while (!((flags = grant_table[entry].flags) & GTF_transfer_completed)) 197 HYPERVISOR_yield(); 198 199 /* Read the frame number /after/ reading completion status. */ 200 __insn_barrier(); 201 page = grant_table[entry].frame; 202 if (page == 0) 203 printf("xengnt_revoke_transfer: guest sent pa 0\n"); 204 205 xengnt_free_entry(entry); 206 return page; 207 } 208 209 int 210 xengnt_status(grant_ref_t entry) 211 { 212 return (grant_table[entry].flags & (GTF_reading|GTF_writing)); 213 } 214