gnttab.c revision 181624
1181624Skmacy/****************************************************************************** 2181624Skmacy * gnttab.c 3181624Skmacy * 4181624Skmacy * Two sets of functionality: 5181624Skmacy * 1. Granting foreign access to our memory reservation. 6181624Skmacy * 2. Accessing others' memory reservations via grant references. 7181624Skmacy * (i.e., mechanisms for both sender and recipient of grant references) 8181624Skmacy * 9181624Skmacy * Copyright (c) 2005, Christopher Clark 10181624Skmacy * Copyright (c) 2004, K A Fraser 11181624Skmacy */ 12181624Skmacy 13181624Skmacy#include <sys/cdefs.h> 14181624Skmacy__FBSDID("$FreeBSD: head/sys/xen/gnttab.c 181624 2008-08-12 07:36:56Z kmacy $"); 15181624Skmacy 16181624Skmacy#include "opt_global.h" 17181624Skmacy#include "opt_pmap.h" 18181624Skmacy#include <sys/param.h> 19181624Skmacy#include <sys/systm.h> 20181624Skmacy#include <sys/bus.h> 21181624Skmacy#include <sys/conf.h> 22181624Skmacy#include <sys/module.h> 23181624Skmacy#include <sys/kernel.h> 24181624Skmacy#include <sys/lock.h> 25181624Skmacy#include <sys/malloc.h> 26181624Skmacy#include <sys/mman.h> 27181624Skmacy#include <vm/vm.h> 28181624Skmacy#include <vm/vm_extern.h> 29181624Skmacy 30181624Skmacy#include <vm/vm_page.h> 31181624Skmacy#include <vm/vm_kern.h> 32181624Skmacy 33181624Skmacy 34181624Skmacy 35181624Skmacy#include <machine/xen/hypervisor.h> 36181624Skmacy#include <machine/xen/synch_bitops.h> 37181624Skmacy#include <xen/gnttab.h> 38181624Skmacy 39181624Skmacy#define cmpxchg(a, b, c) atomic_cmpset_int((volatile u_int *)(a),(b),(c)) 40181624Skmacy 41181624Skmacy 42181624Skmacy#if 1 43181624Skmacy#define ASSERT(_p) \ 44181624Skmacy if ( !(_p) ) { printk("Assertion '%s': line %d, file %s\n", \ 45181624Skmacy #_p , __LINE__, __FILE__); *(int*)0=0; } 46181624Skmacy#else 47181624Skmacy#define ASSERT(_p) ((void)0) 48181624Skmacy#endif 49181624Skmacy 50181624Skmacy#define WPRINTK(fmt, args...) \ 51181624Skmacy printk("xen_grant: " fmt, ##args) 52181624Skmacy 53181624Skmacy/* External tools reserve first few grant table entries. */ 54181624Skmacy#define NR_RESERVED_ENTRIES 8 55181624Skmacy#define GNTTAB_LIST_END 0xffffffff 56181624Skmacy#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(grant_entry_t)) 57181624Skmacy 58181624Skmacystatic grant_ref_t **gnttab_list; 59181624Skmacystatic unsigned int nr_grant_frames; 60181624Skmacystatic unsigned int boot_max_nr_grant_frames; 61181624Skmacystatic int gnttab_free_count; 62181624Skmacystatic grant_ref_t gnttab_free_head; 63181624Skmacystatic struct mtx gnttab_list_lock; 64181624Skmacy 65181624Skmacystatic grant_entry_t *shared; 66181624Skmacy 67181624Skmacystatic struct gnttab_free_callback *gnttab_free_callback_list = NULL; 68181624Skmacy 69181624Skmacystatic int gnttab_expand(unsigned int req_entries); 70181624Skmacy 71181624Skmacy#define RPP (PAGE_SIZE / sizeof(grant_ref_t)) 72181624Skmacy#define gnttab_entry(entry) (gnttab_list[(entry) / RPP][(entry) % RPP]) 73181624Skmacy 74181624Skmacystatic int 75181624Skmacyget_free_entries(int count) 76181624Skmacy{ 77181624Skmacy int ref, rc; 78181624Skmacy grant_ref_t head; 79181624Skmacy 80181624Skmacy mtx_lock(&gnttab_list_lock); 81181624Skmacy if ((gnttab_free_count < count) && 82181624Skmacy ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) { 83181624Skmacy mtx_unlock(&gnttab_list_lock); 84181624Skmacy return (rc); 85181624Skmacy } 86181624Skmacy ref = head = gnttab_free_head; 87181624Skmacy gnttab_free_count -= count; 88181624Skmacy while (count-- > 1) 89181624Skmacy head = gnttab_entry(head); 90181624Skmacy gnttab_free_head = gnttab_entry(head); 91181624Skmacy gnttab_entry(head) = GNTTAB_LIST_END; 92181624Skmacy mtx_unlock(&gnttab_list_lock); 93181624Skmacy return (ref); 94181624Skmacy} 95181624Skmacy 96181624Skmacy#define get_free_entry() get_free_entries(1) 97181624Skmacy 98181624Skmacystatic void 99181624Skmacydo_free_callbacks(void) 100181624Skmacy{ 101181624Skmacy struct gnttab_free_callback *callback, *next; 102181624Skmacy 103181624Skmacy callback = gnttab_free_callback_list; 104181624Skmacy gnttab_free_callback_list = NULL; 105181624Skmacy 106181624Skmacy while (callback != NULL) { 107181624Skmacy next = callback->next; 108181624Skmacy if (gnttab_free_count >= callback->count) { 109181624Skmacy callback->next = NULL; 110181624Skmacy callback->fn(callback->arg); 111181624Skmacy } else { 112181624Skmacy callback->next = gnttab_free_callback_list; 113181624Skmacy gnttab_free_callback_list = callback; 114181624Skmacy } 115181624Skmacy callback = next; 116181624Skmacy } 117181624Skmacy} 118181624Skmacy 119181624Skmacystatic inline void 120181624Skmacycheck_free_callbacks(void) 121181624Skmacy{ 122181624Skmacy if (unlikely(gnttab_free_callback_list != NULL)) 123181624Skmacy do_free_callbacks(); 124181624Skmacy} 125181624Skmacy 126181624Skmacystatic void 127181624Skmacyput_free_entry(grant_ref_t ref) 128181624Skmacy{ 129181624Skmacy 130181624Skmacy mtx_lock(&gnttab_list_lock); 131181624Skmacy gnttab_entry(ref) = gnttab_free_head; 132181624Skmacy gnttab_free_head = ref; 133181624Skmacy gnttab_free_count++; 134181624Skmacy check_free_callbacks(); 135181624Skmacy mtx_unlock(&gnttab_list_lock); 136181624Skmacy} 137181624Skmacy 138181624Skmacy/* 139181624Skmacy * Public grant-issuing interface functions 140181624Skmacy */ 141181624Skmacy 142181624Skmacyint 143181624Skmacygnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly) 144181624Skmacy{ 145181624Skmacy int ref; 146181624Skmacy 147181624Skmacy if (unlikely((ref = get_free_entry()) == -1)) 148181624Skmacy return -ENOSPC; 149181624Skmacy 150181624Skmacy shared[ref].frame = frame; 151181624Skmacy shared[ref].domid = domid; 152181624Skmacy wmb(); 153181624Skmacy shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 154181624Skmacy 155181624Skmacy return ref; 156181624Skmacy} 157181624Skmacy 158181624Skmacyvoid 159181624Skmacygnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, 160181624Skmacy unsigned long frame, int readonly) 161181624Skmacy{ 162181624Skmacy shared[ref].frame = frame; 163181624Skmacy shared[ref].domid = domid; 164181624Skmacy wmb(); 165181624Skmacy shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 166181624Skmacy} 167181624Skmacy 168181624Skmacyint 169181624Skmacygnttab_query_foreign_access(grant_ref_t ref) 170181624Skmacy{ 171181624Skmacy uint16_t nflags; 172181624Skmacy 173181624Skmacy nflags = shared[ref].flags; 174181624Skmacy 175181624Skmacy return (nflags & (GTF_reading|GTF_writing)); 176181624Skmacy} 177181624Skmacy 178181624Skmacyint 179181624Skmacygnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) 180181624Skmacy{ 181181624Skmacy uint16_t flags, nflags; 182181624Skmacy 183181624Skmacy nflags = shared[ref].flags; 184181624Skmacy do { 185181624Skmacy if ( (flags = nflags) & (GTF_reading|GTF_writing) ) { 186181624Skmacy printf("WARNING: g.e. still in use!\n"); 187181624Skmacy return (0); 188181624Skmacy } 189181624Skmacy } while ((nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) != 190181624Skmacy flags); 191181624Skmacy 192181624Skmacy return (1); 193181624Skmacy} 194181624Skmacy 195181624Skmacyvoid 196181624Skmacygnttab_end_foreign_access(grant_ref_t ref, int readonly, void *page) 197181624Skmacy{ 198181624Skmacy if (gnttab_end_foreign_access_ref(ref, readonly)) { 199181624Skmacy put_free_entry(ref); 200181624Skmacy if (page != NULL) { 201181624Skmacy free(page, M_DEVBUF); 202181624Skmacy } 203181624Skmacy } 204181624Skmacy else { 205181624Skmacy /* XXX This needs to be fixed so that the ref and page are 206181624Skmacy placed on a list to be freed up later. */ 207181624Skmacy printf("WARNING: leaking g.e. and page still in use!\n"); 208181624Skmacy } 209181624Skmacy} 210181624Skmacy 211181624Skmacyint 212181624Skmacygnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn) 213181624Skmacy{ 214181624Skmacy int ref; 215181624Skmacy 216181624Skmacy if (unlikely((ref = get_free_entry()) == -1)) 217181624Skmacy return -ENOSPC; 218181624Skmacy 219181624Skmacy gnttab_grant_foreign_transfer_ref(ref, domid, pfn); 220181624Skmacy 221181624Skmacy return (ref); 222181624Skmacy} 223181624Skmacy 224181624Skmacyvoid 225181624Skmacygnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, 226181624Skmacy unsigned long pfn) 227181624Skmacy{ 228181624Skmacy shared[ref].frame = pfn; 229181624Skmacy shared[ref].domid = domid; 230181624Skmacy wmb(); 231181624Skmacy shared[ref].flags = GTF_accept_transfer; 232181624Skmacy} 233181624Skmacy 234181624Skmacyunsigned long 235181624Skmacygnttab_end_foreign_transfer_ref(grant_ref_t ref) 236181624Skmacy{ 237181624Skmacy unsigned long frame; 238181624Skmacy uint16_t flags; 239181624Skmacy 240181624Skmacy /* 241181624Skmacy * If a transfer is not even yet started, try to reclaim the grant 242181624Skmacy * reference and return failure (== 0). 243181624Skmacy */ 244181624Skmacy while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { 245181624Skmacy if ( synch_cmpxchg(&shared[ref].flags, flags, 0) == flags ) 246181624Skmacy return (0); 247181624Skmacy cpu_relax(); 248181624Skmacy } 249181624Skmacy 250181624Skmacy /* If a transfer is in progress then wait until it is completed. */ 251181624Skmacy while (!(flags & GTF_transfer_completed)) { 252181624Skmacy flags = shared[ref].flags; 253181624Skmacy cpu_relax(); 254181624Skmacy } 255181624Skmacy 256181624Skmacy /* Read the frame number /after/ reading completion status. */ 257181624Skmacy rmb(); 258181624Skmacy frame = shared[ref].frame; 259181624Skmacy PANIC_IF(frame == 0); 260181624Skmacy 261181624Skmacy return (frame); 262181624Skmacy} 263181624Skmacy 264181624Skmacyunsigned long 265181624Skmacygnttab_end_foreign_transfer(grant_ref_t ref) 266181624Skmacy{ 267181624Skmacy unsigned long frame = gnttab_end_foreign_transfer_ref(ref); 268181624Skmacy 269181624Skmacy put_free_entry(ref); 270181624Skmacy return (frame); 271181624Skmacy} 272181624Skmacy 273181624Skmacyvoid 274181624Skmacygnttab_free_grant_reference(grant_ref_t ref) 275181624Skmacy{ 276181624Skmacy 277181624Skmacy put_free_entry(ref); 278181624Skmacy} 279181624Skmacy 280181624Skmacyvoid 281181624Skmacygnttab_free_grant_references(grant_ref_t head) 282181624Skmacy{ 283181624Skmacy grant_ref_t ref; 284181624Skmacy int count = 1; 285181624Skmacy 286181624Skmacy if (head == GNTTAB_LIST_END) 287181624Skmacy return; 288181624Skmacy 289181624Skmacy mtx_lock(&gnttab_list_lock); 290181624Skmacy ref = head; 291181624Skmacy while (gnttab_entry(ref) != GNTTAB_LIST_END) { 292181624Skmacy ref = gnttab_entry(ref); 293181624Skmacy count++; 294181624Skmacy } 295181624Skmacy gnttab_entry(ref) = gnttab_free_head; 296181624Skmacy gnttab_free_head = head; 297181624Skmacy gnttab_free_count += count; 298181624Skmacy check_free_callbacks(); 299181624Skmacy mtx_unlock(&gnttab_list_lock); 300181624Skmacy} 301181624Skmacy 302181624Skmacyint 303181624Skmacygnttab_alloc_grant_references(uint16_t count, grant_ref_t *head) 304181624Skmacy{ 305181624Skmacy int h = get_free_entries(count); 306181624Skmacy 307181624Skmacy if (h == -1) 308181624Skmacy return -ENOSPC; 309181624Skmacy 310181624Skmacy *head = h; 311181624Skmacy 312181624Skmacy return 0; 313181624Skmacy} 314181624Skmacy 315181624Skmacyint 316181624Skmacygnttab_empty_grant_references(const grant_ref_t *private_head) 317181624Skmacy{ 318181624Skmacy return (*private_head == GNTTAB_LIST_END); 319181624Skmacy} 320181624Skmacy 321181624Skmacyint 322181624Skmacygnttab_claim_grant_reference(grant_ref_t *private_head) 323181624Skmacy{ 324181624Skmacy grant_ref_t g = *private_head; 325181624Skmacy 326181624Skmacy if (unlikely(g == GNTTAB_LIST_END)) 327181624Skmacy return -ENOSPC; 328181624Skmacy *private_head = gnttab_entry(g); 329181624Skmacy 330181624Skmacy return (g); 331181624Skmacy} 332181624Skmacy 333181624Skmacyvoid 334181624Skmacygnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release) 335181624Skmacy{ 336181624Skmacy gnttab_entry(release) = *private_head; 337181624Skmacy *private_head = release; 338181624Skmacy} 339181624Skmacy 340181624Skmacyvoid 341181624Skmacygnttab_request_free_callback(struct gnttab_free_callback *callback, 342181624Skmacy void (*fn)(void *), void *arg, uint16_t count) 343181624Skmacy{ 344181624Skmacy 345181624Skmacy mtx_lock(&gnttab_list_lock); 346181624Skmacy if (callback->next) 347181624Skmacy goto out; 348181624Skmacy callback->fn = fn; 349181624Skmacy callback->arg = arg; 350181624Skmacy callback->count = count; 351181624Skmacy callback->next = gnttab_free_callback_list; 352181624Skmacy gnttab_free_callback_list = callback; 353181624Skmacy check_free_callbacks(); 354181624Skmacy out: 355181624Skmacy mtx_unlock(&gnttab_list_lock); 356181624Skmacy 357181624Skmacy} 358181624Skmacy 359181624Skmacyvoid 360181624Skmacygnttab_cancel_free_callback(struct gnttab_free_callback *callback) 361181624Skmacy{ 362181624Skmacy struct gnttab_free_callback **pcb; 363181624Skmacy 364181624Skmacy mtx_lock(&gnttab_list_lock); 365181624Skmacy for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) { 366181624Skmacy if (*pcb == callback) { 367181624Skmacy *pcb = callback->next; 368181624Skmacy break; 369181624Skmacy } 370181624Skmacy } 371181624Skmacy mtx_unlock(&gnttab_list_lock); 372181624Skmacy} 373181624Skmacy 374181624Skmacy 375181624Skmacystatic int 376181624Skmacygrow_gnttab_list(unsigned int more_frames) 377181624Skmacy{ 378181624Skmacy unsigned int new_nr_grant_frames, extra_entries, i; 379181624Skmacy 380181624Skmacy new_nr_grant_frames = nr_grant_frames + more_frames; 381181624Skmacy extra_entries = more_frames * GREFS_PER_GRANT_FRAME; 382181624Skmacy 383181624Skmacy for (i = nr_grant_frames; i < new_nr_grant_frames; i++) 384181624Skmacy { 385181624Skmacy gnttab_list[i] = (grant_ref_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); 386181624Skmacy 387181624Skmacy if (!gnttab_list[i]) 388181624Skmacy goto grow_nomem; 389181624Skmacy } 390181624Skmacy 391181624Skmacy for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames; 392181624Skmacy i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++) 393181624Skmacy gnttab_entry(i) = i + 1; 394181624Skmacy 395181624Skmacy gnttab_entry(i) = gnttab_free_head; 396181624Skmacy gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames; 397181624Skmacy gnttab_free_count += extra_entries; 398181624Skmacy 399181624Skmacy nr_grant_frames = new_nr_grant_frames; 400181624Skmacy 401181624Skmacy check_free_callbacks(); 402181624Skmacy 403181624Skmacy return 0; 404181624Skmacy 405181624Skmacygrow_nomem: 406181624Skmacy for ( ; i >= nr_grant_frames; i--) 407181624Skmacy free(gnttab_list[i], M_DEVBUF); 408181624Skmacy return (-ENOMEM); 409181624Skmacy} 410181624Skmacy 411181624Skmacystatic unsigned int 412181624Skmacy__max_nr_grant_frames(void) 413181624Skmacy{ 414181624Skmacy struct gnttab_query_size query; 415181624Skmacy int rc; 416181624Skmacy 417181624Skmacy query.dom = DOMID_SELF; 418181624Skmacy 419181624Skmacy rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1); 420181624Skmacy if ((rc < 0) || (query.status != GNTST_okay)) 421181624Skmacy return (4); /* Legacy max supported number of frames */ 422181624Skmacy 423181624Skmacy return (query.max_nr_frames); 424181624Skmacy} 425181624Skmacy 426181624Skmacystatic inline 427181624Skmacyunsigned int max_nr_grant_frames(void) 428181624Skmacy{ 429181624Skmacy unsigned int xen_max = __max_nr_grant_frames(); 430181624Skmacy 431181624Skmacy if (xen_max > boot_max_nr_grant_frames) 432181624Skmacy return (boot_max_nr_grant_frames); 433181624Skmacy return (xen_max); 434181624Skmacy} 435181624Skmacy 436181624Skmacy#ifdef notyet 437181624Skmacy/* 438181624Skmacy * XXX needed for backend support 439181624Skmacy * 440181624Skmacy */ 441181624Skmacystatic int 442181624Skmacymap_pte_fn(pte_t *pte, struct page *pmd_page, 443181624Skmacy unsigned long addr, void *data) 444181624Skmacy{ 445181624Skmacy unsigned long **frames = (unsigned long **)data; 446181624Skmacy 447181624Skmacy set_pte_at(&init_mm, addr, pte, pfn_pte_ma((*frames)[0], PAGE_KERNEL)); 448181624Skmacy (*frames)++; 449181624Skmacy return 0; 450181624Skmacy} 451181624Skmacy 452181624Skmacystatic int 453181624Skmacyunmap_pte_fn(pte_t *pte, struct page *pmd_page, 454181624Skmacy unsigned long addr, void *data) 455181624Skmacy{ 456181624Skmacy 457181624Skmacy set_pte_at(&init_mm, addr, pte, __pte(0)); 458181624Skmacy return 0; 459181624Skmacy} 460181624Skmacy#endif 461181624Skmacy 462181624Skmacystatic int 463181624Skmacygnttab_map(unsigned int start_idx, unsigned int end_idx) 464181624Skmacy{ 465181624Skmacy struct gnttab_setup_table setup; 466181624Skmacy unsigned long *frames; 467181624Skmacy unsigned int nr_gframes = end_idx + 1; 468181624Skmacy int i, rc; 469181624Skmacy 470181624Skmacy frames = malloc(nr_gframes * sizeof(unsigned long), M_DEVBUF, M_NOWAIT); 471181624Skmacy if (!frames) 472181624Skmacy return -ENOMEM; 473181624Skmacy 474181624Skmacy setup.dom = DOMID_SELF; 475181624Skmacy setup.nr_frames = nr_gframes; 476181624Skmacy set_xen_guest_handle(setup.frame_list, frames); 477181624Skmacy 478181624Skmacy rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1); 479181624Skmacy if (rc == -ENOSYS) { 480181624Skmacy free(frames, M_DEVBUF); 481181624Skmacy return -ENOSYS; 482181624Skmacy } 483181624Skmacy PANIC_IF(rc || setup.status); 484181624Skmacy 485181624Skmacy if (shared == NULL) { 486181624Skmacy vm_offset_t area; 487181624Skmacy 488181624Skmacy area = kmem_alloc_nofault(kernel_map, 489181624Skmacy PAGE_SIZE * max_nr_grant_frames()); 490181624Skmacy PANIC_IF(area == 0); 491181624Skmacy shared = (grant_entry_t *)area; 492181624Skmacy } 493181624Skmacy for (i = 0; i < nr_gframes; i++) 494181624Skmacy PT_SET_MA(((caddr_t)shared) + i*PAGE_SIZE, 495181624Skmacy frames[i] << PAGE_SHIFT | PG_RW | PG_V); 496181624Skmacy 497181624Skmacy free(frames, M_DEVBUF); 498181624Skmacy 499181624Skmacy return 0; 500181624Skmacy} 501181624Skmacy 502181624Skmacyint 503181624Skmacygnttab_resume(void) 504181624Skmacy{ 505181624Skmacy if (max_nr_grant_frames() < nr_grant_frames) 506181624Skmacy return -ENOSYS; 507181624Skmacy return gnttab_map(0, nr_grant_frames - 1); 508181624Skmacy} 509181624Skmacy 510181624Skmacyint 511181624Skmacygnttab_suspend(void) 512181624Skmacy{ 513181624Skmacy int i, pages; 514181624Skmacy 515181624Skmacy pages = (PAGE_SIZE*nr_grant_frames) >> PAGE_SHIFT; 516181624Skmacy 517181624Skmacy for (i = 0; i < pages; i++) 518181624Skmacy PT_SET_MA(shared + (i*PAGE_SIZE), (vm_paddr_t)0); 519181624Skmacy 520181624Skmacy return (0); 521181624Skmacy} 522181624Skmacy 523181624Skmacystatic int 524181624Skmacygnttab_expand(unsigned int req_entries) 525181624Skmacy{ 526181624Skmacy int rc; 527181624Skmacy unsigned int cur, extra; 528181624Skmacy 529181624Skmacy cur = nr_grant_frames; 530181624Skmacy extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / 531181624Skmacy GREFS_PER_GRANT_FRAME); 532181624Skmacy if (cur + extra > max_nr_grant_frames()) 533181624Skmacy return -ENOSPC; 534181624Skmacy 535181624Skmacy if ((rc = gnttab_map(cur, cur + extra - 1)) == 0) 536181624Skmacy rc = grow_gnttab_list(extra); 537181624Skmacy 538181624Skmacy return rc; 539181624Skmacy} 540181624Skmacy 541181624Skmacystatic int 542181624Skmacygnttab_init(void *unused) 543181624Skmacy{ 544181624Skmacy int i; 545181624Skmacy unsigned int max_nr_glist_frames; 546181624Skmacy unsigned int nr_init_grefs; 547181624Skmacy 548181624Skmacy if (!is_running_on_xen()) 549181624Skmacy return -ENODEV; 550181624Skmacy 551181624Skmacy nr_grant_frames = 1; 552181624Skmacy boot_max_nr_grant_frames = __max_nr_grant_frames(); 553181624Skmacy 554181624Skmacy /* Determine the maximum number of frames required for the 555181624Skmacy * grant reference free list on the current hypervisor. 556181624Skmacy */ 557181624Skmacy max_nr_glist_frames = (boot_max_nr_grant_frames * 558181624Skmacy GREFS_PER_GRANT_FRAME / 559181624Skmacy (PAGE_SIZE / sizeof(grant_ref_t))); 560181624Skmacy 561181624Skmacy gnttab_list = malloc(max_nr_glist_frames * sizeof(grant_ref_t *), 562181624Skmacy M_DEVBUF, M_NOWAIT); 563181624Skmacy 564181624Skmacy if (gnttab_list == NULL) 565181624Skmacy return -ENOMEM; 566181624Skmacy 567181624Skmacy for (i = 0; i < nr_grant_frames; i++) { 568181624Skmacy gnttab_list[i] = (grant_ref_t *)malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); 569181624Skmacy if (gnttab_list[i] == NULL) 570181624Skmacy goto ini_nomem; 571181624Skmacy } 572181624Skmacy 573181624Skmacy if (gnttab_resume() < 0) 574181624Skmacy return -ENODEV; 575181624Skmacy 576181624Skmacy nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME; 577181624Skmacy 578181624Skmacy for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) 579181624Skmacy gnttab_entry(i) = i + 1; 580181624Skmacy 581181624Skmacy gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END; 582181624Skmacy gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES; 583181624Skmacy gnttab_free_head = NR_RESERVED_ENTRIES; 584181624Skmacy 585181624Skmacy printk("Grant table initialized\n"); 586181624Skmacy return 0; 587181624Skmacy 588181624Skmacyini_nomem: 589181624Skmacy for (i--; i >= 0; i--) 590181624Skmacy free(gnttab_list[i], M_DEVBUF); 591181624Skmacy free(gnttab_list, M_DEVBUF); 592181624Skmacy return -ENOMEM; 593181624Skmacy 594181624Skmacy} 595181624Skmacy 596181624SkmacyMTX_SYSINIT(gnttab, &gnttab_list_lock, "GNTTAB LOCK", MTX_DEF); 597181624SkmacySYSINIT(gnttab, SI_SUB_PSEUDO, SI_ORDER_FIRST, gnttab_init, NULL); 598