1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * gnttab.c 31 * 32 * Granting foreign access to our memory reservation. 33 * 34 * Copyright (c) 2005-2006, Christopher Clark 35 * Copyright (c) 2004-2005, K A Fraser 36 * 37 * This program is free software; you can redistribute it and/or 38 * modify it under the terms of the GNU General Public License version 2 39 * as published by the Free Software Foundation; or, when distributed 40 * separately from the Linux kernel or incorporated into other 41 * software packages, subject to the following license: 42 * 43 * Permission is hereby granted, free of charge, to any person obtaining a copy 44 * of this source file (the "Software"), to deal in the Software without 45 * restriction, including without limitation the rights to use, copy, modify, 46 * merge, publish, distribute, sublicense, and/or sell copies of the Software, 47 * and to permit persons to whom the Software is furnished to do so, subject to 48 * the following conditions: 49 * 50 * The above copyright notice and this permission notice shall be included in 51 * all copies or substantial portions of the Software. 52 * 53 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 54 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 55 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 56 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 57 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 58 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 59 * IN THE SOFTWARE. 60 */ 61 62 #include <sys/types.h> 63 #include <sys/archsystm.h> 64 #ifdef XPV_HVM_DRIVER 65 #include <sys/xpv_support.h> 66 #include <sys/mman.h> 67 #include <vm/hat.h> 68 #endif 69 #include <sys/hypervisor.h> 70 #include <sys/gnttab.h> 71 #include <sys/sysmacros.h> 72 #include <sys/machsystm.h> 73 #include <sys/systm.h> 74 #include <sys/mutex.h> 75 #include <sys/atomic.h> 76 #include <sys/spl.h> 77 #include <sys/condvar.h> 78 #include <sys/cpuvar.h> 79 #include <sys/taskq.h> 80 #include <sys/panic.h> 81 #include <sys/cmn_err.h> 82 #include <sys/promif.h> 83 #include <sys/cpu.h> 84 #include <sys/vmem.h> 85 #include <vm/hat_i86.h> 86 #include <sys/bootconf.h> 87 #include <sys/bootsvcs.h> 88 #ifndef XPV_HVM_DRIVER 89 #include <sys/bootinfo.h> 90 #include <sys/multiboot.h> 91 #include <vm/kboot_mmu.h> 92 #endif 93 #include <sys/bootvfs.h> 94 #include <sys/bootprops.h> 95 #include <vm/seg_kmem.h> 96 #include <sys/mman.h> 97 98 /* Globals */ 99 100 static grant_ref_t **gnttab_list; 101 static uint_t nr_grant_frames; 102 static int gnttab_free_count; 103 static grant_ref_t gnttab_free_head; 104 static kmutex_t gnttab_list_lock; 105 static grant_entry_t *shared; 106 static struct gnttab_free_callback *gnttab_free_callback_list; 107 108 /* Macros */ 109 110 #define GT_PGADDR(i) ((uintptr_t)shared + ((i) << MMU_PAGESHIFT)) 111 #define VALID_GRANT_REF(r) ((r) < (nr_grant_frames * GREFS_PER_GRANT_FRAME)) 112 #define RPP (PAGESIZE / sizeof (grant_ref_t)) 113 #define GNTTAB_ENTRY(entry) (gnttab_list[(entry) / RPP][(entry) % RPP]) 114 #define CMPXCHG(t, c, n) atomic_cas_16((t), (c), (n)) 115 /* External tools reserve first few grant table entries. */ 116 #define NR_RESERVED_ENTRIES 8 117 #define GNTTAB_LIST_END 0xffffffff 118 #define GREFS_PER_GRANT_FRAME (PAGESIZE / sizeof (grant_entry_t)) 119 120 /* Implementation */ 121 122 static uint_t 123 max_nr_grant_frames(void) 124 { 125 struct gnttab_query_size query; 126 int rc; 127 128 query.dom = DOMID_SELF; 129 130 rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1); 131 if ((rc < 0) || (query.status != GNTST_okay)) 132 return (4); /* Legacy max supported number of frames */ 133 134 ASSERT(query.max_nr_frames); 135 return (query.max_nr_frames); 136 } 137 138 static void 139 do_free_callbacks(void) 140 { 141 struct gnttab_free_callback *callback, *next; 142 143 callback = gnttab_free_callback_list; 144 gnttab_free_callback_list = NULL; 145 146 while (callback != NULL) { 147 next = callback->next; 148 if (gnttab_free_count >= callback->count) { 149 callback->next = NULL; 150 callback->fn(callback->arg); 151 } else { 152 callback->next = gnttab_free_callback_list; 153 gnttab_free_callback_list = callback; 154 } 155 callback = next; 156 } 157 } 158 159 static void 160 check_free_callbacks(void) 161 { 162 if (gnttab_free_callback_list) 163 do_free_callbacks(); 164 } 165 166 static int 167 grow_gnttab_list(uint_t more_frames) 168 { 169 uint_t new_nr_grant_frames, extra_entries, i; 170 uint_t nr_glist_frames, new_nr_glist_frames; 171 172 ASSERT(MUTEX_HELD(&gnttab_list_lock)); 173 174 new_nr_grant_frames = nr_grant_frames + more_frames; 175 extra_entries = more_frames * GREFS_PER_GRANT_FRAME; 176 177 nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) 178 / RPP; 179 new_nr_glist_frames = (new_nr_grant_frames * GREFS_PER_GRANT_FRAME 180 + RPP - 1) / RPP; 181 for (i = nr_glist_frames; i < new_nr_glist_frames; i++) 182 gnttab_list[i] = kmem_alloc(PAGESIZE, KM_SLEEP); 183 184 for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames; 185 i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++) 186 GNTTAB_ENTRY(i) = i + 1; 187 188 GNTTAB_ENTRY(i) = gnttab_free_head; 189 gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames; 190 gnttab_free_count += extra_entries; 191 192 nr_grant_frames = new_nr_grant_frames; 193 194 check_free_callbacks(); 195 196 return (0); 197 } 198 199 static int 200 gnttab_expand(uint_t req_entries) 201 { 202 uint_t cur, extra; 203 204 ASSERT(MUTEX_HELD(&gnttab_list_lock)); 205 206 cur = nr_grant_frames; 207 extra = ((req_entries + (GREFS_PER_GRANT_FRAME - 1)) / 208 GREFS_PER_GRANT_FRAME); 209 if (cur + extra > max_nr_grant_frames()) 210 return (-1); 211 212 return (grow_gnttab_list(extra)); 213 } 214 215 static int 216 get_free_entries(int count) 217 { 218 int ref, rc; 219 grant_ref_t head; 220 221 mutex_enter(&gnttab_list_lock); 222 if (gnttab_free_count < count && 223 ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) { 224 mutex_exit(&gnttab_list_lock); 225 return (rc); 226 } 227 ref = head = gnttab_free_head; 228 gnttab_free_count -= count; 229 while (count-- > 1) 230 head = GNTTAB_ENTRY(head); 231 gnttab_free_head = GNTTAB_ENTRY(head); 232 GNTTAB_ENTRY(head) = GNTTAB_LIST_END; 233 mutex_exit(&gnttab_list_lock); 234 return (ref); 235 } 236 237 static void 238 put_free_entry(grant_ref_t ref) 239 { 240 ASSERT(VALID_GRANT_REF(ref)); 241 242 mutex_enter(&gnttab_list_lock); 243 GNTTAB_ENTRY(ref) = gnttab_free_head; 244 gnttab_free_head = ref; 245 gnttab_free_count++; 246 check_free_callbacks(); 247 mutex_exit(&gnttab_list_lock); 248 } 249 250 /* 251 * Public grant-issuing interface functions 252 */ 253 254 int 255 gnttab_grant_foreign_access(domid_t domid, gnttab_frame_t frame, int readonly) 256 { 257 int ref; 258 259 if ((ref = get_free_entries(1)) == -1) 260 return (-1); 261 262 ASSERT(VALID_GRANT_REF(ref)); 263 264 shared[ref].frame = frame; 265 shared[ref].domid = domid; 266 membar_producer(); 267 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 268 269 return (ref); 270 } 271 272 void 273 gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, 274 gnttab_frame_t frame, int readonly) 275 { 276 ASSERT(VALID_GRANT_REF(ref)); 277 278 shared[ref].frame = frame; 279 shared[ref].domid = domid; 280 membar_producer(); 281 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 282 } 283 284 285 int 286 gnttab_query_foreign_access(grant_ref_t ref) 287 { 288 uint16_t nflags; 289 290 ASSERT(VALID_GRANT_REF(ref)); 291 292 nflags = shared[ref].flags; 293 294 return (nflags & (GTF_reading|GTF_writing)); 295 } 296 297 /* ARGSUSED */ 298 int 299 gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) 300 { 301 uint16_t flags, nflags; 302 303 ASSERT(VALID_GRANT_REF(ref)); 304 305 nflags = shared[ref].flags; 306 do { 307 if ((flags = nflags) & (GTF_reading|GTF_writing)) { 308 cmn_err(CE_WARN, "g.e. still in use!"); 309 return (0); 310 } 311 } while ((nflags = CMPXCHG(&shared[ref].flags, flags, 0)) != flags); 312 313 return (1); 314 } 315 316 void 317 gnttab_end_foreign_access(grant_ref_t ref, int readonly, gnttab_frame_t page) 318 { 319 ASSERT(VALID_GRANT_REF(ref)); 320 321 if (gnttab_end_foreign_access_ref(ref, readonly)) { 322 put_free_entry(ref); 323 /* 324 * XXPV - we don't support freeing a page here 325 */ 326 if (page != 0) { 327 cmn_err(CE_WARN, 328 "gnttab_end_foreign_access_ref: using unsupported free_page interface"); 329 /* free_page(page); */ 330 } 331 } else { 332 /* 333 * XXX This needs to be fixed so that the ref and page are 334 * placed on a list to be freed up later. 335 */ 336 cmn_err(CE_WARN, "leaking g.e. and page still in use!"); 337 } 338 } 339 340 int 341 gnttab_grant_foreign_transfer(domid_t domid, pfn_t pfn) 342 { 343 int ref; 344 345 if ((ref = get_free_entries(1)) == -1) 346 return (-1); 347 348 ASSERT(VALID_GRANT_REF(ref)); 349 350 gnttab_grant_foreign_transfer_ref(ref, domid, pfn); 351 352 return (ref); 353 } 354 355 void 356 gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, pfn_t pfn) 357 { 358 ASSERT(VALID_GRANT_REF(ref)); 359 360 shared[ref].frame = pfn; 361 shared[ref].domid = domid; 362 membar_producer(); 363 shared[ref].flags = GTF_accept_transfer; 364 } 365 366 gnttab_frame_t 367 gnttab_end_foreign_transfer_ref(grant_ref_t ref) 368 { 369 gnttab_frame_t frame; 370 uint16_t flags; 371 372 ASSERT(VALID_GRANT_REF(ref)); 373 374 /* 375 * If a transfer is not even yet started, try to reclaim the grant 376 * reference and return failure (== 0). 377 */ 378 while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { 379 if (CMPXCHG(&shared[ref].flags, flags, 0) == flags) 380 return (0); 381 (void) HYPERVISOR_yield(); 382 } 383 384 /* If a transfer is in progress then wait until it is completed. */ 385 while (!(flags & GTF_transfer_completed)) { 386 flags = shared[ref].flags; 387 (void) HYPERVISOR_yield(); 388 } 389 390 /* Read the frame number /after/ reading completion status. */ 391 membar_consumer(); 392 frame = shared[ref].frame; 393 ASSERT(frame != 0); 394 395 return (frame); 396 } 397 398 gnttab_frame_t 399 gnttab_end_foreign_transfer(grant_ref_t ref) 400 { 401 gnttab_frame_t frame; 402 403 ASSERT(VALID_GRANT_REF(ref)); 404 405 frame = gnttab_end_foreign_transfer_ref(ref); 406 put_free_entry(ref); 407 return (frame); 408 } 409 410 void 411 gnttab_free_grant_reference(grant_ref_t ref) 412 { 413 ASSERT(VALID_GRANT_REF(ref)); 414 415 put_free_entry(ref); 416 } 417 418 void 419 gnttab_free_grant_references(grant_ref_t head) 420 { 421 grant_ref_t ref; 422 int count = 1; 423 424 if (head == GNTTAB_LIST_END) 425 return; 426 mutex_enter(&gnttab_list_lock); 427 ref = head; 428 while (GNTTAB_ENTRY(ref) != GNTTAB_LIST_END) { 429 ref = GNTTAB_ENTRY(ref); 430 count++; 431 } 432 GNTTAB_ENTRY(ref) = gnttab_free_head; 433 gnttab_free_head = head; 434 gnttab_free_count += count; 435 check_free_callbacks(); 436 mutex_exit(&gnttab_list_lock); 437 } 438 439 int 440 gnttab_alloc_grant_references(uint16_t count, grant_ref_t *head) 441 { 442 int h = get_free_entries(count); 443 444 if (h == -1) 445 return (-1); 446 447 *head = h; 448 449 return (0); 450 } 451 452 int 453 gnttab_empty_grant_references(const grant_ref_t *private_head) 454 { 455 return (*private_head == GNTTAB_LIST_END); 456 } 457 458 int 459 gnttab_claim_grant_reference(grant_ref_t *private_head) 460 { 461 grant_ref_t g = *private_head; 462 463 if (g == GNTTAB_LIST_END) 464 return (-1); 465 *private_head = GNTTAB_ENTRY(g); 466 return (g); 467 } 468 469 void 470 gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release) 471 { 472 ASSERT(VALID_GRANT_REF(release)); 473 474 GNTTAB_ENTRY(release) = *private_head; 475 *private_head = release; 476 } 477 478 void 479 gnttab_request_free_callback(struct gnttab_free_callback *callback, 480 void (*fn)(void *), void *arg, uint16_t count) 481 { 482 mutex_enter(&gnttab_list_lock); 483 if (callback->next) 484 goto out; 485 callback->fn = fn; 486 callback->arg = arg; 487 callback->count = count; 488 callback->next = gnttab_free_callback_list; 489 gnttab_free_callback_list = callback; 490 check_free_callbacks(); 491 out: 492 mutex_exit(&gnttab_list_lock); 493 } 494 495 void 496 gnttab_cancel_free_callback(struct gnttab_free_callback *callback) 497 { 498 struct gnttab_free_callback **pcb; 499 500 mutex_enter(&gnttab_list_lock); 501 for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) { 502 if (*pcb == callback) { 503 *pcb = callback->next; 504 break; 505 } 506 } 507 mutex_exit(&gnttab_list_lock); 508 } 509 510 static gnttab_frame_t * 511 gnttab_setup(gnttab_setup_table_t *pset) 512 { 513 gnttab_frame_t *frames; 514 515 frames = kmem_alloc(pset->nr_frames * sizeof (gnttab_frame_t), 516 KM_SLEEP); 517 518 /*LINTED: constant in conditional context*/ 519 set_xen_guest_handle(pset->frame_list, frames); 520 521 #ifndef XPV_HVM_DRIVER 522 /* 523 * Take pset->nr_frames pages of grant table space from 524 * the hypervisor and map it 525 */ 526 if ((HYPERVISOR_grant_table_op(GNTTABOP_setup_table, pset, 1) != 0) || 527 (pset->status != 0)) { 528 cmn_err(CE_PANIC, "Grant Table setup failed"); 529 } 530 #endif 531 532 return (frames); 533 } 534 535 #ifdef XPV_HVM_DRIVER 536 static void 537 gnttab_map(void) 538 { 539 struct xen_add_to_physmap xatp; 540 caddr_t va; 541 pfn_t pfn; 542 int i; 543 544 va = (caddr_t)shared; 545 for (i = 0; i < max_nr_grant_frames(); i++) { 546 if ((pfn = hat_getpfnum(kas.a_hat, va)) == PFN_INVALID) 547 cmn_err(CE_PANIC, "gnttab_map: Invalid pfn"); 548 549 xatp.domid = DOMID_SELF; 550 xatp.idx = i; 551 xatp.space = XENMAPSPACE_grant_table; 552 xatp.gpfn = pfn; 553 hat_unload(kas.a_hat, va, MMU_PAGESIZE, HAT_UNLOAD); 554 /* 555 * This call replaces the existing machine page backing 556 * the given gpfn with the page from the allocated grant 557 * table at index idx. The existing machine page is 558 * returned to the free list. 559 */ 560 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0) 561 panic("Couldn't map grant table"); 562 hat_devload(kas.a_hat, va, MMU_PAGESIZE, pfn, 563 PROT_READ | PROT_WRITE | HAT_STORECACHING_OK, 564 HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST); 565 va += MMU_PAGESIZE; 566 } 567 } 568 #endif /* XPV_HVM_DRIVER */ 569 570 void 571 gnttab_init(void) 572 { 573 gnttab_setup_table_t set; 574 int i; 575 uint_t nr_init_grefs, max_nr_glist_frames, nr_glist_frames; 576 gnttab_frame_t *frames; 577 578 /* 579 * gnttab_init() should only be invoked once. 580 */ 581 mutex_enter(&gnttab_list_lock); 582 ASSERT(nr_grant_frames == 0); 583 nr_grant_frames = 1; 584 mutex_exit(&gnttab_list_lock); 585 586 max_nr_glist_frames = (max_nr_grant_frames() * 587 GREFS_PER_GRANT_FRAME / RPP); 588 589 set.dom = DOMID_SELF; 590 set.nr_frames = max_nr_grant_frames(); 591 frames = gnttab_setup(&set); 592 593 #ifdef XPV_HVM_DRIVER 594 shared = (grant_entry_t *)xen_alloc_pages(set.nr_frames); 595 596 gnttab_map(); 597 #else /* XPV_HVM_DRIVER */ 598 shared = vmem_xalloc(heap_arena, set.nr_frames * MMU_PAGESIZE, 599 MMU_PAGESIZE, 0, 0, 0, 0, VM_SLEEP); 600 for (i = 0; i < set.nr_frames; i++) { 601 hat_devload(kas.a_hat, (caddr_t)GT_PGADDR(i), PAGESIZE, 602 xen_assign_pfn(frames[i]), 603 PROT_READ | PROT_WRITE | HAT_STORECACHING_OK, 604 HAT_LOAD_LOCK); 605 } 606 #endif 607 608 gnttab_list = kmem_alloc(max_nr_glist_frames * sizeof (grant_ref_t *), 609 KM_SLEEP); 610 611 nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) 612 / RPP; 613 for (i = 0; i < nr_glist_frames; i++) { 614 gnttab_list[i] = kmem_alloc(PAGESIZE, KM_SLEEP); 615 } 616 617 kmem_free(frames, set.nr_frames * sizeof (gnttab_frame_t)); 618 619 nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME; 620 621 for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) 622 GNTTAB_ENTRY(i) = i + 1; 623 624 GNTTAB_ENTRY(nr_init_grefs - 1) = GNTTAB_LIST_END; 625 gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES; 626 gnttab_free_head = NR_RESERVED_ENTRIES; 627 } 628 629 void 630 gnttab_resume(void) 631 { 632 gnttab_setup_table_t set; 633 int i; 634 gnttab_frame_t *frames; 635 uint_t available_frames = max_nr_grant_frames(); 636 637 if (available_frames < nr_grant_frames) { 638 cmn_err(CE_PANIC, "Hypervisor does not have enough grant " 639 "frames: required(%u), available(%u)", nr_grant_frames, 640 available_frames); 641 } 642 643 #ifdef XPV_HVM_DRIVER 644 gnttab_map(); 645 #endif /* XPV_HVM_DRIVER */ 646 647 set.dom = DOMID_SELF; 648 set.nr_frames = available_frames; 649 frames = gnttab_setup(&set); 650 651 for (i = 0; i < available_frames; i++) { 652 (void) HYPERVISOR_update_va_mapping(GT_PGADDR(i), 653 FRAME_TO_MA(frames[i]) | PT_VALID | PT_WRITABLE, 654 UVMF_INVLPG | UVMF_ALL); 655 } 656 kmem_free(frames, set.nr_frames * sizeof (gnttab_frame_t)); 657 } 658 659 void 660 gnttab_suspend(void) 661 { 662 int i; 663 664 /* 665 * clear grant table mappings before suspending 666 */ 667 for (i = 0; i < max_nr_grant_frames(); i++) { 668 (void) HYPERVISOR_update_va_mapping(GT_PGADDR(i), 669 0, UVMF_INVLPG); 670 } 671 } 672 673 /* 674 * Local variables: 675 * c-file-style: "solaris" 676 * indent-tabs-mode: t 677 * c-indent-level: 8 678 * c-basic-offset: 8 679 * tab-width: 8 680 * End: 681 */ 682