2 * Copyright (c) 2007 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Shared region (... and comm page)
27 * This file handles the VM shared region and comm page.
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).
38 * The point of a shared region is to reduce the setup overhead when exec'ing
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
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.
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.
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.
64 * The shared region is inherited on fork() and the child simply takes an
65 * extra reference on its parent's shared region.
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.
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.
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 !
84 * The comm pages are created and populated at boot time.
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().
90 * The comm page is shared between the kernel and all applications of
91 * a given platform. Only the kernel can modify it.
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.
101 #include <kern/ipc_tt.h>
102 #include <kern/kalloc.h>
104 #include <mach/mach_vm.h>
106 #include <vm/vm_map.h>
107 #include <vm/vm_shared_region.h>
109 #include <vm/vm_protos.h>
111 #include <machine/commpage.h>
112 #include <machine/cpu_capabilities.h>
114 /* "dyld" uses this to figure out what the kernel supports */
115 int shared_region_version
= 3;
117 /* should local (non-chroot) shared regions persist when no task uses them ? */
118 int shared_region_persistence
= 1; /* yes by default */
120 /* trace level, output is sent to the system log file */
121 int shared_region_trace_level
= SHARED_REGION_TRACE_ERROR_LVL
;
123 /* this lock protects all the shared region data structures */
124 lck_grp_t
*vm_shared_region_lck_grp
;
125 lck_mtx_t vm_shared_region_lock
;
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, \
135 /* the list of currently available shared regions (one per environment) */
136 queue_head_t vm_shared_region_queue
;
138 static void vm_shared_region_reference_locked(vm_shared_region_t shared_region
);
139 static vm_shared_region_t
vm_shared_region_create(
143 static void vm_shared_region_destroy(vm_shared_region_t shared_region
);
146 * Initialize the module...
149 vm_shared_region_init(void)
151 SHARED_REGION_TRACE_DEBUG(
152 ("shared_region: -> init\n"));
154 vm_shared_region_lck_grp
= lck_grp_alloc_init("vm shared region",
156 lck_mtx_init(&vm_shared_region_lock
,
157 vm_shared_region_lck_grp
,
160 queue_init(&vm_shared_region_queue
);
162 SHARED_REGION_TRACE_DEBUG(
163 ("shared_region: <- init\n"));
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
173 vm_shared_region_get(
176 vm_shared_region_t shared_region
;
178 SHARED_REGION_TRACE_DEBUG(
179 ("shared_region: -> get(%p)\n",
183 vm_shared_region_lock();
184 shared_region
= task
->shared_region
;
186 assert(shared_region
->sr_ref_count
> 0);
187 vm_shared_region_reference_locked(shared_region
);
189 vm_shared_region_unlock();
192 SHARED_REGION_TRACE_DEBUG(
193 ("shared_region: get(%p) <- %p\n",
194 task
, shared_region
));
196 return shared_region
;
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
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.
208 vm_shared_region_base_address(
209 vm_shared_region_t shared_region
)
211 SHARED_REGION_TRACE_DEBUG(
212 ("shared_region: -> base_address(%p)\n",
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
;
222 * Get the size of the shared region.
223 * That's the size that needs to be mapped in the process's address
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.
230 vm_shared_region_size(
231 vm_shared_region_t shared_region
)
233 SHARED_REGION_TRACE_DEBUG(
234 ("shared_region: -> size(%p)\n",
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
;
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
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.
252 vm_shared_region_mem_entry(
253 vm_shared_region_t shared_region
)
255 SHARED_REGION_TRACE_DEBUG(
256 ("shared_region: -> mem_entry(%p)\n",
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
;
266 * Set the shared region the process should use.
267 * A NULL new shared region means that we just want to release the old
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).
273 vm_shared_region_set(
275 vm_shared_region_t new_shared_region
)
277 vm_shared_region_t old_shared_region
;
279 SHARED_REGION_TRACE_DEBUG(
280 ("shared_region: -> set(%p, %p)\n",
281 task
, new_shared_region
));
284 vm_shared_region_lock();
286 old_shared_region
= task
->shared_region
;
287 if (new_shared_region
) {
288 assert(new_shared_region
->sr_ref_count
> 0);
291 task
->shared_region
= new_shared_region
;
293 vm_shared_region_unlock();
296 if (old_shared_region
) {
297 assert(old_shared_region
->sr_ref_count
> 0);
298 vm_shared_region_deallocate(old_shared_region
);
301 SHARED_REGION_TRACE_DEBUG(
302 ("shared_region: set(%p) <- old=%p new=%p\n",
303 task
, old_shared_region
, new_shared_region
));
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.
314 vm_shared_region_lookup(
319 vm_shared_region_t shared_region
;
320 vm_shared_region_t new_shared_region
;
322 SHARED_REGION_TRACE_DEBUG(
323 ("shared_region: -> lookup(root=%p,cpu=%d,64bit=%d)\n",
324 root_dir
, cputype
, is_64bit
));
326 shared_region
= NULL
;
327 new_shared_region
= NULL
;
329 vm_shared_region_lock();
331 queue_iterate(&vm_shared_region_queue
,
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
);
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
,
350 /* do the lookup again, in case we lost a race */
351 vm_shared_region_lock();
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
,
365 vm_shared_region_unlock();
367 if (new_shared_region
) {
369 * We lost a race with someone else to create a new shared
370 * region for that environment. Get rid of our unused one.
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
;
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
));
382 assert(shared_region
->sr_ref_count
> 0);
383 return shared_region
;
387 * Take an extra reference on a shared region.
388 * The vm_shared_region_lock should already be held by the caller.
391 vm_shared_region_reference_locked(
392 vm_shared_region_t shared_region
)
395 lck_mtx_assert(&vm_shared_region_lock
, LCK_MTX_ASSERT_OWNED
);
398 SHARED_REGION_TRACE_DEBUG(
399 ("shared_region: -> reference_locked(%p)\n",
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
));
409 * Release a reference on the shared region.
410 * Destroy it if there are no references left.
413 vm_shared_region_deallocate(
414 vm_shared_region_t shared_region
)
416 SHARED_REGION_TRACE_DEBUG(
417 ("shared_region: -> deallocate(%p)\n",
420 vm_shared_region_lock();
422 assert(shared_region
->sr_ref_count
> 0);
424 if (shared_region
->sr_root_dir
== NULL
) {
426 * Local (i.e. based on the boot volume) shared regions
427 * can persist or not based on the "shared_region_persistence"
429 * Make sure that this one complies.
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
;
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
));
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
,
458 vm_shared_region_unlock();
459 /* ... and destroy it */
460 vm_shared_region_destroy(shared_region
);
461 shared_region
= NULL
;
463 vm_shared_region_unlock();
466 SHARED_REGION_TRACE_DEBUG(
467 ("shared_region: deallocate(%p) <-\n",
472 * Create a new (empty) shared region for a new environment.
474 static vm_shared_region_t
475 vm_shared_region_create(
481 vm_named_entry_t mem_entry
;
482 ipc_port_t mem_entry_port
;
483 vm_shared_region_t shared_region
;
485 mach_vm_offset_t base_address
, pmap_nesting_start
;
486 mach_vm_size_t size
, pmap_nesting_size
;
488 SHARED_REGION_TRACE_DEBUG(
489 ("shared_region: -> create(root=%p,cpu=%d,64bit=%d)\n",
490 root_dir
, cputype
, is_64bit
));
495 mem_entry_port
= IPC_PORT_NULL
;
496 sub_map
= VM_MAP_NULL
;
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"));
506 /* figure out the correct settings for the desired environment */
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
;
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
;
522 SHARED_REGION_TRACE_ERROR(
523 ("shared_region: create: unknown cpu type %d\n",
525 kfree(shared_region
, sizeof (*shared_region
));
526 shared_region
= NULL
;
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
;
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
;
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
;
550 #endif /* CPU_TYPE_ARM */
552 SHARED_REGION_TRACE_ERROR(
553 ("shared_region: create: unknown cpu type %d\n",
555 kfree(shared_region
, sizeof (*shared_region
));
556 shared_region
= NULL
;
562 /* create a memory entry structure and a Mach port handle */
563 kr
= mach_memory_entry_allocate(&mem_entry
,
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"));
574 /* create a VM sub map and its pmap */
575 sub_map
= vm_map_create(pmap_create(0, is_64bit
),
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"));
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
;
594 /* make the shared region point at the memory entry */
595 shared_region
->sr_mem_entry
= mem_entry_port
;
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
;
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;
611 /* grab a reference for the caller */
612 shared_region
->sr_ref_count
= 1;
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
));
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
,
630 return shared_region
;
634 * Destroy a now-unused shared region.
635 * The shared region is no longer in the queue and can not be looked up.
638 vm_shared_region_destroy(
639 vm_shared_region_t shared_region
)
641 vm_named_entry_t mem_entry
;
644 SHARED_REGION_TRACE_INFO(
645 ("shared_region: -> destroy(%p) (root=%p,cpu=%d,64bit=%d)\n",
647 shared_region
->sr_root_dir
,
648 shared_region
->sr_cpu_type
,
649 shared_region
->sr_64bit
));
651 assert(shared_region
->sr_ref_count
== 0);
652 assert(!shared_region
->sr_persists
);
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
;
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
669 pmap_remove(map
->pmap
,
670 shared_region
->sr_base_address
,
671 (shared_region
->sr_base_address
+
672 shared_region
->sr_size
));
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.
682 mach_memory_entry_port_release(shared_region
->sr_mem_entry
);
684 shared_region
->sr_mem_entry
= IPC_PORT_NULL
;
686 /* release the shared region structure... */
687 kfree(shared_region
, sizeof (*shared_region
));
688 SHARED_REGION_TRACE_DEBUG(
689 ("shared_region: destroy(%p) <-\n",
691 shared_region
= NULL
;
696 * Gets the address of the first (in time) mapping in the shared region.
699 vm_shared_region_start_address(
700 vm_shared_region_t shared_region
,
701 mach_vm_offset_t
*start_address
)
704 mach_vm_offset_t sr_base_address
;
705 mach_vm_offset_t sr_first_mapping
;
707 SHARED_REGION_TRACE_DEBUG(
708 ("shared_region: -> start_address(%p)\n",
710 assert(shared_region
->sr_ref_count
> 1);
712 vm_shared_region_lock();
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...
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
,
725 assert(! shared_region
->sr_mapping_in_progress
);
726 assert(shared_region
->sr_ref_count
> 1);
728 sr_base_address
= shared_region
->sr_base_address
;
729 sr_first_mapping
= shared_region
->sr_first_mapping
;
731 if (sr_first_mapping
== (mach_vm_offset_t
) -1) {
732 /* shared region is empty */
733 kr
= KERN_INVALID_ADDRESS
;
736 *start_address
= sr_base_address
+ sr_first_mapping
;
739 vm_shared_region_unlock();
741 SHARED_REGION_TRACE_DEBUG(
742 ("shared_region: start_address(%p) <- 0x%llx\n",
743 shared_region
, (long long)shared_region
->sr_base_address
));
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.
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.
758 vm_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
,
767 vm_object_t file_object
;
768 ipc_port_t sr_handle
;
769 vm_named_entry_t sr_mem_entry
;
771 mach_vm_offset_t sr_base_address
;
773 mach_port_t map_port
;
774 mach_vm_offset_t target_address
;
776 vm_object_size_t obj_size
;
781 vm_shared_region_lock();
782 assert(shared_region
->sr_ref_count
> 1);
784 if (shared_region
->sr_root_dir
!= root_dir
) {
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.
791 vm_shared_region_unlock();
792 kr
= KERN_PROTECTION_FAILURE
;
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...
801 while (shared_region
->sr_mapping_in_progress
) {
802 /* wait for our turn... */
803 vm_shared_region_sleep(&shared_region
->sr_mapping_in_progress
,
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
;
811 vm_shared_region_unlock();
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
;
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
));
824 /* get the VM object associated with the file to be mapped */
825 file_object
= memory_object_control_to_vm_object(file_control
);
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",
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
));
840 if (mappings
[i
].sfm_init_prot
& VM_PROT_ZF
) {
841 /* zero-filled memory */
842 map_port
= MACH_PORT_NULL
;
844 /* file-backed memory */
845 map_port
= (ipc_port_t
) file_object
->pager
;
848 /* mapping's address is relative to the shared region base */
850 mappings
[i
].sfm_address
- sr_base_address
;
852 /* establish that mapping, OK if it's "already" there */
853 if (map_port
== MACH_PORT_NULL
) {
855 * We want to map some anonymous memory in a
857 * We have to create the VM object now, so that it
858 * can be mapped "copy-on-write".
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
;
868 vm_map_round_page(mappings
[i
].sfm_size
),
870 VM_FLAGS_FIXED
| VM_FLAGS_ALREADY
,
874 mappings
[i
].sfm_init_prot
& VM_PROT_ALL
,
875 mappings
[i
].sfm_max_prot
& VM_PROT_ALL
,
879 object
= VM_OBJECT_NULL
; /* no anonymous memory here */
880 kr
= vm_map_enter_mem_object(
883 vm_map_round_page(mappings
[i
].sfm_size
),
885 VM_FLAGS_FIXED
| VM_FLAGS_ALREADY
,
887 mappings
[i
].sfm_file_offset
,
889 mappings
[i
].sfm_init_prot
& VM_PROT_ALL
,
890 mappings
[i
].sfm_max_prot
& VM_PROT_ALL
,
894 if (kr
!= KERN_SUCCESS
) {
895 if (map_port
== MACH_PORT_NULL
) {
897 * Get rid of the VM object we just created
900 vm_object_deallocate(object
);
901 object
= VM_OBJECT_NULL
;
903 if (kr
== KERN_MEMORY_PRESENT
) {
905 * This exact mapping was already there:
908 SHARED_REGION_TRACE_INFO(
909 ("shared_region: mapping[%d]: "
910 "address:0x%016llx size:0x%016llx "
912 "maxprot:0x%x prot:0x%x "
913 "already mapped...\n",
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
));
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.
925 mappings
[i
].sfm_size
= 0;
930 /* this mapping failed ! */
931 SHARED_REGION_TRACE_ERROR(
932 ("shared_region: mapping[%d]: "
933 "address:0x%016llx size:0x%016llx "
935 "maxprot:0x%x prot:0x%x failed 0x%x\n",
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
,
945 * Undo the mappings we've established so far.
947 for (j
= 0; j
< i
; j
++) {
950 if (mappings
[j
].sfm_size
== 0) {
952 * We didn't establish this
953 * mapping, so nothing to undo.
957 SHARED_REGION_TRACE_INFO(
958 ("shared_region: mapping[%d]: "
962 "maxprot:0x%x prot:0x%x: "
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(
972 (mappings
[j
].sfm_address
-
974 mappings
[j
].sfm_size
);
975 assert(kr2
== KERN_SUCCESS
);
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".
989 if (shared_region
->sr_first_mapping
== (mach_vm_offset_t
) -1) {
990 shared_region
->sr_first_mapping
= target_address
;
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();
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
));
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.
1017 vm_shared_region_enter(
1018 struct _vm_map
*map
,
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
;
1032 is_64bit
= task_has_64BitAddr(task
);
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
));
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
;
1052 /* let the task use that shared region */
1053 vm_shared_region_set(task
, shared_region
);
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
;
1064 * Start mapping the shared region's VM sub map into the task's VM map.
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(
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
));
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
,
1099 sr_offset
+= mapping_size
;
1100 sr_size
-= mapping_size
;
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...
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
;
1117 kr
= vm_map_enter_mem_object(
1122 (VM_FLAGS_FIXED
| VM_MAKE_TAG(VM_MEMORY_SHARED_PMAP
)),
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
));
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
,
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(
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
));
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
,
1176 sr_offset
+= mapping_size
;
1177 sr_size
-= mapping_size
;
1179 assert(sr_size
== 0);
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
));
1188 /******************************************************************************/
1189 /* Comm page support */
1190 /******************************************************************************/
1192 ipc_port_t commpage32_handle
= IPC_PORT_NULL
;
1193 ipc_port_t commpage64_handle
= IPC_PORT_NULL
;
1194 vm_named_entry_t commpage32_entry
= NULL
;
1195 vm_named_entry_t commpage64_entry
= NULL
;
1196 vm_map_t commpage32_map
= VM_MAP_NULL
;
1197 vm_map_t commpage64_map
= VM_MAP_NULL
;
1200 * Create a memory entry, VM submap and pmap for one commpage.
1204 ipc_port_t
*handlep
,
1208 vm_named_entry_t mem_entry
;
1211 SHARED_REGION_TRACE_DEBUG(
1212 ("commpage: -> _init(0x%llx)\n",
1215 kr
= mach_memory_entry_allocate(&mem_entry
,
1217 if (kr
!= KERN_SUCCESS
) {
1218 panic("_vm_commpage_init: could not allocate mem_entry");
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");
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
;
1231 SHARED_REGION_TRACE_DEBUG(
1232 ("commpage: _init(0x%llx) <- %p\n",
1233 (long long)size
, *handlep
));
1237 * Initialize the comm pages at boot time.
1240 vm_commpage_init(void)
1242 SHARED_REGION_TRACE_DEBUG(
1243 ("commpage: -> init()\n"));
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
;
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
;
1256 /* populate them according to this specific platform */
1257 commpage_populate();
1259 SHARED_REGION_TRACE_DEBUG(
1260 ("commpage: init() <-\n"));
1264 * Enter the appropriate comm page into the task's address space.
1265 * This is called at exec() time via vm_map_exec().
1272 ipc_port_t commpage_handle
;
1273 vm_map_offset_t commpage_address
, objc_address
;
1274 vm_map_size_t commpage_size
, objc_size
;
1278 SHARED_REGION_TRACE_DEBUG(
1279 ("commpage: -> enter(%p,%p)\n",
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
;
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
)) {
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.
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
;
1302 commpage_handle
= commpage32_handle
;
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
;
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
);
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(
1327 VM_PROT_READ
|VM_PROT_EXECUTE
,
1328 VM_PROT_READ
|VM_PROT_EXECUTE
,
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
));
1339 * Since we're here, we also pre-allocate some virtual space for the
1340 * Objective-C run-time, if needed...
1342 if (objc_size
!= 0) {
1343 kr
= vm_map_enter_mem_object(
1348 VM_FLAGS_FIXED
| VM_FLAGS_BEYOND_MAX
,
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
));
1364 SHARED_REGION_TRACE_DEBUG(
1365 ("commpage: enter(%p,%p) <- 0x%x\n",