1/* 2 * Copyright (c) 2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * Shared region (... and comm page) 26 * 27 * This file handles the VM shared region and comm page. 28 * 29 */ 30/* 31 * SHARED REGIONS 32 * -------------- 33 * 34 * A shared region is a submap that contains the most common system shared 35 * libraries for a given environment. 36 * An environment is defined by (cpu-type, 64-bitness, root directory). 37 * 38 * The point of a shared region is to reduce the setup overhead when exec'ing 39 * a new process. 40 * A shared region uses a shared VM submap that gets mapped automatically 41 * at exec() time (see vm_map_exec()). The first process of a given 42 * environment sets up the shared region and all further processes in that 43 * environment can re-use that shared region without having to re-create 44 * the same mappings in their VM map. All they need is contained in the shared 45 * region. 46 * It can also shared a pmap (mostly for read-only parts but also for the 47 * initial version of some writable parts), which gets "nested" into the 48 * process's pmap. This reduces the number of soft faults: once one process 49 * brings in a page in the shared region, all the other processes can access 50 * it without having to enter it in their own pmap. 51 * 52 * 53 * When a process is being exec'ed, vm_map_exec() calls vm_shared_region_enter() 54 * to map the appropriate shared region in the process's address space. 55 * We look up the appropriate shared region for the process's environment. 56 * If we can't find one, we create a new (empty) one and add it to the list. 57 * Otherwise, we just take an extra reference on the shared region we found. 58 * 59 * The "dyld" runtime (mapped into the process's address space at exec() time) 60 * will then use the shared_region_check_np() and shared_region_map_np() 61 * system call to validate and/or populate the shared region with the 62 * appropriate dyld_shared_cache file. 63 * 64 * The shared region is inherited on fork() and the child simply takes an 65 * extra reference on its parent's shared region. 66 * 67 * When the task terminates, we release a reference on its shared region. 68 * When the last reference is released, we destroy the shared region. 69 * 70 * After a chroot(), the calling process keeps using its original shared region, 71 * since that's what was mapped when it was started. But its children 72 * will use a different shared region, because they need to use the shared 73 * cache that's relative to the new root directory. 74 */ 75/* 76 * COMM PAGE 77 * 78 * A "comm page" is an area of memory that is populated by the kernel with 79 * the appropriate platform-specific version of some commonly used code. 80 * There is one "comm page" per platform (cpu-type, 64-bitness) but only 81 * for the native cpu-type. No need to overly optimize translated code 82 * for hardware that is not really there ! 83 * 84 * The comm pages are created and populated at boot time. 85 * 86 * The appropriate comm page is mapped into a process's address space 87 * at exec() time, in vm_map_exec(). 88 * It is then inherited on fork(). 89 * 90 * The comm page is shared between the kernel and all applications of 91 * a given platform. Only the kernel can modify it. 92 * 93 * Applications just branch to fixed addresses in the comm page and find 94 * the right version of the code for the platform. There is also some 95 * data provided and updated by the kernel for processes to retrieve easily 96 * without having to do a system call. 97 */ 98 99#include <debug.h> 100 101#include <kern/ipc_tt.h> 102#include <kern/kalloc.h> 103 104#include <mach/mach_vm.h> 105 106#include <vm/vm_map.h> 107#include <vm/vm_shared_region.h> 108 109#include <vm/vm_protos.h> 110 111#include <machine/commpage.h> 112#include <machine/cpu_capabilities.h> 113 114/* "dyld" uses this to figure out what the kernel supports */ 115int shared_region_version = 3; 116 117/* should local (non-chroot) shared regions persist when no task uses them ? */ 118int shared_region_persistence = 1; /* yes by default */ 119 120/* trace level, output is sent to the system log file */ 121int shared_region_trace_level = SHARED_REGION_TRACE_ERROR_LVL; 122 123/* this lock protects all the shared region data structures */ 124lck_grp_t *vm_shared_region_lck_grp; 125lck_mtx_t vm_shared_region_lock; 126 127#define vm_shared_region_lock() lck_mtx_lock(&vm_shared_region_lock) 128#define vm_shared_region_unlock() lck_mtx_unlock(&vm_shared_region_lock) 129#define vm_shared_region_sleep(event, interruptible) \ 130 lck_mtx_sleep(&vm_shared_region_lock, \ 131 LCK_SLEEP_DEFAULT, \ 132 (event_t) (event), \ 133 (interruptible)) 134 135/* the list of currently available shared regions (one per environment) */ 136queue_head_t vm_shared_region_queue; 137 138static void vm_shared_region_reference_locked(vm_shared_region_t shared_region); 139static vm_shared_region_t vm_shared_region_create( 140 void *root_dir, 141 cpu_type_t cputype, 142 boolean_t is_64bit); 143static void vm_shared_region_destroy(vm_shared_region_t shared_region); 144 145/* 146 * Initialize the module... 147 */ 148void 149vm_shared_region_init(void) 150{ 151 SHARED_REGION_TRACE_DEBUG( 152 ("shared_region: -> init\n")); 153 154 vm_shared_region_lck_grp = lck_grp_alloc_init("vm shared region", 155 LCK_GRP_ATTR_NULL); 156 lck_mtx_init(&vm_shared_region_lock, 157 vm_shared_region_lck_grp, 158 LCK_ATTR_NULL); 159 160 queue_init(&vm_shared_region_queue); 161 162 SHARED_REGION_TRACE_DEBUG( 163 ("shared_region: <- init\n")); 164} 165 166/* 167 * Retrieve a task's shared region and grab an extra reference to 168 * make sure it doesn't disappear while the caller is using it. 169 * The caller is responsible for consuming that extra reference if 170 * necessary. 171 */ 172vm_shared_region_t 173vm_shared_region_get( 174 task_t task) 175{ 176 vm_shared_region_t shared_region; 177 178 SHARED_REGION_TRACE_DEBUG( 179 ("shared_region: -> get(%p)\n", 180 task)); 181 182 task_lock(task); 183 vm_shared_region_lock(); 184 shared_region = task->shared_region; 185 if (shared_region) { 186 assert(shared_region->sr_ref_count > 0); 187 vm_shared_region_reference_locked(shared_region); 188 } 189 vm_shared_region_unlock(); 190 task_unlock(task); 191 192 SHARED_REGION_TRACE_DEBUG( 193 ("shared_region: get(%p) <- %p\n", 194 task, shared_region)); 195 196 return shared_region; 197} 198 199/* 200 * Get the base address of the shared region. 201 * That's the address at which it needs to be mapped in the process's address 202 * space. 203 * No need to lock since this data is set when the shared region is 204 * created and is never modified after that. The caller must hold an extra 205 * reference on the shared region to prevent it from being destroyed. 206 */ 207mach_vm_offset_t 208vm_shared_region_base_address( 209 vm_shared_region_t shared_region) 210{ 211 SHARED_REGION_TRACE_DEBUG( 212 ("shared_region: -> base_address(%p)\n", 213 shared_region)); 214 assert(shared_region->sr_ref_count > 1); 215 SHARED_REGION_TRACE_DEBUG( 216 ("shared_region: base_address(%p) <- 0x%llx\n", 217 shared_region, (long long)shared_region->sr_base_address)); 218 return shared_region->sr_base_address; 219} 220 221/* 222 * Get the size of the shared region. 223 * That's the size that needs to be mapped in the process's address 224 * space. 225 * No need to lock since this data is set when the shared region is 226 * created and is never modified after that. The caller must hold an extra 227 * reference on the shared region to prevent it from being destroyed. 228 */ 229mach_vm_size_t 230vm_shared_region_size( 231 vm_shared_region_t shared_region) 232{ 233 SHARED_REGION_TRACE_DEBUG( 234 ("shared_region: -> size(%p)\n", 235 shared_region)); 236 assert(shared_region->sr_ref_count > 1); 237 SHARED_REGION_TRACE_DEBUG( 238 ("shared_region: size(%p) <- 0x%llx\n", 239 shared_region, (long long)shared_region->sr_size)); 240 return shared_region->sr_size; 241} 242 243/* 244 * Get the memory entry of the shared region. 245 * That's the "memory object" that needs to be mapped in the process's address 246 * space. 247 * No need to lock since this data is set when the shared region is 248 * created and is never modified after that. The caller must hold an extra 249 * reference on the shared region to prevent it from being destroyed. 250 */ 251ipc_port_t 252vm_shared_region_mem_entry( 253 vm_shared_region_t shared_region) 254{ 255 SHARED_REGION_TRACE_DEBUG( 256 ("shared_region: -> mem_entry(%p)\n", 257 shared_region)); 258 assert(shared_region->sr_ref_count > 1); 259 SHARED_REGION_TRACE_DEBUG( 260 ("shared_region: mem_entry(%p) <- %p\n", 261 shared_region, shared_region->sr_mem_entry)); 262 return shared_region->sr_mem_entry; 263} 264 265/* 266 * Set the shared region the process should use. 267 * A NULL new shared region means that we just want to release the old 268 * shared region. 269 * The caller should already have an extra reference on the new shared region 270 * (if any). We release a reference on the old shared region (if any). 271 */ 272void 273vm_shared_region_set( 274 task_t task, 275 vm_shared_region_t new_shared_region) 276{ 277 vm_shared_region_t old_shared_region; 278 279 SHARED_REGION_TRACE_DEBUG( 280 ("shared_region: -> set(%p, %p)\n", 281 task, new_shared_region)); 282 283 task_lock(task); 284 vm_shared_region_lock(); 285 286 old_shared_region = task->shared_region; 287 if (new_shared_region) { 288 assert(new_shared_region->sr_ref_count > 0); 289 } 290 291 task->shared_region = new_shared_region; 292 293 vm_shared_region_unlock(); 294 task_unlock(task); 295 296 if (old_shared_region) { 297 assert(old_shared_region->sr_ref_count > 0); 298 vm_shared_region_deallocate(old_shared_region); 299 } 300 301 SHARED_REGION_TRACE_DEBUG( 302 ("shared_region: set(%p) <- old=%p new=%p\n", 303 task, old_shared_region, new_shared_region)); 304} 305 306/* 307 * Lookup up the shared region for the desired environment. 308 * If none is found, create a new (empty) one. 309 * Grab an extra reference on the returned shared region, to make sure 310 * it doesn't get destroyed before the caller is done with it. The caller 311 * is responsible for consuming that extra reference if necessary. 312 */ 313vm_shared_region_t 314vm_shared_region_lookup( 315 void *root_dir, 316 cpu_type_t cputype, 317 boolean_t is_64bit) 318{ 319 vm_shared_region_t shared_region; 320 vm_shared_region_t new_shared_region; 321 322 SHARED_REGION_TRACE_DEBUG( 323 ("shared_region: -> lookup(root=%p,cpu=%d,64bit=%d)\n", 324 root_dir, cputype, is_64bit)); 325 326 shared_region = NULL; 327 new_shared_region = NULL; 328 329 vm_shared_region_lock(); 330 for (;;) { 331 queue_iterate(&vm_shared_region_queue, 332 shared_region, 333 vm_shared_region_t, 334 sr_q) { 335 assert(shared_region->sr_ref_count > 0); 336 if (shared_region->sr_cpu_type == cputype && 337 shared_region->sr_root_dir == root_dir && 338 shared_region->sr_64bit == is_64bit) { 339 /* found a match ! */ 340 vm_shared_region_reference_locked(shared_region); 341 goto done; 342 } 343 } 344 if (new_shared_region == NULL) { 345 /* no match: create a new one */ 346 vm_shared_region_unlock(); 347 new_shared_region = vm_shared_region_create(root_dir, 348 cputype, 349 is_64bit); 350 /* do the lookup again, in case we lost a race */ 351 vm_shared_region_lock(); 352 continue; 353 } 354 /* still no match: use our new one */ 355 shared_region = new_shared_region; 356 new_shared_region = NULL; 357 queue_enter(&vm_shared_region_queue, 358 shared_region, 359 vm_shared_region_t, 360 sr_q); 361 break; 362 } 363 364done: 365 vm_shared_region_unlock(); 366 367 if (new_shared_region) { 368 /* 369 * We lost a race with someone else to create a new shared 370 * region for that environment. Get rid of our unused one. 371 */ 372 assert(new_shared_region->sr_ref_count == 1); 373 new_shared_region->sr_ref_count--; 374 vm_shared_region_destroy(new_shared_region); 375 new_shared_region = NULL; 376 } 377 378 SHARED_REGION_TRACE_DEBUG( 379 ("shared_region: lookup(root=%p,cpu=%d,64bit=%d) <- %p\n", 380 root_dir, cputype, is_64bit, shared_region)); 381 382 assert(shared_region->sr_ref_count > 0); 383 return shared_region; 384} 385 386/* 387 * Take an extra reference on a shared region. 388 * The vm_shared_region_lock should already be held by the caller. 389 */ 390static void 391vm_shared_region_reference_locked( 392 vm_shared_region_t shared_region) 393{ 394#if DEBUG 395 lck_mtx_assert(&vm_shared_region_lock, LCK_MTX_ASSERT_OWNED); 396#endif 397 398 SHARED_REGION_TRACE_DEBUG( 399 ("shared_region: -> reference_locked(%p)\n", 400 shared_region)); 401 assert(shared_region->sr_ref_count > 0); 402 shared_region->sr_ref_count++; 403 SHARED_REGION_TRACE_DEBUG( 404 ("shared_region: reference_locked(%p) <- %d\n", 405 shared_region, shared_region->sr_ref_count)); 406} 407 408/* 409 * Release a reference on the shared region. 410 * Destroy it if there are no references left. 411 */ 412void 413vm_shared_region_deallocate( 414 vm_shared_region_t shared_region) 415{ 416 SHARED_REGION_TRACE_DEBUG( 417 ("shared_region: -> deallocate(%p)\n", 418 shared_region)); 419 420 vm_shared_region_lock(); 421 422 assert(shared_region->sr_ref_count > 0); 423 424 if (shared_region->sr_root_dir == NULL) { 425 /* 426 * Local (i.e. based on the boot volume) shared regions 427 * can persist or not based on the "shared_region_persistence" 428 * sysctl. 429 * Make sure that this one complies. 430 */ 431 if (shared_region_persistence && 432 !shared_region->sr_persists) { 433 /* make this one persistent */ 434 shared_region->sr_ref_count++; 435 shared_region->sr_persists = TRUE; 436 } else if (!shared_region_persistence && 437 shared_region->sr_persists) { 438 /* make this one no longer persistent */ 439 assert(shared_region->sr_ref_count > 1); 440 shared_region->sr_ref_count--; 441 shared_region->sr_persists = FALSE; 442 } 443 } 444 445 assert(shared_region->sr_ref_count > 0); 446 shared_region->sr_ref_count--; 447 SHARED_REGION_TRACE_DEBUG( 448 ("shared_region: deallocate(%p): ref now %d\n", 449 shared_region, shared_region->sr_ref_count)); 450 451 if (shared_region->sr_ref_count == 0) { 452 assert(! shared_region->sr_mapping_in_progress); 453 /* remove it from the queue first, so no one can find it... */ 454 queue_remove(&vm_shared_region_queue, 455 shared_region, 456 vm_shared_region_t, 457 sr_q); 458 vm_shared_region_unlock(); 459 /* ... and destroy it */ 460 vm_shared_region_destroy(shared_region); 461 shared_region = NULL; 462 } else { 463 vm_shared_region_unlock(); 464 } 465 466 SHARED_REGION_TRACE_DEBUG( 467 ("shared_region: deallocate(%p) <-\n", 468 shared_region)); 469} 470 471/* 472 * Create a new (empty) shared region for a new environment. 473 */ 474static vm_shared_region_t 475vm_shared_region_create( 476 void *root_dir, 477 cpu_type_t cputype, 478 boolean_t is_64bit) 479{ 480 kern_return_t kr; 481 vm_named_entry_t mem_entry; 482 ipc_port_t mem_entry_port; 483 vm_shared_region_t shared_region; 484 vm_map_t sub_map; 485 mach_vm_offset_t base_address, pmap_nesting_start; 486 mach_vm_size_t size, pmap_nesting_size; 487 488 SHARED_REGION_TRACE_DEBUG( 489 ("shared_region: -> create(root=%p,cpu=%d,64bit=%d)\n", 490 root_dir, cputype, is_64bit)); 491 492 base_address = 0; 493 size = 0; 494 mem_entry = NULL; 495 mem_entry_port = IPC_PORT_NULL; 496 sub_map = VM_MAP_NULL; 497 498 /* create a new shared region structure... */ 499 shared_region = kalloc(sizeof (*shared_region)); 500 if (shared_region == NULL) { 501 SHARED_REGION_TRACE_ERROR( 502 ("shared_region: create: couldn't allocate\n")); 503 goto done; 504 } 505 506 /* figure out the correct settings for the desired environment */ 507 if (is_64bit) { 508 switch (cputype) { 509 case CPU_TYPE_I386: 510 base_address = SHARED_REGION_BASE_X86_64; 511 size = SHARED_REGION_SIZE_X86_64; 512 pmap_nesting_start = SHARED_REGION_NESTING_BASE_X86_64; 513 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_X86_64; 514 break; 515 case CPU_TYPE_POWERPC: 516 base_address = SHARED_REGION_BASE_PPC64; 517 size = SHARED_REGION_SIZE_PPC64; 518 pmap_nesting_start = SHARED_REGION_NESTING_BASE_PPC64; 519 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_PPC64; 520 break; 521 default: 522 SHARED_REGION_TRACE_ERROR( 523 ("shared_region: create: unknown cpu type %d\n", 524 cputype)); 525 kfree(shared_region, sizeof (*shared_region)); 526 shared_region = NULL; 527 goto done; 528 } 529 } else { 530 switch (cputype) { 531 case CPU_TYPE_I386: 532 base_address = SHARED_REGION_BASE_I386; 533 size = SHARED_REGION_SIZE_I386; 534 pmap_nesting_start = SHARED_REGION_NESTING_BASE_I386; 535 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_I386; 536 break; 537 case CPU_TYPE_POWERPC: 538 base_address = SHARED_REGION_BASE_PPC; 539 size = SHARED_REGION_SIZE_PPC; 540 pmap_nesting_start = SHARED_REGION_NESTING_BASE_PPC; 541 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_PPC; 542 break; 543#ifdef CPU_TYPE_ARM 544 case CPU_TYPE_ARM: 545 base_address = SHARED_REGION_BASE_ARM; 546 size = SHARED_REGION_SIZE_ARM; 547 pmap_nesting_start = SHARED_REGION_NESTING_BASE_ARM; 548 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_ARM; 549 break; 550#endif /* CPU_TYPE_ARM */ 551 default: 552 SHARED_REGION_TRACE_ERROR( 553 ("shared_region: create: unknown cpu type %d\n", 554 cputype)); 555 kfree(shared_region, sizeof (*shared_region)); 556 shared_region = NULL; 557 goto done; 558 559 } 560 } 561 562 /* create a memory entry structure and a Mach port handle */ 563 kr = mach_memory_entry_allocate(&mem_entry, 564 &mem_entry_port); 565 if (kr != KERN_SUCCESS) { 566 kfree(shared_region, sizeof (*shared_region)); 567 shared_region = NULL; 568 SHARED_REGION_TRACE_ERROR( 569 ("shared_region: create: " 570 "couldn't allocate mem_entry\n")); 571 goto done; 572 } 573 574 /* create a VM sub map and its pmap */ 575 sub_map = vm_map_create(pmap_create(0, is_64bit), 576 0, size, 577 TRUE); 578 if (sub_map == VM_MAP_NULL) { 579 ipc_port_release_send(mem_entry_port); 580 kfree(shared_region, sizeof (*shared_region)); 581 shared_region = NULL; 582 SHARED_REGION_TRACE_ERROR( 583 ("shared_region: create: " 584 "couldn't allocate map\n")); 585 goto done; 586 } 587 588 /* make the memory entry point to the VM sub map */ 589 mem_entry->is_sub_map = TRUE; 590 mem_entry->backing.map = sub_map; 591 mem_entry->size = size; 592 mem_entry->protection = VM_PROT_ALL; 593 594 /* make the shared region point at the memory entry */ 595 shared_region->sr_mem_entry = mem_entry_port; 596 597 /* fill in the shared region's environment and settings */ 598 shared_region->sr_base_address = base_address; 599 shared_region->sr_size = size; 600 shared_region->sr_pmap_nesting_start = pmap_nesting_start; 601 shared_region->sr_pmap_nesting_size = pmap_nesting_size; 602 shared_region->sr_cpu_type = cputype; 603 shared_region->sr_64bit = is_64bit; 604 shared_region->sr_root_dir = root_dir; 605 606 queue_init(&shared_region->sr_q); 607 shared_region->sr_mapping_in_progress = FALSE; 608 shared_region->sr_persists = FALSE; 609 shared_region->sr_first_mapping = (mach_vm_offset_t) -1; 610 611 /* grab a reference for the caller */ 612 shared_region->sr_ref_count = 1; 613 614done: 615 if (shared_region) { 616 SHARED_REGION_TRACE_INFO( 617 ("shared_region: create(root=%p,cpu=%d,64bit=%d," 618 "base=0x%llx,size=0x%llx) <- " 619 "%p mem=(%p,%p) map=%p pmap=%p\n", 620 root_dir, cputype, is_64bit, (long long)base_address, 621 (long long)size, shared_region, 622 mem_entry_port, mem_entry, sub_map, sub_map->pmap)); 623 } else { 624 SHARED_REGION_TRACE_INFO( 625 ("shared_region: create(root=%p,cpu=%d,64bit=%d," 626 "base=0x%llx,size=0x%llx) <- NULL", 627 root_dir, cputype, is_64bit, (long long)base_address, 628 (long long)size)); 629 } 630 return shared_region; 631} 632 633/* 634 * Destroy a now-unused shared region. 635 * The shared region is no longer in the queue and can not be looked up. 636 */ 637static void 638vm_shared_region_destroy( 639 vm_shared_region_t shared_region) 640{ 641 vm_named_entry_t mem_entry; 642 vm_map_t map; 643 644 SHARED_REGION_TRACE_INFO( 645 ("shared_region: -> destroy(%p) (root=%p,cpu=%d,64bit=%d)\n", 646 shared_region, 647 shared_region->sr_root_dir, 648 shared_region->sr_cpu_type, 649 shared_region->sr_64bit)); 650 651 assert(shared_region->sr_ref_count == 0); 652 assert(!shared_region->sr_persists); 653 654 mem_entry = (vm_named_entry_t) shared_region->sr_mem_entry->ip_kobject; 655 assert(mem_entry->is_sub_map); 656 assert(!mem_entry->internal); 657 assert(!mem_entry->is_pager); 658 map = mem_entry->backing.map; 659 660 /* 661 * Clean up the pmap first. The virtual addresses that were 662 * entered in this possibly "nested" pmap may have different values 663 * than the VM map's min and max offsets, if the VM sub map was 664 * mapped at a non-zero offset in the processes' main VM maps, which 665 * is usually the case, so the clean-up we do in vm_map_destroy() would 666 * not be enough. 667 */ 668 if (map->pmap) { 669 pmap_remove(map->pmap, 670 shared_region->sr_base_address, 671 (shared_region->sr_base_address + 672 shared_region->sr_size)); 673 } 674 675 /* 676 * Release our (one and only) handle on the memory entry. 677 * This will generate a no-senders notification, which will be processed 678 * by ipc_kobject_notify(), which will release the one and only 679 * reference on the memory entry and cause it to be destroyed, along 680 * with the VM sub map and its pmap. 681 */ 682 mach_memory_entry_port_release(shared_region->sr_mem_entry); 683 mem_entry = NULL; 684 shared_region->sr_mem_entry = IPC_PORT_NULL; 685 686 /* release the shared region structure... */ 687 kfree(shared_region, sizeof (*shared_region)); 688 SHARED_REGION_TRACE_DEBUG( 689 ("shared_region: destroy(%p) <-\n", 690 shared_region)); 691 shared_region = NULL; 692 693} 694 695/* 696 * Gets the address of the first (in time) mapping in the shared region. 697 */ 698kern_return_t 699vm_shared_region_start_address( 700 vm_shared_region_t shared_region, 701 mach_vm_offset_t *start_address) 702{ 703 kern_return_t kr; 704 mach_vm_offset_t sr_base_address; 705 mach_vm_offset_t sr_first_mapping; 706 707 SHARED_REGION_TRACE_DEBUG( 708 ("shared_region: -> start_address(%p)\n", 709 shared_region)); 710 assert(shared_region->sr_ref_count > 1); 711 712 vm_shared_region_lock(); 713 714 /* 715 * Wait if there's another thread establishing a mapping 716 * in this shared region right when we're looking at it. 717 * We want a consistent view of the map... 718 */ 719 while (shared_region->sr_mapping_in_progress) { 720 /* wait for our turn... */ 721 assert(shared_region->sr_ref_count > 1); 722 vm_shared_region_sleep(&shared_region->sr_mapping_in_progress, 723 THREAD_UNINT); 724 } 725 assert(! shared_region->sr_mapping_in_progress); 726 assert(shared_region->sr_ref_count > 1); 727 728 sr_base_address = shared_region->sr_base_address; 729 sr_first_mapping = shared_region->sr_first_mapping; 730 731 if (sr_first_mapping == (mach_vm_offset_t) -1) { 732 /* shared region is empty */ 733 kr = KERN_INVALID_ADDRESS; 734 } else { 735 kr = KERN_SUCCESS; 736 *start_address = sr_base_address + sr_first_mapping; 737 } 738 739 vm_shared_region_unlock(); 740 741 SHARED_REGION_TRACE_DEBUG( 742 ("shared_region: start_address(%p) <- 0x%llx\n", 743 shared_region, (long long)shared_region->sr_base_address)); 744 745 return kr; 746} 747/* 748 * Establish some mappings of a file in the shared region. 749 * This is used by "dyld" via the shared_region_map_np() system call 750 * to populate the shared region with the appropriate shared cache. 751 * 752 * One could also call it several times to incrementally load several 753 * libraries, as long as they do not overlap. 754 * It will return KERN_SUCCESS if the mappings were successfully established 755 * or if they were already established identically by another process. 756 */ 757kern_return_t 758vm_shared_region_map_file( 759 vm_shared_region_t shared_region, 760 unsigned int mappings_count, 761 struct shared_file_mapping_np *mappings, 762 memory_object_control_t file_control, 763 memory_object_size_t file_size, 764 void *root_dir) 765{ 766 kern_return_t kr; 767 vm_object_t file_object; 768 ipc_port_t sr_handle; 769 vm_named_entry_t sr_mem_entry; 770 vm_map_t sr_map; 771 mach_vm_offset_t sr_base_address; 772 unsigned int i; 773 mach_port_t map_port; 774 mach_vm_offset_t target_address; 775 vm_object_t object; 776 vm_object_size_t obj_size; 777 778 779 kr = KERN_SUCCESS; 780 781 vm_shared_region_lock(); 782 assert(shared_region->sr_ref_count > 1); 783 784 if (shared_region->sr_root_dir != root_dir) { 785 /* 786 * This shared region doesn't match the current root 787 * directory of this process. Deny the mapping to 788 * avoid tainting the shared region with something that 789 * doesn't quite belong into it. 790 */ 791 vm_shared_region_unlock(); 792 kr = KERN_PROTECTION_FAILURE; 793 goto done; 794 } 795 796 /* 797 * Make sure we handle only one mapping at a time in a given 798 * shared region, to avoid race conditions. This should not 799 * happen frequently... 800 */ 801 while (shared_region->sr_mapping_in_progress) { 802 /* wait for our turn... */ 803 vm_shared_region_sleep(&shared_region->sr_mapping_in_progress, 804 THREAD_UNINT); 805 } 806 assert(! shared_region->sr_mapping_in_progress); 807 assert(shared_region->sr_ref_count > 1); 808 /* let others know we're working in this shared region */ 809 shared_region->sr_mapping_in_progress = TRUE; 810 811 vm_shared_region_unlock(); 812 813 /* no need to lock because this data is never modified... */ 814 sr_handle = shared_region->sr_mem_entry; 815 sr_mem_entry = (vm_named_entry_t) sr_handle->ip_kobject; 816 sr_map = sr_mem_entry->backing.map; 817 sr_base_address = shared_region->sr_base_address; 818 819 SHARED_REGION_TRACE_DEBUG( 820 ("shared_region: -> map(%p,%d,%p,%p,0x%llx)\n", 821 shared_region, mappings_count, mappings, 822 file_control, file_size)); 823 824 /* get the VM object associated with the file to be mapped */ 825 file_object = memory_object_control_to_vm_object(file_control); 826 827 /* establish the mappings */ 828 for (i = 0; i < mappings_count; i++) { 829 SHARED_REGION_TRACE_INFO( 830 ("shared_region: mapping[%d]: " 831 "address:0x%016llx size:0x%016llx offset:0x%016llx " 832 "maxprot:0x%x prot:0x%x\n", 833 i, 834 (long long)mappings[i].sfm_address, 835 (long long)mappings[i].sfm_size, 836 (long long)mappings[i].sfm_file_offset, 837 mappings[i].sfm_max_prot, 838 mappings[i].sfm_init_prot)); 839 840 if (mappings[i].sfm_init_prot & VM_PROT_ZF) { 841 /* zero-filled memory */ 842 map_port = MACH_PORT_NULL; 843 } else { 844 /* file-backed memory */ 845 map_port = (ipc_port_t) file_object->pager; 846 } 847 848 /* mapping's address is relative to the shared region base */ 849 target_address = 850 mappings[i].sfm_address - sr_base_address; 851 852 /* establish that mapping, OK if it's "already" there */ 853 if (map_port == MACH_PORT_NULL) { 854 /* 855 * We want to map some anonymous memory in a 856 * shared region. 857 * We have to create the VM object now, so that it 858 * can be mapped "copy-on-write". 859 */ 860 obj_size = vm_map_round_page(mappings[i].sfm_size); 861 object = vm_object_allocate(obj_size); 862 if (object == VM_OBJECT_NULL) { 863 kr = KERN_RESOURCE_SHORTAGE; 864 } else { 865 kr = vm_map_enter( 866 sr_map, 867 &target_address, 868 vm_map_round_page(mappings[i].sfm_size), 869 0, 870 VM_FLAGS_FIXED | VM_FLAGS_ALREADY, 871 object, 872 0, 873 TRUE, 874 mappings[i].sfm_init_prot & VM_PROT_ALL, 875 mappings[i].sfm_max_prot & VM_PROT_ALL, 876 VM_INHERIT_DEFAULT); 877 } 878 } else { 879 object = VM_OBJECT_NULL; /* no anonymous memory here */ 880 kr = vm_map_enter_mem_object( 881 sr_map, 882 &target_address, 883 vm_map_round_page(mappings[i].sfm_size), 884 0, 885 VM_FLAGS_FIXED | VM_FLAGS_ALREADY, 886 map_port, 887 mappings[i].sfm_file_offset, 888 TRUE, 889 mappings[i].sfm_init_prot & VM_PROT_ALL, 890 mappings[i].sfm_max_prot & VM_PROT_ALL, 891 VM_INHERIT_DEFAULT); 892 } 893 894 if (kr != KERN_SUCCESS) { 895 if (map_port == MACH_PORT_NULL) { 896 /* 897 * Get rid of the VM object we just created 898 * but failed to map. 899 */ 900 vm_object_deallocate(object); 901 object = VM_OBJECT_NULL; 902 } 903 if (kr == KERN_MEMORY_PRESENT) { 904 /* 905 * This exact mapping was already there: 906 * that's fine. 907 */ 908 SHARED_REGION_TRACE_INFO( 909 ("shared_region: mapping[%d]: " 910 "address:0x%016llx size:0x%016llx " 911 "offset:0x%016llx " 912 "maxprot:0x%x prot:0x%x " 913 "already mapped...\n", 914 i, 915 (long long)mappings[i].sfm_address, 916 (long long)mappings[i].sfm_size, 917 (long long)mappings[i].sfm_file_offset, 918 mappings[i].sfm_max_prot, 919 mappings[i].sfm_init_prot)); 920 /* 921 * We didn't establish this mapping ourselves; 922 * let's reset its size, so that we do not 923 * attempt to undo it if an error occurs later. 924 */ 925 mappings[i].sfm_size = 0; 926 kr = KERN_SUCCESS; 927 } else { 928 unsigned int j; 929 930 /* this mapping failed ! */ 931 SHARED_REGION_TRACE_ERROR( 932 ("shared_region: mapping[%d]: " 933 "address:0x%016llx size:0x%016llx " 934 "offset:0x%016llx " 935 "maxprot:0x%x prot:0x%x failed 0x%x\n", 936 i, 937 (long long)mappings[i].sfm_address, 938 (long long)mappings[i].sfm_size, 939 (long long)mappings[i].sfm_file_offset, 940 mappings[i].sfm_max_prot, 941 mappings[i].sfm_init_prot, 942 kr)); 943 944 /* 945 * Undo the mappings we've established so far. 946 */ 947 for (j = 0; j < i; j++) { 948 kern_return_t kr2; 949 950 if (mappings[j].sfm_size == 0) { 951 /* 952 * We didn't establish this 953 * mapping, so nothing to undo. 954 */ 955 continue; 956 } 957 SHARED_REGION_TRACE_INFO( 958 ("shared_region: mapping[%d]: " 959 "address:0x%016llx " 960 "size:0x%016llx " 961 "offset:0x%016llx " 962 "maxprot:0x%x prot:0x%x: " 963 "undoing...\n", 964 j, 965 (long long)mappings[j].sfm_address, 966 (long long)mappings[j].sfm_size, 967 (long long)mappings[j].sfm_file_offset, 968 mappings[j].sfm_max_prot, 969 mappings[j].sfm_init_prot)); 970 kr2 = mach_vm_deallocate( 971 sr_map, 972 (mappings[j].sfm_address - 973 sr_base_address), 974 mappings[j].sfm_size); 975 assert(kr2 == KERN_SUCCESS); 976 } 977 978 break; 979 } 980 981 } 982 983 /* 984 * Record the first (chronologically) mapping in 985 * this shared region. 986 * We're protected by "sr_mapping_in_progress" here, 987 * so no need to lock "shared_region". 988 */ 989 if (shared_region->sr_first_mapping == (mach_vm_offset_t) -1) { 990 shared_region->sr_first_mapping = target_address; 991 } 992 } 993 994 vm_shared_region_lock(); 995 assert(shared_region->sr_ref_count > 1); 996 assert(shared_region->sr_mapping_in_progress); 997 /* we're done working on that shared region */ 998 shared_region->sr_mapping_in_progress = FALSE; 999 thread_wakeup((event_t) &shared_region->sr_mapping_in_progress); 1000 vm_shared_region_unlock(); 1001 1002done: 1003 SHARED_REGION_TRACE_DEBUG( 1004 ("shared_region: map(%p,%d,%p,%p,0x%llx) <- 0x%x \n", 1005 shared_region, mappings_count, mappings, 1006 file_control, file_size, kr)); 1007 return kr; 1008} 1009 1010/* 1011 * Enter the appropriate shared region into "map" for "task". 1012 * This involves looking up the shared region (and possibly creating a new 1013 * one) for the desired environment, then mapping the VM sub map into the 1014 * task's VM "map", with the appropriate level of pmap-nesting. 1015 */ 1016kern_return_t 1017vm_shared_region_enter( 1018 struct _vm_map *map, 1019 struct task *task, 1020 void *fsroot, 1021 cpu_type_t cpu) 1022{ 1023 kern_return_t kr; 1024 vm_shared_region_t shared_region; 1025 vm_map_offset_t sr_address, sr_offset, target_address; 1026 vm_map_size_t sr_size, mapping_size; 1027 vm_map_offset_t sr_pmap_nesting_start; 1028 vm_map_size_t sr_pmap_nesting_size; 1029 ipc_port_t sr_handle; 1030 boolean_t is_64bit; 1031 1032 is_64bit = task_has_64BitAddr(task); 1033 1034 SHARED_REGION_TRACE_DEBUG( 1035 ("shared_region: -> " 1036 "enter(map=%p,task=%p,root=%p,cpu=%d,64bit=%d)\n", 1037 map, task, fsroot, cpu, is_64bit)); 1038 1039 /* lookup (create if needed) the shared region for this environment */ 1040 shared_region = vm_shared_region_lookup(fsroot, cpu, is_64bit); 1041 if (shared_region == NULL) { 1042 /* this should not happen ! */ 1043 SHARED_REGION_TRACE_ERROR( 1044 ("shared_region: -> " 1045 "enter(map=%p,task=%p,root=%p,cpu=%d,64bit=%d): " 1046 "lookup failed !\n", 1047 map, task, fsroot, cpu, is_64bit)); 1048 //panic("shared_region_enter: lookup failed\n"); 1049 return KERN_FAILURE; 1050 } 1051 1052 /* let the task use that shared region */ 1053 vm_shared_region_set(task, shared_region); 1054 1055 kr = KERN_SUCCESS; 1056 /* no need to lock since this data is never modified */ 1057 sr_address = shared_region->sr_base_address; 1058 sr_size = shared_region->sr_size; 1059 sr_handle = shared_region->sr_mem_entry; 1060 sr_pmap_nesting_start = shared_region->sr_pmap_nesting_start; 1061 sr_pmap_nesting_size = shared_region->sr_pmap_nesting_size; 1062 1063 /* 1064 * Start mapping the shared region's VM sub map into the task's VM map. 1065 */ 1066 sr_offset = 0; 1067 1068 if (sr_pmap_nesting_start > sr_address) { 1069 /* we need to map a range without pmap-nesting first */ 1070 target_address = sr_address; 1071 mapping_size = sr_pmap_nesting_start - sr_address; 1072 kr = vm_map_enter_mem_object( 1073 map, 1074 &target_address, 1075 mapping_size, 1076 0, 1077 VM_FLAGS_FIXED, 1078 sr_handle, 1079 sr_offset, 1080 TRUE, 1081 VM_PROT_READ, 1082 VM_PROT_ALL, 1083 VM_INHERIT_SHARE); 1084 if (kr != KERN_SUCCESS) { 1085 SHARED_REGION_TRACE_ERROR( 1086 ("shared_region: enter(%p,%p,%p,%d,%d): " 1087 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n", 1088 map, task, fsroot, cpu, is_64bit, 1089 (long long)target_address, 1090 (long long)mapping_size, sr_handle, kr)); 1091 goto done; 1092 } 1093 SHARED_REGION_TRACE_DEBUG( 1094 ("shared_region: enter(%p,%p,%p,%d,%d): " 1095 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n", 1096 map, task, fsroot, cpu, is_64bit, 1097 (long long)target_address, (long long)mapping_size, 1098 sr_handle, kr)); 1099 sr_offset += mapping_size; 1100 sr_size -= mapping_size; 1101 } 1102 /* 1103 * We may need to map several pmap-nested portions, due to platform 1104 * specific restrictions on pmap nesting. 1105 * The pmap-nesting is triggered by the "VM_MEMORY_SHARED_PMAP" alias... 1106 */ 1107 for (; 1108 sr_pmap_nesting_size > 0; 1109 sr_offset += mapping_size, 1110 sr_size -= mapping_size, 1111 sr_pmap_nesting_size -= mapping_size) { 1112 target_address = sr_address + sr_offset; 1113 mapping_size = sr_pmap_nesting_size; 1114 if (mapping_size > pmap_nesting_size_max) { 1115 mapping_size = (vm_map_offset_t) pmap_nesting_size_max; 1116 } 1117 kr = vm_map_enter_mem_object( 1118 map, 1119 &target_address, 1120 mapping_size, 1121 0, 1122 (VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_SHARED_PMAP)), 1123 sr_handle, 1124 sr_offset, 1125 TRUE, 1126 VM_PROT_READ, 1127 VM_PROT_ALL, 1128 VM_INHERIT_SHARE); 1129 if (kr != KERN_SUCCESS) { 1130 SHARED_REGION_TRACE_ERROR( 1131 ("shared_region: enter(%p,%p,%p,%d,%d): " 1132 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n", 1133 map, task, fsroot, cpu, is_64bit, 1134 (long long)target_address, 1135 (long long)mapping_size, sr_handle, kr)); 1136 goto done; 1137 } 1138 SHARED_REGION_TRACE_DEBUG( 1139 ("shared_region: enter(%p,%p,%p,%d,%d): " 1140 "nested vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n", 1141 map, task, fsroot, cpu, is_64bit, 1142 (long long)target_address, (long long)mapping_size, 1143 sr_handle, kr)); 1144 } 1145 if (sr_size > 0) { 1146 /* and there's some left to be mapped without pmap-nesting */ 1147 target_address = sr_address + sr_offset; 1148 mapping_size = sr_size; 1149 kr = vm_map_enter_mem_object( 1150 map, 1151 &target_address, 1152 mapping_size, 1153 0, 1154 VM_FLAGS_FIXED, 1155 sr_handle, 1156 sr_offset, 1157 TRUE, 1158 VM_PROT_READ, 1159 VM_PROT_ALL, 1160 VM_INHERIT_SHARE); 1161 if (kr != KERN_SUCCESS) { 1162 SHARED_REGION_TRACE_ERROR( 1163 ("shared_region: enter(%p,%p,%p,%d,%d): " 1164 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n", 1165 map, task, fsroot, cpu, is_64bit, 1166 (long long)target_address, 1167 (long long)mapping_size, sr_handle, kr)); 1168 goto done; 1169 } 1170 SHARED_REGION_TRACE_DEBUG( 1171 ("shared_region: enter(%p,%p,%p,%d,%d): " 1172 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n", 1173 map, task, fsroot, cpu, is_64bit, 1174 (long long)target_address, (long long)mapping_size, 1175 sr_handle, kr)); 1176 sr_offset += mapping_size; 1177 sr_size -= mapping_size; 1178 } 1179 assert(sr_size == 0); 1180 1181done: 1182 SHARED_REGION_TRACE_DEBUG( 1183 ("shared_region: enter(%p,%p,%p,%d,%d) <- 0x%x\n", 1184 map, task, fsroot, cpu, is_64bit, kr)); 1185 return kr; 1186} 1187 1188/******************************************************************************/ 1189/* Comm page support */ 1190/******************************************************************************/ 1191 1192ipc_port_t commpage32_handle = IPC_PORT_NULL; 1193ipc_port_t commpage64_handle = IPC_PORT_NULL; 1194vm_named_entry_t commpage32_entry = NULL; 1195vm_named_entry_t commpage64_entry = NULL; 1196vm_map_t commpage32_map = VM_MAP_NULL; 1197vm_map_t commpage64_map = VM_MAP_NULL; 1198 1199/* 1200 * Create a memory entry, VM submap and pmap for one commpage. 1201 */ 1202static void 1203_vm_commpage_init( 1204 ipc_port_t *handlep, 1205 vm_map_size_t size) 1206{ 1207 kern_return_t kr; 1208 vm_named_entry_t mem_entry; 1209 vm_map_t new_map; 1210 1211 SHARED_REGION_TRACE_DEBUG( 1212 ("commpage: -> _init(0x%llx)\n", 1213 (long long)size)); 1214 1215 kr = mach_memory_entry_allocate(&mem_entry, 1216 handlep); 1217 if (kr != KERN_SUCCESS) { 1218 panic("_vm_commpage_init: could not allocate mem_entry"); 1219 } 1220 new_map = vm_map_create(pmap_create(0, FALSE), 0, size, TRUE); 1221 if (new_map == VM_MAP_NULL) { 1222 panic("_vm_commpage_init: could not allocate VM map"); 1223 } 1224 mem_entry->backing.map = new_map; 1225 mem_entry->internal = TRUE; 1226 mem_entry->is_sub_map = TRUE; 1227 mem_entry->offset = 0; 1228 mem_entry->protection = VM_PROT_ALL; 1229 mem_entry->size = size; 1230 1231 SHARED_REGION_TRACE_DEBUG( 1232 ("commpage: _init(0x%llx) <- %p\n", 1233 (long long)size, *handlep)); 1234} 1235 1236/* 1237 * Initialize the comm pages at boot time. 1238 */ 1239void 1240vm_commpage_init(void) 1241{ 1242 SHARED_REGION_TRACE_DEBUG( 1243 ("commpage: -> init()\n")); 1244 1245 /* create the 32-bit comm page */ 1246 _vm_commpage_init(&commpage32_handle, _COMM_PAGE32_AREA_LENGTH); 1247 commpage32_entry = (vm_named_entry_t) commpage32_handle->ip_kobject; 1248 commpage32_map = commpage32_entry->backing.map; 1249 1250 /* XXX if (cpu_is_64bit_capable()) ? */ 1251 /* create the 64-bit comm page */ 1252 _vm_commpage_init(&commpage64_handle, _COMM_PAGE64_AREA_LENGTH); 1253 commpage64_entry = (vm_named_entry_t) commpage64_handle->ip_kobject; 1254 commpage64_map = commpage64_entry->backing.map; 1255 1256 /* populate them according to this specific platform */ 1257 commpage_populate(); 1258 1259 SHARED_REGION_TRACE_DEBUG( 1260 ("commpage: init() <-\n")); 1261} 1262 1263/* 1264 * Enter the appropriate comm page into the task's address space. 1265 * This is called at exec() time via vm_map_exec(). 1266 */ 1267kern_return_t 1268vm_commpage_enter( 1269 vm_map_t map, 1270 task_t task) 1271{ 1272 ipc_port_t commpage_handle; 1273 vm_map_offset_t commpage_address, objc_address; 1274 vm_map_size_t commpage_size, objc_size; 1275 int vm_flags; 1276 kern_return_t kr; 1277 1278 SHARED_REGION_TRACE_DEBUG( 1279 ("commpage: -> enter(%p,%p)\n", 1280 map, task)); 1281 1282 /* the comm page is likely to be beyond the actual end of the VM map */ 1283 vm_flags = VM_FLAGS_FIXED | VM_FLAGS_BEYOND_MAX; 1284 1285 /* select the appropriate comm page for this task */ 1286 assert(! (task_has_64BitAddr(task) ^ vm_map_is_64bit(map))); 1287 if (task_has_64BitAddr(task)) { 1288#ifdef __ppc__ 1289 /* 1290 * PPC51: ppc64 is limited to 51-bit addresses. 1291 * Memory above that limit is handled specially at the 1292 * pmap level, so do not interfere. 1293 */ 1294 vm_flags |= VM_FLAGS_NO_PMAP_CHECK; 1295#endif /* __ppc__ */ 1296 commpage_handle = commpage64_handle; 1297 commpage_address = (vm_map_offset_t) _COMM_PAGE64_BASE_ADDRESS; 1298 commpage_size = _COMM_PAGE64_AREA_LENGTH; 1299 objc_size = _COMM_PAGE64_OBJC_SIZE; 1300 objc_address = _COMM_PAGE64_OBJC_BASE; 1301 } else { 1302 commpage_handle = commpage32_handle; 1303 commpage_address = 1304 (vm_map_offset_t)(unsigned) _COMM_PAGE32_BASE_ADDRESS; 1305 commpage_size = _COMM_PAGE32_AREA_LENGTH; 1306 objc_size = _COMM_PAGE32_OBJC_SIZE; 1307 objc_address = _COMM_PAGE32_OBJC_BASE; 1308 } 1309 1310 if ((commpage_address & (pmap_nesting_size_min - 1)) == 0 && 1311 (commpage_size & (pmap_nesting_size_min - 1)) == 0) { 1312 /* the commpage is properly aligned or sized for pmap-nesting */ 1313 vm_flags |= VM_MAKE_TAG(VM_MEMORY_SHARED_PMAP); 1314 } 1315 1316 /* map the comm page in the task's address space */ 1317 assert(commpage_handle != IPC_PORT_NULL); 1318 kr = vm_map_enter_mem_object( 1319 map, 1320 &commpage_address, 1321 commpage_size, 1322 0, 1323 vm_flags, 1324 commpage_handle, 1325 0, 1326 FALSE, 1327 VM_PROT_READ|VM_PROT_EXECUTE, 1328 VM_PROT_READ|VM_PROT_EXECUTE, 1329 VM_INHERIT_SHARE); 1330 if (kr != KERN_SUCCESS) { 1331 SHARED_REGION_TRACE_ERROR( 1332 ("commpage: enter(%p,0x%llx,0x%llx) " 1333 "commpage %p mapping failed 0x%x\n", 1334 map, (long long)commpage_address, 1335 (long long)commpage_size, commpage_handle, kr)); 1336 } 1337 1338 /* 1339 * Since we're here, we also pre-allocate some virtual space for the 1340 * Objective-C run-time, if needed... 1341 */ 1342 if (objc_size != 0) { 1343 kr = vm_map_enter_mem_object( 1344 map, 1345 &objc_address, 1346 objc_size, 1347 0, 1348 VM_FLAGS_FIXED | VM_FLAGS_BEYOND_MAX, 1349 IPC_PORT_NULL, 1350 0, 1351 FALSE, 1352 VM_PROT_ALL, 1353 VM_PROT_ALL, 1354 VM_INHERIT_DEFAULT); 1355 if (kr != KERN_SUCCESS) { 1356 SHARED_REGION_TRACE_ERROR( 1357 ("commpage: enter(%p,0x%llx,0x%llx) " 1358 "objc mapping failed 0x%x\n", 1359 map, (long long)objc_address, 1360 (long long)objc_size, kr)); 1361 } 1362 } 1363 1364 SHARED_REGION_TRACE_DEBUG( 1365 ("commpage: enter(%p,%p) <- 0x%x\n", 1366 map, task, kr)); 1367 return kr; 1368} 1369