]> git.saurik.com Git - apple/xnu.git/blob - osfmk/vm/vm_shared_region.c
xnu-2422.1.72.tar.gz
[apple/xnu.git] / osfmk / vm / vm_shared_region.c
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 #include <kern/thread_call.h>
104
105 #include <mach/mach_vm.h>
106
107 #include <vm/vm_map.h>
108 #include <vm/vm_shared_region.h>
109
110 #include <vm/vm_protos.h>
111
112 #include <machine/commpage.h>
113 #include <machine/cpu_capabilities.h>
114
115 /* "dyld" uses this to figure out what the kernel supports */
116 int shared_region_version = 3;
117
118 /* trace level, output is sent to the system log file */
119 int shared_region_trace_level = SHARED_REGION_TRACE_ERROR_LVL;
120
121 /* should local (non-chroot) shared regions persist when no task uses them ? */
122 int shared_region_persistence = 0; /* no by default */
123
124 /* delay before reclaiming an unused shared region */
125 int shared_region_destroy_delay = 120; /* in seconds */
126
127 /*
128 * Only one cache gets to slide on Desktop, since we can't
129 * tear down slide info properly today and the desktop actually
130 * produces lots of shared caches.
131 */
132 boolean_t shared_region_completed_slide = FALSE;
133
134 /* this lock protects all the shared region data structures */
135 lck_grp_t *vm_shared_region_lck_grp;
136 lck_mtx_t vm_shared_region_lock;
137
138 #define vm_shared_region_lock() lck_mtx_lock(&vm_shared_region_lock)
139 #define vm_shared_region_unlock() lck_mtx_unlock(&vm_shared_region_lock)
140 #define vm_shared_region_sleep(event, interruptible) \
141 lck_mtx_sleep(&vm_shared_region_lock, \
142 LCK_SLEEP_DEFAULT, \
143 (event_t) (event), \
144 (interruptible))
145
146 /* the list of currently available shared regions (one per environment) */
147 queue_head_t vm_shared_region_queue;
148
149 static void vm_shared_region_reference_locked(vm_shared_region_t shared_region);
150 static vm_shared_region_t vm_shared_region_create(
151 void *root_dir,
152 cpu_type_t cputype,
153 boolean_t is_64bit);
154 static void vm_shared_region_destroy(vm_shared_region_t shared_region);
155
156 static void vm_shared_region_timeout(thread_call_param_t param0,
157 thread_call_param_t param1);
158
159 static int __commpage_setup = 0;
160 #if defined(__i386__) || defined(__x86_64__)
161 static int __system_power_source = 1; /* init to extrnal power source */
162 static void post_sys_powersource_internal(int i, int internal);
163 #endif /* __i386__ || __x86_64__ */
164
165
166 /*
167 * Initialize the module...
168 */
169 void
170 vm_shared_region_init(void)
171 {
172 SHARED_REGION_TRACE_DEBUG(
173 ("shared_region: -> init\n"));
174
175 vm_shared_region_lck_grp = lck_grp_alloc_init("vm shared region",
176 LCK_GRP_ATTR_NULL);
177 lck_mtx_init(&vm_shared_region_lock,
178 vm_shared_region_lck_grp,
179 LCK_ATTR_NULL);
180
181 queue_init(&vm_shared_region_queue);
182
183 SHARED_REGION_TRACE_DEBUG(
184 ("shared_region: <- init\n"));
185 }
186
187 /*
188 * Retrieve a task's shared region and grab an extra reference to
189 * make sure it doesn't disappear while the caller is using it.
190 * The caller is responsible for consuming that extra reference if
191 * necessary.
192 */
193 vm_shared_region_t
194 vm_shared_region_get(
195 task_t task)
196 {
197 vm_shared_region_t shared_region;
198
199 SHARED_REGION_TRACE_DEBUG(
200 ("shared_region: -> get(%p)\n",
201 task));
202
203 task_lock(task);
204 vm_shared_region_lock();
205 shared_region = task->shared_region;
206 if (shared_region) {
207 assert(shared_region->sr_ref_count > 0);
208 vm_shared_region_reference_locked(shared_region);
209 }
210 vm_shared_region_unlock();
211 task_unlock(task);
212
213 SHARED_REGION_TRACE_DEBUG(
214 ("shared_region: get(%p) <- %p\n",
215 task, shared_region));
216
217 return shared_region;
218 }
219
220 /*
221 * Get the base address of the shared region.
222 * That's the address at which it needs to be mapped in the process's address
223 * space.
224 * No need to lock since this data is set when the shared region is
225 * created and is never modified after that. The caller must hold an extra
226 * reference on the shared region to prevent it from being destroyed.
227 */
228 mach_vm_offset_t
229 vm_shared_region_base_address(
230 vm_shared_region_t shared_region)
231 {
232 SHARED_REGION_TRACE_DEBUG(
233 ("shared_region: -> base_address(%p)\n",
234 shared_region));
235 assert(shared_region->sr_ref_count > 1);
236 SHARED_REGION_TRACE_DEBUG(
237 ("shared_region: base_address(%p) <- 0x%llx\n",
238 shared_region, (long long)shared_region->sr_base_address));
239 return shared_region->sr_base_address;
240 }
241
242 /*
243 * Get the size of the shared region.
244 * That's the size that needs to be mapped in the process's address
245 * space.
246 * No need to lock since this data is set when the shared region is
247 * created and is never modified after that. The caller must hold an extra
248 * reference on the shared region to prevent it from being destroyed.
249 */
250 mach_vm_size_t
251 vm_shared_region_size(
252 vm_shared_region_t shared_region)
253 {
254 SHARED_REGION_TRACE_DEBUG(
255 ("shared_region: -> size(%p)\n",
256 shared_region));
257 assert(shared_region->sr_ref_count > 1);
258 SHARED_REGION_TRACE_DEBUG(
259 ("shared_region: size(%p) <- 0x%llx\n",
260 shared_region, (long long)shared_region->sr_size));
261 return shared_region->sr_size;
262 }
263
264 /*
265 * Get the memory entry of the shared region.
266 * That's the "memory object" that needs to be mapped in the process's address
267 * space.
268 * No need to lock since this data is set when the shared region is
269 * created and is never modified after that. The caller must hold an extra
270 * reference on the shared region to prevent it from being destroyed.
271 */
272 ipc_port_t
273 vm_shared_region_mem_entry(
274 vm_shared_region_t shared_region)
275 {
276 SHARED_REGION_TRACE_DEBUG(
277 ("shared_region: -> mem_entry(%p)\n",
278 shared_region));
279 assert(shared_region->sr_ref_count > 1);
280 SHARED_REGION_TRACE_DEBUG(
281 ("shared_region: mem_entry(%p) <- %p\n",
282 shared_region, shared_region->sr_mem_entry));
283 return shared_region->sr_mem_entry;
284 }
285
286 uint32_t
287 vm_shared_region_get_slide(
288 vm_shared_region_t shared_region)
289 {
290 SHARED_REGION_TRACE_DEBUG(
291 ("shared_region: -> vm_shared_region_get_slide(%p)\n",
292 shared_region));
293 assert(shared_region->sr_ref_count > 1);
294 SHARED_REGION_TRACE_DEBUG(
295 ("shared_region: vm_shared_region_get_slide(%p) <- %u\n",
296 shared_region, shared_region->sr_slide_info.slide));
297
298 /* 0 if we haven't slid */
299 assert(shared_region->sr_slide_info.slide_object != NULL ||
300 shared_region->sr_slide_info.slide == 0);
301
302 return shared_region->sr_slide_info.slide;
303 }
304
305 vm_shared_region_slide_info_t
306 vm_shared_region_get_slide_info(
307 vm_shared_region_t shared_region)
308 {
309 SHARED_REGION_TRACE_DEBUG(
310 ("shared_region: -> vm_shared_region_get_slide_info(%p)\n",
311 shared_region));
312 assert(shared_region->sr_ref_count > 1);
313 SHARED_REGION_TRACE_DEBUG(
314 ("shared_region: vm_shared_region_get_slide_info(%p) <- %p\n",
315 shared_region, &shared_region->sr_slide_info));
316 return &shared_region->sr_slide_info;
317 }
318
319 /*
320 * Set the shared region the process should use.
321 * A NULL new shared region means that we just want to release the old
322 * shared region.
323 * The caller should already have an extra reference on the new shared region
324 * (if any). We release a reference on the old shared region (if any).
325 */
326 void
327 vm_shared_region_set(
328 task_t task,
329 vm_shared_region_t new_shared_region)
330 {
331 vm_shared_region_t old_shared_region;
332
333 SHARED_REGION_TRACE_DEBUG(
334 ("shared_region: -> set(%p, %p)\n",
335 task, new_shared_region));
336
337 task_lock(task);
338 vm_shared_region_lock();
339
340 old_shared_region = task->shared_region;
341 if (new_shared_region) {
342 assert(new_shared_region->sr_ref_count > 0);
343 }
344
345 task->shared_region = new_shared_region;
346
347 vm_shared_region_unlock();
348 task_unlock(task);
349
350 if (old_shared_region) {
351 assert(old_shared_region->sr_ref_count > 0);
352 vm_shared_region_deallocate(old_shared_region);
353 }
354
355 SHARED_REGION_TRACE_DEBUG(
356 ("shared_region: set(%p) <- old=%p new=%p\n",
357 task, old_shared_region, new_shared_region));
358 }
359
360 /*
361 * Lookup up the shared region for the desired environment.
362 * If none is found, create a new (empty) one.
363 * Grab an extra reference on the returned shared region, to make sure
364 * it doesn't get destroyed before the caller is done with it. The caller
365 * is responsible for consuming that extra reference if necessary.
366 */
367 vm_shared_region_t
368 vm_shared_region_lookup(
369 void *root_dir,
370 cpu_type_t cputype,
371 boolean_t is_64bit)
372 {
373 vm_shared_region_t shared_region;
374 vm_shared_region_t new_shared_region;
375
376 SHARED_REGION_TRACE_DEBUG(
377 ("shared_region: -> lookup(root=%p,cpu=%d,64bit=%d)\n",
378 root_dir, cputype, is_64bit));
379
380 shared_region = NULL;
381 new_shared_region = NULL;
382
383 vm_shared_region_lock();
384 for (;;) {
385 queue_iterate(&vm_shared_region_queue,
386 shared_region,
387 vm_shared_region_t,
388 sr_q) {
389 assert(shared_region->sr_ref_count > 0);
390 if (shared_region->sr_cpu_type == cputype &&
391 shared_region->sr_root_dir == root_dir &&
392 shared_region->sr_64bit == is_64bit) {
393 /* found a match ! */
394 vm_shared_region_reference_locked(shared_region);
395 goto done;
396 }
397 }
398 if (new_shared_region == NULL) {
399 /* no match: create a new one */
400 vm_shared_region_unlock();
401 new_shared_region = vm_shared_region_create(root_dir,
402 cputype,
403 is_64bit);
404 /* do the lookup again, in case we lost a race */
405 vm_shared_region_lock();
406 continue;
407 }
408 /* still no match: use our new one */
409 shared_region = new_shared_region;
410 new_shared_region = NULL;
411 queue_enter(&vm_shared_region_queue,
412 shared_region,
413 vm_shared_region_t,
414 sr_q);
415 break;
416 }
417
418 done:
419 vm_shared_region_unlock();
420
421 if (new_shared_region) {
422 /*
423 * We lost a race with someone else to create a new shared
424 * region for that environment. Get rid of our unused one.
425 */
426 assert(new_shared_region->sr_ref_count == 1);
427 new_shared_region->sr_ref_count--;
428 vm_shared_region_destroy(new_shared_region);
429 new_shared_region = NULL;
430 }
431
432 SHARED_REGION_TRACE_DEBUG(
433 ("shared_region: lookup(root=%p,cpu=%d,64bit=%d) <- %p\n",
434 root_dir, cputype, is_64bit, shared_region));
435
436 assert(shared_region->sr_ref_count > 0);
437 return shared_region;
438 }
439
440 /*
441 * Take an extra reference on a shared region.
442 * The vm_shared_region_lock should already be held by the caller.
443 */
444 static void
445 vm_shared_region_reference_locked(
446 vm_shared_region_t shared_region)
447 {
448 #if DEBUG
449 lck_mtx_assert(&vm_shared_region_lock, LCK_MTX_ASSERT_OWNED);
450 #endif
451
452 SHARED_REGION_TRACE_DEBUG(
453 ("shared_region: -> reference_locked(%p)\n",
454 shared_region));
455 assert(shared_region->sr_ref_count > 0);
456 shared_region->sr_ref_count++;
457
458 if (shared_region->sr_timer_call != NULL) {
459 boolean_t cancelled;
460
461 /* cancel and free any pending timeout */
462 cancelled = thread_call_cancel(shared_region->sr_timer_call);
463 if (cancelled) {
464 thread_call_free(shared_region->sr_timer_call);
465 shared_region->sr_timer_call = NULL;
466 /* release the reference held by the cancelled timer */
467 shared_region->sr_ref_count--;
468 } else {
469 /* the timer will drop the reference and free itself */
470 }
471 }
472
473 SHARED_REGION_TRACE_DEBUG(
474 ("shared_region: reference_locked(%p) <- %d\n",
475 shared_region, shared_region->sr_ref_count));
476 }
477
478 /*
479 * Release a reference on the shared region.
480 * Destroy it if there are no references left.
481 */
482 void
483 vm_shared_region_deallocate(
484 vm_shared_region_t shared_region)
485 {
486 SHARED_REGION_TRACE_DEBUG(
487 ("shared_region: -> deallocate(%p)\n",
488 shared_region));
489
490 vm_shared_region_lock();
491
492 assert(shared_region->sr_ref_count > 0);
493
494 if (shared_region->sr_root_dir == NULL) {
495 /*
496 * Local (i.e. based on the boot volume) shared regions
497 * can persist or not based on the "shared_region_persistence"
498 * sysctl.
499 * Make sure that this one complies.
500 *
501 * See comments in vm_shared_region_slide() for notes about
502 * shared regions we have slid (which are not torn down currently).
503 */
504 if (shared_region_persistence &&
505 !shared_region->sr_persists) {
506 /* make this one persistent */
507 shared_region->sr_ref_count++;
508 shared_region->sr_persists = TRUE;
509 } else if (!shared_region_persistence &&
510 shared_region->sr_persists) {
511 /* make this one no longer persistent */
512 assert(shared_region->sr_ref_count > 1);
513 shared_region->sr_ref_count--;
514 shared_region->sr_persists = FALSE;
515 }
516 }
517
518 assert(shared_region->sr_ref_count > 0);
519 shared_region->sr_ref_count--;
520 SHARED_REGION_TRACE_DEBUG(
521 ("shared_region: deallocate(%p): ref now %d\n",
522 shared_region, shared_region->sr_ref_count));
523
524 if (shared_region->sr_ref_count == 0) {
525 uint64_t deadline;
526
527 assert(!shared_region->sr_slid);
528
529 if (shared_region->sr_timer_call == NULL) {
530 /* hold one reference for the timer */
531 assert(! shared_region->sr_mapping_in_progress);
532 shared_region->sr_ref_count++;
533
534 /* set up the timer */
535 shared_region->sr_timer_call = thread_call_allocate(
536 (thread_call_func_t) vm_shared_region_timeout,
537 (thread_call_param_t) shared_region);
538
539 /* schedule the timer */
540 clock_interval_to_deadline(shared_region_destroy_delay,
541 1000 * 1000 * 1000,
542 &deadline);
543 thread_call_enter_delayed(shared_region->sr_timer_call,
544 deadline);
545
546 SHARED_REGION_TRACE_DEBUG(
547 ("shared_region: deallocate(%p): armed timer\n",
548 shared_region));
549
550 vm_shared_region_unlock();
551 } else {
552 /* timer expired: let go of this shared region */
553
554 /*
555 * We can't properly handle teardown of a slid object today.
556 */
557 assert(!shared_region->sr_slid);
558
559 /*
560 * Remove it from the queue first, so no one can find
561 * it...
562 */
563 queue_remove(&vm_shared_region_queue,
564 shared_region,
565 vm_shared_region_t,
566 sr_q);
567 vm_shared_region_unlock();
568
569 /* ... and destroy it */
570 vm_shared_region_destroy(shared_region);
571 shared_region = NULL;
572 }
573 } else {
574 vm_shared_region_unlock();
575 }
576
577 SHARED_REGION_TRACE_DEBUG(
578 ("shared_region: deallocate(%p) <-\n",
579 shared_region));
580 }
581
582 void
583 vm_shared_region_timeout(
584 thread_call_param_t param0,
585 __unused thread_call_param_t param1)
586 {
587 vm_shared_region_t shared_region;
588
589 shared_region = (vm_shared_region_t) param0;
590
591 vm_shared_region_deallocate(shared_region);
592 }
593
594 /*
595 * Create a new (empty) shared region for a new environment.
596 */
597 static vm_shared_region_t
598 vm_shared_region_create(
599 void *root_dir,
600 cpu_type_t cputype,
601 boolean_t is_64bit)
602 {
603 kern_return_t kr;
604 vm_named_entry_t mem_entry;
605 ipc_port_t mem_entry_port;
606 vm_shared_region_t shared_region;
607 vm_shared_region_slide_info_t si;
608 vm_map_t sub_map;
609 mach_vm_offset_t base_address, pmap_nesting_start;
610 mach_vm_size_t size, pmap_nesting_size;
611
612 SHARED_REGION_TRACE_DEBUG(
613 ("shared_region: -> create(root=%p,cpu=%d,64bit=%d)\n",
614 root_dir, cputype, is_64bit));
615
616 base_address = 0;
617 size = 0;
618 mem_entry = NULL;
619 mem_entry_port = IPC_PORT_NULL;
620 sub_map = VM_MAP_NULL;
621
622 /* create a new shared region structure... */
623 shared_region = kalloc(sizeof (*shared_region));
624 if (shared_region == NULL) {
625 SHARED_REGION_TRACE_ERROR(
626 ("shared_region: create: couldn't allocate\n"));
627 goto done;
628 }
629
630 /* figure out the correct settings for the desired environment */
631 if (is_64bit) {
632 switch (cputype) {
633 case CPU_TYPE_I386:
634 base_address = SHARED_REGION_BASE_X86_64;
635 size = SHARED_REGION_SIZE_X86_64;
636 pmap_nesting_start = SHARED_REGION_NESTING_BASE_X86_64;
637 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_X86_64;
638 break;
639 case CPU_TYPE_POWERPC:
640 base_address = SHARED_REGION_BASE_PPC64;
641 size = SHARED_REGION_SIZE_PPC64;
642 pmap_nesting_start = SHARED_REGION_NESTING_BASE_PPC64;
643 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_PPC64;
644 break;
645 default:
646 SHARED_REGION_TRACE_ERROR(
647 ("shared_region: create: unknown cpu type %d\n",
648 cputype));
649 kfree(shared_region, sizeof (*shared_region));
650 shared_region = NULL;
651 goto done;
652 }
653 } else {
654 switch (cputype) {
655 case CPU_TYPE_I386:
656 base_address = SHARED_REGION_BASE_I386;
657 size = SHARED_REGION_SIZE_I386;
658 pmap_nesting_start = SHARED_REGION_NESTING_BASE_I386;
659 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_I386;
660 break;
661 case CPU_TYPE_POWERPC:
662 base_address = SHARED_REGION_BASE_PPC;
663 size = SHARED_REGION_SIZE_PPC;
664 pmap_nesting_start = SHARED_REGION_NESTING_BASE_PPC;
665 pmap_nesting_size = SHARED_REGION_NESTING_SIZE_PPC;
666 break;
667 default:
668 SHARED_REGION_TRACE_ERROR(
669 ("shared_region: create: unknown cpu type %d\n",
670 cputype));
671 kfree(shared_region, sizeof (*shared_region));
672 shared_region = NULL;
673 goto done;
674 }
675 }
676
677 /* create a memory entry structure and a Mach port handle */
678 kr = mach_memory_entry_allocate(&mem_entry,
679 &mem_entry_port);
680 if (kr != KERN_SUCCESS) {
681 kfree(shared_region, sizeof (*shared_region));
682 shared_region = NULL;
683 SHARED_REGION_TRACE_ERROR(
684 ("shared_region: create: "
685 "couldn't allocate mem_entry\n"));
686 goto done;
687 }
688
689 /* create a VM sub map and its pmap */
690 sub_map = vm_map_create(pmap_create(NULL, 0, is_64bit),
691 0, size,
692 TRUE);
693 if (sub_map == VM_MAP_NULL) {
694 ipc_port_release_send(mem_entry_port);
695 kfree(shared_region, sizeof (*shared_region));
696 shared_region = NULL;
697 SHARED_REGION_TRACE_ERROR(
698 ("shared_region: create: "
699 "couldn't allocate map\n"));
700 goto done;
701 }
702
703 /* make the memory entry point to the VM sub map */
704 mem_entry->is_sub_map = TRUE;
705 mem_entry->backing.map = sub_map;
706 mem_entry->size = size;
707 mem_entry->protection = VM_PROT_ALL;
708
709 /* make the shared region point at the memory entry */
710 shared_region->sr_mem_entry = mem_entry_port;
711
712 /* fill in the shared region's environment and settings */
713 shared_region->sr_base_address = base_address;
714 shared_region->sr_size = size;
715 shared_region->sr_pmap_nesting_start = pmap_nesting_start;
716 shared_region->sr_pmap_nesting_size = pmap_nesting_size;
717 shared_region->sr_cpu_type = cputype;
718 shared_region->sr_64bit = is_64bit;
719 shared_region->sr_root_dir = root_dir;
720
721 queue_init(&shared_region->sr_q);
722 shared_region->sr_mapping_in_progress = FALSE;
723 shared_region->sr_slide_in_progress = FALSE;
724 shared_region->sr_persists = FALSE;
725 shared_region->sr_slid = FALSE;
726 shared_region->sr_timer_call = NULL;
727 shared_region->sr_first_mapping = (mach_vm_offset_t) -1;
728
729 /* grab a reference for the caller */
730 shared_region->sr_ref_count = 1;
731
732 /* And set up slide info */
733 si = &shared_region->sr_slide_info;
734 si->start = 0;
735 si->end = 0;
736 si->slide = 0;
737 si->slide_object = NULL;
738 si->slide_info_size = 0;
739 si->slide_info_entry = NULL;
740
741 done:
742 if (shared_region) {
743 SHARED_REGION_TRACE_INFO(
744 ("shared_region: create(root=%p,cpu=%d,64bit=%d,"
745 "base=0x%llx,size=0x%llx) <- "
746 "%p mem=(%p,%p) map=%p pmap=%p\n",
747 root_dir, cputype, is_64bit, (long long)base_address,
748 (long long)size, shared_region,
749 mem_entry_port, mem_entry, sub_map, sub_map->pmap));
750 } else {
751 SHARED_REGION_TRACE_INFO(
752 ("shared_region: create(root=%p,cpu=%d,64bit=%d,"
753 "base=0x%llx,size=0x%llx) <- NULL",
754 root_dir, cputype, is_64bit, (long long)base_address,
755 (long long)size));
756 }
757 return shared_region;
758 }
759
760 /*
761 * Destroy a now-unused shared region.
762 * The shared region is no longer in the queue and can not be looked up.
763 */
764 static void
765 vm_shared_region_destroy(
766 vm_shared_region_t shared_region)
767 {
768 vm_named_entry_t mem_entry;
769 vm_map_t map;
770
771 SHARED_REGION_TRACE_INFO(
772 ("shared_region: -> destroy(%p) (root=%p,cpu=%d,64bit=%d)\n",
773 shared_region,
774 shared_region->sr_root_dir,
775 shared_region->sr_cpu_type,
776 shared_region->sr_64bit));
777
778 assert(shared_region->sr_ref_count == 0);
779 assert(!shared_region->sr_persists);
780 assert(!shared_region->sr_slid);
781
782 mem_entry = (vm_named_entry_t) shared_region->sr_mem_entry->ip_kobject;
783 assert(mem_entry->is_sub_map);
784 assert(!mem_entry->internal);
785 assert(!mem_entry->is_pager);
786 assert(!mem_entry->is_copy);
787 map = mem_entry->backing.map;
788
789 /*
790 * Clean up the pmap first. The virtual addresses that were
791 * entered in this possibly "nested" pmap may have different values
792 * than the VM map's min and max offsets, if the VM sub map was
793 * mapped at a non-zero offset in the processes' main VM maps, which
794 * is usually the case, so the clean-up we do in vm_map_destroy() would
795 * not be enough.
796 */
797 if (map->pmap) {
798 pmap_remove(map->pmap,
799 shared_region->sr_base_address,
800 (shared_region->sr_base_address +
801 shared_region->sr_size));
802 }
803
804 /*
805 * Release our (one and only) handle on the memory entry.
806 * This will generate a no-senders notification, which will be processed
807 * by ipc_kobject_notify(), which will release the one and only
808 * reference on the memory entry and cause it to be destroyed, along
809 * with the VM sub map and its pmap.
810 */
811 mach_memory_entry_port_release(shared_region->sr_mem_entry);
812 mem_entry = NULL;
813 shared_region->sr_mem_entry = IPC_PORT_NULL;
814
815 if (shared_region->sr_timer_call) {
816 thread_call_free(shared_region->sr_timer_call);
817 }
818
819 #if 0
820 /*
821 * If slid, free those resources. We'll want this eventually,
822 * but can't handle it properly today.
823 */
824 si = &shared_region->sr_slide_info;
825 if (si->slide_info_entry) {
826 kmem_free(kernel_map,
827 (vm_offset_t) si->slide_info_entry,
828 (vm_size_t) si->slide_info_size);
829 vm_object_deallocate(si->slide_object);
830 }
831 #endif
832
833 /* release the shared region structure... */
834 kfree(shared_region, sizeof (*shared_region));
835
836 SHARED_REGION_TRACE_DEBUG(
837 ("shared_region: destroy(%p) <-\n",
838 shared_region));
839 shared_region = NULL;
840
841 }
842
843 /*
844 * Gets the address of the first (in time) mapping in the shared region.
845 */
846 kern_return_t
847 vm_shared_region_start_address(
848 vm_shared_region_t shared_region,
849 mach_vm_offset_t *start_address)
850 {
851 kern_return_t kr;
852 mach_vm_offset_t sr_base_address;
853 mach_vm_offset_t sr_first_mapping;
854
855 SHARED_REGION_TRACE_DEBUG(
856 ("shared_region: -> start_address(%p)\n",
857 shared_region));
858 assert(shared_region->sr_ref_count > 1);
859
860 vm_shared_region_lock();
861
862 /*
863 * Wait if there's another thread establishing a mapping
864 * in this shared region right when we're looking at it.
865 * We want a consistent view of the map...
866 */
867 while (shared_region->sr_mapping_in_progress) {
868 /* wait for our turn... */
869 assert(shared_region->sr_ref_count > 1);
870 vm_shared_region_sleep(&shared_region->sr_mapping_in_progress,
871 THREAD_UNINT);
872 }
873 assert(! shared_region->sr_mapping_in_progress);
874 assert(shared_region->sr_ref_count > 1);
875
876 sr_base_address = shared_region->sr_base_address;
877 sr_first_mapping = shared_region->sr_first_mapping;
878
879 if (sr_first_mapping == (mach_vm_offset_t) -1) {
880 /* shared region is empty */
881 kr = KERN_INVALID_ADDRESS;
882 } else {
883 kr = KERN_SUCCESS;
884 *start_address = sr_base_address + sr_first_mapping;
885 }
886
887 vm_shared_region_unlock();
888
889 SHARED_REGION_TRACE_DEBUG(
890 ("shared_region: start_address(%p) <- 0x%llx\n",
891 shared_region, (long long)shared_region->sr_base_address));
892
893 return kr;
894 }
895
896 void
897 vm_shared_region_undo_mappings(
898 vm_map_t sr_map,
899 mach_vm_offset_t sr_base_address,
900 struct shared_file_mapping_np *mappings,
901 unsigned int mappings_count)
902 {
903 unsigned int j = 0;
904 vm_shared_region_t shared_region = NULL;
905 boolean_t reset_shared_region_state = FALSE;
906
907 shared_region = vm_shared_region_get(current_task());
908 if (shared_region == NULL) {
909 printf("Failed to undo mappings because of NULL shared region.\n");
910 return;
911 }
912
913
914 if (sr_map == NULL) {
915 ipc_port_t sr_handle;
916 vm_named_entry_t sr_mem_entry;
917
918 vm_shared_region_lock();
919 assert(shared_region->sr_ref_count > 1);
920
921 while (shared_region->sr_mapping_in_progress) {
922 /* wait for our turn... */
923 vm_shared_region_sleep(&shared_region->sr_mapping_in_progress,
924 THREAD_UNINT);
925 }
926 assert(! shared_region->sr_mapping_in_progress);
927 assert(shared_region->sr_ref_count > 1);
928 /* let others know we're working in this shared region */
929 shared_region->sr_mapping_in_progress = TRUE;
930
931 vm_shared_region_unlock();
932
933 reset_shared_region_state = TRUE;
934
935 /* no need to lock because this data is never modified... */
936 sr_handle = shared_region->sr_mem_entry;
937 sr_mem_entry = (vm_named_entry_t) sr_handle->ip_kobject;
938 sr_map = sr_mem_entry->backing.map;
939 sr_base_address = shared_region->sr_base_address;
940 }
941 /*
942 * Undo the mappings we've established so far.
943 */
944 for (j = 0; j < mappings_count; j++) {
945 kern_return_t kr2;
946
947 if (mappings[j].sfm_size == 0) {
948 /*
949 * We didn't establish this
950 * mapping, so nothing to undo.
951 */
952 continue;
953 }
954 SHARED_REGION_TRACE_INFO(
955 ("shared_region: mapping[%d]: "
956 "address:0x%016llx "
957 "size:0x%016llx "
958 "offset:0x%016llx "
959 "maxprot:0x%x prot:0x%x: "
960 "undoing...\n",
961 j,
962 (long long)mappings[j].sfm_address,
963 (long long)mappings[j].sfm_size,
964 (long long)mappings[j].sfm_file_offset,
965 mappings[j].sfm_max_prot,
966 mappings[j].sfm_init_prot));
967 kr2 = mach_vm_deallocate(
968 sr_map,
969 (mappings[j].sfm_address -
970 sr_base_address),
971 mappings[j].sfm_size);
972 assert(kr2 == KERN_SUCCESS);
973 }
974
975 /*
976 * This is how check_np() knows if the shared region
977 * is mapped. So clear it here.
978 */
979 shared_region->sr_first_mapping = (mach_vm_offset_t) -1;
980
981 if (reset_shared_region_state) {
982 vm_shared_region_lock();
983 assert(shared_region->sr_ref_count > 1);
984 assert(shared_region->sr_mapping_in_progress);
985 /* we're done working on that shared region */
986 shared_region->sr_mapping_in_progress = FALSE;
987 thread_wakeup((event_t) &shared_region->sr_mapping_in_progress);
988 vm_shared_region_unlock();
989 reset_shared_region_state = FALSE;
990 }
991
992 vm_shared_region_deallocate(shared_region);
993 }
994
995 /*
996 * Establish some mappings of a file in the shared region.
997 * This is used by "dyld" via the shared_region_map_np() system call
998 * to populate the shared region with the appropriate shared cache.
999 *
1000 * One could also call it several times to incrementally load several
1001 * libraries, as long as they do not overlap.
1002 * It will return KERN_SUCCESS if the mappings were successfully established
1003 * or if they were already established identically by another process.
1004 */
1005 kern_return_t
1006 vm_shared_region_map_file(
1007 vm_shared_region_t shared_region,
1008 unsigned int mappings_count,
1009 struct shared_file_mapping_np *mappings,
1010 memory_object_control_t file_control,
1011 memory_object_size_t file_size,
1012 void *root_dir,
1013 struct shared_file_mapping_np *mapping_to_slide)
1014 {
1015 kern_return_t kr;
1016 vm_object_t file_object;
1017 ipc_port_t sr_handle;
1018 vm_named_entry_t sr_mem_entry;
1019 vm_map_t sr_map;
1020 mach_vm_offset_t sr_base_address;
1021 unsigned int i;
1022 mach_port_t map_port;
1023 vm_map_offset_t target_address;
1024 vm_object_t object;
1025 vm_object_size_t obj_size;
1026 boolean_t found_mapping_to_slide = FALSE;
1027
1028
1029 kr = KERN_SUCCESS;
1030
1031 vm_shared_region_lock();
1032 assert(shared_region->sr_ref_count > 1);
1033
1034 if (shared_region->sr_root_dir != root_dir) {
1035 /*
1036 * This shared region doesn't match the current root
1037 * directory of this process. Deny the mapping to
1038 * avoid tainting the shared region with something that
1039 * doesn't quite belong into it.
1040 */
1041 vm_shared_region_unlock();
1042 kr = KERN_PROTECTION_FAILURE;
1043 goto done;
1044 }
1045
1046 /*
1047 * Make sure we handle only one mapping at a time in a given
1048 * shared region, to avoid race conditions. This should not
1049 * happen frequently...
1050 */
1051 while (shared_region->sr_mapping_in_progress) {
1052 /* wait for our turn... */
1053 vm_shared_region_sleep(&shared_region->sr_mapping_in_progress,
1054 THREAD_UNINT);
1055 }
1056 assert(! shared_region->sr_mapping_in_progress);
1057 assert(shared_region->sr_ref_count > 1);
1058 /* let others know we're working in this shared region */
1059 shared_region->sr_mapping_in_progress = TRUE;
1060
1061 vm_shared_region_unlock();
1062
1063 /* no need to lock because this data is never modified... */
1064 sr_handle = shared_region->sr_mem_entry;
1065 sr_mem_entry = (vm_named_entry_t) sr_handle->ip_kobject;
1066 sr_map = sr_mem_entry->backing.map;
1067 sr_base_address = shared_region->sr_base_address;
1068
1069 SHARED_REGION_TRACE_DEBUG(
1070 ("shared_region: -> map(%p,%d,%p,%p,0x%llx)\n",
1071 shared_region, mappings_count, mappings,
1072 file_control, file_size));
1073
1074 /* get the VM object associated with the file to be mapped */
1075 file_object = memory_object_control_to_vm_object(file_control);
1076
1077 /* establish the mappings */
1078 for (i = 0; i < mappings_count; i++) {
1079 SHARED_REGION_TRACE_INFO(
1080 ("shared_region: mapping[%d]: "
1081 "address:0x%016llx size:0x%016llx offset:0x%016llx "
1082 "maxprot:0x%x prot:0x%x\n",
1083 i,
1084 (long long)mappings[i].sfm_address,
1085 (long long)mappings[i].sfm_size,
1086 (long long)mappings[i].sfm_file_offset,
1087 mappings[i].sfm_max_prot,
1088 mappings[i].sfm_init_prot));
1089
1090 if (mappings[i].sfm_init_prot & VM_PROT_ZF) {
1091 /* zero-filled memory */
1092 map_port = MACH_PORT_NULL;
1093 } else {
1094 /* file-backed memory */
1095 map_port = (ipc_port_t) file_object->pager;
1096 }
1097
1098 if (mappings[i].sfm_init_prot & VM_PROT_SLIDE) {
1099 /*
1100 * This is the mapping that needs to be slid.
1101 */
1102 if (found_mapping_to_slide == TRUE) {
1103 SHARED_REGION_TRACE_INFO(
1104 ("shared_region: mapping[%d]: "
1105 "address:0x%016llx size:0x%016llx "
1106 "offset:0x%016llx "
1107 "maxprot:0x%x prot:0x%x "
1108 "will not be slid as only one such mapping is allowed...\n",
1109 i,
1110 (long long)mappings[i].sfm_address,
1111 (long long)mappings[i].sfm_size,
1112 (long long)mappings[i].sfm_file_offset,
1113 mappings[i].sfm_max_prot,
1114 mappings[i].sfm_init_prot));
1115 } else {
1116 if (mapping_to_slide != NULL) {
1117 mapping_to_slide->sfm_file_offset = mappings[i].sfm_file_offset;
1118 mapping_to_slide->sfm_size = mappings[i].sfm_size;
1119 found_mapping_to_slide = TRUE;
1120 }
1121 }
1122 }
1123
1124 /* mapping's address is relative to the shared region base */
1125 target_address =
1126 mappings[i].sfm_address - sr_base_address;
1127
1128 /* establish that mapping, OK if it's "already" there */
1129 if (map_port == MACH_PORT_NULL) {
1130 /*
1131 * We want to map some anonymous memory in a
1132 * shared region.
1133 * We have to create the VM object now, so that it
1134 * can be mapped "copy-on-write".
1135 */
1136 obj_size = vm_map_round_page(mappings[i].sfm_size,
1137 VM_MAP_PAGE_MASK(sr_map));
1138 object = vm_object_allocate(obj_size);
1139 if (object == VM_OBJECT_NULL) {
1140 kr = KERN_RESOURCE_SHORTAGE;
1141 } else {
1142 kr = vm_map_enter(
1143 sr_map,
1144 &target_address,
1145 vm_map_round_page(mappings[i].sfm_size,
1146 VM_MAP_PAGE_MASK(sr_map)),
1147 0,
1148 VM_FLAGS_FIXED | VM_FLAGS_ALREADY,
1149 object,
1150 0,
1151 TRUE,
1152 mappings[i].sfm_init_prot & VM_PROT_ALL,
1153 mappings[i].sfm_max_prot & VM_PROT_ALL,
1154 VM_INHERIT_DEFAULT);
1155 }
1156 } else {
1157 object = VM_OBJECT_NULL; /* no anonymous memory here */
1158 kr = vm_map_enter_mem_object(
1159 sr_map,
1160 &target_address,
1161 vm_map_round_page(mappings[i].sfm_size,
1162 VM_MAP_PAGE_MASK(sr_map)),
1163 0,
1164 VM_FLAGS_FIXED | VM_FLAGS_ALREADY,
1165 map_port,
1166 mappings[i].sfm_file_offset,
1167 TRUE,
1168 mappings[i].sfm_init_prot & VM_PROT_ALL,
1169 mappings[i].sfm_max_prot & VM_PROT_ALL,
1170 VM_INHERIT_DEFAULT);
1171 }
1172
1173 if (kr != KERN_SUCCESS) {
1174 if (map_port == MACH_PORT_NULL) {
1175 /*
1176 * Get rid of the VM object we just created
1177 * but failed to map.
1178 */
1179 vm_object_deallocate(object);
1180 object = VM_OBJECT_NULL;
1181 }
1182 if (kr == KERN_MEMORY_PRESENT) {
1183 /*
1184 * This exact mapping was already there:
1185 * that's fine.
1186 */
1187 SHARED_REGION_TRACE_INFO(
1188 ("shared_region: mapping[%d]: "
1189 "address:0x%016llx size:0x%016llx "
1190 "offset:0x%016llx "
1191 "maxprot:0x%x prot:0x%x "
1192 "already mapped...\n",
1193 i,
1194 (long long)mappings[i].sfm_address,
1195 (long long)mappings[i].sfm_size,
1196 (long long)mappings[i].sfm_file_offset,
1197 mappings[i].sfm_max_prot,
1198 mappings[i].sfm_init_prot));
1199 /*
1200 * We didn't establish this mapping ourselves;
1201 * let's reset its size, so that we do not
1202 * attempt to undo it if an error occurs later.
1203 */
1204 mappings[i].sfm_size = 0;
1205 kr = KERN_SUCCESS;
1206 } else {
1207 /* this mapping failed ! */
1208 SHARED_REGION_TRACE_ERROR(
1209 ("shared_region: mapping[%d]: "
1210 "address:0x%016llx size:0x%016llx "
1211 "offset:0x%016llx "
1212 "maxprot:0x%x prot:0x%x failed 0x%x\n",
1213 i,
1214 (long long)mappings[i].sfm_address,
1215 (long long)mappings[i].sfm_size,
1216 (long long)mappings[i].sfm_file_offset,
1217 mappings[i].sfm_max_prot,
1218 mappings[i].sfm_init_prot,
1219 kr));
1220
1221 vm_shared_region_undo_mappings(sr_map, sr_base_address, mappings, i);
1222 break;
1223 }
1224
1225 }
1226
1227 /*
1228 * Record the first (chronologically) mapping in
1229 * this shared region.
1230 * We're protected by "sr_mapping_in_progress" here,
1231 * so no need to lock "shared_region".
1232 */
1233 if (shared_region->sr_first_mapping == (mach_vm_offset_t) -1) {
1234 shared_region->sr_first_mapping = target_address;
1235 }
1236 }
1237
1238 vm_shared_region_lock();
1239 assert(shared_region->sr_ref_count > 1);
1240 assert(shared_region->sr_mapping_in_progress);
1241 /* we're done working on that shared region */
1242 shared_region->sr_mapping_in_progress = FALSE;
1243 thread_wakeup((event_t) &shared_region->sr_mapping_in_progress);
1244 vm_shared_region_unlock();
1245
1246 done:
1247 SHARED_REGION_TRACE_DEBUG(
1248 ("shared_region: map(%p,%d,%p,%p,0x%llx) <- 0x%x \n",
1249 shared_region, mappings_count, mappings,
1250 file_control, file_size, kr));
1251 return kr;
1252 }
1253
1254 /*
1255 * Enter the appropriate shared region into "map" for "task".
1256 * This involves looking up the shared region (and possibly creating a new
1257 * one) for the desired environment, then mapping the VM sub map into the
1258 * task's VM "map", with the appropriate level of pmap-nesting.
1259 */
1260 kern_return_t
1261 vm_shared_region_enter(
1262 struct _vm_map *map,
1263 struct task *task,
1264 void *fsroot,
1265 cpu_type_t cpu)
1266 {
1267 kern_return_t kr;
1268 vm_shared_region_t shared_region;
1269 vm_map_offset_t sr_address, sr_offset, target_address;
1270 vm_map_size_t sr_size, mapping_size;
1271 vm_map_offset_t sr_pmap_nesting_start;
1272 vm_map_size_t sr_pmap_nesting_size;
1273 ipc_port_t sr_handle;
1274 boolean_t is_64bit;
1275
1276 is_64bit = task_has_64BitAddr(task);
1277
1278 SHARED_REGION_TRACE_DEBUG(
1279 ("shared_region: -> "
1280 "enter(map=%p,task=%p,root=%p,cpu=%d,64bit=%d)\n",
1281 map, task, fsroot, cpu, is_64bit));
1282
1283 /* lookup (create if needed) the shared region for this environment */
1284 shared_region = vm_shared_region_lookup(fsroot, cpu, is_64bit);
1285 if (shared_region == NULL) {
1286 /* this should not happen ! */
1287 SHARED_REGION_TRACE_ERROR(
1288 ("shared_region: -> "
1289 "enter(map=%p,task=%p,root=%p,cpu=%d,64bit=%d): "
1290 "lookup failed !\n",
1291 map, task, fsroot, cpu, is_64bit));
1292 //panic("shared_region_enter: lookup failed\n");
1293 return KERN_FAILURE;
1294 }
1295
1296 /* let the task use that shared region */
1297 vm_shared_region_set(task, shared_region);
1298
1299 kr = KERN_SUCCESS;
1300 /* no need to lock since this data is never modified */
1301 sr_address = shared_region->sr_base_address;
1302 sr_size = shared_region->sr_size;
1303 sr_handle = shared_region->sr_mem_entry;
1304 sr_pmap_nesting_start = shared_region->sr_pmap_nesting_start;
1305 sr_pmap_nesting_size = shared_region->sr_pmap_nesting_size;
1306
1307 /*
1308 * Start mapping the shared region's VM sub map into the task's VM map.
1309 */
1310 sr_offset = 0;
1311
1312 if (sr_pmap_nesting_start > sr_address) {
1313 /* we need to map a range without pmap-nesting first */
1314 target_address = sr_address;
1315 mapping_size = sr_pmap_nesting_start - sr_address;
1316 kr = vm_map_enter_mem_object(
1317 map,
1318 &target_address,
1319 mapping_size,
1320 0,
1321 VM_FLAGS_FIXED,
1322 sr_handle,
1323 sr_offset,
1324 TRUE,
1325 VM_PROT_READ,
1326 VM_PROT_ALL,
1327 VM_INHERIT_SHARE);
1328 if (kr != KERN_SUCCESS) {
1329 SHARED_REGION_TRACE_ERROR(
1330 ("shared_region: enter(%p,%p,%p,%d,%d): "
1331 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
1332 map, task, fsroot, cpu, is_64bit,
1333 (long long)target_address,
1334 (long long)mapping_size, sr_handle, kr));
1335 goto done;
1336 }
1337 SHARED_REGION_TRACE_DEBUG(
1338 ("shared_region: enter(%p,%p,%p,%d,%d): "
1339 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
1340 map, task, fsroot, cpu, is_64bit,
1341 (long long)target_address, (long long)mapping_size,
1342 sr_handle, kr));
1343 sr_offset += mapping_size;
1344 sr_size -= mapping_size;
1345 }
1346 /*
1347 * We may need to map several pmap-nested portions, due to platform
1348 * specific restrictions on pmap nesting.
1349 * The pmap-nesting is triggered by the "VM_MEMORY_SHARED_PMAP" alias...
1350 */
1351 for (;
1352 sr_pmap_nesting_size > 0;
1353 sr_offset += mapping_size,
1354 sr_size -= mapping_size,
1355 sr_pmap_nesting_size -= mapping_size) {
1356 target_address = sr_address + sr_offset;
1357 mapping_size = sr_pmap_nesting_size;
1358 if (mapping_size > pmap_nesting_size_max) {
1359 mapping_size = (vm_map_offset_t) pmap_nesting_size_max;
1360 }
1361 kr = vm_map_enter_mem_object(
1362 map,
1363 &target_address,
1364 mapping_size,
1365 0,
1366 (VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_SHARED_PMAP)),
1367 sr_handle,
1368 sr_offset,
1369 TRUE,
1370 VM_PROT_READ,
1371 VM_PROT_ALL,
1372 VM_INHERIT_SHARE);
1373 if (kr != KERN_SUCCESS) {
1374 SHARED_REGION_TRACE_ERROR(
1375 ("shared_region: enter(%p,%p,%p,%d,%d): "
1376 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
1377 map, task, fsroot, cpu, is_64bit,
1378 (long long)target_address,
1379 (long long)mapping_size, sr_handle, kr));
1380 goto done;
1381 }
1382 SHARED_REGION_TRACE_DEBUG(
1383 ("shared_region: enter(%p,%p,%p,%d,%d): "
1384 "nested vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
1385 map, task, fsroot, cpu, is_64bit,
1386 (long long)target_address, (long long)mapping_size,
1387 sr_handle, kr));
1388 }
1389 if (sr_size > 0) {
1390 /* and there's some left to be mapped without pmap-nesting */
1391 target_address = sr_address + sr_offset;
1392 mapping_size = sr_size;
1393 kr = vm_map_enter_mem_object(
1394 map,
1395 &target_address,
1396 mapping_size,
1397 0,
1398 VM_FLAGS_FIXED,
1399 sr_handle,
1400 sr_offset,
1401 TRUE,
1402 VM_PROT_READ,
1403 VM_PROT_ALL,
1404 VM_INHERIT_SHARE);
1405 if (kr != KERN_SUCCESS) {
1406 SHARED_REGION_TRACE_ERROR(
1407 ("shared_region: enter(%p,%p,%p,%d,%d): "
1408 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
1409 map, task, fsroot, cpu, is_64bit,
1410 (long long)target_address,
1411 (long long)mapping_size, sr_handle, kr));
1412 goto done;
1413 }
1414 SHARED_REGION_TRACE_DEBUG(
1415 ("shared_region: enter(%p,%p,%p,%d,%d): "
1416 "vm_map_enter(0x%llx,0x%llx,%p) error 0x%x\n",
1417 map, task, fsroot, cpu, is_64bit,
1418 (long long)target_address, (long long)mapping_size,
1419 sr_handle, kr));
1420 sr_offset += mapping_size;
1421 sr_size -= mapping_size;
1422 }
1423 assert(sr_size == 0);
1424
1425 done:
1426 SHARED_REGION_TRACE_DEBUG(
1427 ("shared_region: enter(%p,%p,%p,%d,%d) <- 0x%x\n",
1428 map, task, fsroot, cpu, is_64bit, kr));
1429 return kr;
1430 }
1431
1432 #define SANE_SLIDE_INFO_SIZE (1024*1024) /*Can be changed if needed*/
1433 struct vm_shared_region_slide_info slide_info;
1434
1435 kern_return_t
1436 vm_shared_region_sliding_valid(uint32_t slide)
1437 {
1438 kern_return_t kr = KERN_SUCCESS;
1439 vm_shared_region_t sr = vm_shared_region_get(current_task());
1440
1441 /* No region yet? we're fine. */
1442 if (sr == NULL) {
1443 return kr;
1444 }
1445
1446 if ((sr->sr_slid == TRUE) && slide) {
1447 if (slide != vm_shared_region_get_slide_info(sr)->slide) {
1448 printf("Only one shared region can be slid\n");
1449 kr = KERN_FAILURE;
1450 } else {
1451 /*
1452 * Request for sliding when we've
1453 * already done it with exactly the
1454 * same slide value before.
1455 * This isn't wrong technically but
1456 * we don't want to slide again and
1457 * so we return this value.
1458 */
1459 kr = KERN_INVALID_ARGUMENT;
1460 }
1461 }
1462 vm_shared_region_deallocate(sr);
1463 return kr;
1464 }
1465
1466 kern_return_t
1467 vm_shared_region_slide_init(
1468 vm_shared_region_t sr,
1469 mach_vm_size_t slide_info_size,
1470 mach_vm_offset_t start,
1471 mach_vm_size_t size,
1472 uint32_t slide,
1473 memory_object_control_t sr_file_control)
1474 {
1475 kern_return_t kr = KERN_SUCCESS;
1476 vm_object_t object = VM_OBJECT_NULL;
1477 vm_object_offset_t offset = 0;
1478 vm_shared_region_slide_info_t si = vm_shared_region_get_slide_info(sr);
1479 vm_offset_t slide_info_entry;
1480
1481 vm_map_t map = NULL, cur_map = NULL;
1482 boolean_t is_map_locked = FALSE;
1483
1484 assert(sr->sr_slide_in_progress);
1485 assert(!sr->sr_slid);
1486 assert(si->slide_object == NULL);
1487 assert(si->slide_info_entry == NULL);
1488
1489 if (slide_info_size > SANE_SLIDE_INFO_SIZE) {
1490 printf("Slide_info_size too large: %lx\n", (uintptr_t)slide_info_size);
1491 kr = KERN_FAILURE;
1492 return kr;
1493 }
1494
1495 kr = kmem_alloc(kernel_map,
1496 (vm_offset_t *) &slide_info_entry,
1497 (vm_size_t) slide_info_size);
1498 if (kr != KERN_SUCCESS) {
1499 return kr;
1500 }
1501
1502 if (sr_file_control != MEMORY_OBJECT_CONTROL_NULL) {
1503
1504 object = memory_object_control_to_vm_object(sr_file_control);
1505 vm_object_reference(object);
1506 offset = start;
1507
1508 vm_object_lock(object);
1509 } else {
1510 /*
1511 * Remove this entire "else" block and all "map" references
1512 * once we get rid of the shared_region_slide_np()
1513 * system call.
1514 */
1515 vm_map_entry_t entry = VM_MAP_ENTRY_NULL;
1516 map = current_map();
1517 vm_map_lock_read(map);
1518 is_map_locked = TRUE;
1519 Retry:
1520 cur_map = map;
1521 if(!vm_map_lookup_entry(map, start, &entry)) {
1522 kr = KERN_INVALID_ARGUMENT;
1523 } else {
1524 vm_object_t shadow_obj = VM_OBJECT_NULL;
1525
1526 if (entry->is_sub_map == TRUE) {
1527 map = entry->object.sub_map;
1528 start -= entry->vme_start;
1529 start += entry->offset;
1530 vm_map_lock_read(map);
1531 vm_map_unlock_read(cur_map);
1532 goto Retry;
1533 } else {
1534 object = entry->object.vm_object;
1535 offset = (start - entry->vme_start) + entry->offset;
1536 }
1537
1538 vm_object_lock(object);
1539 while (object->shadow != VM_OBJECT_NULL) {
1540 shadow_obj = object->shadow;
1541 vm_object_lock(shadow_obj);
1542 vm_object_unlock(object);
1543 object = shadow_obj;
1544 }
1545 }
1546 }
1547
1548 if (object->internal == TRUE) {
1549 kr = KERN_INVALID_ADDRESS;
1550 } else if (object->object_slid) {
1551 /* Can only be slid once */
1552 printf("%s: found vm_object %p already slid?\n", __FUNCTION__, object);
1553 kr = KERN_FAILURE;
1554 } else {
1555
1556 si->slide_info_entry = (vm_shared_region_slide_info_entry_t)slide_info_entry;
1557 si->slide_info_size = slide_info_size;
1558 si->slide_object = object;
1559 si->start = offset;
1560 si->end = si->start + size;
1561 si->slide = slide;
1562
1563 /*
1564 * If we want to have this region get deallocated/freed
1565 * then we will have to make sure that we msync(..MS_INVALIDATE..)
1566 * the pages associated with this shared region. Those pages would
1567 * have been slid with an older slide value.
1568 */
1569
1570 /*
1571 * Pointers in object are held without references; they
1572 * are disconnected at the time that we destroy the
1573 * shared region, and since the shared region holds
1574 * a reference on the object, no references in the other
1575 * direction are required.
1576 */
1577 object->object_slid = TRUE;
1578 object->vo_slide_info = si;
1579 }
1580
1581 vm_object_unlock(object);
1582 if (is_map_locked == TRUE) {
1583 vm_map_unlock_read(map);
1584 }
1585
1586 if (kr != KERN_SUCCESS) {
1587 kmem_free(kernel_map, slide_info_entry, slide_info_size);
1588 }
1589 return kr;
1590 }
1591
1592 void*
1593 vm_shared_region_get_slide_info_entry(vm_shared_region_t sr) {
1594 return (void*)sr->sr_slide_info.slide_info_entry;
1595 }
1596
1597
1598 kern_return_t
1599 vm_shared_region_slide_sanity_check(vm_shared_region_t sr)
1600 {
1601 uint32_t pageIndex=0;
1602 uint16_t entryIndex=0;
1603 uint16_t *toc = NULL;
1604 vm_shared_region_slide_info_t si;
1605 vm_shared_region_slide_info_entry_t s_info;
1606 kern_return_t kr;
1607
1608 si = vm_shared_region_get_slide_info(sr);
1609 s_info = si->slide_info_entry;
1610 toc = (uint16_t*)((uintptr_t)s_info + s_info->toc_offset);
1611
1612 kr = mach_vm_protect(kernel_map,
1613 (mach_vm_offset_t)(vm_offset_t)s_info,
1614 (mach_vm_size_t) si->slide_info_size,
1615 TRUE, VM_PROT_READ);
1616 if (kr != KERN_SUCCESS) {
1617 panic("vm_shared_region_slide_sanity_check: vm_protect() error 0x%x\n", kr);
1618 }
1619
1620 for (;pageIndex < s_info->toc_count; pageIndex++) {
1621
1622 entryIndex = (uint16_t)(toc[pageIndex]);
1623
1624 if (entryIndex >= s_info->entry_count) {
1625 printf("No sliding bitmap entry for pageIndex: %d at entryIndex: %d amongst %d entries\n", pageIndex, entryIndex, s_info->entry_count);
1626 goto fail;
1627 }
1628
1629 }
1630 return KERN_SUCCESS;
1631 fail:
1632 if (si->slide_info_entry != NULL) {
1633 kmem_free(kernel_map,
1634 (vm_offset_t) si->slide_info_entry,
1635 (vm_size_t) si->slide_info_size);
1636
1637 vm_object_lock(si->slide_object);
1638 si->slide_object->object_slid = FALSE;
1639 si->slide_object->vo_slide_info = NULL;
1640 vm_object_unlock(si->slide_object);
1641
1642 vm_object_deallocate(si->slide_object);
1643 si->slide_object = NULL;
1644 si->start = 0;
1645 si->end = 0;
1646 si->slide = 0;
1647 si->slide_info_entry = NULL;
1648 si->slide_info_size = 0;
1649 }
1650 return KERN_FAILURE;
1651 }
1652
1653 kern_return_t
1654 vm_shared_region_slide_page(vm_shared_region_slide_info_t si, vm_offset_t vaddr, uint32_t pageIndex)
1655 {
1656 uint16_t *toc = NULL;
1657 slide_info_entry_toc_t bitmap = NULL;
1658 uint32_t i=0, j=0;
1659 uint8_t b = 0;
1660 uint32_t slide = si->slide;
1661 int is_64 = task_has_64BitAddr(current_task());
1662
1663 vm_shared_region_slide_info_entry_t s_info = si->slide_info_entry;
1664 toc = (uint16_t*)((uintptr_t)s_info + s_info->toc_offset);
1665
1666 if (pageIndex >= s_info->toc_count) {
1667 printf("No slide entry for this page in toc. PageIndex: %d Toc Count: %d\n", pageIndex, s_info->toc_count);
1668 } else {
1669 uint16_t entryIndex = (uint16_t)(toc[pageIndex]);
1670 slide_info_entry_toc_t slide_info_entries = (slide_info_entry_toc_t)((uintptr_t)s_info + s_info->entry_offset);
1671
1672 if (entryIndex >= s_info->entry_count) {
1673 printf("No sliding bitmap entry for entryIndex: %d amongst %d entries\n", entryIndex, s_info->entry_count);
1674 } else {
1675 bitmap = &slide_info_entries[entryIndex];
1676
1677 for(i=0; i < NUM_SLIDING_BITMAPS_PER_PAGE; ++i) {
1678 b = bitmap->entry[i];
1679 if (b!=0) {
1680 for (j=0; j <8; ++j) {
1681 if (b & (1 <<j)){
1682 uint32_t *ptr_to_slide;
1683 uint32_t old_value;
1684
1685 ptr_to_slide = (uint32_t*)((uintptr_t)(vaddr)+(sizeof(uint32_t)*(i*8 +j)));
1686 old_value = *ptr_to_slide;
1687 *ptr_to_slide += slide;
1688 if (is_64 && *ptr_to_slide < old_value) {
1689 /*
1690 * We just slid the low 32 bits of a 64-bit pointer
1691 * and it looks like there should have been a carry-over
1692 * to the upper 32 bits.
1693 * The sliding failed...
1694 */
1695 printf("vm_shared_region_slide() carry over: i=%d j=%d b=0x%x slide=0x%x old=0x%x new=0x%x\n",
1696 i, j, b, slide, old_value, *ptr_to_slide);
1697 return KERN_FAILURE;
1698 }
1699 }
1700 }
1701 }
1702 }
1703 }
1704 }
1705
1706 return KERN_SUCCESS;
1707 }
1708
1709 /******************************************************************************/
1710 /* Comm page support */
1711 /******************************************************************************/
1712
1713 ipc_port_t commpage32_handle = IPC_PORT_NULL;
1714 ipc_port_t commpage64_handle = IPC_PORT_NULL;
1715 vm_named_entry_t commpage32_entry = NULL;
1716 vm_named_entry_t commpage64_entry = NULL;
1717 vm_map_t commpage32_map = VM_MAP_NULL;
1718 vm_map_t commpage64_map = VM_MAP_NULL;
1719
1720 ipc_port_t commpage_text32_handle = IPC_PORT_NULL;
1721 ipc_port_t commpage_text64_handle = IPC_PORT_NULL;
1722 vm_named_entry_t commpage_text32_entry = NULL;
1723 vm_named_entry_t commpage_text64_entry = NULL;
1724 vm_map_t commpage_text32_map = VM_MAP_NULL;
1725 vm_map_t commpage_text64_map = VM_MAP_NULL;
1726
1727 user32_addr_t commpage_text32_location = (user32_addr_t) _COMM_PAGE32_TEXT_START;
1728 user64_addr_t commpage_text64_location = (user64_addr_t) _COMM_PAGE64_TEXT_START;
1729
1730 #if defined(__i386__) || defined(__x86_64__)
1731 /*
1732 * Create a memory entry, VM submap and pmap for one commpage.
1733 */
1734 static void
1735 _vm_commpage_init(
1736 ipc_port_t *handlep,
1737 vm_map_size_t size)
1738 {
1739 kern_return_t kr;
1740 vm_named_entry_t mem_entry;
1741 vm_map_t new_map;
1742
1743 SHARED_REGION_TRACE_DEBUG(
1744 ("commpage: -> _init(0x%llx)\n",
1745 (long long)size));
1746
1747 kr = mach_memory_entry_allocate(&mem_entry,
1748 handlep);
1749 if (kr != KERN_SUCCESS) {
1750 panic("_vm_commpage_init: could not allocate mem_entry");
1751 }
1752 new_map = vm_map_create(pmap_create(NULL, 0, FALSE), 0, size, TRUE);
1753 if (new_map == VM_MAP_NULL) {
1754 panic("_vm_commpage_init: could not allocate VM map");
1755 }
1756 mem_entry->backing.map = new_map;
1757 mem_entry->internal = TRUE;
1758 mem_entry->is_sub_map = TRUE;
1759 mem_entry->offset = 0;
1760 mem_entry->protection = VM_PROT_ALL;
1761 mem_entry->size = size;
1762
1763 SHARED_REGION_TRACE_DEBUG(
1764 ("commpage: _init(0x%llx) <- %p\n",
1765 (long long)size, *handlep));
1766 }
1767 #endif
1768
1769
1770 /*
1771 *Initialize the comm text pages at boot time
1772 */
1773 extern u_int32_t random(void);
1774 void
1775 vm_commpage_text_init(void)
1776 {
1777 SHARED_REGION_TRACE_DEBUG(
1778 ("commpage text: ->init()\n"));
1779 #if defined(__i386__) || defined(__x86_64__)
1780 /* create the 32 bit comm text page */
1781 unsigned int offset = (random() % _PFZ32_SLIDE_RANGE) << PAGE_SHIFT; /* restricting to 32bMAX-2PAGE */
1782 _vm_commpage_init(&commpage_text32_handle, _COMM_PAGE_TEXT_AREA_LENGTH);
1783 commpage_text32_entry = (vm_named_entry_t) commpage_text32_handle->ip_kobject;
1784 commpage_text32_map = commpage_text32_entry->backing.map;
1785 commpage_text32_location = (user32_addr_t) (_COMM_PAGE32_TEXT_START + offset);
1786 /* XXX if (cpu_is_64bit_capable()) ? */
1787 /* create the 64-bit comm page */
1788 offset = (random() % _PFZ64_SLIDE_RANGE) << PAGE_SHIFT; /* restricting sliding upto 2Mb range */
1789 _vm_commpage_init(&commpage_text64_handle, _COMM_PAGE_TEXT_AREA_LENGTH);
1790 commpage_text64_entry = (vm_named_entry_t) commpage_text64_handle->ip_kobject;
1791 commpage_text64_map = commpage_text64_entry->backing.map;
1792 commpage_text64_location = (user64_addr_t) (_COMM_PAGE64_TEXT_START + offset);
1793
1794 commpage_text_populate();
1795 #else
1796 #error Unknown architecture.
1797 #endif /* __i386__ || __x86_64__ */
1798 /* populate the routines in here */
1799 SHARED_REGION_TRACE_DEBUG(
1800 ("commpage text: init() <-\n"));
1801
1802 }
1803
1804 /*
1805 * Initialize the comm pages at boot time.
1806 */
1807 void
1808 vm_commpage_init(void)
1809 {
1810 SHARED_REGION_TRACE_DEBUG(
1811 ("commpage: -> init()\n"));
1812
1813 #if defined(__i386__) || defined(__x86_64__)
1814 /* create the 32-bit comm page */
1815 _vm_commpage_init(&commpage32_handle, _COMM_PAGE32_AREA_LENGTH);
1816 commpage32_entry = (vm_named_entry_t) commpage32_handle->ip_kobject;
1817 commpage32_map = commpage32_entry->backing.map;
1818
1819 /* XXX if (cpu_is_64bit_capable()) ? */
1820 /* create the 64-bit comm page */
1821 _vm_commpage_init(&commpage64_handle, _COMM_PAGE64_AREA_LENGTH);
1822 commpage64_entry = (vm_named_entry_t) commpage64_handle->ip_kobject;
1823 commpage64_map = commpage64_entry->backing.map;
1824
1825 #endif /* __i386__ || __x86_64__ */
1826
1827 /* populate them according to this specific platform */
1828 commpage_populate();
1829 __commpage_setup = 1;
1830 #if defined(__i386__) || defined(__x86_64__)
1831 if (__system_power_source == 0) {
1832 post_sys_powersource_internal(0, 1);
1833 }
1834 #endif /* __i386__ || __x86_64__ */
1835
1836 SHARED_REGION_TRACE_DEBUG(
1837 ("commpage: init() <-\n"));
1838 }
1839
1840 /*
1841 * Enter the appropriate comm page into the task's address space.
1842 * This is called at exec() time via vm_map_exec().
1843 */
1844 kern_return_t
1845 vm_commpage_enter(
1846 vm_map_t map,
1847 task_t task)
1848 {
1849 ipc_port_t commpage_handle, commpage_text_handle;
1850 vm_map_offset_t commpage_address, objc_address, commpage_text_address;
1851 vm_map_size_t commpage_size, objc_size, commpage_text_size;
1852 int vm_flags;
1853 kern_return_t kr;
1854
1855 SHARED_REGION_TRACE_DEBUG(
1856 ("commpage: -> enter(%p,%p)\n",
1857 map, task));
1858
1859 commpage_text_size = _COMM_PAGE_TEXT_AREA_LENGTH;
1860 /* the comm page is likely to be beyond the actual end of the VM map */
1861 vm_flags = VM_FLAGS_FIXED | VM_FLAGS_BEYOND_MAX;
1862
1863 /* select the appropriate comm page for this task */
1864 assert(! (task_has_64BitAddr(task) ^ vm_map_is_64bit(map)));
1865 if (task_has_64BitAddr(task)) {
1866 commpage_handle = commpage64_handle;
1867 commpage_address = (vm_map_offset_t) _COMM_PAGE64_BASE_ADDRESS;
1868 commpage_size = _COMM_PAGE64_AREA_LENGTH;
1869 objc_size = _COMM_PAGE64_OBJC_SIZE;
1870 objc_address = _COMM_PAGE64_OBJC_BASE;
1871 commpage_text_handle = commpage_text64_handle;
1872 commpage_text_address = (vm_map_offset_t) commpage_text64_location;
1873 } else {
1874 commpage_handle = commpage32_handle;
1875 commpage_address =
1876 (vm_map_offset_t)(unsigned) _COMM_PAGE32_BASE_ADDRESS;
1877 commpage_size = _COMM_PAGE32_AREA_LENGTH;
1878 objc_size = _COMM_PAGE32_OBJC_SIZE;
1879 objc_address = _COMM_PAGE32_OBJC_BASE;
1880 commpage_text_handle = commpage_text32_handle;
1881 commpage_text_address = (vm_map_offset_t) commpage_text32_location;
1882 }
1883
1884 if ((commpage_address & (pmap_nesting_size_min - 1)) == 0 &&
1885 (commpage_size & (pmap_nesting_size_min - 1)) == 0) {
1886 /* the commpage is properly aligned or sized for pmap-nesting */
1887 vm_flags |= VM_MAKE_TAG(VM_MEMORY_SHARED_PMAP);
1888 }
1889 /* map the comm page in the task's address space */
1890 assert(commpage_handle != IPC_PORT_NULL);
1891 kr = vm_map_enter_mem_object(
1892 map,
1893 &commpage_address,
1894 commpage_size,
1895 0,
1896 vm_flags,
1897 commpage_handle,
1898 0,
1899 FALSE,
1900 VM_PROT_READ,
1901 VM_PROT_READ,
1902 VM_INHERIT_SHARE);
1903 if (kr != KERN_SUCCESS) {
1904 SHARED_REGION_TRACE_ERROR(
1905 ("commpage: enter(%p,0x%llx,0x%llx) "
1906 "commpage %p mapping failed 0x%x\n",
1907 map, (long long)commpage_address,
1908 (long long)commpage_size, commpage_handle, kr));
1909 }
1910
1911 /* map the comm text page in the task's address space */
1912 assert(commpage_text_handle != IPC_PORT_NULL);
1913 kr = vm_map_enter_mem_object(
1914 map,
1915 &commpage_text_address,
1916 commpage_text_size,
1917 0,
1918 vm_flags,
1919 commpage_text_handle,
1920 0,
1921 FALSE,
1922 VM_PROT_READ|VM_PROT_EXECUTE,
1923 VM_PROT_READ|VM_PROT_EXECUTE,
1924 VM_INHERIT_SHARE);
1925 if (kr != KERN_SUCCESS) {
1926 SHARED_REGION_TRACE_ERROR(
1927 ("commpage text: enter(%p,0x%llx,0x%llx) "
1928 "commpage text %p mapping failed 0x%x\n",
1929 map, (long long)commpage_text_address,
1930 (long long)commpage_text_size, commpage_text_handle, kr));
1931 }
1932
1933 /*
1934 * Since we're here, we also pre-allocate some virtual space for the
1935 * Objective-C run-time, if needed...
1936 */
1937 if (objc_size != 0) {
1938 kr = vm_map_enter_mem_object(
1939 map,
1940 &objc_address,
1941 objc_size,
1942 0,
1943 VM_FLAGS_FIXED | VM_FLAGS_BEYOND_MAX,
1944 IPC_PORT_NULL,
1945 0,
1946 FALSE,
1947 VM_PROT_ALL,
1948 VM_PROT_ALL,
1949 VM_INHERIT_DEFAULT);
1950 if (kr != KERN_SUCCESS) {
1951 SHARED_REGION_TRACE_ERROR(
1952 ("commpage: enter(%p,0x%llx,0x%llx) "
1953 "objc mapping failed 0x%x\n",
1954 map, (long long)objc_address,
1955 (long long)objc_size, kr));
1956 }
1957 }
1958
1959 SHARED_REGION_TRACE_DEBUG(
1960 ("commpage: enter(%p,%p) <- 0x%x\n",
1961 map, task, kr));
1962 return kr;
1963 }
1964
1965 int
1966 vm_shared_region_slide(uint32_t slide,
1967 mach_vm_offset_t entry_start_address,
1968 mach_vm_size_t entry_size,
1969 mach_vm_offset_t slide_start,
1970 mach_vm_size_t slide_size,
1971 memory_object_control_t sr_file_control)
1972 {
1973 void *slide_info_entry = NULL;
1974 int error;
1975 vm_shared_region_t sr;
1976
1977 SHARED_REGION_TRACE_DEBUG(
1978 ("vm_shared_region_slide: -> slide %#x, entry_start %#llx, entry_size %#llx, slide_start %#llx, slide_size %#llx\n",
1979 slide, entry_start_address, entry_size, slide_start, slide_size));
1980
1981 sr = vm_shared_region_get(current_task());
1982 if (sr == NULL) {
1983 printf("%s: no shared region?\n", __FUNCTION__);
1984 SHARED_REGION_TRACE_DEBUG(
1985 ("vm_shared_region_slide: <- %d (no shared region)\n",
1986 KERN_FAILURE));
1987 return KERN_FAILURE;
1988 }
1989
1990 /*
1991 * Protect from concurrent access.
1992 */
1993 vm_shared_region_lock();
1994 while(sr->sr_slide_in_progress) {
1995 vm_shared_region_sleep(&sr->sr_slide_in_progress, THREAD_UNINT);
1996 }
1997 if (sr->sr_slid
1998 || shared_region_completed_slide
1999 ) {
2000 vm_shared_region_unlock();
2001
2002 vm_shared_region_deallocate(sr);
2003 printf("%s: shared region already slid?\n", __FUNCTION__);
2004 SHARED_REGION_TRACE_DEBUG(
2005 ("vm_shared_region_slide: <- %d (already slid)\n",
2006 KERN_FAILURE));
2007 return KERN_FAILURE;
2008 }
2009
2010 sr->sr_slide_in_progress = TRUE;
2011 vm_shared_region_unlock();
2012
2013 if((error = vm_shared_region_slide_init(sr, slide_size, entry_start_address, entry_size, slide, sr_file_control))) {
2014 printf("slide_info initialization failed with kr=%d\n", error);
2015 goto done;
2016 }
2017
2018 slide_info_entry = vm_shared_region_get_slide_info_entry(sr);
2019 if (slide_info_entry == NULL){
2020 error = KERN_FAILURE;
2021 } else {
2022 error = copyin((user_addr_t)slide_start,
2023 slide_info_entry,
2024 (vm_size_t)slide_size);
2025 if (error) {
2026 error = KERN_INVALID_ADDRESS;
2027 }
2028 }
2029 if (error) {
2030 goto done;
2031 }
2032
2033 if (vm_shared_region_slide_sanity_check(sr) != KERN_SUCCESS) {
2034 error = KERN_INVALID_ARGUMENT;
2035 printf("Sanity Check failed for slide_info\n");
2036 } else {
2037 #if DEBUG
2038 printf("Succesfully init slide_info with start_address: %p region_size: %ld slide_header_size: %ld\n",
2039 (void*)(uintptr_t)entry_start_address,
2040 (unsigned long)entry_size,
2041 (unsigned long)slide_size);
2042 #endif
2043 }
2044 done:
2045 vm_shared_region_lock();
2046
2047 assert(sr->sr_slide_in_progress);
2048 assert(sr->sr_slid == FALSE);
2049 sr->sr_slide_in_progress = FALSE;
2050 thread_wakeup(&sr->sr_slide_in_progress);
2051
2052 if (error == KERN_SUCCESS) {
2053 sr->sr_slid = TRUE;
2054
2055 /*
2056 * We don't know how to tear down a slid shared region today, because
2057 * we would have to invalidate all the pages that have been slid
2058 * atomically with respect to anyone mapping the shared region afresh.
2059 * Therefore, take a dangling reference to prevent teardown.
2060 */
2061 sr->sr_ref_count++;
2062 shared_region_completed_slide = TRUE;
2063 }
2064 vm_shared_region_unlock();
2065
2066 vm_shared_region_deallocate(sr);
2067
2068 SHARED_REGION_TRACE_DEBUG(
2069 ("vm_shared_region_slide: <- %d\n",
2070 error));
2071
2072 return error;
2073 }
2074
2075 /*
2076 * This is called from powermanagement code to let kernel know the current source of power.
2077 * 0 if it is external source (connected to power )
2078 * 1 if it is internal power source ie battery
2079 */
2080 void
2081 #if defined(__i386__) || defined(__x86_64__)
2082 post_sys_powersource(int i)
2083 #else
2084 post_sys_powersource(__unused int i)
2085 #endif
2086 {
2087 #if defined(__i386__) || defined(__x86_64__)
2088 post_sys_powersource_internal(i, 0);
2089 #endif /* __i386__ || __x86_64__ */
2090 }
2091
2092
2093 #if defined(__i386__) || defined(__x86_64__)
2094 static void
2095 post_sys_powersource_internal(int i, int internal)
2096 {
2097 if (internal == 0)
2098 __system_power_source = i;
2099
2100 if (__commpage_setup != 0) {
2101 if (__system_power_source != 0)
2102 commpage_set_spin_count(0);
2103 else
2104 commpage_set_spin_count(MP_SPIN_TRIES);
2105 }
2106 }
2107 #endif /* __i386__ || __x86_64__ */
2108