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 2007 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, Christopher Clark 35 * Copyright (c) 2004-2005, K A Fraser 36 * 37 * This file may be distributed separately from the Linux kernel, or 38 * incorporated into other software packages, subject to the following license: 39 * 40 * Permission is hereby granted, free of charge, to any person obtaining a copy 41 * of this source file (the "Software"), to deal in the Software without 42 * restriction, including without limitation the rights to use, copy, modify, 43 * merge, publish, distribute, sublicense, and/or sell copies of the Software, 44 * and to permit persons to whom the Software is furnished to do so, subject to 45 * the following conditions: 46 * 47 * The above copyright notice and this permission notice shall be included in 48 * all copies or substantial portions of the Software. 49 * 50 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 51 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 52 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 53 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 54 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 55 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 56 * IN THE SOFTWARE. 57 */ 58 59 #include <sys/types.h> 60 #include <sys/archsystm.h> 61 #ifdef XPV_HVM_DRIVER 62 #include <sys/xpv_support.h> 63 #include <sys/mman.h> 64 #include <vm/hat.h> 65 #endif 66 #include <sys/hypervisor.h> 67 #include <sys/gnttab.h> 68 #include <sys/sysmacros.h> 69 #include <sys/machsystm.h> 70 #include <sys/systm.h> 71 #include <sys/mutex.h> 72 #include <sys/atomic.h> 73 #include <sys/spl.h> 74 #include <sys/condvar.h> 75 #include <sys/cpuvar.h> 76 #include <sys/taskq.h> 77 #include <sys/panic.h> 78 #include <sys/cmn_err.h> 79 #include <sys/promif.h> 80 #include <sys/cpu.h> 81 #include <sys/vmem.h> 82 #include <vm/hat_i86.h> 83 #include <sys/bootconf.h> 84 #include <sys/bootsvcs.h> 85 #ifndef XPV_HVM_DRIVER 86 #include <sys/bootinfo.h> 87 #include <sys/multiboot.h> 88 #include <vm/kboot_mmu.h> 89 #endif 90 #include <sys/bootvfs.h> 91 #include <sys/bootprops.h> 92 #include <vm/seg_kmem.h> 93 94 #define cmpxchg(t, c, n) atomic_cas_16((t), (c), (n)) 95 96 /* External tools reserve first few grant table entries. */ 97 #define NR_RESERVED_ENTRIES 8 98 99 #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * \ 100 MMU_PAGESIZE / sizeof (grant_entry_t)) 101 #define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1) 102 #define VALID_GRANT_REF(r) ((r) < NR_GRANT_ENTRIES) 103 104 static grant_ref_t gnttab_list[NR_GRANT_ENTRIES]; 105 static int gnttab_free_count; 106 static grant_ref_t gnttab_free_head; 107 static kmutex_t gnttab_list_lock; 108 109 static grant_entry_t *shared; 110 #define GT_PGADDR(i) ((uintptr_t)shared + ((i) << PAGESHIFT)) 111 112 static struct gnttab_free_callback *gnttab_free_callback_list = NULL; 113 114 static int 115 get_free_entries(int count) 116 { 117 int ref; 118 grant_ref_t head; 119 120 mutex_enter(&gnttab_list_lock); 121 if (gnttab_free_count < count) { 122 mutex_exit(&gnttab_list_lock); 123 return (-1); 124 } 125 ref = head = gnttab_free_head; 126 gnttab_free_count -= count; 127 while (count-- > 1) 128 head = gnttab_list[head]; 129 gnttab_free_head = gnttab_list[head]; 130 gnttab_list[head] = GNTTAB_LIST_END; 131 mutex_exit(&gnttab_list_lock); 132 return (ref); 133 } 134 135 #define get_free_entry() get_free_entries(1) 136 137 static void 138 do_free_callbacks(void) 139 { 140 struct gnttab_free_callback *callback, *next; 141 142 callback = gnttab_free_callback_list; 143 gnttab_free_callback_list = NULL; 144 145 while (callback != NULL) { 146 next = callback->next; 147 if (gnttab_free_count >= callback->count) { 148 callback->next = NULL; 149 callback->fn(callback->arg); 150 } else { 151 callback->next = gnttab_free_callback_list; 152 gnttab_free_callback_list = callback; 153 } 154 callback = next; 155 } 156 } 157 158 static void 159 check_free_callbacks(void) 160 { 161 if (gnttab_free_callback_list) 162 do_free_callbacks(); 163 } 164 165 static void 166 put_free_entry(grant_ref_t ref) 167 { 168 ASSERT(VALID_GRANT_REF(ref)); 169 170 mutex_enter(&gnttab_list_lock); 171 gnttab_list[ref] = gnttab_free_head; 172 gnttab_free_head = ref; 173 gnttab_free_count++; 174 check_free_callbacks(); 175 mutex_exit(&gnttab_list_lock); 176 } 177 178 /* 179 * Public grant-issuing interface functions 180 */ 181 182 int 183 gnttab_grant_foreign_access(domid_t domid, gnttab_frame_t frame, int readonly) 184 { 185 int ref; 186 187 if ((ref = get_free_entry()) == -1) 188 return (-1); 189 190 ASSERT(VALID_GRANT_REF(ref)); 191 192 shared[ref].frame = frame; 193 shared[ref].domid = domid; 194 membar_producer(); 195 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 196 197 return (ref); 198 } 199 200 void 201 gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, 202 gnttab_frame_t frame, int readonly) 203 { 204 ASSERT(VALID_GRANT_REF(ref)); 205 206 shared[ref].frame = frame; 207 shared[ref].domid = domid; 208 membar_producer(); 209 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 210 } 211 212 213 int 214 gnttab_query_foreign_access(grant_ref_t ref) 215 { 216 uint16_t nflags; 217 218 ASSERT(VALID_GRANT_REF(ref)); 219 220 nflags = shared[ref].flags; 221 222 return (nflags & (GTF_reading|GTF_writing)); 223 } 224 225 /* ARGSUSED */ 226 int 227 gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) 228 { 229 uint16_t flags, nflags; 230 231 ASSERT(VALID_GRANT_REF(ref)); 232 233 nflags = shared[ref].flags; 234 do { 235 if ((flags = nflags) & (GTF_reading|GTF_writing)) { 236 cmn_err(CE_WARN, "g.e. still in use!"); 237 return (0); 238 } 239 } while ((nflags = cmpxchg(&shared[ref].flags, flags, 0)) != flags); 240 241 return (1); 242 } 243 244 void 245 gnttab_end_foreign_access(grant_ref_t ref, int readonly, gnttab_frame_t page) 246 { 247 ASSERT(VALID_GRANT_REF(ref)); 248 249 if (gnttab_end_foreign_access_ref(ref, readonly)) { 250 put_free_entry(ref); 251 /* 252 * XXPV - we don't support freeing a page here 253 */ 254 if (page != 0) { 255 cmn_err(CE_WARN, 256 "gnttab_end_foreign_access_ref: using unsupported free_page interface"); 257 /* free_page(page); */ 258 } 259 } else { 260 /* 261 * XXX This needs to be fixed so that the ref and page are 262 * placed on a list to be freed up later. 263 */ 264 cmn_err(CE_WARN, "leaking g.e. and page still in use!"); 265 } 266 } 267 268 int 269 gnttab_grant_foreign_transfer(domid_t domid) 270 { 271 int ref; 272 273 if ((ref = get_free_entry()) == -1) 274 return (-1); 275 276 ASSERT(VALID_GRANT_REF(ref)); 277 278 shared[ref].frame = 0; 279 shared[ref].domid = domid; 280 membar_producer(); 281 shared[ref].flags = GTF_accept_transfer; 282 283 return (ref); 284 } 285 286 void 287 gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid) 288 { 289 ASSERT(VALID_GRANT_REF(ref)); 290 291 shared[ref].frame = 0; 292 shared[ref].domid = domid; 293 membar_producer(); 294 shared[ref].flags = GTF_accept_transfer; 295 } 296 297 gnttab_frame_t 298 gnttab_end_foreign_transfer_ref(grant_ref_t ref) 299 { 300 gnttab_frame_t frame; 301 uint16_t flags; 302 303 ASSERT(VALID_GRANT_REF(ref)); 304 305 /* 306 * If a transfer is not even yet started, try to reclaim the grant 307 * reference and return failure (== 0). 308 */ 309 while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { 310 if (cmpxchg(&shared[ref].flags, flags, 0) == flags) 311 return (0); 312 (void) HYPERVISOR_yield(); 313 } 314 315 /* If a transfer is in progress then wait until it is completed. */ 316 while (!(flags & GTF_transfer_completed)) { 317 flags = shared[ref].flags; 318 (void) HYPERVISOR_yield(); 319 } 320 321 /* Read the frame number /after/ reading completion status. */ 322 membar_consumer(); 323 frame = shared[ref].frame; 324 ASSERT(frame != 0); 325 326 return (frame); 327 } 328 329 gnttab_frame_t 330 gnttab_end_foreign_transfer(grant_ref_t ref) 331 { 332 gnttab_frame_t frame; 333 334 ASSERT(VALID_GRANT_REF(ref)); 335 336 frame = gnttab_end_foreign_transfer_ref(ref); 337 put_free_entry(ref); 338 return (frame); 339 } 340 341 void 342 gnttab_free_grant_reference(grant_ref_t ref) 343 { 344 ASSERT(VALID_GRANT_REF(ref)); 345 346 put_free_entry(ref); 347 } 348 349 void 350 gnttab_free_grant_references(grant_ref_t head) 351 { 352 grant_ref_t ref; 353 int count = 1; 354 355 if (head == GNTTAB_LIST_END) 356 return; 357 mutex_enter(&gnttab_list_lock); 358 ref = head; 359 while (gnttab_list[ref] != GNTTAB_LIST_END) { 360 ref = gnttab_list[ref]; 361 count++; 362 } 363 gnttab_list[ref] = gnttab_free_head; 364 gnttab_free_head = head; 365 gnttab_free_count += count; 366 check_free_callbacks(); 367 mutex_exit(&gnttab_list_lock); 368 } 369 370 int 371 gnttab_alloc_grant_references(uint16_t count, grant_ref_t *head) 372 { 373 int h = get_free_entries(count); 374 375 if (h == -1) 376 return (-1); 377 378 *head = h; 379 380 return (0); 381 } 382 383 int 384 gnttab_claim_grant_reference(grant_ref_t *private_head) 385 { 386 grant_ref_t g = *private_head; 387 388 if (g == GNTTAB_LIST_END) 389 return (-1); 390 *private_head = gnttab_list[g]; 391 return (g); 392 } 393 394 void 395 gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release) 396 { 397 ASSERT(VALID_GRANT_REF(release)); 398 399 gnttab_list[release] = *private_head; 400 *private_head = release; 401 } 402 403 void 404 gnttab_request_free_callback(struct gnttab_free_callback *callback, 405 void (*fn)(void *), void *arg, uint16_t count) 406 { 407 mutex_enter(&gnttab_list_lock); 408 if (callback->next) 409 goto out; 410 callback->fn = fn; 411 callback->arg = arg; 412 callback->count = count; 413 callback->next = gnttab_free_callback_list; 414 gnttab_free_callback_list = callback; 415 check_free_callbacks(); 416 out: 417 mutex_exit(&gnttab_list_lock); 418 } 419 420 #ifdef XPV_HVM_DRIVER 421 422 static void 423 gnttab_map(void) 424 { 425 struct xen_add_to_physmap xatp; 426 caddr_t va; 427 pfn_t pfn; 428 int i; 429 430 va = (caddr_t)shared; 431 for (i = 0; i < NR_GRANT_FRAMES; i++) { 432 pfn = hat_getpfnum(kas.a_hat, va); 433 434 xatp.domid = DOMID_SELF; 435 xatp.idx = i; 436 xatp.space = XENMAPSPACE_grant_table; 437 xatp.gpfn = pfn; 438 hat_unload(kas.a_hat, va, MMU_PAGESIZE, HAT_UNLOAD); 439 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0) 440 panic("Couldn't map grant table"); 441 442 hat_devload(kas.a_hat, va, MMU_PAGESIZE, pfn, 443 PROT_READ | PROT_WRITE, 444 HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST); 445 446 va += MMU_PAGESIZE; 447 } 448 } 449 450 void 451 gnttab_init(void) 452 { 453 int i; 454 455 shared = (grant_entry_t *)xen_alloc_pages(NR_GRANT_FRAMES); 456 457 gnttab_map(); 458 459 for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++) 460 gnttab_list[i] = i + 1; 461 gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES; 462 gnttab_free_head = NR_RESERVED_ENTRIES; 463 464 mutex_init(&gnttab_list_lock, NULL, MUTEX_DEFAULT, NULL); 465 } 466 467 void 468 gnttab_resume(void) 469 { 470 gnttab_map(); 471 } 472 473 #else /* XPV_HVM_DRIVER */ 474 475 void 476 gnttab_init(void) 477 { 478 gnttab_setup_table_t set; 479 gnttab_frame_t frames[NR_GRANT_FRAMES]; 480 int i; 481 482 set.dom = DOMID_SELF; 483 set.nr_frames = NR_GRANT_FRAMES; 484 /*LINTED: constant in conditional context*/ 485 set_xen_guest_handle(set.frame_list, frames); 486 487 /* 488 * Take 4 pages of grant table space from the hypervisor and map it 489 */ 490 if ((HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &set, 1) != 0) || 491 (set.status != 0)) { 492 cmn_err(CE_PANIC, "Grant Table setup failed"); 493 } 494 495 shared = vmem_xalloc(heap_arena, NR_GRANT_FRAMES * MMU_PAGESIZE, 496 MMU_PAGESIZE, 0, 0, 0, 0, VM_SLEEP); 497 498 for (i = 0; i < NR_GRANT_FRAMES; i++) 499 kbm_map_ma(FRAME_TO_MA(frames[i]), GT_PGADDR(i), 0); 500 501 for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++) 502 gnttab_list[i] = i + 1; 503 gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES; 504 gnttab_free_head = NR_RESERVED_ENTRIES; 505 506 mutex_init(&gnttab_list_lock, NULL, MUTEX_DEFAULT, NULL); 507 } 508 509 void 510 gnttab_resume(void) 511 { 512 gnttab_setup_table_t set; 513 gnttab_frame_t frames[NR_GRANT_FRAMES]; 514 int i; 515 516 set.dom = DOMID_SELF; 517 set.nr_frames = NR_GRANT_FRAMES; 518 /*LINTED: constant in conditional context*/ 519 set_xen_guest_handle(set.frame_list, frames); 520 521 /* 522 * Take NR_GRANT_FRAMES pages of grant table space from the 523 * hypervisor and map it 524 */ 525 if ((HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &set, 1) != 0) || 526 (set.status != 0)) { 527 cmn_err(CE_PANIC, "Grant Table setup failed"); 528 } 529 530 for (i = 0; i < NR_GRANT_FRAMES; i++) { 531 (void) HYPERVISOR_update_va_mapping(GT_PGADDR(i), 532 FRAME_TO_MA(frames[i]) | PT_VALID | PT_WRITABLE, 533 UVMF_INVLPG | UVMF_ALL); 534 } 535 } 536 537 #endif /* XPV_HVM_DRIVER */ 538 539 void 540 gnttab_suspend(void) 541 { 542 int i; 543 544 /* 545 * clear grant table mappings before suspending 546 */ 547 for (i = 0; i < NR_GRANT_FRAMES; i++) { 548 (void) HYPERVISOR_update_va_mapping(GT_PGADDR(i), 549 0, UVMF_INVLPG); 550 } 551 } 552 553 /* 554 * Local variables: 555 * c-file-style: "solaris" 556 * indent-tabs-mode: t 557 * c-indent-level: 8 558 * c-basic-offset: 8 559 * tab-width: 8 560 * End: 561 */ 562