1*0767e98aSRoger Pau Monné /****************************************************************************** 2*0767e98aSRoger Pau Monné * gnttab.c 3*0767e98aSRoger Pau Monné * 4*0767e98aSRoger Pau Monné * Two sets of functionality: 5*0767e98aSRoger Pau Monné * 1. Granting foreign access to our memory reservation. 6*0767e98aSRoger Pau Monné * 2. Accessing others' memory reservations via grant references. 7*0767e98aSRoger Pau Monné * (i.e., mechanisms for both sender and recipient of grant references) 8*0767e98aSRoger Pau Monné * 9*0767e98aSRoger Pau Monné * Copyright (c) 2005, Christopher Clark 10*0767e98aSRoger Pau Monné * Copyright (c) 2004, K A Fraser 11*0767e98aSRoger Pau Monné */ 12*0767e98aSRoger Pau Monné 13*0767e98aSRoger Pau Monné #include <sys/cdefs.h> 14*0767e98aSRoger Pau Monné __FBSDID("$FreeBSD$"); 15*0767e98aSRoger Pau Monné 16*0767e98aSRoger Pau Monné #include "opt_pmap.h" 17*0767e98aSRoger Pau Monné 18*0767e98aSRoger Pau Monné #include <sys/param.h> 19*0767e98aSRoger Pau Monné #include <sys/systm.h> 20*0767e98aSRoger Pau Monné #include <sys/bus.h> 21*0767e98aSRoger Pau Monné #include <sys/conf.h> 22*0767e98aSRoger Pau Monné #include <sys/module.h> 23*0767e98aSRoger Pau Monné #include <sys/kernel.h> 24*0767e98aSRoger Pau Monné #include <sys/lock.h> 25*0767e98aSRoger Pau Monné #include <sys/malloc.h> 26*0767e98aSRoger Pau Monné #include <sys/mman.h> 27*0767e98aSRoger Pau Monné #include <sys/limits.h> 28*0767e98aSRoger Pau Monné #include <sys/rman.h> 29*0767e98aSRoger Pau Monné #include <machine/resource.h> 30*0767e98aSRoger Pau Monné 31*0767e98aSRoger Pau Monné #include <xen/xen-os.h> 32*0767e98aSRoger Pau Monné #include <xen/hypervisor.h> 33*0767e98aSRoger Pau Monné #include <machine/xen/synch_bitops.h> 34*0767e98aSRoger Pau Monné 35*0767e98aSRoger Pau Monné #include <xen/hypervisor.h> 36*0767e98aSRoger Pau Monné #include <xen/gnttab.h> 37*0767e98aSRoger Pau Monné 38*0767e98aSRoger Pau Monné #include <vm/vm.h> 39*0767e98aSRoger Pau Monné #include <vm/vm_kern.h> 40*0767e98aSRoger Pau Monné #include <vm/vm_extern.h> 41*0767e98aSRoger Pau Monné #include <vm/pmap.h> 42*0767e98aSRoger Pau Monné 43*0767e98aSRoger Pau Monné #define cmpxchg(a, b, c) atomic_cmpset_int((volatile u_int *)(a),(b),(c)) 44*0767e98aSRoger Pau Monné 45*0767e98aSRoger Pau Monné /* External tools reserve first few grant table entries. */ 46*0767e98aSRoger Pau Monné #define NR_RESERVED_ENTRIES 8 47*0767e98aSRoger Pau Monné #define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(grant_entry_t)) 48*0767e98aSRoger Pau Monné 49*0767e98aSRoger Pau Monné static grant_ref_t **gnttab_list; 50*0767e98aSRoger Pau Monné static unsigned int nr_grant_frames; 51*0767e98aSRoger Pau Monné static unsigned int boot_max_nr_grant_frames; 52*0767e98aSRoger Pau Monné static int gnttab_free_count; 53*0767e98aSRoger Pau Monné static grant_ref_t gnttab_free_head; 54*0767e98aSRoger Pau Monné static struct mtx gnttab_list_lock; 55*0767e98aSRoger Pau Monné 56*0767e98aSRoger Pau Monné #ifdef XENHVM 57*0767e98aSRoger Pau Monné /* 58*0767e98aSRoger Pau Monné * Resource representing allocated physical address space 59*0767e98aSRoger Pau Monné * for the grant table metainfo 60*0767e98aSRoger Pau Monné */ 61*0767e98aSRoger Pau Monné static struct resource *gnttab_pseudo_phys_res; 62*0767e98aSRoger Pau Monné 63*0767e98aSRoger Pau Monné /* Resource id for allocated physical address space. */ 64*0767e98aSRoger Pau Monné static int gnttab_pseudo_phys_res_id; 65*0767e98aSRoger Pau Monné #endif 66*0767e98aSRoger Pau Monné 67*0767e98aSRoger Pau Monné static grant_entry_t *shared; 68*0767e98aSRoger Pau Monné 69*0767e98aSRoger Pau Monné static struct gnttab_free_callback *gnttab_free_callback_list = NULL; 70*0767e98aSRoger Pau Monné 71*0767e98aSRoger Pau Monné static int gnttab_expand(unsigned int req_entries); 72*0767e98aSRoger Pau Monné 73*0767e98aSRoger Pau Monné #define RPP (PAGE_SIZE / sizeof(grant_ref_t)) 74*0767e98aSRoger Pau Monné #define gnttab_entry(entry) (gnttab_list[(entry) / RPP][(entry) % RPP]) 75*0767e98aSRoger Pau Monné 76*0767e98aSRoger Pau Monné static int 77*0767e98aSRoger Pau Monné get_free_entries(int count, int *entries) 78*0767e98aSRoger Pau Monné { 79*0767e98aSRoger Pau Monné int ref, error; 80*0767e98aSRoger Pau Monné grant_ref_t head; 81*0767e98aSRoger Pau Monné 82*0767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 83*0767e98aSRoger Pau Monné if ((gnttab_free_count < count) && 84*0767e98aSRoger Pau Monné ((error = gnttab_expand(count - gnttab_free_count)) != 0)) { 85*0767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 86*0767e98aSRoger Pau Monné return (error); 87*0767e98aSRoger Pau Monné } 88*0767e98aSRoger Pau Monné ref = head = gnttab_free_head; 89*0767e98aSRoger Pau Monné gnttab_free_count -= count; 90*0767e98aSRoger Pau Monné while (count-- > 1) 91*0767e98aSRoger Pau Monné head = gnttab_entry(head); 92*0767e98aSRoger Pau Monné gnttab_free_head = gnttab_entry(head); 93*0767e98aSRoger Pau Monné gnttab_entry(head) = GNTTAB_LIST_END; 94*0767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 95*0767e98aSRoger Pau Monné 96*0767e98aSRoger Pau Monné *entries = ref; 97*0767e98aSRoger Pau Monné return (0); 98*0767e98aSRoger Pau Monné } 99*0767e98aSRoger Pau Monné 100*0767e98aSRoger Pau Monné static void 101*0767e98aSRoger Pau Monné do_free_callbacks(void) 102*0767e98aSRoger Pau Monné { 103*0767e98aSRoger Pau Monné struct gnttab_free_callback *callback, *next; 104*0767e98aSRoger Pau Monné 105*0767e98aSRoger Pau Monné callback = gnttab_free_callback_list; 106*0767e98aSRoger Pau Monné gnttab_free_callback_list = NULL; 107*0767e98aSRoger Pau Monné 108*0767e98aSRoger Pau Monné while (callback != NULL) { 109*0767e98aSRoger Pau Monné next = callback->next; 110*0767e98aSRoger Pau Monné if (gnttab_free_count >= callback->count) { 111*0767e98aSRoger Pau Monné callback->next = NULL; 112*0767e98aSRoger Pau Monné callback->fn(callback->arg); 113*0767e98aSRoger Pau Monné } else { 114*0767e98aSRoger Pau Monné callback->next = gnttab_free_callback_list; 115*0767e98aSRoger Pau Monné gnttab_free_callback_list = callback; 116*0767e98aSRoger Pau Monné } 117*0767e98aSRoger Pau Monné callback = next; 118*0767e98aSRoger Pau Monné } 119*0767e98aSRoger Pau Monné } 120*0767e98aSRoger Pau Monné 121*0767e98aSRoger Pau Monné static inline void 122*0767e98aSRoger Pau Monné check_free_callbacks(void) 123*0767e98aSRoger Pau Monné { 124*0767e98aSRoger Pau Monné if (__predict_false(gnttab_free_callback_list != NULL)) 125*0767e98aSRoger Pau Monné do_free_callbacks(); 126*0767e98aSRoger Pau Monné } 127*0767e98aSRoger Pau Monné 128*0767e98aSRoger Pau Monné static void 129*0767e98aSRoger Pau Monné put_free_entry(grant_ref_t ref) 130*0767e98aSRoger Pau Monné { 131*0767e98aSRoger Pau Monné 132*0767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 133*0767e98aSRoger Pau Monné gnttab_entry(ref) = gnttab_free_head; 134*0767e98aSRoger Pau Monné gnttab_free_head = ref; 135*0767e98aSRoger Pau Monné gnttab_free_count++; 136*0767e98aSRoger Pau Monné check_free_callbacks(); 137*0767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 138*0767e98aSRoger Pau Monné } 139*0767e98aSRoger Pau Monné 140*0767e98aSRoger Pau Monné /* 141*0767e98aSRoger Pau Monné * Public grant-issuing interface functions 142*0767e98aSRoger Pau Monné */ 143*0767e98aSRoger Pau Monné 144*0767e98aSRoger Pau Monné int 145*0767e98aSRoger Pau Monné gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly, 146*0767e98aSRoger Pau Monné grant_ref_t *result) 147*0767e98aSRoger Pau Monné { 148*0767e98aSRoger Pau Monné int error, ref; 149*0767e98aSRoger Pau Monné 150*0767e98aSRoger Pau Monné error = get_free_entries(1, &ref); 151*0767e98aSRoger Pau Monné 152*0767e98aSRoger Pau Monné if (__predict_false(error)) 153*0767e98aSRoger Pau Monné return (error); 154*0767e98aSRoger Pau Monné 155*0767e98aSRoger Pau Monné shared[ref].frame = frame; 156*0767e98aSRoger Pau Monné shared[ref].domid = domid; 157*0767e98aSRoger Pau Monné wmb(); 158*0767e98aSRoger Pau Monné shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 159*0767e98aSRoger Pau Monné 160*0767e98aSRoger Pau Monné if (result) 161*0767e98aSRoger Pau Monné *result = ref; 162*0767e98aSRoger Pau Monné 163*0767e98aSRoger Pau Monné return (0); 164*0767e98aSRoger Pau Monné } 165*0767e98aSRoger Pau Monné 166*0767e98aSRoger Pau Monné void 167*0767e98aSRoger Pau Monné gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, 168*0767e98aSRoger Pau Monné unsigned long frame, int readonly) 169*0767e98aSRoger Pau Monné { 170*0767e98aSRoger Pau Monné 171*0767e98aSRoger Pau Monné shared[ref].frame = frame; 172*0767e98aSRoger Pau Monné shared[ref].domid = domid; 173*0767e98aSRoger Pau Monné wmb(); 174*0767e98aSRoger Pau Monné shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 175*0767e98aSRoger Pau Monné } 176*0767e98aSRoger Pau Monné 177*0767e98aSRoger Pau Monné int 178*0767e98aSRoger Pau Monné gnttab_query_foreign_access(grant_ref_t ref) 179*0767e98aSRoger Pau Monné { 180*0767e98aSRoger Pau Monné uint16_t nflags; 181*0767e98aSRoger Pau Monné 182*0767e98aSRoger Pau Monné nflags = shared[ref].flags; 183*0767e98aSRoger Pau Monné 184*0767e98aSRoger Pau Monné return (nflags & (GTF_reading|GTF_writing)); 185*0767e98aSRoger Pau Monné } 186*0767e98aSRoger Pau Monné 187*0767e98aSRoger Pau Monné int 188*0767e98aSRoger Pau Monné gnttab_end_foreign_access_ref(grant_ref_t ref) 189*0767e98aSRoger Pau Monné { 190*0767e98aSRoger Pau Monné uint16_t flags, nflags; 191*0767e98aSRoger Pau Monné 192*0767e98aSRoger Pau Monné nflags = shared[ref].flags; 193*0767e98aSRoger Pau Monné do { 194*0767e98aSRoger Pau Monné if ( (flags = nflags) & (GTF_reading|GTF_writing) ) { 195*0767e98aSRoger Pau Monné printf("%s: WARNING: g.e. still in use!\n", __func__); 196*0767e98aSRoger Pau Monné return (0); 197*0767e98aSRoger Pau Monné } 198*0767e98aSRoger Pau Monné } while ((nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) != 199*0767e98aSRoger Pau Monné flags); 200*0767e98aSRoger Pau Monné 201*0767e98aSRoger Pau Monné return (1); 202*0767e98aSRoger Pau Monné } 203*0767e98aSRoger Pau Monné 204*0767e98aSRoger Pau Monné void 205*0767e98aSRoger Pau Monné gnttab_end_foreign_access(grant_ref_t ref, void *page) 206*0767e98aSRoger Pau Monné { 207*0767e98aSRoger Pau Monné if (gnttab_end_foreign_access_ref(ref)) { 208*0767e98aSRoger Pau Monné put_free_entry(ref); 209*0767e98aSRoger Pau Monné if (page != NULL) { 210*0767e98aSRoger Pau Monné free(page, M_DEVBUF); 211*0767e98aSRoger Pau Monné } 212*0767e98aSRoger Pau Monné } 213*0767e98aSRoger Pau Monné else { 214*0767e98aSRoger Pau Monné /* XXX This needs to be fixed so that the ref and page are 215*0767e98aSRoger Pau Monné placed on a list to be freed up later. */ 216*0767e98aSRoger Pau Monné printf("%s: WARNING: leaking g.e. and page still in use!\n", 217*0767e98aSRoger Pau Monné __func__); 218*0767e98aSRoger Pau Monné } 219*0767e98aSRoger Pau Monné } 220*0767e98aSRoger Pau Monné 221*0767e98aSRoger Pau Monné void 222*0767e98aSRoger Pau Monné gnttab_end_foreign_access_references(u_int count, grant_ref_t *refs) 223*0767e98aSRoger Pau Monné { 224*0767e98aSRoger Pau Monné grant_ref_t *last_ref; 225*0767e98aSRoger Pau Monné grant_ref_t head; 226*0767e98aSRoger Pau Monné grant_ref_t tail; 227*0767e98aSRoger Pau Monné 228*0767e98aSRoger Pau Monné head = GNTTAB_LIST_END; 229*0767e98aSRoger Pau Monné tail = *refs; 230*0767e98aSRoger Pau Monné last_ref = refs + count; 231*0767e98aSRoger Pau Monné while (refs != last_ref) { 232*0767e98aSRoger Pau Monné 233*0767e98aSRoger Pau Monné if (gnttab_end_foreign_access_ref(*refs)) { 234*0767e98aSRoger Pau Monné gnttab_entry(*refs) = head; 235*0767e98aSRoger Pau Monné head = *refs; 236*0767e98aSRoger Pau Monné } else { 237*0767e98aSRoger Pau Monné /* 238*0767e98aSRoger Pau Monné * XXX This needs to be fixed so that the ref 239*0767e98aSRoger Pau Monné * is placed on a list to be freed up later. 240*0767e98aSRoger Pau Monné */ 241*0767e98aSRoger Pau Monné printf("%s: WARNING: leaking g.e. still in use!\n", 242*0767e98aSRoger Pau Monné __func__); 243*0767e98aSRoger Pau Monné count--; 244*0767e98aSRoger Pau Monné } 245*0767e98aSRoger Pau Monné refs++; 246*0767e98aSRoger Pau Monné } 247*0767e98aSRoger Pau Monné 248*0767e98aSRoger Pau Monné if (count != 0) { 249*0767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 250*0767e98aSRoger Pau Monné gnttab_free_count += count; 251*0767e98aSRoger Pau Monné gnttab_entry(tail) = gnttab_free_head; 252*0767e98aSRoger Pau Monné gnttab_free_head = head; 253*0767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 254*0767e98aSRoger Pau Monné } 255*0767e98aSRoger Pau Monné } 256*0767e98aSRoger Pau Monné 257*0767e98aSRoger Pau Monné int 258*0767e98aSRoger Pau Monné gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn, 259*0767e98aSRoger Pau Monné grant_ref_t *result) 260*0767e98aSRoger Pau Monné { 261*0767e98aSRoger Pau Monné int error, ref; 262*0767e98aSRoger Pau Monné 263*0767e98aSRoger Pau Monné error = get_free_entries(1, &ref); 264*0767e98aSRoger Pau Monné if (__predict_false(error)) 265*0767e98aSRoger Pau Monné return (error); 266*0767e98aSRoger Pau Monné 267*0767e98aSRoger Pau Monné gnttab_grant_foreign_transfer_ref(ref, domid, pfn); 268*0767e98aSRoger Pau Monné 269*0767e98aSRoger Pau Monné *result = ref; 270*0767e98aSRoger Pau Monné return (0); 271*0767e98aSRoger Pau Monné } 272*0767e98aSRoger Pau Monné 273*0767e98aSRoger Pau Monné void 274*0767e98aSRoger Pau Monné gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, 275*0767e98aSRoger Pau Monné unsigned long pfn) 276*0767e98aSRoger Pau Monné { 277*0767e98aSRoger Pau Monné shared[ref].frame = pfn; 278*0767e98aSRoger Pau Monné shared[ref].domid = domid; 279*0767e98aSRoger Pau Monné wmb(); 280*0767e98aSRoger Pau Monné shared[ref].flags = GTF_accept_transfer; 281*0767e98aSRoger Pau Monné } 282*0767e98aSRoger Pau Monné 283*0767e98aSRoger Pau Monné unsigned long 284*0767e98aSRoger Pau Monné gnttab_end_foreign_transfer_ref(grant_ref_t ref) 285*0767e98aSRoger Pau Monné { 286*0767e98aSRoger Pau Monné unsigned long frame; 287*0767e98aSRoger Pau Monné uint16_t flags; 288*0767e98aSRoger Pau Monné 289*0767e98aSRoger Pau Monné /* 290*0767e98aSRoger Pau Monné * If a transfer is not even yet started, try to reclaim the grant 291*0767e98aSRoger Pau Monné * reference and return failure (== 0). 292*0767e98aSRoger Pau Monné */ 293*0767e98aSRoger Pau Monné while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { 294*0767e98aSRoger Pau Monné if ( synch_cmpxchg(&shared[ref].flags, flags, 0) == flags ) 295*0767e98aSRoger Pau Monné return (0); 296*0767e98aSRoger Pau Monné cpu_relax(); 297*0767e98aSRoger Pau Monné } 298*0767e98aSRoger Pau Monné 299*0767e98aSRoger Pau Monné /* If a transfer is in progress then wait until it is completed. */ 300*0767e98aSRoger Pau Monné while (!(flags & GTF_transfer_completed)) { 301*0767e98aSRoger Pau Monné flags = shared[ref].flags; 302*0767e98aSRoger Pau Monné cpu_relax(); 303*0767e98aSRoger Pau Monné } 304*0767e98aSRoger Pau Monné 305*0767e98aSRoger Pau Monné /* Read the frame number /after/ reading completion status. */ 306*0767e98aSRoger Pau Monné rmb(); 307*0767e98aSRoger Pau Monné frame = shared[ref].frame; 308*0767e98aSRoger Pau Monné KASSERT(frame != 0, ("grant table inconsistent")); 309*0767e98aSRoger Pau Monné 310*0767e98aSRoger Pau Monné return (frame); 311*0767e98aSRoger Pau Monné } 312*0767e98aSRoger Pau Monné 313*0767e98aSRoger Pau Monné unsigned long 314*0767e98aSRoger Pau Monné gnttab_end_foreign_transfer(grant_ref_t ref) 315*0767e98aSRoger Pau Monné { 316*0767e98aSRoger Pau Monné unsigned long frame = gnttab_end_foreign_transfer_ref(ref); 317*0767e98aSRoger Pau Monné 318*0767e98aSRoger Pau Monné put_free_entry(ref); 319*0767e98aSRoger Pau Monné return (frame); 320*0767e98aSRoger Pau Monné } 321*0767e98aSRoger Pau Monné 322*0767e98aSRoger Pau Monné void 323*0767e98aSRoger Pau Monné gnttab_free_grant_reference(grant_ref_t ref) 324*0767e98aSRoger Pau Monné { 325*0767e98aSRoger Pau Monné 326*0767e98aSRoger Pau Monné put_free_entry(ref); 327*0767e98aSRoger Pau Monné } 328*0767e98aSRoger Pau Monné 329*0767e98aSRoger Pau Monné void 330*0767e98aSRoger Pau Monné gnttab_free_grant_references(grant_ref_t head) 331*0767e98aSRoger Pau Monné { 332*0767e98aSRoger Pau Monné grant_ref_t ref; 333*0767e98aSRoger Pau Monné int count = 1; 334*0767e98aSRoger Pau Monné 335*0767e98aSRoger Pau Monné if (head == GNTTAB_LIST_END) 336*0767e98aSRoger Pau Monné return; 337*0767e98aSRoger Pau Monné 338*0767e98aSRoger Pau Monné ref = head; 339*0767e98aSRoger Pau Monné while (gnttab_entry(ref) != GNTTAB_LIST_END) { 340*0767e98aSRoger Pau Monné ref = gnttab_entry(ref); 341*0767e98aSRoger Pau Monné count++; 342*0767e98aSRoger Pau Monné } 343*0767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 344*0767e98aSRoger Pau Monné gnttab_entry(ref) = gnttab_free_head; 345*0767e98aSRoger Pau Monné gnttab_free_head = head; 346*0767e98aSRoger Pau Monné gnttab_free_count += count; 347*0767e98aSRoger Pau Monné check_free_callbacks(); 348*0767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 349*0767e98aSRoger Pau Monné } 350*0767e98aSRoger Pau Monné 351*0767e98aSRoger Pau Monné int 352*0767e98aSRoger Pau Monné gnttab_alloc_grant_references(uint16_t count, grant_ref_t *head) 353*0767e98aSRoger Pau Monné { 354*0767e98aSRoger Pau Monné int ref, error; 355*0767e98aSRoger Pau Monné 356*0767e98aSRoger Pau Monné error = get_free_entries(count, &ref); 357*0767e98aSRoger Pau Monné if (__predict_false(error)) 358*0767e98aSRoger Pau Monné return (error); 359*0767e98aSRoger Pau Monné 360*0767e98aSRoger Pau Monné *head = ref; 361*0767e98aSRoger Pau Monné return (0); 362*0767e98aSRoger Pau Monné } 363*0767e98aSRoger Pau Monné 364*0767e98aSRoger Pau Monné int 365*0767e98aSRoger Pau Monné gnttab_empty_grant_references(const grant_ref_t *private_head) 366*0767e98aSRoger Pau Monné { 367*0767e98aSRoger Pau Monné 368*0767e98aSRoger Pau Monné return (*private_head == GNTTAB_LIST_END); 369*0767e98aSRoger Pau Monné } 370*0767e98aSRoger Pau Monné 371*0767e98aSRoger Pau Monné int 372*0767e98aSRoger Pau Monné gnttab_claim_grant_reference(grant_ref_t *private_head) 373*0767e98aSRoger Pau Monné { 374*0767e98aSRoger Pau Monné grant_ref_t g = *private_head; 375*0767e98aSRoger Pau Monné 376*0767e98aSRoger Pau Monné if (__predict_false(g == GNTTAB_LIST_END)) 377*0767e98aSRoger Pau Monné return (g); 378*0767e98aSRoger Pau Monné *private_head = gnttab_entry(g); 379*0767e98aSRoger Pau Monné return (g); 380*0767e98aSRoger Pau Monné } 381*0767e98aSRoger Pau Monné 382*0767e98aSRoger Pau Monné void 383*0767e98aSRoger Pau Monné gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release) 384*0767e98aSRoger Pau Monné { 385*0767e98aSRoger Pau Monné 386*0767e98aSRoger Pau Monné gnttab_entry(release) = *private_head; 387*0767e98aSRoger Pau Monné *private_head = release; 388*0767e98aSRoger Pau Monné } 389*0767e98aSRoger Pau Monné 390*0767e98aSRoger Pau Monné void 391*0767e98aSRoger Pau Monné gnttab_request_free_callback(struct gnttab_free_callback *callback, 392*0767e98aSRoger Pau Monné void (*fn)(void *), void *arg, uint16_t count) 393*0767e98aSRoger Pau Monné { 394*0767e98aSRoger Pau Monné 395*0767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 396*0767e98aSRoger Pau Monné if (callback->next) 397*0767e98aSRoger Pau Monné goto out; 398*0767e98aSRoger Pau Monné callback->fn = fn; 399*0767e98aSRoger Pau Monné callback->arg = arg; 400*0767e98aSRoger Pau Monné callback->count = count; 401*0767e98aSRoger Pau Monné callback->next = gnttab_free_callback_list; 402*0767e98aSRoger Pau Monné gnttab_free_callback_list = callback; 403*0767e98aSRoger Pau Monné check_free_callbacks(); 404*0767e98aSRoger Pau Monné out: 405*0767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 406*0767e98aSRoger Pau Monné 407*0767e98aSRoger Pau Monné } 408*0767e98aSRoger Pau Monné 409*0767e98aSRoger Pau Monné void 410*0767e98aSRoger Pau Monné gnttab_cancel_free_callback(struct gnttab_free_callback *callback) 411*0767e98aSRoger Pau Monné { 412*0767e98aSRoger Pau Monné struct gnttab_free_callback **pcb; 413*0767e98aSRoger Pau Monné 414*0767e98aSRoger Pau Monné mtx_lock(&gnttab_list_lock); 415*0767e98aSRoger Pau Monné for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) { 416*0767e98aSRoger Pau Monné if (*pcb == callback) { 417*0767e98aSRoger Pau Monné *pcb = callback->next; 418*0767e98aSRoger Pau Monné break; 419*0767e98aSRoger Pau Monné } 420*0767e98aSRoger Pau Monné } 421*0767e98aSRoger Pau Monné mtx_unlock(&gnttab_list_lock); 422*0767e98aSRoger Pau Monné } 423*0767e98aSRoger Pau Monné 424*0767e98aSRoger Pau Monné 425*0767e98aSRoger Pau Monné static int 426*0767e98aSRoger Pau Monné grow_gnttab_list(unsigned int more_frames) 427*0767e98aSRoger Pau Monné { 428*0767e98aSRoger Pau Monné unsigned int new_nr_grant_frames, extra_entries, i; 429*0767e98aSRoger Pau Monné 430*0767e98aSRoger Pau Monné new_nr_grant_frames = nr_grant_frames + more_frames; 431*0767e98aSRoger Pau Monné extra_entries = more_frames * GREFS_PER_GRANT_FRAME; 432*0767e98aSRoger Pau Monné 433*0767e98aSRoger Pau Monné for (i = nr_grant_frames; i < new_nr_grant_frames; i++) 434*0767e98aSRoger Pau Monné { 435*0767e98aSRoger Pau Monné gnttab_list[i] = (grant_ref_t *) 436*0767e98aSRoger Pau Monné malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); 437*0767e98aSRoger Pau Monné 438*0767e98aSRoger Pau Monné if (!gnttab_list[i]) 439*0767e98aSRoger Pau Monné goto grow_nomem; 440*0767e98aSRoger Pau Monné } 441*0767e98aSRoger Pau Monné 442*0767e98aSRoger Pau Monné for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames; 443*0767e98aSRoger Pau Monné i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++) 444*0767e98aSRoger Pau Monné gnttab_entry(i) = i + 1; 445*0767e98aSRoger Pau Monné 446*0767e98aSRoger Pau Monné gnttab_entry(i) = gnttab_free_head; 447*0767e98aSRoger Pau Monné gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames; 448*0767e98aSRoger Pau Monné gnttab_free_count += extra_entries; 449*0767e98aSRoger Pau Monné 450*0767e98aSRoger Pau Monné nr_grant_frames = new_nr_grant_frames; 451*0767e98aSRoger Pau Monné 452*0767e98aSRoger Pau Monné check_free_callbacks(); 453*0767e98aSRoger Pau Monné 454*0767e98aSRoger Pau Monné return (0); 455*0767e98aSRoger Pau Monné 456*0767e98aSRoger Pau Monné grow_nomem: 457*0767e98aSRoger Pau Monné for ( ; i >= nr_grant_frames; i--) 458*0767e98aSRoger Pau Monné free(gnttab_list[i], M_DEVBUF); 459*0767e98aSRoger Pau Monné return (ENOMEM); 460*0767e98aSRoger Pau Monné } 461*0767e98aSRoger Pau Monné 462*0767e98aSRoger Pau Monné static unsigned int 463*0767e98aSRoger Pau Monné __max_nr_grant_frames(void) 464*0767e98aSRoger Pau Monné { 465*0767e98aSRoger Pau Monné struct gnttab_query_size query; 466*0767e98aSRoger Pau Monné int rc; 467*0767e98aSRoger Pau Monné 468*0767e98aSRoger Pau Monné query.dom = DOMID_SELF; 469*0767e98aSRoger Pau Monné 470*0767e98aSRoger Pau Monné rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1); 471*0767e98aSRoger Pau Monné if ((rc < 0) || (query.status != GNTST_okay)) 472*0767e98aSRoger Pau Monné return (4); /* Legacy max supported number of frames */ 473*0767e98aSRoger Pau Monné 474*0767e98aSRoger Pau Monné return (query.max_nr_frames); 475*0767e98aSRoger Pau Monné } 476*0767e98aSRoger Pau Monné 477*0767e98aSRoger Pau Monné static inline 478*0767e98aSRoger Pau Monné unsigned int max_nr_grant_frames(void) 479*0767e98aSRoger Pau Monné { 480*0767e98aSRoger Pau Monné unsigned int xen_max = __max_nr_grant_frames(); 481*0767e98aSRoger Pau Monné 482*0767e98aSRoger Pau Monné if (xen_max > boot_max_nr_grant_frames) 483*0767e98aSRoger Pau Monné return (boot_max_nr_grant_frames); 484*0767e98aSRoger Pau Monné return (xen_max); 485*0767e98aSRoger Pau Monné } 486*0767e98aSRoger Pau Monné 487*0767e98aSRoger Pau Monné #ifdef notyet 488*0767e98aSRoger Pau Monné /* 489*0767e98aSRoger Pau Monné * XXX needed for backend support 490*0767e98aSRoger Pau Monné * 491*0767e98aSRoger Pau Monné */ 492*0767e98aSRoger Pau Monné static int 493*0767e98aSRoger Pau Monné map_pte_fn(pte_t *pte, struct page *pmd_page, 494*0767e98aSRoger Pau Monné unsigned long addr, void *data) 495*0767e98aSRoger Pau Monné { 496*0767e98aSRoger Pau Monné unsigned long **frames = (unsigned long **)data; 497*0767e98aSRoger Pau Monné 498*0767e98aSRoger Pau Monné set_pte_at(&init_mm, addr, pte, pfn_pte_ma((*frames)[0], PAGE_KERNEL)); 499*0767e98aSRoger Pau Monné (*frames)++; 500*0767e98aSRoger Pau Monné return 0; 501*0767e98aSRoger Pau Monné } 502*0767e98aSRoger Pau Monné 503*0767e98aSRoger Pau Monné static int 504*0767e98aSRoger Pau Monné unmap_pte_fn(pte_t *pte, struct page *pmd_page, 505*0767e98aSRoger Pau Monné unsigned long addr, void *data) 506*0767e98aSRoger Pau Monné { 507*0767e98aSRoger Pau Monné 508*0767e98aSRoger Pau Monné set_pte_at(&init_mm, addr, pte, __pte(0)); 509*0767e98aSRoger Pau Monné return 0; 510*0767e98aSRoger Pau Monné } 511*0767e98aSRoger Pau Monné #endif 512*0767e98aSRoger Pau Monné 513*0767e98aSRoger Pau Monné #ifndef XENHVM 514*0767e98aSRoger Pau Monné 515*0767e98aSRoger Pau Monné static int 516*0767e98aSRoger Pau Monné gnttab_map(unsigned int start_idx, unsigned int end_idx) 517*0767e98aSRoger Pau Monné { 518*0767e98aSRoger Pau Monné struct gnttab_setup_table setup; 519*0767e98aSRoger Pau Monné u_long *frames; 520*0767e98aSRoger Pau Monné 521*0767e98aSRoger Pau Monné unsigned int nr_gframes = end_idx + 1; 522*0767e98aSRoger Pau Monné int i, rc; 523*0767e98aSRoger Pau Monné 524*0767e98aSRoger Pau Monné frames = malloc(nr_gframes * sizeof(unsigned long), M_DEVBUF, M_NOWAIT); 525*0767e98aSRoger Pau Monné if (!frames) 526*0767e98aSRoger Pau Monné return (ENOMEM); 527*0767e98aSRoger Pau Monné 528*0767e98aSRoger Pau Monné setup.dom = DOMID_SELF; 529*0767e98aSRoger Pau Monné setup.nr_frames = nr_gframes; 530*0767e98aSRoger Pau Monné set_xen_guest_handle(setup.frame_list, frames); 531*0767e98aSRoger Pau Monné 532*0767e98aSRoger Pau Monné rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); 533*0767e98aSRoger Pau Monné if (rc == -ENOSYS) { 534*0767e98aSRoger Pau Monné free(frames, M_DEVBUF); 535*0767e98aSRoger Pau Monné return (ENOSYS); 536*0767e98aSRoger Pau Monné } 537*0767e98aSRoger Pau Monné KASSERT(!(rc || setup.status), 538*0767e98aSRoger Pau Monné ("unexpected result from grant_table_op")); 539*0767e98aSRoger Pau Monné 540*0767e98aSRoger Pau Monné if (shared == NULL) { 541*0767e98aSRoger Pau Monné vm_offset_t area; 542*0767e98aSRoger Pau Monné 543*0767e98aSRoger Pau Monné area = kva_alloc(PAGE_SIZE * max_nr_grant_frames()); 544*0767e98aSRoger Pau Monné KASSERT(area, ("can't allocate VM space for grant table")); 545*0767e98aSRoger Pau Monné shared = (grant_entry_t *)area; 546*0767e98aSRoger Pau Monné } 547*0767e98aSRoger Pau Monné 548*0767e98aSRoger Pau Monné for (i = 0; i < nr_gframes; i++) 549*0767e98aSRoger Pau Monné PT_SET_MA(((caddr_t)shared) + i*PAGE_SIZE, 550*0767e98aSRoger Pau Monné ((vm_paddr_t)frames[i]) << PAGE_SHIFT | PG_RW | PG_V); 551*0767e98aSRoger Pau Monné 552*0767e98aSRoger Pau Monné free(frames, M_DEVBUF); 553*0767e98aSRoger Pau Monné 554*0767e98aSRoger Pau Monné return (0); 555*0767e98aSRoger Pau Monné } 556*0767e98aSRoger Pau Monné 557*0767e98aSRoger Pau Monné int 558*0767e98aSRoger Pau Monné gnttab_resume(device_t dev) 559*0767e98aSRoger Pau Monné { 560*0767e98aSRoger Pau Monné 561*0767e98aSRoger Pau Monné if (max_nr_grant_frames() < nr_grant_frames) 562*0767e98aSRoger Pau Monné return (ENOSYS); 563*0767e98aSRoger Pau Monné return (gnttab_map(0, nr_grant_frames - 1)); 564*0767e98aSRoger Pau Monné } 565*0767e98aSRoger Pau Monné 566*0767e98aSRoger Pau Monné int 567*0767e98aSRoger Pau Monné gnttab_suspend(void) 568*0767e98aSRoger Pau Monné { 569*0767e98aSRoger Pau Monné int i; 570*0767e98aSRoger Pau Monné 571*0767e98aSRoger Pau Monné for (i = 0; i < nr_grant_frames; i++) 572*0767e98aSRoger Pau Monné pmap_kremove((vm_offset_t) shared + i * PAGE_SIZE); 573*0767e98aSRoger Pau Monné 574*0767e98aSRoger Pau Monné return (0); 575*0767e98aSRoger Pau Monné } 576*0767e98aSRoger Pau Monné 577*0767e98aSRoger Pau Monné #else /* XENHVM */ 578*0767e98aSRoger Pau Monné 579*0767e98aSRoger Pau Monné static vm_paddr_t resume_frames; 580*0767e98aSRoger Pau Monné 581*0767e98aSRoger Pau Monné static int 582*0767e98aSRoger Pau Monné gnttab_map(unsigned int start_idx, unsigned int end_idx) 583*0767e98aSRoger Pau Monné { 584*0767e98aSRoger Pau Monné struct xen_add_to_physmap xatp; 585*0767e98aSRoger Pau Monné unsigned int i = end_idx; 586*0767e98aSRoger Pau Monné 587*0767e98aSRoger Pau Monné /* 588*0767e98aSRoger Pau Monné * Loop backwards, so that the first hypercall has the largest index, 589*0767e98aSRoger Pau Monné * ensuring that the table will grow only once. 590*0767e98aSRoger Pau Monné */ 591*0767e98aSRoger Pau Monné do { 592*0767e98aSRoger Pau Monné xatp.domid = DOMID_SELF; 593*0767e98aSRoger Pau Monné xatp.idx = i; 594*0767e98aSRoger Pau Monné xatp.space = XENMAPSPACE_grant_table; 595*0767e98aSRoger Pau Monné xatp.gpfn = (resume_frames >> PAGE_SHIFT) + i; 596*0767e98aSRoger Pau Monné if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) 597*0767e98aSRoger Pau Monné panic("HYPERVISOR_memory_op failed to map gnttab"); 598*0767e98aSRoger Pau Monné } while (i-- > start_idx); 599*0767e98aSRoger Pau Monné 600*0767e98aSRoger Pau Monné if (shared == NULL) { 601*0767e98aSRoger Pau Monné vm_offset_t area; 602*0767e98aSRoger Pau Monné 603*0767e98aSRoger Pau Monné area = kva_alloc(PAGE_SIZE * max_nr_grant_frames()); 604*0767e98aSRoger Pau Monné KASSERT(area, ("can't allocate VM space for grant table")); 605*0767e98aSRoger Pau Monné shared = (grant_entry_t *)area; 606*0767e98aSRoger Pau Monné } 607*0767e98aSRoger Pau Monné 608*0767e98aSRoger Pau Monné for (i = start_idx; i <= end_idx; i++) { 609*0767e98aSRoger Pau Monné pmap_kenter((vm_offset_t) shared + i * PAGE_SIZE, 610*0767e98aSRoger Pau Monné resume_frames + i * PAGE_SIZE); 611*0767e98aSRoger Pau Monné } 612*0767e98aSRoger Pau Monné 613*0767e98aSRoger Pau Monné return (0); 614*0767e98aSRoger Pau Monné } 615*0767e98aSRoger Pau Monné 616*0767e98aSRoger Pau Monné int 617*0767e98aSRoger Pau Monné gnttab_resume(device_t dev) 618*0767e98aSRoger Pau Monné { 619*0767e98aSRoger Pau Monné unsigned int max_nr_gframes, nr_gframes; 620*0767e98aSRoger Pau Monné 621*0767e98aSRoger Pau Monné nr_gframes = nr_grant_frames; 622*0767e98aSRoger Pau Monné max_nr_gframes = max_nr_grant_frames(); 623*0767e98aSRoger Pau Monné if (max_nr_gframes < nr_gframes) 624*0767e98aSRoger Pau Monné return (ENOSYS); 625*0767e98aSRoger Pau Monné 626*0767e98aSRoger Pau Monné if (!resume_frames) { 627*0767e98aSRoger Pau Monné KASSERT(dev != NULL, 628*0767e98aSRoger Pau Monné ("No resume frames and no device provided")); 629*0767e98aSRoger Pau Monné 630*0767e98aSRoger Pau Monné gnttab_pseudo_phys_res = bus_alloc_resource(dev, 631*0767e98aSRoger Pau Monné SYS_RES_MEMORY, &gnttab_pseudo_phys_res_id, 0, ~0, 632*0767e98aSRoger Pau Monné PAGE_SIZE * max_nr_gframes, RF_ACTIVE); 633*0767e98aSRoger Pau Monné if (gnttab_pseudo_phys_res == NULL) 634*0767e98aSRoger Pau Monné panic("Unable to reserve physical memory for gnttab"); 635*0767e98aSRoger Pau Monné resume_frames = rman_get_start(gnttab_pseudo_phys_res); 636*0767e98aSRoger Pau Monné } 637*0767e98aSRoger Pau Monné 638*0767e98aSRoger Pau Monné return (gnttab_map(0, nr_gframes - 1)); 639*0767e98aSRoger Pau Monné } 640*0767e98aSRoger Pau Monné 641*0767e98aSRoger Pau Monné #endif 642*0767e98aSRoger Pau Monné 643*0767e98aSRoger Pau Monné static int 644*0767e98aSRoger Pau Monné gnttab_expand(unsigned int req_entries) 645*0767e98aSRoger Pau Monné { 646*0767e98aSRoger Pau Monné int error; 647*0767e98aSRoger Pau Monné unsigned int cur, extra; 648*0767e98aSRoger Pau Monné 649*0767e98aSRoger Pau Monné cur = nr_grant_frames; 650*0767e98aSRoger Pau Monné extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / 651*0767e98aSRoger Pau Monné GREFS_PER_GRANT_FRAME); 652*0767e98aSRoger Pau Monné if (cur + extra > max_nr_grant_frames()) 653*0767e98aSRoger Pau Monné return (ENOSPC); 654*0767e98aSRoger Pau Monné 655*0767e98aSRoger Pau Monné error = gnttab_map(cur, cur + extra - 1); 656*0767e98aSRoger Pau Monné if (!error) 657*0767e98aSRoger Pau Monné error = grow_gnttab_list(extra); 658*0767e98aSRoger Pau Monné 659*0767e98aSRoger Pau Monné return (error); 660*0767e98aSRoger Pau Monné } 661*0767e98aSRoger Pau Monné 662*0767e98aSRoger Pau Monné int 663*0767e98aSRoger Pau Monné gnttab_init(device_t dev) 664*0767e98aSRoger Pau Monné { 665*0767e98aSRoger Pau Monné int i; 666*0767e98aSRoger Pau Monné unsigned int max_nr_glist_frames; 667*0767e98aSRoger Pau Monné unsigned int nr_init_grefs; 668*0767e98aSRoger Pau Monné 669*0767e98aSRoger Pau Monné if (!is_running_on_xen()) 670*0767e98aSRoger Pau Monné return (ENODEV); 671*0767e98aSRoger Pau Monné 672*0767e98aSRoger Pau Monné nr_grant_frames = 1; 673*0767e98aSRoger Pau Monné boot_max_nr_grant_frames = __max_nr_grant_frames(); 674*0767e98aSRoger Pau Monné 675*0767e98aSRoger Pau Monné /* Determine the maximum number of frames required for the 676*0767e98aSRoger Pau Monné * grant reference free list on the current hypervisor. 677*0767e98aSRoger Pau Monné */ 678*0767e98aSRoger Pau Monné max_nr_glist_frames = (boot_max_nr_grant_frames * 679*0767e98aSRoger Pau Monné GREFS_PER_GRANT_FRAME / 680*0767e98aSRoger Pau Monné (PAGE_SIZE / sizeof(grant_ref_t))); 681*0767e98aSRoger Pau Monné 682*0767e98aSRoger Pau Monné gnttab_list = malloc(max_nr_glist_frames * sizeof(grant_ref_t *), 683*0767e98aSRoger Pau Monné M_DEVBUF, M_NOWAIT); 684*0767e98aSRoger Pau Monné 685*0767e98aSRoger Pau Monné if (gnttab_list == NULL) 686*0767e98aSRoger Pau Monné return (ENOMEM); 687*0767e98aSRoger Pau Monné 688*0767e98aSRoger Pau Monné for (i = 0; i < nr_grant_frames; i++) { 689*0767e98aSRoger Pau Monné gnttab_list[i] = (grant_ref_t *) 690*0767e98aSRoger Pau Monné malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); 691*0767e98aSRoger Pau Monné if (gnttab_list[i] == NULL) 692*0767e98aSRoger Pau Monné goto ini_nomem; 693*0767e98aSRoger Pau Monné } 694*0767e98aSRoger Pau Monné 695*0767e98aSRoger Pau Monné if (gnttab_resume(dev)) 696*0767e98aSRoger Pau Monné return (ENODEV); 697*0767e98aSRoger Pau Monné 698*0767e98aSRoger Pau Monné nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME; 699*0767e98aSRoger Pau Monné 700*0767e98aSRoger Pau Monné for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) 701*0767e98aSRoger Pau Monné gnttab_entry(i) = i + 1; 702*0767e98aSRoger Pau Monné 703*0767e98aSRoger Pau Monné gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END; 704*0767e98aSRoger Pau Monné gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES; 705*0767e98aSRoger Pau Monné gnttab_free_head = NR_RESERVED_ENTRIES; 706*0767e98aSRoger Pau Monné 707*0767e98aSRoger Pau Monné if (bootverbose) 708*0767e98aSRoger Pau Monné printf("Grant table initialized\n"); 709*0767e98aSRoger Pau Monné 710*0767e98aSRoger Pau Monné return (0); 711*0767e98aSRoger Pau Monné 712*0767e98aSRoger Pau Monné ini_nomem: 713*0767e98aSRoger Pau Monné for (i--; i >= 0; i--) 714*0767e98aSRoger Pau Monné free(gnttab_list[i], M_DEVBUF); 715*0767e98aSRoger Pau Monné free(gnttab_list, M_DEVBUF); 716*0767e98aSRoger Pau Monné return (ENOMEM); 717*0767e98aSRoger Pau Monné 718*0767e98aSRoger Pau Monné } 719*0767e98aSRoger Pau Monné 720*0767e98aSRoger Pau Monné MTX_SYSINIT(gnttab, &gnttab_list_lock, "GNTTAB LOCK", MTX_DEF); 721