]> git.saurik.com Git - apple/xnu.git/blob - osfmk/vm/vm_user.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / osfmk / vm / vm_user.c
1 /*
2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 */
58 /*
59 * File: vm/vm_user.c
60 * Author: Avadis Tevanian, Jr., Michael Wayne Young
61 *
62 * User-exported virtual memory functions.
63 */
64
65 /*
66 * There are three implementations of the "XXX_allocate" functionality in
67 * the kernel: mach_vm_allocate (for any task on the platform), vm_allocate
68 * (for a task with the same address space size, especially the current task),
69 * and vm32_vm_allocate (for the specific case of a 32-bit task). vm_allocate
70 * in the kernel should only be used on the kernel_task. vm32_vm_allocate only
71 * makes sense on platforms where a user task can either be 32 or 64, or the kernel
72 * task can be 32 or 64. mach_vm_allocate makes sense everywhere, and is preferred
73 * for new code.
74 *
75 * The entrypoints into the kernel are more complex. All platforms support a
76 * mach_vm_allocate-style API (subsystem 4800) which operates with the largest
77 * size types for the platform. On platforms that only support U32/K32,
78 * subsystem 4800 is all you need. On platforms that support both U32 and U64,
79 * subsystem 3800 is used disambiguate the size of parameters, and they will
80 * always be 32-bit and call into the vm32_vm_allocate APIs. On non-U32/K32 platforms,
81 * the MIG glue should never call into vm_allocate directly, because the calling
82 * task and kernel_task are unlikely to use the same size parameters
83 *
84 * New VM call implementations should be added here and to mach_vm.defs
85 * (subsystem 4800), and use mach_vm_* "wide" types.
86 */
87
88 #include <debug.h>
89
90 #include <vm_cpm.h>
91 #include <mach/boolean.h>
92 #include <mach/kern_return.h>
93 #include <mach/mach_types.h> /* to get vm_address_t */
94 #include <mach/memory_object.h>
95 #include <mach/std_types.h> /* to get pointer_t */
96 #include <mach/upl.h>
97 #include <mach/vm_attributes.h>
98 #include <mach/vm_param.h>
99 #include <mach/vm_statistics.h>
100 #include <mach/mach_syscalls.h>
101 #include <mach/sdt.h>
102
103 #include <mach/host_priv_server.h>
104 #include <mach/mach_vm_server.h>
105 #include <mach/memory_entry_server.h>
106 #include <mach/vm_map_server.h>
107
108 #include <kern/host.h>
109 #include <kern/kalloc.h>
110 #include <kern/task.h>
111 #include <kern/misc_protos.h>
112 #include <vm/vm_fault.h>
113 #include <vm/vm_map.h>
114 #include <vm/vm_object.h>
115 #include <vm/vm_page.h>
116 #include <vm/memory_object.h>
117 #include <vm/vm_pageout.h>
118 #include <vm/vm_protos.h>
119 #include <vm/vm_purgeable_internal.h>
120 #include <vm/vm_init.h>
121
122 #include <san/kasan.h>
123
124 #include <libkern/OSDebug.h>
125 #include <IOKit/IOBSD.h>
126
127 vm_size_t upl_offset_to_pagelist = 0;
128
129 #if VM_CPM
130 #include <vm/cpm.h>
131 #endif /* VM_CPM */
132
133 /*
134 * mach_vm_allocate allocates "zero fill" memory in the specfied
135 * map.
136 */
137 kern_return_t
138 mach_vm_allocate_external(
139 vm_map_t map,
140 mach_vm_offset_t *addr,
141 mach_vm_size_t size,
142 int flags)
143 {
144 vm_tag_t tag;
145
146 VM_GET_FLAGS_ALIAS(flags, tag);
147 return mach_vm_allocate_kernel(map, addr, size, flags, tag);
148 }
149
150 kern_return_t
151 mach_vm_allocate_kernel(
152 vm_map_t map,
153 mach_vm_offset_t *addr,
154 mach_vm_size_t size,
155 int flags,
156 vm_tag_t tag)
157 {
158 vm_map_offset_t map_addr;
159 vm_map_size_t map_size;
160 kern_return_t result;
161 boolean_t anywhere;
162
163 /* filter out any kernel-only flags */
164 if (flags & ~VM_FLAGS_USER_ALLOCATE) {
165 return KERN_INVALID_ARGUMENT;
166 }
167
168 if (map == VM_MAP_NULL) {
169 return KERN_INVALID_ARGUMENT;
170 }
171 if (size == 0) {
172 *addr = 0;
173 return KERN_SUCCESS;
174 }
175
176 anywhere = ((VM_FLAGS_ANYWHERE & flags) != 0);
177 if (anywhere) {
178 /*
179 * No specific address requested, so start candidate address
180 * search at the minimum address in the map. However, if that
181 * minimum is 0, bump it up by PAGE_SIZE. We want to limit
182 * allocations of PAGEZERO to explicit requests since its
183 * normal use is to catch dereferences of NULL and many
184 * applications also treat pointers with a value of 0 as
185 * special and suddenly having address 0 contain useable
186 * memory would tend to confuse those applications.
187 */
188 map_addr = vm_map_min(map);
189 if (map_addr == 0) {
190 map_addr += VM_MAP_PAGE_SIZE(map);
191 }
192 } else {
193 map_addr = vm_map_trunc_page(*addr,
194 VM_MAP_PAGE_MASK(map));
195 }
196 map_size = vm_map_round_page(size,
197 VM_MAP_PAGE_MASK(map));
198 if (map_size == 0) {
199 return KERN_INVALID_ARGUMENT;
200 }
201
202 result = vm_map_enter(
203 map,
204 &map_addr,
205 map_size,
206 (vm_map_offset_t)0,
207 flags,
208 VM_MAP_KERNEL_FLAGS_NONE,
209 tag,
210 VM_OBJECT_NULL,
211 (vm_object_offset_t)0,
212 FALSE,
213 VM_PROT_DEFAULT,
214 VM_PROT_ALL,
215 VM_INHERIT_DEFAULT);
216
217 *addr = map_addr;
218 return result;
219 }
220
221 /*
222 * vm_allocate
223 * Legacy routine that allocates "zero fill" memory in the specfied
224 * map (which is limited to the same size as the kernel).
225 */
226 kern_return_t
227 vm_allocate_external(
228 vm_map_t map,
229 vm_offset_t *addr,
230 vm_size_t size,
231 int flags)
232 {
233 vm_tag_t tag;
234
235 VM_GET_FLAGS_ALIAS(flags, tag);
236 return vm_allocate_kernel(map, addr, size, flags, tag);
237 }
238
239 kern_return_t
240 vm_allocate_kernel(
241 vm_map_t map,
242 vm_offset_t *addr,
243 vm_size_t size,
244 int flags,
245 vm_tag_t tag)
246 {
247 vm_map_offset_t map_addr;
248 vm_map_size_t map_size;
249 kern_return_t result;
250 boolean_t anywhere;
251
252 /* filter out any kernel-only flags */
253 if (flags & ~VM_FLAGS_USER_ALLOCATE) {
254 return KERN_INVALID_ARGUMENT;
255 }
256
257 if (map == VM_MAP_NULL) {
258 return KERN_INVALID_ARGUMENT;
259 }
260 if (size == 0) {
261 *addr = 0;
262 return KERN_SUCCESS;
263 }
264
265 anywhere = ((VM_FLAGS_ANYWHERE & flags) != 0);
266 if (anywhere) {
267 /*
268 * No specific address requested, so start candidate address
269 * search at the minimum address in the map. However, if that
270 * minimum is 0, bump it up by PAGE_SIZE. We want to limit
271 * allocations of PAGEZERO to explicit requests since its
272 * normal use is to catch dereferences of NULL and many
273 * applications also treat pointers with a value of 0 as
274 * special and suddenly having address 0 contain useable
275 * memory would tend to confuse those applications.
276 */
277 map_addr = vm_map_min(map);
278 if (map_addr == 0) {
279 map_addr += VM_MAP_PAGE_SIZE(map);
280 }
281 } else {
282 map_addr = vm_map_trunc_page(*addr,
283 VM_MAP_PAGE_MASK(map));
284 }
285 map_size = vm_map_round_page(size,
286 VM_MAP_PAGE_MASK(map));
287 if (map_size == 0) {
288 return KERN_INVALID_ARGUMENT;
289 }
290
291 result = vm_map_enter(
292 map,
293 &map_addr,
294 map_size,
295 (vm_map_offset_t)0,
296 flags,
297 VM_MAP_KERNEL_FLAGS_NONE,
298 tag,
299 VM_OBJECT_NULL,
300 (vm_object_offset_t)0,
301 FALSE,
302 VM_PROT_DEFAULT,
303 VM_PROT_ALL,
304 VM_INHERIT_DEFAULT);
305
306 #if KASAN
307 if (result == KERN_SUCCESS && map->pmap == kernel_pmap) {
308 kasan_notify_address(map_addr, map_size);
309 }
310 #endif
311
312 *addr = CAST_DOWN(vm_offset_t, map_addr);
313 return result;
314 }
315
316 /*
317 * mach_vm_deallocate -
318 * deallocates the specified range of addresses in the
319 * specified address map.
320 */
321 kern_return_t
322 mach_vm_deallocate(
323 vm_map_t map,
324 mach_vm_offset_t start,
325 mach_vm_size_t size)
326 {
327 if ((map == VM_MAP_NULL) || (start + size < start)) {
328 return KERN_INVALID_ARGUMENT;
329 }
330
331 if (size == (mach_vm_offset_t) 0) {
332 return KERN_SUCCESS;
333 }
334
335 return vm_map_remove(map,
336 vm_map_trunc_page(start,
337 VM_MAP_PAGE_MASK(map)),
338 vm_map_round_page(start + size,
339 VM_MAP_PAGE_MASK(map)),
340 VM_MAP_REMOVE_NO_FLAGS);
341 }
342
343 /*
344 * vm_deallocate -
345 * deallocates the specified range of addresses in the
346 * specified address map (limited to addresses the same
347 * size as the kernel).
348 */
349 kern_return_t
350 vm_deallocate(
351 vm_map_t map,
352 vm_offset_t start,
353 vm_size_t size)
354 {
355 if ((map == VM_MAP_NULL) || (start + size < start)) {
356 return KERN_INVALID_ARGUMENT;
357 }
358
359 if (size == (vm_offset_t) 0) {
360 return KERN_SUCCESS;
361 }
362
363 return vm_map_remove(map,
364 vm_map_trunc_page(start,
365 VM_MAP_PAGE_MASK(map)),
366 vm_map_round_page(start + size,
367 VM_MAP_PAGE_MASK(map)),
368 VM_MAP_REMOVE_NO_FLAGS);
369 }
370
371 /*
372 * mach_vm_inherit -
373 * Sets the inheritance of the specified range in the
374 * specified map.
375 */
376 kern_return_t
377 mach_vm_inherit(
378 vm_map_t map,
379 mach_vm_offset_t start,
380 mach_vm_size_t size,
381 vm_inherit_t new_inheritance)
382 {
383 if ((map == VM_MAP_NULL) || (start + size < start) ||
384 (new_inheritance > VM_INHERIT_LAST_VALID)) {
385 return KERN_INVALID_ARGUMENT;
386 }
387
388 if (size == 0) {
389 return KERN_SUCCESS;
390 }
391
392 return vm_map_inherit(map,
393 vm_map_trunc_page(start,
394 VM_MAP_PAGE_MASK(map)),
395 vm_map_round_page(start + size,
396 VM_MAP_PAGE_MASK(map)),
397 new_inheritance);
398 }
399
400 /*
401 * vm_inherit -
402 * Sets the inheritance of the specified range in the
403 * specified map (range limited to addresses
404 */
405 kern_return_t
406 vm_inherit(
407 vm_map_t map,
408 vm_offset_t start,
409 vm_size_t size,
410 vm_inherit_t new_inheritance)
411 {
412 if ((map == VM_MAP_NULL) || (start + size < start) ||
413 (new_inheritance > VM_INHERIT_LAST_VALID)) {
414 return KERN_INVALID_ARGUMENT;
415 }
416
417 if (size == 0) {
418 return KERN_SUCCESS;
419 }
420
421 return vm_map_inherit(map,
422 vm_map_trunc_page(start,
423 VM_MAP_PAGE_MASK(map)),
424 vm_map_round_page(start + size,
425 VM_MAP_PAGE_MASK(map)),
426 new_inheritance);
427 }
428
429 /*
430 * mach_vm_protect -
431 * Sets the protection of the specified range in the
432 * specified map.
433 */
434
435 kern_return_t
436 mach_vm_protect(
437 vm_map_t map,
438 mach_vm_offset_t start,
439 mach_vm_size_t size,
440 boolean_t set_maximum,
441 vm_prot_t new_protection)
442 {
443 if ((map == VM_MAP_NULL) || (start + size < start) ||
444 (new_protection & ~(VM_PROT_ALL | VM_PROT_COPY))) {
445 return KERN_INVALID_ARGUMENT;
446 }
447
448 if (size == 0) {
449 return KERN_SUCCESS;
450 }
451
452 return vm_map_protect(map,
453 vm_map_trunc_page(start,
454 VM_MAP_PAGE_MASK(map)),
455 vm_map_round_page(start + size,
456 VM_MAP_PAGE_MASK(map)),
457 new_protection,
458 set_maximum);
459 }
460
461 /*
462 * vm_protect -
463 * Sets the protection of the specified range in the
464 * specified map. Addressability of the range limited
465 * to the same size as the kernel.
466 */
467
468 kern_return_t
469 vm_protect(
470 vm_map_t map,
471 vm_offset_t start,
472 vm_size_t size,
473 boolean_t set_maximum,
474 vm_prot_t new_protection)
475 {
476 if ((map == VM_MAP_NULL) || (start + size < start) ||
477 (new_protection & ~(VM_PROT_ALL | VM_PROT_COPY))) {
478 return KERN_INVALID_ARGUMENT;
479 }
480
481 if (size == 0) {
482 return KERN_SUCCESS;
483 }
484
485 return vm_map_protect(map,
486 vm_map_trunc_page(start,
487 VM_MAP_PAGE_MASK(map)),
488 vm_map_round_page(start + size,
489 VM_MAP_PAGE_MASK(map)),
490 new_protection,
491 set_maximum);
492 }
493
494 /*
495 * mach_vm_machine_attributes -
496 * Handle machine-specific attributes for a mapping, such
497 * as cachability, migrability, etc.
498 */
499 kern_return_t
500 mach_vm_machine_attribute(
501 vm_map_t map,
502 mach_vm_address_t addr,
503 mach_vm_size_t size,
504 vm_machine_attribute_t attribute,
505 vm_machine_attribute_val_t* value) /* IN/OUT */
506 {
507 if ((map == VM_MAP_NULL) || (addr + size < addr)) {
508 return KERN_INVALID_ARGUMENT;
509 }
510
511 if (size == 0) {
512 return KERN_SUCCESS;
513 }
514
515 return vm_map_machine_attribute(
516 map,
517 vm_map_trunc_page(addr,
518 VM_MAP_PAGE_MASK(map)),
519 vm_map_round_page(addr + size,
520 VM_MAP_PAGE_MASK(map)),
521 attribute,
522 value);
523 }
524
525 /*
526 * vm_machine_attribute -
527 * Handle machine-specific attributes for a mapping, such
528 * as cachability, migrability, etc. Limited addressability
529 * (same range limits as for the native kernel map).
530 */
531 kern_return_t
532 vm_machine_attribute(
533 vm_map_t map,
534 vm_address_t addr,
535 vm_size_t size,
536 vm_machine_attribute_t attribute,
537 vm_machine_attribute_val_t* value) /* IN/OUT */
538 {
539 if ((map == VM_MAP_NULL) || (addr + size < addr)) {
540 return KERN_INVALID_ARGUMENT;
541 }
542
543 if (size == 0) {
544 return KERN_SUCCESS;
545 }
546
547 return vm_map_machine_attribute(
548 map,
549 vm_map_trunc_page(addr,
550 VM_MAP_PAGE_MASK(map)),
551 vm_map_round_page(addr + size,
552 VM_MAP_PAGE_MASK(map)),
553 attribute,
554 value);
555 }
556
557 /*
558 * mach_vm_read -
559 * Read/copy a range from one address space and return it to the caller.
560 *
561 * It is assumed that the address for the returned memory is selected by
562 * the IPC implementation as part of receiving the reply to this call.
563 * If IPC isn't used, the caller must deal with the vm_map_copy_t object
564 * that gets returned.
565 *
566 * JMM - because of mach_msg_type_number_t, this call is limited to a
567 * single 4GB region at this time.
568 *
569 */
570 kern_return_t
571 mach_vm_read(
572 vm_map_t map,
573 mach_vm_address_t addr,
574 mach_vm_size_t size,
575 pointer_t *data,
576 mach_msg_type_number_t *data_size)
577 {
578 kern_return_t error;
579 vm_map_copy_t ipc_address;
580
581 if (map == VM_MAP_NULL) {
582 return KERN_INVALID_ARGUMENT;
583 }
584
585 if ((mach_msg_type_number_t) size != size) {
586 return KERN_INVALID_ARGUMENT;
587 }
588
589 error = vm_map_copyin(map,
590 (vm_map_address_t)addr,
591 (vm_map_size_t)size,
592 FALSE, /* src_destroy */
593 &ipc_address);
594
595 if (KERN_SUCCESS == error) {
596 *data = (pointer_t) ipc_address;
597 *data_size = (mach_msg_type_number_t) size;
598 assert(*data_size == size);
599 }
600 return error;
601 }
602
603 /*
604 * vm_read -
605 * Read/copy a range from one address space and return it to the caller.
606 * Limited addressability (same range limits as for the native kernel map).
607 *
608 * It is assumed that the address for the returned memory is selected by
609 * the IPC implementation as part of receiving the reply to this call.
610 * If IPC isn't used, the caller must deal with the vm_map_copy_t object
611 * that gets returned.
612 */
613 kern_return_t
614 vm_read(
615 vm_map_t map,
616 vm_address_t addr,
617 vm_size_t size,
618 pointer_t *data,
619 mach_msg_type_number_t *data_size)
620 {
621 kern_return_t error;
622 vm_map_copy_t ipc_address;
623
624 if (map == VM_MAP_NULL) {
625 return KERN_INVALID_ARGUMENT;
626 }
627
628 mach_msg_type_number_t dsize;
629 if (os_convert_overflow(size, &dsize)) {
630 /*
631 * The kernel could handle a 64-bit "size" value, but
632 * it could not return the size of the data in "*data_size"
633 * without overflowing.
634 * Let's reject this "size" as invalid.
635 */
636 return KERN_INVALID_ARGUMENT;
637 }
638
639 error = vm_map_copyin(map,
640 (vm_map_address_t)addr,
641 (vm_map_size_t)size,
642 FALSE, /* src_destroy */
643 &ipc_address);
644
645 if (KERN_SUCCESS == error) {
646 *data = (pointer_t) ipc_address;
647 *data_size = dsize;
648 assert(*data_size == size);
649 }
650 return error;
651 }
652
653 /*
654 * mach_vm_read_list -
655 * Read/copy a list of address ranges from specified map.
656 *
657 * MIG does not know how to deal with a returned array of
658 * vm_map_copy_t structures, so we have to do the copyout
659 * manually here.
660 */
661 kern_return_t
662 mach_vm_read_list(
663 vm_map_t map,
664 mach_vm_read_entry_t data_list,
665 natural_t count)
666 {
667 mach_msg_type_number_t i;
668 kern_return_t error;
669 vm_map_copy_t copy;
670
671 if (map == VM_MAP_NULL ||
672 count > VM_MAP_ENTRY_MAX) {
673 return KERN_INVALID_ARGUMENT;
674 }
675
676 error = KERN_SUCCESS;
677 for (i = 0; i < count; i++) {
678 vm_map_address_t map_addr;
679 vm_map_size_t map_size;
680
681 map_addr = (vm_map_address_t)(data_list[i].address);
682 map_size = (vm_map_size_t)(data_list[i].size);
683
684 if (map_size != 0) {
685 error = vm_map_copyin(map,
686 map_addr,
687 map_size,
688 FALSE, /* src_destroy */
689 &copy);
690 if (KERN_SUCCESS == error) {
691 error = vm_map_copyout(
692 current_task()->map,
693 &map_addr,
694 copy);
695 if (KERN_SUCCESS == error) {
696 data_list[i].address = map_addr;
697 continue;
698 }
699 vm_map_copy_discard(copy);
700 }
701 }
702 data_list[i].address = (mach_vm_address_t)0;
703 data_list[i].size = (mach_vm_size_t)0;
704 }
705 return error;
706 }
707
708 /*
709 * vm_read_list -
710 * Read/copy a list of address ranges from specified map.
711 *
712 * MIG does not know how to deal with a returned array of
713 * vm_map_copy_t structures, so we have to do the copyout
714 * manually here.
715 *
716 * The source and destination ranges are limited to those
717 * that can be described with a vm_address_t (i.e. same
718 * size map as the kernel).
719 *
720 * JMM - If the result of the copyout is an address range
721 * that cannot be described with a vm_address_t (i.e. the
722 * caller had a larger address space but used this call
723 * anyway), it will result in a truncated address being
724 * returned (and a likely confused caller).
725 */
726
727 kern_return_t
728 vm_read_list(
729 vm_map_t map,
730 vm_read_entry_t data_list,
731 natural_t count)
732 {
733 mach_msg_type_number_t i;
734 kern_return_t error;
735 vm_map_copy_t copy;
736
737 if (map == VM_MAP_NULL ||
738 count > VM_MAP_ENTRY_MAX) {
739 return KERN_INVALID_ARGUMENT;
740 }
741
742 error = KERN_SUCCESS;
743 for (i = 0; i < count; i++) {
744 vm_map_address_t map_addr;
745 vm_map_size_t map_size;
746
747 map_addr = (vm_map_address_t)(data_list[i].address);
748 map_size = (vm_map_size_t)(data_list[i].size);
749
750 if (map_size != 0) {
751 error = vm_map_copyin(map,
752 map_addr,
753 map_size,
754 FALSE, /* src_destroy */
755 &copy);
756 if (KERN_SUCCESS == error) {
757 error = vm_map_copyout(current_task()->map,
758 &map_addr,
759 copy);
760 if (KERN_SUCCESS == error) {
761 data_list[i].address =
762 CAST_DOWN(vm_offset_t, map_addr);
763 continue;
764 }
765 vm_map_copy_discard(copy);
766 }
767 }
768 data_list[i].address = (mach_vm_address_t)0;
769 data_list[i].size = (mach_vm_size_t)0;
770 }
771 return error;
772 }
773
774 /*
775 * mach_vm_read_overwrite -
776 * Overwrite a range of the current map with data from the specified
777 * map/address range.
778 *
779 * In making an assumption that the current thread is local, it is
780 * no longer cluster-safe without a fully supportive local proxy
781 * thread/task (but we don't support cluster's anymore so this is moot).
782 */
783
784 kern_return_t
785 mach_vm_read_overwrite(
786 vm_map_t map,
787 mach_vm_address_t address,
788 mach_vm_size_t size,
789 mach_vm_address_t data,
790 mach_vm_size_t *data_size)
791 {
792 kern_return_t error;
793 vm_map_copy_t copy;
794
795 if (map == VM_MAP_NULL) {
796 return KERN_INVALID_ARGUMENT;
797 }
798
799 error = vm_map_copyin(map, (vm_map_address_t)address,
800 (vm_map_size_t)size, FALSE, &copy);
801
802 if (KERN_SUCCESS == error) {
803 if (copy) {
804 assertf(copy->size == (vm_map_size_t) size, "Req size: 0x%llx, Copy size: 0x%llx\n", (uint64_t) size, (uint64_t) copy->size);
805 }
806
807 error = vm_map_copy_overwrite(current_thread()->map,
808 (vm_map_address_t)data,
809 copy, (vm_map_size_t) size, FALSE);
810 if (KERN_SUCCESS == error) {
811 *data_size = size;
812 return error;
813 }
814 vm_map_copy_discard(copy);
815 }
816 return error;
817 }
818
819 /*
820 * vm_read_overwrite -
821 * Overwrite a range of the current map with data from the specified
822 * map/address range.
823 *
824 * This routine adds the additional limitation that the source and
825 * destination ranges must be describable with vm_address_t values
826 * (i.e. the same size address spaces as the kernel, or at least the
827 * the ranges are in that first portion of the respective address
828 * spaces).
829 */
830
831 kern_return_t
832 vm_read_overwrite(
833 vm_map_t map,
834 vm_address_t address,
835 vm_size_t size,
836 vm_address_t data,
837 vm_size_t *data_size)
838 {
839 kern_return_t error;
840 vm_map_copy_t copy;
841
842 if (map == VM_MAP_NULL) {
843 return KERN_INVALID_ARGUMENT;
844 }
845
846 error = vm_map_copyin(map, (vm_map_address_t)address,
847 (vm_map_size_t)size, FALSE, &copy);
848
849 if (KERN_SUCCESS == error) {
850 if (copy) {
851 assertf(copy->size == (vm_map_size_t) size, "Req size: 0x%llx, Copy size: 0x%llx\n", (uint64_t) size, (uint64_t) copy->size);
852 }
853
854 error = vm_map_copy_overwrite(current_thread()->map,
855 (vm_map_address_t)data,
856 copy, (vm_map_size_t) size, FALSE);
857 if (KERN_SUCCESS == error) {
858 *data_size = size;
859 return error;
860 }
861 vm_map_copy_discard(copy);
862 }
863 return error;
864 }
865
866
867 /*
868 * mach_vm_write -
869 * Overwrite the specified address range with the data provided
870 * (from the current map).
871 */
872 kern_return_t
873 mach_vm_write(
874 vm_map_t map,
875 mach_vm_address_t address,
876 pointer_t data,
877 mach_msg_type_number_t size)
878 {
879 if (map == VM_MAP_NULL) {
880 return KERN_INVALID_ARGUMENT;
881 }
882
883 return vm_map_copy_overwrite(map, (vm_map_address_t)address,
884 (vm_map_copy_t) data, size, FALSE /* interruptible XXX */);
885 }
886
887 /*
888 * vm_write -
889 * Overwrite the specified address range with the data provided
890 * (from the current map).
891 *
892 * The addressability of the range of addresses to overwrite is
893 * limited bu the use of a vm_address_t (same size as kernel map).
894 * Either the target map is also small, or the range is in the
895 * low addresses within it.
896 */
897 kern_return_t
898 vm_write(
899 vm_map_t map,
900 vm_address_t address,
901 pointer_t data,
902 mach_msg_type_number_t size)
903 {
904 if (map == VM_MAP_NULL) {
905 return KERN_INVALID_ARGUMENT;
906 }
907
908 return vm_map_copy_overwrite(map, (vm_map_address_t)address,
909 (vm_map_copy_t) data, size, FALSE /* interruptible XXX */);
910 }
911
912 /*
913 * mach_vm_copy -
914 * Overwrite one range of the specified map with the contents of
915 * another range within that same map (i.e. both address ranges
916 * are "over there").
917 */
918 kern_return_t
919 mach_vm_copy(
920 vm_map_t map,
921 mach_vm_address_t source_address,
922 mach_vm_size_t size,
923 mach_vm_address_t dest_address)
924 {
925 vm_map_copy_t copy;
926 kern_return_t kr;
927
928 if (map == VM_MAP_NULL) {
929 return KERN_INVALID_ARGUMENT;
930 }
931
932 kr = vm_map_copyin(map, (vm_map_address_t)source_address,
933 (vm_map_size_t)size, FALSE, &copy);
934
935 if (KERN_SUCCESS == kr) {
936 if (copy) {
937 assertf(copy->size == (vm_map_size_t) size, "Req size: 0x%llx, Copy size: 0x%llx\n", (uint64_t) size, (uint64_t) copy->size);
938 }
939
940 kr = vm_map_copy_overwrite(map,
941 (vm_map_address_t)dest_address,
942 copy, (vm_map_size_t) size, FALSE /* interruptible XXX */);
943
944 if (KERN_SUCCESS != kr) {
945 vm_map_copy_discard(copy);
946 }
947 }
948 return kr;
949 }
950
951 kern_return_t
952 vm_copy(
953 vm_map_t map,
954 vm_address_t source_address,
955 vm_size_t size,
956 vm_address_t dest_address)
957 {
958 vm_map_copy_t copy;
959 kern_return_t kr;
960
961 if (map == VM_MAP_NULL) {
962 return KERN_INVALID_ARGUMENT;
963 }
964
965 kr = vm_map_copyin(map, (vm_map_address_t)source_address,
966 (vm_map_size_t)size, FALSE, &copy);
967
968 if (KERN_SUCCESS == kr) {
969 if (copy) {
970 assertf(copy->size == (vm_map_size_t) size, "Req size: 0x%llx, Copy size: 0x%llx\n", (uint64_t) size, (uint64_t) copy->size);
971 }
972
973 kr = vm_map_copy_overwrite(map,
974 (vm_map_address_t)dest_address,
975 copy, (vm_map_size_t) size, FALSE /* interruptible XXX */);
976
977 if (KERN_SUCCESS != kr) {
978 vm_map_copy_discard(copy);
979 }
980 }
981 return kr;
982 }
983
984 /*
985 * mach_vm_map -
986 * Map some range of an object into an address space.
987 *
988 * The object can be one of several types of objects:
989 * NULL - anonymous memory
990 * a named entry - a range within another address space
991 * or a range within a memory object
992 * a whole memory object
993 *
994 */
995 kern_return_t
996 mach_vm_map_external(
997 vm_map_t target_map,
998 mach_vm_offset_t *address,
999 mach_vm_size_t initial_size,
1000 mach_vm_offset_t mask,
1001 int flags,
1002 ipc_port_t port,
1003 vm_object_offset_t offset,
1004 boolean_t copy,
1005 vm_prot_t cur_protection,
1006 vm_prot_t max_protection,
1007 vm_inherit_t inheritance)
1008 {
1009 vm_tag_t tag;
1010
1011 VM_GET_FLAGS_ALIAS(flags, tag);
1012 return mach_vm_map_kernel(target_map, address, initial_size, mask,
1013 flags, VM_MAP_KERNEL_FLAGS_NONE, tag,
1014 port, offset, copy,
1015 cur_protection, max_protection,
1016 inheritance);
1017 }
1018
1019 kern_return_t
1020 mach_vm_map_kernel(
1021 vm_map_t target_map,
1022 mach_vm_offset_t *address,
1023 mach_vm_size_t initial_size,
1024 mach_vm_offset_t mask,
1025 int flags,
1026 vm_map_kernel_flags_t vmk_flags,
1027 vm_tag_t tag,
1028 ipc_port_t port,
1029 vm_object_offset_t offset,
1030 boolean_t copy,
1031 vm_prot_t cur_protection,
1032 vm_prot_t max_protection,
1033 vm_inherit_t inheritance)
1034 {
1035 kern_return_t kr;
1036 vm_map_offset_t vmmaddr;
1037
1038 vmmaddr = (vm_map_offset_t) *address;
1039
1040 /* filter out any kernel-only flags */
1041 if (flags & ~VM_FLAGS_USER_MAP) {
1042 return KERN_INVALID_ARGUMENT;
1043 }
1044
1045 kr = vm_map_enter_mem_object(target_map,
1046 &vmmaddr,
1047 initial_size,
1048 mask,
1049 flags,
1050 vmk_flags,
1051 tag,
1052 port,
1053 offset,
1054 copy,
1055 cur_protection,
1056 max_protection,
1057 inheritance);
1058
1059 #if KASAN
1060 if (kr == KERN_SUCCESS && target_map->pmap == kernel_pmap) {
1061 kasan_notify_address(vmmaddr, initial_size);
1062 }
1063 #endif
1064
1065 *address = vmmaddr;
1066 return kr;
1067 }
1068
1069
1070 /* legacy interface */
1071 kern_return_t
1072 vm_map_64_external(
1073 vm_map_t target_map,
1074 vm_offset_t *address,
1075 vm_size_t size,
1076 vm_offset_t mask,
1077 int flags,
1078 ipc_port_t port,
1079 vm_object_offset_t offset,
1080 boolean_t copy,
1081 vm_prot_t cur_protection,
1082 vm_prot_t max_protection,
1083 vm_inherit_t inheritance)
1084 {
1085 vm_tag_t tag;
1086
1087 VM_GET_FLAGS_ALIAS(flags, tag);
1088 return vm_map_64_kernel(target_map, address, size, mask,
1089 flags, VM_MAP_KERNEL_FLAGS_NONE,
1090 tag, port, offset, copy,
1091 cur_protection, max_protection,
1092 inheritance);
1093 }
1094
1095 kern_return_t
1096 vm_map_64_kernel(
1097 vm_map_t target_map,
1098 vm_offset_t *address,
1099 vm_size_t size,
1100 vm_offset_t mask,
1101 int flags,
1102 vm_map_kernel_flags_t vmk_flags,
1103 vm_tag_t tag,
1104 ipc_port_t port,
1105 vm_object_offset_t offset,
1106 boolean_t copy,
1107 vm_prot_t cur_protection,
1108 vm_prot_t max_protection,
1109 vm_inherit_t inheritance)
1110 {
1111 mach_vm_address_t map_addr;
1112 mach_vm_size_t map_size;
1113 mach_vm_offset_t map_mask;
1114 kern_return_t kr;
1115
1116 map_addr = (mach_vm_address_t)*address;
1117 map_size = (mach_vm_size_t)size;
1118 map_mask = (mach_vm_offset_t)mask;
1119
1120 kr = mach_vm_map_kernel(target_map, &map_addr, map_size, map_mask,
1121 flags, vmk_flags, tag,
1122 port, offset, copy,
1123 cur_protection, max_protection, inheritance);
1124 *address = CAST_DOWN(vm_offset_t, map_addr);
1125 return kr;
1126 }
1127
1128 /* temporary, until world build */
1129 kern_return_t
1130 vm_map_external(
1131 vm_map_t target_map,
1132 vm_offset_t *address,
1133 vm_size_t size,
1134 vm_offset_t mask,
1135 int flags,
1136 ipc_port_t port,
1137 vm_offset_t offset,
1138 boolean_t copy,
1139 vm_prot_t cur_protection,
1140 vm_prot_t max_protection,
1141 vm_inherit_t inheritance)
1142 {
1143 vm_tag_t tag;
1144
1145 VM_GET_FLAGS_ALIAS(flags, tag);
1146 return vm_map_kernel(target_map, address, size, mask,
1147 flags, VM_MAP_KERNEL_FLAGS_NONE, tag,
1148 port, offset, copy,
1149 cur_protection, max_protection, inheritance);
1150 }
1151
1152 kern_return_t
1153 vm_map_kernel(
1154 vm_map_t target_map,
1155 vm_offset_t *address,
1156 vm_size_t size,
1157 vm_offset_t mask,
1158 int flags,
1159 vm_map_kernel_flags_t vmk_flags,
1160 vm_tag_t tag,
1161 ipc_port_t port,
1162 vm_offset_t offset,
1163 boolean_t copy,
1164 vm_prot_t cur_protection,
1165 vm_prot_t max_protection,
1166 vm_inherit_t inheritance)
1167 {
1168 mach_vm_address_t map_addr;
1169 mach_vm_size_t map_size;
1170 mach_vm_offset_t map_mask;
1171 vm_object_offset_t obj_offset;
1172 kern_return_t kr;
1173
1174 map_addr = (mach_vm_address_t)*address;
1175 map_size = (mach_vm_size_t)size;
1176 map_mask = (mach_vm_offset_t)mask;
1177 obj_offset = (vm_object_offset_t)offset;
1178
1179 kr = mach_vm_map_kernel(target_map, &map_addr, map_size, map_mask,
1180 flags, vmk_flags, tag,
1181 port, obj_offset, copy,
1182 cur_protection, max_protection, inheritance);
1183 *address = CAST_DOWN(vm_offset_t, map_addr);
1184 return kr;
1185 }
1186
1187 /*
1188 * mach_vm_remap -
1189 * Remap a range of memory from one task into another,
1190 * to another address range within the same task, or
1191 * over top of itself (with altered permissions and/or
1192 * as an in-place copy of itself).
1193 */
1194 kern_return_t
1195 mach_vm_remap_external(
1196 vm_map_t target_map,
1197 mach_vm_offset_t *address,
1198 mach_vm_size_t size,
1199 mach_vm_offset_t mask,
1200 int flags,
1201 vm_map_t src_map,
1202 mach_vm_offset_t memory_address,
1203 boolean_t copy,
1204 vm_prot_t *cur_protection,
1205 vm_prot_t *max_protection,
1206 vm_inherit_t inheritance)
1207 {
1208 vm_tag_t tag;
1209 VM_GET_FLAGS_ALIAS(flags, tag);
1210
1211 return mach_vm_remap_kernel(target_map, address, size, mask, flags, tag, src_map, memory_address,
1212 copy, cur_protection, max_protection, inheritance);
1213 }
1214
1215 kern_return_t
1216 mach_vm_remap_kernel(
1217 vm_map_t target_map,
1218 mach_vm_offset_t *address,
1219 mach_vm_size_t size,
1220 mach_vm_offset_t mask,
1221 int flags,
1222 vm_tag_t tag,
1223 vm_map_t src_map,
1224 mach_vm_offset_t memory_address,
1225 boolean_t copy,
1226 vm_prot_t *cur_protection,
1227 vm_prot_t *max_protection,
1228 vm_inherit_t inheritance)
1229 {
1230 vm_map_offset_t map_addr;
1231 kern_return_t kr;
1232
1233 if (VM_MAP_NULL == target_map || VM_MAP_NULL == src_map) {
1234 return KERN_INVALID_ARGUMENT;
1235 }
1236
1237 /* filter out any kernel-only flags */
1238 if (flags & ~VM_FLAGS_USER_REMAP) {
1239 return KERN_INVALID_ARGUMENT;
1240 }
1241
1242 map_addr = (vm_map_offset_t)*address;
1243
1244 kr = vm_map_remap(target_map,
1245 &map_addr,
1246 size,
1247 mask,
1248 flags,
1249 VM_MAP_KERNEL_FLAGS_NONE,
1250 tag,
1251 src_map,
1252 memory_address,
1253 copy,
1254 cur_protection,
1255 max_protection,
1256 inheritance);
1257 *address = map_addr;
1258 return kr;
1259 }
1260
1261 /*
1262 * vm_remap -
1263 * Remap a range of memory from one task into another,
1264 * to another address range within the same task, or
1265 * over top of itself (with altered permissions and/or
1266 * as an in-place copy of itself).
1267 *
1268 * The addressability of the source and target address
1269 * range is limited by the size of vm_address_t (in the
1270 * kernel context).
1271 */
1272 kern_return_t
1273 vm_remap_external(
1274 vm_map_t target_map,
1275 vm_offset_t *address,
1276 vm_size_t size,
1277 vm_offset_t mask,
1278 int flags,
1279 vm_map_t src_map,
1280 vm_offset_t memory_address,
1281 boolean_t copy,
1282 vm_prot_t *cur_protection,
1283 vm_prot_t *max_protection,
1284 vm_inherit_t inheritance)
1285 {
1286 vm_tag_t tag;
1287 VM_GET_FLAGS_ALIAS(flags, tag);
1288
1289 return vm_remap_kernel(target_map, address, size, mask, flags, tag, src_map,
1290 memory_address, copy, cur_protection, max_protection, inheritance);
1291 }
1292
1293 kern_return_t
1294 vm_remap_kernel(
1295 vm_map_t target_map,
1296 vm_offset_t *address,
1297 vm_size_t size,
1298 vm_offset_t mask,
1299 int flags,
1300 vm_tag_t tag,
1301 vm_map_t src_map,
1302 vm_offset_t memory_address,
1303 boolean_t copy,
1304 vm_prot_t *cur_protection,
1305 vm_prot_t *max_protection,
1306 vm_inherit_t inheritance)
1307 {
1308 vm_map_offset_t map_addr;
1309 kern_return_t kr;
1310
1311 if (VM_MAP_NULL == target_map || VM_MAP_NULL == src_map) {
1312 return KERN_INVALID_ARGUMENT;
1313 }
1314
1315 /* filter out any kernel-only flags */
1316 if (flags & ~VM_FLAGS_USER_REMAP) {
1317 return KERN_INVALID_ARGUMENT;
1318 }
1319
1320 map_addr = (vm_map_offset_t)*address;
1321
1322 kr = vm_map_remap(target_map,
1323 &map_addr,
1324 size,
1325 mask,
1326 flags,
1327 VM_MAP_KERNEL_FLAGS_NONE,
1328 tag,
1329 src_map,
1330 memory_address,
1331 copy,
1332 cur_protection,
1333 max_protection,
1334 inheritance);
1335 *address = CAST_DOWN(vm_offset_t, map_addr);
1336 return kr;
1337 }
1338
1339 /*
1340 * NOTE: these routine (and this file) will no longer require mach_host_server.h
1341 * when mach_vm_wire and vm_wire are changed to use ledgers.
1342 */
1343 #include <mach/mach_host_server.h>
1344 /*
1345 * mach_vm_wire
1346 * Specify that the range of the virtual address space
1347 * of the target task must not cause page faults for
1348 * the indicated accesses.
1349 *
1350 * [ To unwire the pages, specify VM_PROT_NONE. ]
1351 */
1352 kern_return_t
1353 mach_vm_wire_external(
1354 host_priv_t host_priv,
1355 vm_map_t map,
1356 mach_vm_offset_t start,
1357 mach_vm_size_t size,
1358 vm_prot_t access)
1359 {
1360 return mach_vm_wire_kernel(host_priv, map, start, size, access, VM_KERN_MEMORY_MLOCK);
1361 }
1362
1363 kern_return_t
1364 mach_vm_wire_kernel(
1365 host_priv_t host_priv,
1366 vm_map_t map,
1367 mach_vm_offset_t start,
1368 mach_vm_size_t size,
1369 vm_prot_t access,
1370 vm_tag_t tag)
1371 {
1372 kern_return_t rc;
1373
1374 if (host_priv == HOST_PRIV_NULL) {
1375 return KERN_INVALID_HOST;
1376 }
1377
1378 assert(host_priv == &realhost);
1379
1380 if (map == VM_MAP_NULL) {
1381 return KERN_INVALID_TASK;
1382 }
1383
1384 if (access & ~VM_PROT_ALL || (start + size < start)) {
1385 return KERN_INVALID_ARGUMENT;
1386 }
1387
1388 if (access != VM_PROT_NONE) {
1389 rc = vm_map_wire_kernel(map,
1390 vm_map_trunc_page(start,
1391 VM_MAP_PAGE_MASK(map)),
1392 vm_map_round_page(start + size,
1393 VM_MAP_PAGE_MASK(map)),
1394 access, tag,
1395 TRUE);
1396 } else {
1397 rc = vm_map_unwire(map,
1398 vm_map_trunc_page(start,
1399 VM_MAP_PAGE_MASK(map)),
1400 vm_map_round_page(start + size,
1401 VM_MAP_PAGE_MASK(map)),
1402 TRUE);
1403 }
1404 return rc;
1405 }
1406
1407 /*
1408 * vm_wire -
1409 * Specify that the range of the virtual address space
1410 * of the target task must not cause page faults for
1411 * the indicated accesses.
1412 *
1413 * [ To unwire the pages, specify VM_PROT_NONE. ]
1414 */
1415 kern_return_t
1416 vm_wire(
1417 host_priv_t host_priv,
1418 vm_map_t map,
1419 vm_offset_t start,
1420 vm_size_t size,
1421 vm_prot_t access)
1422 {
1423 kern_return_t rc;
1424
1425 if (host_priv == HOST_PRIV_NULL) {
1426 return KERN_INVALID_HOST;
1427 }
1428
1429 assert(host_priv == &realhost);
1430
1431 if (map == VM_MAP_NULL) {
1432 return KERN_INVALID_TASK;
1433 }
1434
1435 if ((access & ~VM_PROT_ALL) || (start + size < start)) {
1436 return KERN_INVALID_ARGUMENT;
1437 }
1438
1439 if (size == 0) {
1440 rc = KERN_SUCCESS;
1441 } else if (access != VM_PROT_NONE) {
1442 rc = vm_map_wire_kernel(map,
1443 vm_map_trunc_page(start,
1444 VM_MAP_PAGE_MASK(map)),
1445 vm_map_round_page(start + size,
1446 VM_MAP_PAGE_MASK(map)),
1447 access, VM_KERN_MEMORY_OSFMK,
1448 TRUE);
1449 } else {
1450 rc = vm_map_unwire(map,
1451 vm_map_trunc_page(start,
1452 VM_MAP_PAGE_MASK(map)),
1453 vm_map_round_page(start + size,
1454 VM_MAP_PAGE_MASK(map)),
1455 TRUE);
1456 }
1457 return rc;
1458 }
1459
1460 /*
1461 * vm_msync
1462 *
1463 * Synchronises the memory range specified with its backing store
1464 * image by either flushing or cleaning the contents to the appropriate
1465 * memory manager.
1466 *
1467 * interpretation of sync_flags
1468 * VM_SYNC_INVALIDATE - discard pages, only return precious
1469 * pages to manager.
1470 *
1471 * VM_SYNC_INVALIDATE & (VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS)
1472 * - discard pages, write dirty or precious
1473 * pages back to memory manager.
1474 *
1475 * VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS
1476 * - write dirty or precious pages back to
1477 * the memory manager.
1478 *
1479 * VM_SYNC_CONTIGUOUS - does everything normally, but if there
1480 * is a hole in the region, and we would
1481 * have returned KERN_SUCCESS, return
1482 * KERN_INVALID_ADDRESS instead.
1483 *
1484 * RETURNS
1485 * KERN_INVALID_TASK Bad task parameter
1486 * KERN_INVALID_ARGUMENT both sync and async were specified.
1487 * KERN_SUCCESS The usual.
1488 * KERN_INVALID_ADDRESS There was a hole in the region.
1489 */
1490
1491 kern_return_t
1492 mach_vm_msync(
1493 vm_map_t map,
1494 mach_vm_address_t address,
1495 mach_vm_size_t size,
1496 vm_sync_t sync_flags)
1497 {
1498 if (map == VM_MAP_NULL) {
1499 return KERN_INVALID_TASK;
1500 }
1501
1502 return vm_map_msync(map, (vm_map_address_t)address,
1503 (vm_map_size_t)size, sync_flags);
1504 }
1505
1506 /*
1507 * vm_msync
1508 *
1509 * Synchronises the memory range specified with its backing store
1510 * image by either flushing or cleaning the contents to the appropriate
1511 * memory manager.
1512 *
1513 * interpretation of sync_flags
1514 * VM_SYNC_INVALIDATE - discard pages, only return precious
1515 * pages to manager.
1516 *
1517 * VM_SYNC_INVALIDATE & (VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS)
1518 * - discard pages, write dirty or precious
1519 * pages back to memory manager.
1520 *
1521 * VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS
1522 * - write dirty or precious pages back to
1523 * the memory manager.
1524 *
1525 * VM_SYNC_CONTIGUOUS - does everything normally, but if there
1526 * is a hole in the region, and we would
1527 * have returned KERN_SUCCESS, return
1528 * KERN_INVALID_ADDRESS instead.
1529 *
1530 * The addressability of the range is limited to that which can
1531 * be described by a vm_address_t.
1532 *
1533 * RETURNS
1534 * KERN_INVALID_TASK Bad task parameter
1535 * KERN_INVALID_ARGUMENT both sync and async were specified.
1536 * KERN_SUCCESS The usual.
1537 * KERN_INVALID_ADDRESS There was a hole in the region.
1538 */
1539
1540 kern_return_t
1541 vm_msync(
1542 vm_map_t map,
1543 vm_address_t address,
1544 vm_size_t size,
1545 vm_sync_t sync_flags)
1546 {
1547 if (map == VM_MAP_NULL) {
1548 return KERN_INVALID_TASK;
1549 }
1550
1551 return vm_map_msync(map, (vm_map_address_t)address,
1552 (vm_map_size_t)size, sync_flags);
1553 }
1554
1555
1556 int
1557 vm_toggle_entry_reuse(int toggle, int *old_value)
1558 {
1559 vm_map_t map = current_map();
1560
1561 assert(!map->is_nested_map);
1562 if (toggle == VM_TOGGLE_GETVALUE && old_value != NULL) {
1563 *old_value = map->disable_vmentry_reuse;
1564 } else if (toggle == VM_TOGGLE_SET) {
1565 vm_map_entry_t map_to_entry;
1566
1567 vm_map_lock(map);
1568 vm_map_disable_hole_optimization(map);
1569 map->disable_vmentry_reuse = TRUE;
1570 __IGNORE_WCASTALIGN(map_to_entry = vm_map_to_entry(map));
1571 if (map->first_free == map_to_entry) {
1572 map->highest_entry_end = vm_map_min(map);
1573 } else {
1574 map->highest_entry_end = map->first_free->vme_end;
1575 }
1576 vm_map_unlock(map);
1577 } else if (toggle == VM_TOGGLE_CLEAR) {
1578 vm_map_lock(map);
1579 map->disable_vmentry_reuse = FALSE;
1580 vm_map_unlock(map);
1581 } else {
1582 return KERN_INVALID_ARGUMENT;
1583 }
1584
1585 return KERN_SUCCESS;
1586 }
1587
1588 /*
1589 * mach_vm_behavior_set
1590 *
1591 * Sets the paging behavior attribute for the specified range
1592 * in the specified map.
1593 *
1594 * This routine will fail with KERN_INVALID_ADDRESS if any address
1595 * in [start,start+size) is not a valid allocated memory region.
1596 */
1597 kern_return_t
1598 mach_vm_behavior_set(
1599 vm_map_t map,
1600 mach_vm_offset_t start,
1601 mach_vm_size_t size,
1602 vm_behavior_t new_behavior)
1603 {
1604 vm_map_offset_t align_mask;
1605
1606 if ((map == VM_MAP_NULL) || (start + size < start)) {
1607 return KERN_INVALID_ARGUMENT;
1608 }
1609
1610 if (size == 0) {
1611 return KERN_SUCCESS;
1612 }
1613
1614 switch (new_behavior) {
1615 case VM_BEHAVIOR_REUSABLE:
1616 case VM_BEHAVIOR_REUSE:
1617 case VM_BEHAVIOR_CAN_REUSE:
1618 /*
1619 * Align to the hardware page size, to allow
1620 * malloc() to maximize the amount of re-usability,
1621 * even on systems with larger software page size.
1622 */
1623 align_mask = PAGE_MASK;
1624 break;
1625 default:
1626 align_mask = VM_MAP_PAGE_MASK(map);
1627 break;
1628 }
1629
1630 return vm_map_behavior_set(map,
1631 vm_map_trunc_page(start, align_mask),
1632 vm_map_round_page(start + size, align_mask),
1633 new_behavior);
1634 }
1635
1636 /*
1637 * vm_behavior_set
1638 *
1639 * Sets the paging behavior attribute for the specified range
1640 * in the specified map.
1641 *
1642 * This routine will fail with KERN_INVALID_ADDRESS if any address
1643 * in [start,start+size) is not a valid allocated memory region.
1644 *
1645 * This routine is potentially limited in addressibility by the
1646 * use of vm_offset_t (if the map provided is larger than the
1647 * kernel's).
1648 */
1649 kern_return_t
1650 vm_behavior_set(
1651 vm_map_t map,
1652 vm_offset_t start,
1653 vm_size_t size,
1654 vm_behavior_t new_behavior)
1655 {
1656 if (start + size < start) {
1657 return KERN_INVALID_ARGUMENT;
1658 }
1659
1660 return mach_vm_behavior_set(map,
1661 (mach_vm_offset_t) start,
1662 (mach_vm_size_t) size,
1663 new_behavior);
1664 }
1665
1666 /*
1667 * mach_vm_region:
1668 *
1669 * User call to obtain information about a region in
1670 * a task's address map. Currently, only one flavor is
1671 * supported.
1672 *
1673 * XXX The reserved and behavior fields cannot be filled
1674 * in until the vm merge from the IK is completed, and
1675 * vm_reserve is implemented.
1676 *
1677 * XXX Dependency: syscall_vm_region() also supports only one flavor.
1678 */
1679
1680 kern_return_t
1681 mach_vm_region(
1682 vm_map_t map,
1683 mach_vm_offset_t *address, /* IN/OUT */
1684 mach_vm_size_t *size, /* OUT */
1685 vm_region_flavor_t flavor, /* IN */
1686 vm_region_info_t info, /* OUT */
1687 mach_msg_type_number_t *count, /* IN/OUT */
1688 mach_port_t *object_name) /* OUT */
1689 {
1690 vm_map_offset_t map_addr;
1691 vm_map_size_t map_size;
1692 kern_return_t kr;
1693
1694 if (VM_MAP_NULL == map) {
1695 return KERN_INVALID_ARGUMENT;
1696 }
1697
1698 map_addr = (vm_map_offset_t)*address;
1699 map_size = (vm_map_size_t)*size;
1700
1701 /* legacy conversion */
1702 if (VM_REGION_BASIC_INFO == flavor) {
1703 flavor = VM_REGION_BASIC_INFO_64;
1704 }
1705
1706 kr = vm_map_region(map,
1707 &map_addr, &map_size,
1708 flavor, info, count,
1709 object_name);
1710
1711 *address = map_addr;
1712 *size = map_size;
1713 return kr;
1714 }
1715
1716 /*
1717 * vm_region_64 and vm_region:
1718 *
1719 * User call to obtain information about a region in
1720 * a task's address map. Currently, only one flavor is
1721 * supported.
1722 *
1723 * XXX The reserved and behavior fields cannot be filled
1724 * in until the vm merge from the IK is completed, and
1725 * vm_reserve is implemented.
1726 *
1727 * XXX Dependency: syscall_vm_region() also supports only one flavor.
1728 */
1729
1730 kern_return_t
1731 vm_region_64(
1732 vm_map_t map,
1733 vm_offset_t *address, /* IN/OUT */
1734 vm_size_t *size, /* OUT */
1735 vm_region_flavor_t flavor, /* IN */
1736 vm_region_info_t info, /* OUT */
1737 mach_msg_type_number_t *count, /* IN/OUT */
1738 mach_port_t *object_name) /* OUT */
1739 {
1740 vm_map_offset_t map_addr;
1741 vm_map_size_t map_size;
1742 kern_return_t kr;
1743
1744 if (VM_MAP_NULL == map) {
1745 return KERN_INVALID_ARGUMENT;
1746 }
1747
1748 map_addr = (vm_map_offset_t)*address;
1749 map_size = (vm_map_size_t)*size;
1750
1751 /* legacy conversion */
1752 if (VM_REGION_BASIC_INFO == flavor) {
1753 flavor = VM_REGION_BASIC_INFO_64;
1754 }
1755
1756 kr = vm_map_region(map,
1757 &map_addr, &map_size,
1758 flavor, info, count,
1759 object_name);
1760
1761 *address = CAST_DOWN(vm_offset_t, map_addr);
1762 *size = CAST_DOWN(vm_size_t, map_size);
1763
1764 if (KERN_SUCCESS == kr && map_addr + map_size > VM_MAX_ADDRESS) {
1765 return KERN_INVALID_ADDRESS;
1766 }
1767 return kr;
1768 }
1769
1770 kern_return_t
1771 vm_region(
1772 vm_map_t map,
1773 vm_address_t *address, /* IN/OUT */
1774 vm_size_t *size, /* OUT */
1775 vm_region_flavor_t flavor, /* IN */
1776 vm_region_info_t info, /* OUT */
1777 mach_msg_type_number_t *count, /* IN/OUT */
1778 mach_port_t *object_name) /* OUT */
1779 {
1780 vm_map_address_t map_addr;
1781 vm_map_size_t map_size;
1782 kern_return_t kr;
1783
1784 if (VM_MAP_NULL == map) {
1785 return KERN_INVALID_ARGUMENT;
1786 }
1787
1788 map_addr = (vm_map_address_t)*address;
1789 map_size = (vm_map_size_t)*size;
1790
1791 kr = vm_map_region(map,
1792 &map_addr, &map_size,
1793 flavor, info, count,
1794 object_name);
1795
1796 *address = CAST_DOWN(vm_address_t, map_addr);
1797 *size = CAST_DOWN(vm_size_t, map_size);
1798
1799 if (KERN_SUCCESS == kr && map_addr + map_size > VM_MAX_ADDRESS) {
1800 return KERN_INVALID_ADDRESS;
1801 }
1802 return kr;
1803 }
1804
1805 /*
1806 * vm_region_recurse: A form of vm_region which follows the
1807 * submaps in a target map
1808 *
1809 */
1810 kern_return_t
1811 mach_vm_region_recurse(
1812 vm_map_t map,
1813 mach_vm_address_t *address,
1814 mach_vm_size_t *size,
1815 uint32_t *depth,
1816 vm_region_recurse_info_t info,
1817 mach_msg_type_number_t *infoCnt)
1818 {
1819 vm_map_address_t map_addr;
1820 vm_map_size_t map_size;
1821 kern_return_t kr;
1822
1823 if (VM_MAP_NULL == map) {
1824 return KERN_INVALID_ARGUMENT;
1825 }
1826
1827 map_addr = (vm_map_address_t)*address;
1828 map_size = (vm_map_size_t)*size;
1829
1830 kr = vm_map_region_recurse_64(
1831 map,
1832 &map_addr,
1833 &map_size,
1834 depth,
1835 (vm_region_submap_info_64_t)info,
1836 infoCnt);
1837
1838 *address = map_addr;
1839 *size = map_size;
1840 return kr;
1841 }
1842
1843 /*
1844 * vm_region_recurse: A form of vm_region which follows the
1845 * submaps in a target map
1846 *
1847 */
1848 kern_return_t
1849 vm_region_recurse_64(
1850 vm_map_t map,
1851 vm_address_t *address,
1852 vm_size_t *size,
1853 uint32_t *depth,
1854 vm_region_recurse_info_64_t info,
1855 mach_msg_type_number_t *infoCnt)
1856 {
1857 vm_map_address_t map_addr;
1858 vm_map_size_t map_size;
1859 kern_return_t kr;
1860
1861 if (VM_MAP_NULL == map) {
1862 return KERN_INVALID_ARGUMENT;
1863 }
1864
1865 map_addr = (vm_map_address_t)*address;
1866 map_size = (vm_map_size_t)*size;
1867
1868 kr = vm_map_region_recurse_64(
1869 map,
1870 &map_addr,
1871 &map_size,
1872 depth,
1873 (vm_region_submap_info_64_t)info,
1874 infoCnt);
1875
1876 *address = CAST_DOWN(vm_address_t, map_addr);
1877 *size = CAST_DOWN(vm_size_t, map_size);
1878
1879 if (KERN_SUCCESS == kr && map_addr + map_size > VM_MAX_ADDRESS) {
1880 return KERN_INVALID_ADDRESS;
1881 }
1882 return kr;
1883 }
1884
1885 kern_return_t
1886 vm_region_recurse(
1887 vm_map_t map,
1888 vm_offset_t *address, /* IN/OUT */
1889 vm_size_t *size, /* OUT */
1890 natural_t *depth, /* IN/OUT */
1891 vm_region_recurse_info_t info32, /* IN/OUT */
1892 mach_msg_type_number_t *infoCnt) /* IN/OUT */
1893 {
1894 vm_region_submap_info_data_64_t info64;
1895 vm_region_submap_info_t info;
1896 vm_map_address_t map_addr;
1897 vm_map_size_t map_size;
1898 kern_return_t kr;
1899
1900 if (VM_MAP_NULL == map || *infoCnt < VM_REGION_SUBMAP_INFO_COUNT) {
1901 return KERN_INVALID_ARGUMENT;
1902 }
1903
1904
1905 map_addr = (vm_map_address_t)*address;
1906 map_size = (vm_map_size_t)*size;
1907 info = (vm_region_submap_info_t)info32;
1908 *infoCnt = VM_REGION_SUBMAP_INFO_COUNT_64;
1909
1910 kr = vm_map_region_recurse_64(map, &map_addr, &map_size,
1911 depth, &info64, infoCnt);
1912
1913 info->protection = info64.protection;
1914 info->max_protection = info64.max_protection;
1915 info->inheritance = info64.inheritance;
1916 info->offset = (uint32_t)info64.offset; /* trouble-maker */
1917 info->user_tag = info64.user_tag;
1918 info->pages_resident = info64.pages_resident;
1919 info->pages_shared_now_private = info64.pages_shared_now_private;
1920 info->pages_swapped_out = info64.pages_swapped_out;
1921 info->pages_dirtied = info64.pages_dirtied;
1922 info->ref_count = info64.ref_count;
1923 info->shadow_depth = info64.shadow_depth;
1924 info->external_pager = info64.external_pager;
1925 info->share_mode = info64.share_mode;
1926 info->is_submap = info64.is_submap;
1927 info->behavior = info64.behavior;
1928 info->object_id = info64.object_id;
1929 info->user_wired_count = info64.user_wired_count;
1930
1931 *address = CAST_DOWN(vm_address_t, map_addr);
1932 *size = CAST_DOWN(vm_size_t, map_size);
1933 *infoCnt = VM_REGION_SUBMAP_INFO_COUNT;
1934
1935 if (KERN_SUCCESS == kr && map_addr + map_size > VM_MAX_ADDRESS) {
1936 return KERN_INVALID_ADDRESS;
1937 }
1938 return kr;
1939 }
1940
1941 kern_return_t
1942 mach_vm_purgable_control(
1943 vm_map_t map,
1944 mach_vm_offset_t address,
1945 vm_purgable_t control,
1946 int *state)
1947 {
1948 if (VM_MAP_NULL == map) {
1949 return KERN_INVALID_ARGUMENT;
1950 }
1951
1952 if (control == VM_PURGABLE_SET_STATE_FROM_KERNEL) {
1953 /* not allowed from user-space */
1954 return KERN_INVALID_ARGUMENT;
1955 }
1956
1957 return vm_map_purgable_control(map,
1958 vm_map_trunc_page(address, VM_MAP_PAGE_MASK(map)),
1959 control,
1960 state);
1961 }
1962
1963 kern_return_t
1964 vm_purgable_control(
1965 vm_map_t map,
1966 vm_offset_t address,
1967 vm_purgable_t control,
1968 int *state)
1969 {
1970 if (VM_MAP_NULL == map) {
1971 return KERN_INVALID_ARGUMENT;
1972 }
1973
1974 if (control == VM_PURGABLE_SET_STATE_FROM_KERNEL) {
1975 /* not allowed from user-space */
1976 return KERN_INVALID_ARGUMENT;
1977 }
1978
1979 return vm_map_purgable_control(map,
1980 vm_map_trunc_page(address, VM_MAP_PAGE_MASK(map)),
1981 control,
1982 state);
1983 }
1984
1985
1986 /*
1987 * Ordinarily, the right to allocate CPM is restricted
1988 * to privileged applications (those that can gain access
1989 * to the host priv port). Set this variable to zero if
1990 * you want to let any application allocate CPM.
1991 */
1992 unsigned int vm_allocate_cpm_privileged = 0;
1993
1994 /*
1995 * Allocate memory in the specified map, with the caveat that
1996 * the memory is physically contiguous. This call may fail
1997 * if the system can't find sufficient contiguous memory.
1998 * This call may cause or lead to heart-stopping amounts of
1999 * paging activity.
2000 *
2001 * Memory obtained from this call should be freed in the
2002 * normal way, viz., via vm_deallocate.
2003 */
2004 kern_return_t
2005 vm_allocate_cpm(
2006 host_priv_t host_priv,
2007 vm_map_t map,
2008 vm_address_t *addr,
2009 vm_size_t size,
2010 int flags)
2011 {
2012 vm_map_address_t map_addr;
2013 vm_map_size_t map_size;
2014 kern_return_t kr;
2015
2016 if (vm_allocate_cpm_privileged && HOST_PRIV_NULL == host_priv) {
2017 return KERN_INVALID_HOST;
2018 }
2019
2020 if (VM_MAP_NULL == map) {
2021 return KERN_INVALID_ARGUMENT;
2022 }
2023
2024 map_addr = (vm_map_address_t)*addr;
2025 map_size = (vm_map_size_t)size;
2026
2027 kr = vm_map_enter_cpm(map,
2028 &map_addr,
2029 map_size,
2030 flags);
2031
2032 *addr = CAST_DOWN(vm_address_t, map_addr);
2033 return kr;
2034 }
2035
2036
2037 kern_return_t
2038 mach_vm_page_query(
2039 vm_map_t map,
2040 mach_vm_offset_t offset,
2041 int *disposition,
2042 int *ref_count)
2043 {
2044 if (VM_MAP_NULL == map) {
2045 return KERN_INVALID_ARGUMENT;
2046 }
2047
2048 return vm_map_page_query_internal(
2049 map,
2050 vm_map_trunc_page(offset, PAGE_MASK),
2051 disposition, ref_count);
2052 }
2053
2054 kern_return_t
2055 vm_map_page_query(
2056 vm_map_t map,
2057 vm_offset_t offset,
2058 int *disposition,
2059 int *ref_count)
2060 {
2061 if (VM_MAP_NULL == map) {
2062 return KERN_INVALID_ARGUMENT;
2063 }
2064
2065 return vm_map_page_query_internal(
2066 map,
2067 vm_map_trunc_page(offset, PAGE_MASK),
2068 disposition, ref_count);
2069 }
2070
2071 kern_return_t
2072 mach_vm_page_range_query(
2073 vm_map_t map,
2074 mach_vm_offset_t address,
2075 mach_vm_size_t size,
2076 mach_vm_address_t dispositions_addr,
2077 mach_vm_size_t *dispositions_count)
2078 {
2079 kern_return_t kr = KERN_SUCCESS;
2080 int num_pages = 0, i = 0;
2081 mach_vm_size_t curr_sz = 0, copy_sz = 0;
2082 mach_vm_size_t disp_buf_req_size = 0, disp_buf_total_size = 0;
2083 mach_msg_type_number_t count = 0;
2084
2085 void *info = NULL;
2086 void *local_disp = NULL;;
2087 vm_map_size_t info_size = 0, local_disp_size = 0;
2088 mach_vm_offset_t start = 0, end = 0;
2089 int effective_page_shift, effective_page_size, effective_page_mask;
2090
2091 if (map == VM_MAP_NULL || dispositions_count == NULL) {
2092 return KERN_INVALID_ARGUMENT;
2093 }
2094
2095 effective_page_shift = vm_self_region_page_shift_safely(map);
2096 if (effective_page_shift == -1) {
2097 return KERN_INVALID_ARGUMENT;
2098 }
2099 effective_page_size = (1 << effective_page_shift);
2100 effective_page_mask = effective_page_size - 1;
2101
2102 disp_buf_req_size = (*dispositions_count * sizeof(int));
2103 start = vm_map_trunc_page(address, effective_page_mask);
2104 end = vm_map_round_page(address + size, effective_page_mask);
2105
2106 if (end < start) {
2107 return KERN_INVALID_ARGUMENT;
2108 }
2109
2110 if ((end - start) < size) {
2111 /*
2112 * Aligned size is less than unaligned size.
2113 */
2114 return KERN_INVALID_ARGUMENT;
2115 }
2116
2117 if (disp_buf_req_size == 0 || (end == start)) {
2118 return KERN_SUCCESS;
2119 }
2120
2121 /*
2122 * For large requests, we will go through them
2123 * MAX_PAGE_RANGE_QUERY chunk at a time.
2124 */
2125
2126 curr_sz = MIN(end - start, MAX_PAGE_RANGE_QUERY);
2127 num_pages = (int) (curr_sz >> effective_page_shift);
2128
2129 info_size = num_pages * sizeof(vm_page_info_basic_data_t);
2130 info = kheap_alloc(KHEAP_TEMP, info_size, Z_WAITOK);
2131
2132 local_disp_size = num_pages * sizeof(int);
2133 local_disp = kheap_alloc(KHEAP_TEMP, local_disp_size, Z_WAITOK);
2134
2135 if (info == NULL || local_disp == NULL) {
2136 kr = KERN_RESOURCE_SHORTAGE;
2137 goto out;
2138 }
2139
2140 while (size) {
2141 count = VM_PAGE_INFO_BASIC_COUNT;
2142 kr = vm_map_page_range_info_internal(
2143 map,
2144 start,
2145 vm_map_round_page(start + curr_sz, effective_page_mask),
2146 effective_page_shift,
2147 VM_PAGE_INFO_BASIC,
2148 (vm_page_info_t) info,
2149 &count);
2150
2151 assert(kr == KERN_SUCCESS);
2152
2153 for (i = 0; i < num_pages; i++) {
2154 ((int*)local_disp)[i] = ((vm_page_info_basic_t)info)[i].disposition;
2155 }
2156
2157 copy_sz = MIN(disp_buf_req_size, num_pages * sizeof(int) /* an int per page */);
2158 kr = copyout(local_disp, (mach_vm_address_t)dispositions_addr, copy_sz);
2159
2160 start += curr_sz;
2161 disp_buf_req_size -= copy_sz;
2162 disp_buf_total_size += copy_sz;
2163
2164 if (kr != 0) {
2165 break;
2166 }
2167
2168 if ((disp_buf_req_size == 0) || (curr_sz >= size)) {
2169 /*
2170 * We might have inspected the full range OR
2171 * more than it esp. if the user passed in
2172 * non-page aligned start/size and/or if we
2173 * descended into a submap. We are done here.
2174 */
2175
2176 size = 0;
2177 } else {
2178 dispositions_addr += copy_sz;
2179
2180 size -= curr_sz;
2181
2182 curr_sz = MIN(vm_map_round_page(size, effective_page_mask), MAX_PAGE_RANGE_QUERY);
2183 num_pages = (int)(curr_sz >> effective_page_shift);
2184 }
2185 }
2186
2187 *dispositions_count = disp_buf_total_size / sizeof(int);
2188
2189 out:
2190 if (local_disp) {
2191 kheap_free(KHEAP_TEMP, local_disp, local_disp_size);
2192 }
2193 if (info) {
2194 kheap_free(KHEAP_TEMP, info, info_size);
2195 }
2196 return kr;
2197 }
2198
2199 kern_return_t
2200 mach_vm_page_info(
2201 vm_map_t map,
2202 mach_vm_address_t address,
2203 vm_page_info_flavor_t flavor,
2204 vm_page_info_t info,
2205 mach_msg_type_number_t *count)
2206 {
2207 kern_return_t kr;
2208
2209 if (map == VM_MAP_NULL) {
2210 return KERN_INVALID_ARGUMENT;
2211 }
2212
2213 kr = vm_map_page_info(map, address, flavor, info, count);
2214 return kr;
2215 }
2216
2217 /* map a (whole) upl into an address space */
2218 kern_return_t
2219 vm_upl_map(
2220 vm_map_t map,
2221 upl_t upl,
2222 vm_address_t *dst_addr)
2223 {
2224 vm_map_offset_t map_addr;
2225 kern_return_t kr;
2226
2227 if (VM_MAP_NULL == map) {
2228 return KERN_INVALID_ARGUMENT;
2229 }
2230
2231 kr = vm_map_enter_upl(map, upl, &map_addr);
2232 *dst_addr = CAST_DOWN(vm_address_t, map_addr);
2233 return kr;
2234 }
2235
2236 kern_return_t
2237 vm_upl_unmap(
2238 vm_map_t map,
2239 upl_t upl)
2240 {
2241 if (VM_MAP_NULL == map) {
2242 return KERN_INVALID_ARGUMENT;
2243 }
2244
2245 return vm_map_remove_upl(map, upl);
2246 }
2247
2248 /* Retrieve a upl for an object underlying an address range in a map */
2249
2250 kern_return_t
2251 vm_map_get_upl(
2252 vm_map_t map,
2253 vm_map_offset_t map_offset,
2254 upl_size_t *upl_size,
2255 upl_t *upl,
2256 upl_page_info_array_t page_list,
2257 unsigned int *count,
2258 upl_control_flags_t *flags,
2259 vm_tag_t tag,
2260 int force_data_sync)
2261 {
2262 upl_control_flags_t map_flags;
2263 kern_return_t kr;
2264
2265 if (VM_MAP_NULL == map) {
2266 return KERN_INVALID_ARGUMENT;
2267 }
2268
2269 map_flags = *flags & ~UPL_NOZEROFILL;
2270 if (force_data_sync) {
2271 map_flags |= UPL_FORCE_DATA_SYNC;
2272 }
2273
2274 kr = vm_map_create_upl(map,
2275 map_offset,
2276 upl_size,
2277 upl,
2278 page_list,
2279 count,
2280 &map_flags,
2281 tag);
2282
2283 *flags = (map_flags & ~UPL_FORCE_DATA_SYNC);
2284 return kr;
2285 }
2286
2287 /*
2288 * mach_make_memory_entry_64
2289 *
2290 * Think of it as a two-stage vm_remap() operation. First
2291 * you get a handle. Second, you get map that handle in
2292 * somewhere else. Rather than doing it all at once (and
2293 * without needing access to the other whole map).
2294 */
2295 kern_return_t
2296 mach_make_memory_entry_64(
2297 vm_map_t target_map,
2298 memory_object_size_t *size,
2299 memory_object_offset_t offset,
2300 vm_prot_t permission,
2301 ipc_port_t *object_handle,
2302 ipc_port_t parent_handle)
2303 {
2304 vm_named_entry_kernel_flags_t vmne_kflags;
2305
2306 if ((permission & MAP_MEM_FLAGS_MASK) & ~MAP_MEM_FLAGS_USER) {
2307 /*
2308 * Unknown flag: reject for forward compatibility.
2309 */
2310 return KERN_INVALID_VALUE;
2311 }
2312
2313 vmne_kflags = VM_NAMED_ENTRY_KERNEL_FLAGS_NONE;
2314 if (permission & MAP_MEM_LEDGER_TAGGED) {
2315 vmne_kflags.vmnekf_ledger_tag = VM_LEDGER_TAG_DEFAULT;
2316 }
2317 return mach_make_memory_entry_internal(target_map,
2318 size,
2319 offset,
2320 permission,
2321 vmne_kflags,
2322 object_handle,
2323 parent_handle);
2324 }
2325
2326 kern_return_t
2327 mach_make_memory_entry_internal(
2328 vm_map_t target_map,
2329 memory_object_size_t *size,
2330 memory_object_offset_t offset,
2331 vm_prot_t permission,
2332 vm_named_entry_kernel_flags_t vmne_kflags,
2333 ipc_port_t *object_handle,
2334 ipc_port_t parent_handle)
2335 {
2336 vm_named_entry_t parent_entry;
2337 vm_named_entry_t user_entry;
2338 ipc_port_t user_handle;
2339 kern_return_t kr;
2340 vm_object_t object;
2341 vm_map_size_t map_size;
2342 vm_map_offset_t map_start, map_end;
2343
2344 /*
2345 * Stash the offset in the page for use by vm_map_enter_mem_object()
2346 * in the VM_FLAGS_RETURN_DATA_ADDR/MAP_MEM_USE_DATA_ADDR case.
2347 */
2348 vm_object_offset_t offset_in_page;
2349
2350 unsigned int access;
2351 vm_prot_t protections;
2352 vm_prot_t original_protections, mask_protections;
2353 unsigned int wimg_mode;
2354 boolean_t use_data_addr;
2355 boolean_t use_4K_compat;
2356
2357 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x\n", target_map, offset, *size, permission);
2358
2359 user_entry = NULL;
2360
2361 if ((permission & MAP_MEM_FLAGS_MASK) & ~MAP_MEM_FLAGS_ALL) {
2362 /*
2363 * Unknown flag: reject for forward compatibility.
2364 */
2365 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_INVALID_VALUE);
2366 return KERN_INVALID_VALUE;
2367 }
2368
2369 if (IP_VALID(parent_handle) &&
2370 ip_kotype(parent_handle) == IKOT_NAMED_ENTRY) {
2371 parent_entry = (vm_named_entry_t) ip_get_kobject(parent_handle);
2372 } else {
2373 parent_entry = NULL;
2374 }
2375
2376 if (parent_entry && parent_entry->is_copy) {
2377 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_INVALID_ARGUMENT);
2378 return KERN_INVALID_ARGUMENT;
2379 }
2380
2381 original_protections = permission & VM_PROT_ALL;
2382 protections = original_protections;
2383 mask_protections = permission & VM_PROT_IS_MASK;
2384 access = GET_MAP_MEM(permission);
2385 use_data_addr = ((permission & MAP_MEM_USE_DATA_ADDR) != 0);
2386 use_4K_compat = ((permission & MAP_MEM_4K_DATA_ADDR) != 0);
2387
2388 user_handle = IP_NULL;
2389 user_entry = NULL;
2390
2391 map_start = vm_map_trunc_page(offset, VM_MAP_PAGE_MASK(target_map));
2392
2393 if (permission & MAP_MEM_ONLY) {
2394 boolean_t parent_is_object;
2395
2396 map_end = vm_map_round_page(offset + *size, VM_MAP_PAGE_MASK(target_map));
2397 map_size = map_end - map_start;
2398
2399 if (use_data_addr || use_4K_compat || parent_entry == NULL) {
2400 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_INVALID_ARGUMENT);
2401 return KERN_INVALID_ARGUMENT;
2402 }
2403
2404 parent_is_object = parent_entry->is_object;
2405 if (!parent_is_object) {
2406 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_INVALID_ARGUMENT);
2407 return KERN_INVALID_ARGUMENT;
2408 }
2409 object = vm_named_entry_to_vm_object(parent_entry);
2410 if (parent_is_object && object != VM_OBJECT_NULL) {
2411 wimg_mode = object->wimg_bits;
2412 } else {
2413 wimg_mode = VM_WIMG_USE_DEFAULT;
2414 }
2415 if ((access != GET_MAP_MEM(parent_entry->protection)) &&
2416 !(parent_entry->protection & VM_PROT_WRITE)) {
2417 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_INVALID_RIGHT);
2418 return KERN_INVALID_RIGHT;
2419 }
2420 vm_prot_to_wimg(access, &wimg_mode);
2421 if (access != MAP_MEM_NOOP) {
2422 SET_MAP_MEM(access, parent_entry->protection);
2423 }
2424 if (parent_is_object && object &&
2425 (access != MAP_MEM_NOOP) &&
2426 (!(object->nophyscache))) {
2427 if (object->wimg_bits != wimg_mode) {
2428 vm_object_lock(object);
2429 vm_object_change_wimg_mode(object, wimg_mode);
2430 vm_object_unlock(object);
2431 }
2432 }
2433 if (object_handle) {
2434 *object_handle = IP_NULL;
2435 }
2436 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_SUCCESS);
2437 return KERN_SUCCESS;
2438 } else if (permission & MAP_MEM_NAMED_CREATE) {
2439 int ledger_flags = 0;
2440 task_t owner;
2441
2442 map_end = vm_map_round_page(offset + *size, VM_MAP_PAGE_MASK(target_map));
2443 map_size = map_end - map_start;
2444
2445 if (use_data_addr || use_4K_compat) {
2446 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_INVALID_ARGUMENT);
2447 return KERN_INVALID_ARGUMENT;
2448 }
2449
2450 if (map_size == 0) {
2451 *size = 0;
2452 *object_handle = IPC_PORT_NULL;
2453 return KERN_SUCCESS;
2454 }
2455
2456 kr = mach_memory_entry_allocate(&user_entry, &user_handle);
2457 if (kr != KERN_SUCCESS) {
2458 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_FAILURE);
2459 return KERN_FAILURE;
2460 }
2461
2462 /*
2463 * Force the creation of the VM object now.
2464 */
2465 if (map_size > (vm_map_size_t) ANON_MAX_SIZE) {
2466 /*
2467 * LP64todo - for now, we can only allocate 4GB-4096
2468 * internal objects because the default pager can't
2469 * page bigger ones. Remove this when it can.
2470 */
2471 kr = KERN_FAILURE;
2472 goto make_mem_done;
2473 }
2474
2475 object = vm_object_allocate(map_size);
2476 assert(object != VM_OBJECT_NULL);
2477
2478 /*
2479 * XXX
2480 * We use this path when we want to make sure that
2481 * nobody messes with the object (coalesce, for
2482 * example) before we map it.
2483 * We might want to use these objects for transposition via
2484 * vm_object_transpose() too, so we don't want any copy or
2485 * shadow objects either...
2486 */
2487 object->copy_strategy = MEMORY_OBJECT_COPY_NONE;
2488 object->true_share = TRUE;
2489
2490 owner = current_task();
2491 if ((permission & MAP_MEM_PURGABLE) ||
2492 vmne_kflags.vmnekf_ledger_tag) {
2493 assert(object->vo_owner == NULL);
2494 assert(object->resident_page_count == 0);
2495 assert(object->wired_page_count == 0);
2496 assert(owner != TASK_NULL);
2497 if (vmne_kflags.vmnekf_ledger_no_footprint) {
2498 ledger_flags |= VM_LEDGER_FLAG_NO_FOOTPRINT;
2499 object->vo_no_footprint = TRUE;
2500 }
2501 if (permission & MAP_MEM_PURGABLE) {
2502 if (!(permission & VM_PROT_WRITE)) {
2503 /* if we can't write, we can't purge */
2504 vm_object_deallocate(object);
2505 kr = KERN_INVALID_ARGUMENT;
2506 goto make_mem_done;
2507 }
2508 object->purgable = VM_PURGABLE_NONVOLATILE;
2509 if (permission & MAP_MEM_PURGABLE_KERNEL_ONLY) {
2510 object->purgeable_only_by_kernel = TRUE;
2511 }
2512 #if __arm64__
2513 if (owner->task_legacy_footprint) {
2514 /*
2515 * For ios11, we failed to account for
2516 * this memory. Keep doing that for
2517 * legacy apps (built before ios12),
2518 * for backwards compatibility's sake...
2519 */
2520 owner = kernel_task;
2521 }
2522 #endif /* __arm64__ */
2523 vm_object_lock(object);
2524 vm_purgeable_nonvolatile_enqueue(object, owner);
2525 vm_object_unlock(object);
2526 }
2527 }
2528
2529 if (vmne_kflags.vmnekf_ledger_tag) {
2530 /*
2531 * Bill this object to the current task's
2532 * ledgers for the given tag.
2533 */
2534 if (vmne_kflags.vmnekf_ledger_no_footprint) {
2535 ledger_flags |= VM_LEDGER_FLAG_NO_FOOTPRINT;
2536 }
2537 vm_object_lock(object);
2538 object->vo_ledger_tag = vmne_kflags.vmnekf_ledger_tag;
2539 kr = vm_object_ownership_change(
2540 object,
2541 vmne_kflags.vmnekf_ledger_tag,
2542 owner, /* new owner */
2543 ledger_flags,
2544 FALSE); /* task_objq locked? */
2545 vm_object_unlock(object);
2546 if (kr != KERN_SUCCESS) {
2547 vm_object_deallocate(object);
2548 goto make_mem_done;
2549 }
2550 }
2551
2552 #if CONFIG_SECLUDED_MEMORY
2553 if (secluded_for_iokit && /* global boot-arg */
2554 ((permission & MAP_MEM_GRAB_SECLUDED)
2555 #if 11
2556 /* XXX FBDP for my testing only */
2557 || (secluded_for_fbdp && map_size == 97550336)
2558 #endif
2559 )) {
2560 #if 11
2561 if (!(permission & MAP_MEM_GRAB_SECLUDED) &&
2562 secluded_for_fbdp) {
2563 printf("FBDP: object %p size %lld can grab secluded\n", object, (uint64_t) map_size);
2564 }
2565 #endif
2566 object->can_grab_secluded = TRUE;
2567 assert(!object->eligible_for_secluded);
2568 }
2569 #endif /* CONFIG_SECLUDED_MEMORY */
2570
2571 /*
2572 * The VM object is brand new and nobody else knows about it,
2573 * so we don't need to lock it.
2574 */
2575
2576 wimg_mode = object->wimg_bits;
2577 vm_prot_to_wimg(access, &wimg_mode);
2578 if (access != MAP_MEM_NOOP) {
2579 object->wimg_bits = wimg_mode;
2580 }
2581
2582 /* the object has no pages, so no WIMG bits to update here */
2583
2584 kr = vm_named_entry_from_vm_object(
2585 user_entry,
2586 object,
2587 0,
2588 map_size,
2589 (protections & VM_PROT_ALL));
2590 if (kr != KERN_SUCCESS) {
2591 vm_object_deallocate(object);
2592 goto make_mem_done;
2593 }
2594 user_entry->internal = TRUE;
2595 user_entry->is_sub_map = FALSE;
2596 user_entry->offset = 0;
2597 user_entry->data_offset = 0;
2598 user_entry->protection = protections;
2599 SET_MAP_MEM(access, user_entry->protection);
2600 user_entry->size = map_size;
2601
2602 /* user_object pager and internal fields are not used */
2603 /* when the object field is filled in. */
2604
2605 *size = CAST_DOWN(vm_size_t, (user_entry->size -
2606 user_entry->data_offset));
2607 *object_handle = user_handle;
2608 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_SUCCESS);
2609 return KERN_SUCCESS;
2610 }
2611
2612 if (permission & MAP_MEM_VM_COPY) {
2613 vm_map_copy_t copy;
2614
2615 if (target_map == VM_MAP_NULL) {
2616 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_INVALID_TASK);
2617 return KERN_INVALID_TASK;
2618 }
2619
2620 map_end = vm_map_round_page(offset + *size, VM_MAP_PAGE_MASK(target_map));
2621 map_size = map_end - map_start;
2622 if (map_size == 0) {
2623 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_INVALID_ARGUMENT);
2624 return KERN_INVALID_ARGUMENT;
2625 }
2626
2627 if (use_data_addr || use_4K_compat) {
2628 offset_in_page = offset - map_start;
2629 if (use_4K_compat) {
2630 offset_in_page &= ~((signed)(0xFFF));
2631 }
2632 } else {
2633 offset_in_page = 0;
2634 }
2635
2636 kr = vm_map_copyin_internal(target_map,
2637 map_start,
2638 map_size,
2639 VM_MAP_COPYIN_ENTRY_LIST,
2640 &copy);
2641 if (kr != KERN_SUCCESS) {
2642 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, kr);
2643 return kr;
2644 }
2645 assert(copy != VM_MAP_COPY_NULL);
2646
2647 kr = mach_memory_entry_allocate(&user_entry, &user_handle);
2648 if (kr != KERN_SUCCESS) {
2649 vm_map_copy_discard(copy);
2650 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_FAILURE);
2651 return KERN_FAILURE;
2652 }
2653
2654 user_entry->backing.copy = copy;
2655 user_entry->internal = FALSE;
2656 user_entry->is_sub_map = FALSE;
2657 user_entry->is_copy = TRUE;
2658 user_entry->offset = 0;
2659 user_entry->protection = protections;
2660 user_entry->size = map_size;
2661 user_entry->data_offset = offset_in_page;
2662
2663 *size = CAST_DOWN(vm_size_t, (user_entry->size -
2664 user_entry->data_offset));
2665 *object_handle = user_handle;
2666 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_SUCCESS);
2667 return KERN_SUCCESS;
2668 }
2669
2670 if ((permission & MAP_MEM_VM_SHARE)
2671 || parent_entry == NULL
2672 || (permission & MAP_MEM_NAMED_REUSE)) {
2673 vm_map_copy_t copy;
2674 vm_prot_t cur_prot, max_prot;
2675 vm_map_kernel_flags_t vmk_flags;
2676 vm_map_entry_t parent_copy_entry;
2677 vm_prot_t required_protection;
2678
2679 if (target_map == VM_MAP_NULL) {
2680 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_INVALID_TASK);
2681 return KERN_INVALID_TASK;
2682 }
2683
2684 map_end = vm_map_round_page(offset + *size, VM_MAP_PAGE_MASK(target_map));
2685 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
2686 parent_copy_entry = VM_MAP_ENTRY_NULL;
2687 if (!(permission & MAP_MEM_VM_SHARE)) {
2688 /* stop extracting if VM object changes */
2689 vmk_flags.vmkf_copy_single_object = TRUE;
2690 if ((permission & MAP_MEM_NAMED_REUSE) &&
2691 parent_entry != NULL &&
2692 parent_entry->is_object) {
2693 vm_map_copy_t parent_copy;
2694 parent_copy = parent_entry->backing.copy;
2695 assert(parent_copy->cpy_hdr.nentries == 1);
2696 parent_copy_entry = vm_map_copy_first_entry(parent_copy);
2697 assert(!parent_copy_entry->is_sub_map);
2698 }
2699 }
2700
2701 map_size = map_end - map_start;
2702 if (map_size == 0) {
2703 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_INVALID_ARGUMENT);
2704 return KERN_INVALID_ARGUMENT;
2705 }
2706
2707 if (use_data_addr || use_4K_compat) {
2708 offset_in_page = offset - map_start;
2709 if (use_4K_compat) {
2710 offset_in_page &= ~((signed)(0xFFF));
2711 }
2712 } else {
2713 offset_in_page = 0;
2714 }
2715
2716 if (mask_protections) {
2717 /*
2718 * caller is asking for whichever proctections are
2719 * available: no required protections.
2720 */
2721 required_protection = VM_PROT_NONE;
2722 } else {
2723 /*
2724 * Caller wants a memory entry with "protections".
2725 * Make sure we extract only memory that matches that.
2726 */
2727 required_protection = protections;
2728 }
2729 cur_prot = VM_PROT_ALL;
2730 if (target_map->pmap == kernel_pmap) {
2731 /*
2732 * Get "reserved" map entries to avoid deadlocking
2733 * on the kernel map or a kernel submap if we
2734 * run out of VM map entries and need to refill that
2735 * zone.
2736 */
2737 vmk_flags.vmkf_copy_pageable = FALSE;
2738 } else {
2739 vmk_flags.vmkf_copy_pageable = TRUE;
2740 }
2741 vmk_flags.vmkf_copy_same_map = FALSE;
2742 assert(map_size != 0);
2743 kr = vm_map_copy_extract(target_map,
2744 map_start,
2745 map_size,
2746 required_protection,
2747 FALSE, /* copy */
2748 &copy,
2749 &cur_prot,
2750 &max_prot,
2751 VM_INHERIT_SHARE,
2752 vmk_flags);
2753 if (kr != KERN_SUCCESS) {
2754 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, kr);
2755 if (VM_MAP_PAGE_SHIFT(target_map) < PAGE_SHIFT) {
2756 // panic("DEBUG4K %s:%d kr 0x%x\n", __FUNCTION__, __LINE__, kr);
2757 }
2758 return kr;
2759 }
2760 assert(copy != VM_MAP_COPY_NULL);
2761 assert((cur_prot & required_protection) == required_protection);
2762
2763 if (mask_protections) {
2764 /*
2765 * We just want as much of "original_protections"
2766 * as we can get out of the actual "cur_prot".
2767 */
2768 protections &= cur_prot;
2769 if (protections == VM_PROT_NONE) {
2770 /* no access at all: fail */
2771 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_PROTECTION_FAILURE);
2772 if (VM_MAP_PAGE_SHIFT(target_map) < PAGE_SHIFT) {
2773 // panic("DEBUG4K %s:%d kr 0x%x\n", __FUNCTION__, __LINE__, kr);
2774 }
2775 vm_map_copy_discard(copy);
2776 return KERN_PROTECTION_FAILURE;
2777 }
2778 } else {
2779 /*
2780 * We want exactly "original_protections"
2781 * out of "cur_prot".
2782 */
2783 if ((cur_prot & protections) != protections) {
2784 if (VM_MAP_PAGE_SHIFT(target_map) < PAGE_SHIFT) {
2785 // panic("DEBUG4K %s:%d kr 0x%x\n", __FUNCTION__, __LINE__, KERN_PROTECTION_FAILURE);
2786 }
2787 vm_map_copy_discard(copy);
2788 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_PROTECTION_FAILURE);
2789 return KERN_PROTECTION_FAILURE;
2790 }
2791 }
2792
2793 if (!(permission & MAP_MEM_VM_SHARE)) {
2794 vm_map_entry_t copy_entry;
2795
2796 /* limit size to what's actually covered by "copy" */
2797 assert(copy->cpy_hdr.nentries == 1);
2798 copy_entry = vm_map_copy_first_entry(copy);
2799 map_size = copy_entry->vme_end - copy_entry->vme_start;
2800
2801 if ((permission & MAP_MEM_NAMED_REUSE) &&
2802 parent_copy_entry != VM_MAP_ENTRY_NULL &&
2803 VME_OBJECT(copy_entry) == VME_OBJECT(parent_copy_entry) &&
2804 VME_OFFSET(copy_entry) == VME_OFFSET(parent_copy_entry) &&
2805 parent_entry->offset == 0 &&
2806 parent_entry->size == map_size &&
2807 (parent_entry->data_offset == offset_in_page)) {
2808 /* we have a match: re-use "parent_entry" */
2809
2810 /* release our new "copy" */
2811 vm_map_copy_discard(copy);
2812 /* get extra send right on handle */
2813 ipc_port_copy_send(parent_handle);
2814
2815 *size = CAST_DOWN(vm_size_t,
2816 (parent_entry->size -
2817 parent_entry->data_offset));
2818 *object_handle = parent_handle;
2819 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_SUCCESS);
2820 return KERN_SUCCESS;
2821 }
2822
2823 /* no match: we need to create a new entry */
2824 object = VME_OBJECT(copy_entry);
2825 vm_object_lock(object);
2826 wimg_mode = object->wimg_bits;
2827 if (!(object->nophyscache)) {
2828 vm_prot_to_wimg(access, &wimg_mode);
2829 }
2830 if (object->wimg_bits != wimg_mode) {
2831 vm_object_change_wimg_mode(object, wimg_mode);
2832 }
2833 vm_object_unlock(object);
2834 }
2835
2836 kr = mach_memory_entry_allocate(&user_entry, &user_handle);
2837 if (kr != KERN_SUCCESS) {
2838 if (VM_MAP_PAGE_SHIFT(target_map) < PAGE_SHIFT) {
2839 // panic("DEBUG4K %s:%d kr 0x%x\n", __FUNCTION__, __LINE__, kr);
2840 }
2841 vm_map_copy_discard(copy);
2842 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_FAILURE);
2843 return KERN_FAILURE;
2844 }
2845
2846 user_entry->backing.copy = copy;
2847 user_entry->is_sub_map = FALSE;
2848 user_entry->is_object = FALSE;
2849 user_entry->internal = FALSE;
2850 user_entry->protection = protections;
2851 user_entry->size = map_size;
2852 user_entry->data_offset = offset_in_page;
2853
2854 if (permission & MAP_MEM_VM_SHARE) {
2855 user_entry->is_copy = TRUE;
2856 user_entry->offset = 0;
2857 } else {
2858 user_entry->is_object = TRUE;
2859 user_entry->internal = object->internal;
2860 user_entry->offset = VME_OFFSET(vm_map_copy_first_entry(copy));
2861 SET_MAP_MEM(GET_MAP_MEM(permission), user_entry->protection);
2862 }
2863
2864 *size = CAST_DOWN(vm_size_t, (user_entry->size -
2865 user_entry->data_offset));
2866 *object_handle = user_handle;
2867 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_SUCCESS);
2868 return KERN_SUCCESS;
2869 }
2870
2871 /* The new object will be based on an existing named object */
2872 if (parent_entry == NULL) {
2873 kr = KERN_INVALID_ARGUMENT;
2874 goto make_mem_done;
2875 }
2876
2877 if (parent_entry->is_copy) {
2878 panic("parent_entry %p is_copy not supported\n", parent_entry);
2879 kr = KERN_INVALID_ARGUMENT;
2880 goto make_mem_done;
2881 }
2882
2883 if (use_data_addr || use_4K_compat) {
2884 /*
2885 * submaps and pagers should only be accessible from within
2886 * the kernel, which shouldn't use the data address flag, so can fail here.
2887 */
2888 if (parent_entry->is_sub_map) {
2889 panic("Shouldn't be using data address with a parent entry that is a submap.");
2890 }
2891 /*
2892 * Account for offset to data in parent entry and
2893 * compute our own offset to data.
2894 */
2895 if ((offset + *size + parent_entry->data_offset) > parent_entry->size) {
2896 kr = KERN_INVALID_ARGUMENT;
2897 goto make_mem_done;
2898 }
2899
2900 map_start = vm_map_trunc_page(offset + parent_entry->data_offset, PAGE_MASK);
2901 offset_in_page = (offset + parent_entry->data_offset) - map_start;
2902 if (use_4K_compat) {
2903 offset_in_page &= ~((signed)(0xFFF));
2904 }
2905 map_end = vm_map_round_page(offset + parent_entry->data_offset + *size, PAGE_MASK);
2906 map_size = map_end - map_start;
2907 } else {
2908 map_end = vm_map_round_page(offset + *size, PAGE_MASK);
2909 map_size = map_end - map_start;
2910 offset_in_page = 0;
2911
2912 if ((offset + map_size) > parent_entry->size) {
2913 kr = KERN_INVALID_ARGUMENT;
2914 goto make_mem_done;
2915 }
2916 }
2917
2918 if (mask_protections) {
2919 /*
2920 * The caller asked us to use the "protections" as
2921 * a mask, so restrict "protections" to what this
2922 * mapping actually allows.
2923 */
2924 protections &= parent_entry->protection;
2925 }
2926 if ((protections & parent_entry->protection) != protections) {
2927 kr = KERN_PROTECTION_FAILURE;
2928 goto make_mem_done;
2929 }
2930
2931 if (mach_memory_entry_allocate(&user_entry, &user_handle)
2932 != KERN_SUCCESS) {
2933 kr = KERN_FAILURE;
2934 goto make_mem_done;
2935 }
2936
2937 user_entry->size = map_size;
2938 user_entry->offset = parent_entry->offset + map_start;
2939 user_entry->data_offset = offset_in_page;
2940 user_entry->is_sub_map = parent_entry->is_sub_map;
2941 user_entry->is_copy = parent_entry->is_copy;
2942 user_entry->internal = parent_entry->internal;
2943 user_entry->protection = protections;
2944
2945 if (access != MAP_MEM_NOOP) {
2946 SET_MAP_MEM(access, user_entry->protection);
2947 }
2948
2949 if (parent_entry->is_sub_map) {
2950 vm_map_t map = parent_entry->backing.map;
2951 user_entry->backing.map = map;
2952 lck_mtx_lock(&map->s_lock);
2953 os_ref_retain_locked(&map->map_refcnt);
2954 lck_mtx_unlock(&map->s_lock);
2955 } else {
2956 object = vm_named_entry_to_vm_object(parent_entry);
2957 assert(object != VM_OBJECT_NULL);
2958 assert(object->copy_strategy != MEMORY_OBJECT_COPY_SYMMETRIC);
2959 kr = vm_named_entry_from_vm_object(
2960 user_entry,
2961 object,
2962 user_entry->offset,
2963 user_entry->size,
2964 (user_entry->protection & VM_PROT_ALL));
2965 if (kr != KERN_SUCCESS) {
2966 goto make_mem_done;
2967 }
2968 assert(user_entry->is_object);
2969 /* we now point to this object, hold on */
2970 vm_object_lock(object);
2971 vm_object_reference_locked(object);
2972 #if VM_OBJECT_TRACKING_OP_TRUESHARE
2973 if (!object->true_share &&
2974 vm_object_tracking_inited) {
2975 void *bt[VM_OBJECT_TRACKING_BTDEPTH];
2976 int num = 0;
2977
2978 num = OSBacktrace(bt,
2979 VM_OBJECT_TRACKING_BTDEPTH);
2980 btlog_add_entry(vm_object_tracking_btlog,
2981 object,
2982 VM_OBJECT_TRACKING_OP_TRUESHARE,
2983 bt,
2984 num);
2985 }
2986 #endif /* VM_OBJECT_TRACKING_OP_TRUESHARE */
2987
2988 object->true_share = TRUE;
2989 if (object->copy_strategy == MEMORY_OBJECT_COPY_SYMMETRIC) {
2990 object->copy_strategy = MEMORY_OBJECT_COPY_DELAY;
2991 }
2992 vm_object_unlock(object);
2993 }
2994 *size = CAST_DOWN(vm_size_t, (user_entry->size -
2995 user_entry->data_offset));
2996 *object_handle = user_handle;
2997 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, KERN_SUCCESS);
2998 return KERN_SUCCESS;
2999
3000 make_mem_done:
3001 if (user_handle != IP_NULL) {
3002 /*
3003 * Releasing "user_handle" causes the kernel object
3004 * associated with it ("user_entry" here) to also be
3005 * released and freed.
3006 */
3007 mach_memory_entry_port_release(user_handle);
3008 }
3009 DEBUG4K_MEMENTRY("map %p offset 0x%llx size 0x%llx prot 0x%x -> entry %p kr 0x%x\n", target_map, offset, *size, permission, user_entry, kr);
3010 return kr;
3011 }
3012
3013 kern_return_t
3014 _mach_make_memory_entry(
3015 vm_map_t target_map,
3016 memory_object_size_t *size,
3017 memory_object_offset_t offset,
3018 vm_prot_t permission,
3019 ipc_port_t *object_handle,
3020 ipc_port_t parent_entry)
3021 {
3022 memory_object_size_t mo_size;
3023 kern_return_t kr;
3024
3025 mo_size = (memory_object_size_t)*size;
3026 kr = mach_make_memory_entry_64(target_map, &mo_size,
3027 (memory_object_offset_t)offset, permission, object_handle,
3028 parent_entry);
3029 *size = mo_size;
3030 return kr;
3031 }
3032
3033 kern_return_t
3034 mach_make_memory_entry(
3035 vm_map_t target_map,
3036 vm_size_t *size,
3037 vm_offset_t offset,
3038 vm_prot_t permission,
3039 ipc_port_t *object_handle,
3040 ipc_port_t parent_entry)
3041 {
3042 memory_object_size_t mo_size;
3043 kern_return_t kr;
3044
3045 mo_size = (memory_object_size_t)*size;
3046 kr = mach_make_memory_entry_64(target_map, &mo_size,
3047 (memory_object_offset_t)offset, permission, object_handle,
3048 parent_entry);
3049 *size = CAST_DOWN(vm_size_t, mo_size);
3050 return kr;
3051 }
3052
3053 /*
3054 * task_wire
3055 *
3056 * Set or clear the map's wiring_required flag. This flag, if set,
3057 * will cause all future virtual memory allocation to allocate
3058 * user wired memory. Unwiring pages wired down as a result of
3059 * this routine is done with the vm_wire interface.
3060 */
3061 kern_return_t
3062 task_wire(
3063 vm_map_t map,
3064 boolean_t must_wire)
3065 {
3066 if (map == VM_MAP_NULL) {
3067 return KERN_INVALID_ARGUMENT;
3068 }
3069
3070 vm_map_lock(map);
3071 map->wiring_required = (must_wire == TRUE);
3072 vm_map_unlock(map);
3073
3074 return KERN_SUCCESS;
3075 }
3076
3077 kern_return_t
3078 vm_map_exec_lockdown(
3079 vm_map_t map)
3080 {
3081 if (map == VM_MAP_NULL) {
3082 return KERN_INVALID_ARGUMENT;
3083 }
3084
3085 vm_map_lock(map);
3086 map->map_disallow_new_exec = TRUE;
3087 vm_map_unlock(map);
3088
3089 return KERN_SUCCESS;
3090 }
3091
3092 #if VM_NAMED_ENTRY_LIST
3093 queue_head_t vm_named_entry_list = QUEUE_HEAD_INITIALIZER(vm_named_entry_list);
3094 int vm_named_entry_count = 0;
3095 LCK_MTX_EARLY_DECLARE_ATTR(vm_named_entry_list_lock_data,
3096 &vm_object_lck_grp, &vm_object_lck_attr);
3097 #endif /* VM_NAMED_ENTRY_LIST */
3098
3099 __private_extern__ kern_return_t
3100 mach_memory_entry_allocate(
3101 vm_named_entry_t *user_entry_p,
3102 ipc_port_t *user_handle_p)
3103 {
3104 vm_named_entry_t user_entry;
3105 ipc_port_t user_handle;
3106
3107 user_entry = (vm_named_entry_t) kalloc(sizeof *user_entry);
3108 if (user_entry == NULL) {
3109 return KERN_FAILURE;
3110 }
3111 bzero(user_entry, sizeof(*user_entry));
3112
3113 named_entry_lock_init(user_entry);
3114
3115 user_entry->backing.copy = NULL;
3116 user_entry->is_object = FALSE;
3117 user_entry->is_sub_map = FALSE;
3118 user_entry->is_copy = FALSE;
3119 user_entry->internal = FALSE;
3120 user_entry->size = 0;
3121 user_entry->offset = 0;
3122 user_entry->data_offset = 0;
3123 user_entry->protection = VM_PROT_NONE;
3124 user_entry->ref_count = 1;
3125
3126 user_handle = ipc_kobject_alloc_port((ipc_kobject_t)user_entry,
3127 IKOT_NAMED_ENTRY,
3128 IPC_KOBJECT_ALLOC_MAKE_SEND | IPC_KOBJECT_ALLOC_NSREQUEST);
3129
3130 *user_entry_p = user_entry;
3131 *user_handle_p = user_handle;
3132
3133 #if VM_NAMED_ENTRY_LIST
3134 /* keep a loose (no reference) pointer to the Mach port, for debugging only */
3135 user_entry->named_entry_port = user_handle;
3136 /* backtrace at allocation time, for debugging only */
3137 OSBacktrace(&user_entry->named_entry_bt[0],
3138 NAMED_ENTRY_BT_DEPTH);
3139
3140 /* add this new named entry to the global list */
3141 lck_mtx_lock_spin(&vm_named_entry_list_lock_data);
3142 queue_enter(&vm_named_entry_list, user_entry,
3143 vm_named_entry_t, named_entry_list);
3144 vm_named_entry_count++;
3145 lck_mtx_unlock(&vm_named_entry_list_lock_data);
3146 #endif /* VM_NAMED_ENTRY_LIST */
3147
3148 return KERN_SUCCESS;
3149 }
3150
3151 /*
3152 * mach_memory_object_memory_entry_64
3153 *
3154 * Create a named entry backed by the provided pager.
3155 *
3156 */
3157 kern_return_t
3158 mach_memory_object_memory_entry_64(
3159 host_t host,
3160 boolean_t internal,
3161 vm_object_offset_t size,
3162 vm_prot_t permission,
3163 memory_object_t pager,
3164 ipc_port_t *entry_handle)
3165 {
3166 unsigned int access;
3167 vm_named_entry_t user_entry;
3168 ipc_port_t user_handle;
3169 vm_object_t object;
3170 kern_return_t kr;
3171
3172 if (host == HOST_NULL) {
3173 return KERN_INVALID_HOST;
3174 }
3175
3176 if (pager == MEMORY_OBJECT_NULL && internal) {
3177 object = vm_object_allocate(size);
3178 if (object->copy_strategy == MEMORY_OBJECT_COPY_SYMMETRIC) {
3179 object->copy_strategy = MEMORY_OBJECT_COPY_DELAY;
3180 }
3181 } else {
3182 object = memory_object_to_vm_object(pager);
3183 if (object != VM_OBJECT_NULL) {
3184 vm_object_reference(object);
3185 }
3186 }
3187 if (object == VM_OBJECT_NULL) {
3188 return KERN_INVALID_ARGUMENT;
3189 }
3190
3191 if (mach_memory_entry_allocate(&user_entry, &user_handle)
3192 != KERN_SUCCESS) {
3193 vm_object_deallocate(object);
3194 return KERN_FAILURE;
3195 }
3196
3197 user_entry->size = size;
3198 user_entry->offset = 0;
3199 user_entry->protection = permission & VM_PROT_ALL;
3200 access = GET_MAP_MEM(permission);
3201 SET_MAP_MEM(access, user_entry->protection);
3202 user_entry->is_sub_map = FALSE;
3203 assert(user_entry->ref_count == 1);
3204
3205 kr = vm_named_entry_from_vm_object(user_entry, object, 0, size,
3206 (user_entry->protection & VM_PROT_ALL));
3207 if (kr != KERN_SUCCESS) {
3208 return kr;
3209 }
3210 user_entry->internal = object->internal;
3211 assert(object->internal == internal);
3212
3213 *entry_handle = user_handle;
3214 return KERN_SUCCESS;
3215 }
3216
3217 kern_return_t
3218 mach_memory_object_memory_entry(
3219 host_t host,
3220 boolean_t internal,
3221 vm_size_t size,
3222 vm_prot_t permission,
3223 memory_object_t pager,
3224 ipc_port_t *entry_handle)
3225 {
3226 return mach_memory_object_memory_entry_64( host, internal,
3227 (vm_object_offset_t)size, permission, pager, entry_handle);
3228 }
3229
3230
3231 kern_return_t
3232 mach_memory_entry_purgable_control(
3233 ipc_port_t entry_port,
3234 vm_purgable_t control,
3235 int *state)
3236 {
3237 if (control == VM_PURGABLE_SET_STATE_FROM_KERNEL) {
3238 /* not allowed from user-space */
3239 return KERN_INVALID_ARGUMENT;
3240 }
3241
3242 return memory_entry_purgeable_control_internal(entry_port, control, state);
3243 }
3244
3245 kern_return_t
3246 memory_entry_purgeable_control_internal(
3247 ipc_port_t entry_port,
3248 vm_purgable_t control,
3249 int *state)
3250 {
3251 kern_return_t kr;
3252 vm_named_entry_t mem_entry;
3253 vm_object_t object;
3254
3255 if (!IP_VALID(entry_port) ||
3256 ip_kotype(entry_port) != IKOT_NAMED_ENTRY) {
3257 return KERN_INVALID_ARGUMENT;
3258 }
3259 if (control != VM_PURGABLE_SET_STATE &&
3260 control != VM_PURGABLE_GET_STATE &&
3261 control != VM_PURGABLE_SET_STATE_FROM_KERNEL) {
3262 return KERN_INVALID_ARGUMENT;
3263 }
3264
3265 if ((control == VM_PURGABLE_SET_STATE ||
3266 control == VM_PURGABLE_SET_STATE_FROM_KERNEL) &&
3267 (((*state & ~(VM_PURGABLE_ALL_MASKS)) != 0) ||
3268 ((*state & VM_PURGABLE_STATE_MASK) > VM_PURGABLE_STATE_MASK))) {
3269 return KERN_INVALID_ARGUMENT;
3270 }
3271
3272 mem_entry = (vm_named_entry_t) ip_get_kobject(entry_port);
3273
3274 named_entry_lock(mem_entry);
3275
3276 if (mem_entry->is_sub_map ||
3277 mem_entry->is_copy) {
3278 named_entry_unlock(mem_entry);
3279 return KERN_INVALID_ARGUMENT;
3280 }
3281
3282 assert(mem_entry->is_object);
3283 object = vm_named_entry_to_vm_object(mem_entry);
3284 if (object == VM_OBJECT_NULL) {
3285 named_entry_unlock(mem_entry);
3286 return KERN_INVALID_ARGUMENT;
3287 }
3288
3289 vm_object_lock(object);
3290
3291 /* check that named entry covers entire object ? */
3292 if (mem_entry->offset != 0 || object->vo_size != mem_entry->size) {
3293 vm_object_unlock(object);
3294 named_entry_unlock(mem_entry);
3295 return KERN_INVALID_ARGUMENT;
3296 }
3297
3298 named_entry_unlock(mem_entry);
3299
3300 kr = vm_object_purgable_control(object, control, state);
3301
3302 vm_object_unlock(object);
3303
3304 return kr;
3305 }
3306
3307 kern_return_t
3308 mach_memory_entry_access_tracking(
3309 ipc_port_t entry_port,
3310 int *access_tracking,
3311 uint32_t *access_tracking_reads,
3312 uint32_t *access_tracking_writes)
3313 {
3314 return memory_entry_access_tracking_internal(entry_port,
3315 access_tracking,
3316 access_tracking_reads,
3317 access_tracking_writes);
3318 }
3319
3320 kern_return_t
3321 memory_entry_access_tracking_internal(
3322 ipc_port_t entry_port,
3323 int *access_tracking,
3324 uint32_t *access_tracking_reads,
3325 uint32_t *access_tracking_writes)
3326 {
3327 vm_named_entry_t mem_entry;
3328 vm_object_t object;
3329 kern_return_t kr;
3330
3331 if (!IP_VALID(entry_port) ||
3332 ip_kotype(entry_port) != IKOT_NAMED_ENTRY) {
3333 return KERN_INVALID_ARGUMENT;
3334 }
3335
3336 mem_entry = (vm_named_entry_t) ip_get_kobject(entry_port);
3337
3338 named_entry_lock(mem_entry);
3339
3340 if (mem_entry->is_sub_map ||
3341 mem_entry->is_copy) {
3342 named_entry_unlock(mem_entry);
3343 return KERN_INVALID_ARGUMENT;
3344 }
3345
3346 assert(mem_entry->is_object);
3347 object = vm_named_entry_to_vm_object(mem_entry);
3348 if (object == VM_OBJECT_NULL) {
3349 named_entry_unlock(mem_entry);
3350 return KERN_INVALID_ARGUMENT;
3351 }
3352
3353 #if VM_OBJECT_ACCESS_TRACKING
3354 vm_object_access_tracking(object,
3355 access_tracking,
3356 access_tracking_reads,
3357 access_tracking_writes);
3358 kr = KERN_SUCCESS;
3359 #else /* VM_OBJECT_ACCESS_TRACKING */
3360 (void) access_tracking;
3361 (void) access_tracking_reads;
3362 (void) access_tracking_writes;
3363 kr = KERN_NOT_SUPPORTED;
3364 #endif /* VM_OBJECT_ACCESS_TRACKING */
3365
3366 named_entry_unlock(mem_entry);
3367
3368 return kr;
3369 }
3370
3371 kern_return_t
3372 mach_memory_entry_ownership(
3373 ipc_port_t entry_port,
3374 task_t owner,
3375 int ledger_tag,
3376 int ledger_flags)
3377 {
3378 task_t cur_task;
3379 kern_return_t kr;
3380 vm_named_entry_t mem_entry;
3381 vm_object_t object;
3382
3383 cur_task = current_task();
3384 if (cur_task != kernel_task &&
3385 (owner != cur_task ||
3386 (ledger_flags & VM_LEDGER_FLAG_NO_FOOTPRINT) ||
3387 ledger_tag == VM_LEDGER_TAG_NETWORK)) {
3388 /*
3389 * An entitlement is required to:
3390 * + tranfer memory ownership to someone else,
3391 * + request that the memory not count against the footprint,
3392 * + tag as "network" (since that implies "no footprint")
3393 */
3394 if (!cur_task->task_can_transfer_memory_ownership &&
3395 IOTaskHasEntitlement(cur_task,
3396 "com.apple.private.memory.ownership_transfer")) {
3397 cur_task->task_can_transfer_memory_ownership = TRUE;
3398 }
3399 if (!cur_task->task_can_transfer_memory_ownership) {
3400 return KERN_NO_ACCESS;
3401 }
3402 }
3403
3404 if (ledger_flags & ~VM_LEDGER_FLAGS) {
3405 return KERN_INVALID_ARGUMENT;
3406 }
3407 if (ledger_tag <= 0 ||
3408 ledger_tag > VM_LEDGER_TAG_MAX) {
3409 return KERN_INVALID_ARGUMENT;
3410 }
3411
3412 if (!IP_VALID(entry_port) ||
3413 ip_kotype(entry_port) != IKOT_NAMED_ENTRY) {
3414 return KERN_INVALID_ARGUMENT;
3415 }
3416 mem_entry = (vm_named_entry_t) ip_get_kobject(entry_port);
3417
3418 named_entry_lock(mem_entry);
3419
3420 if (mem_entry->is_sub_map ||
3421 mem_entry->is_copy) {
3422 named_entry_unlock(mem_entry);
3423 return KERN_INVALID_ARGUMENT;
3424 }
3425
3426 assert(mem_entry->is_object);
3427 object = vm_named_entry_to_vm_object(mem_entry);
3428 if (object == VM_OBJECT_NULL) {
3429 named_entry_unlock(mem_entry);
3430 return KERN_INVALID_ARGUMENT;
3431 }
3432
3433 vm_object_lock(object);
3434
3435 /* check that named entry covers entire object ? */
3436 if (mem_entry->offset != 0 || object->vo_size != mem_entry->size) {
3437 vm_object_unlock(object);
3438 named_entry_unlock(mem_entry);
3439 return KERN_INVALID_ARGUMENT;
3440 }
3441
3442 named_entry_unlock(mem_entry);
3443
3444 kr = vm_object_ownership_change(object,
3445 ledger_tag,
3446 owner,
3447 ledger_flags,
3448 FALSE); /* task_objq_locked */
3449 vm_object_unlock(object);
3450
3451 return kr;
3452 }
3453
3454 kern_return_t
3455 mach_memory_entry_get_page_counts(
3456 ipc_port_t entry_port,
3457 unsigned int *resident_page_count,
3458 unsigned int *dirty_page_count)
3459 {
3460 kern_return_t kr;
3461 vm_named_entry_t mem_entry;
3462 vm_object_t object;
3463 vm_object_offset_t offset;
3464 vm_object_size_t size;
3465
3466 if (!IP_VALID(entry_port) ||
3467 ip_kotype(entry_port) != IKOT_NAMED_ENTRY) {
3468 return KERN_INVALID_ARGUMENT;
3469 }
3470
3471 mem_entry = (vm_named_entry_t) ip_get_kobject(entry_port);
3472
3473 named_entry_lock(mem_entry);
3474
3475 if (mem_entry->is_sub_map ||
3476 mem_entry->is_copy) {
3477 named_entry_unlock(mem_entry);
3478 return KERN_INVALID_ARGUMENT;
3479 }
3480
3481 assert(mem_entry->is_object);
3482 object = vm_named_entry_to_vm_object(mem_entry);
3483 if (object == VM_OBJECT_NULL) {
3484 named_entry_unlock(mem_entry);
3485 return KERN_INVALID_ARGUMENT;
3486 }
3487
3488 vm_object_lock(object);
3489
3490 offset = mem_entry->offset;
3491 size = mem_entry->size;
3492 size = vm_object_round_page(offset + size) - vm_object_trunc_page(offset);
3493 offset = vm_object_trunc_page(offset);
3494
3495 named_entry_unlock(mem_entry);
3496
3497 kr = vm_object_get_page_counts(object, offset, size, resident_page_count, dirty_page_count);
3498
3499 vm_object_unlock(object);
3500
3501 return kr;
3502 }
3503
3504 kern_return_t
3505 mach_memory_entry_phys_page_offset(
3506 ipc_port_t entry_port,
3507 vm_object_offset_t *offset_p)
3508 {
3509 vm_named_entry_t mem_entry;
3510 vm_object_t object;
3511 vm_object_offset_t offset;
3512 vm_object_offset_t data_offset;
3513
3514 if (!IP_VALID(entry_port) ||
3515 ip_kotype(entry_port) != IKOT_NAMED_ENTRY) {
3516 return KERN_INVALID_ARGUMENT;
3517 }
3518
3519 mem_entry = (vm_named_entry_t) entry_port->ip_kobject;
3520
3521 named_entry_lock(mem_entry);
3522
3523 if (mem_entry->is_sub_map ||
3524 mem_entry->is_copy) {
3525 named_entry_unlock(mem_entry);
3526 return KERN_INVALID_ARGUMENT;
3527 }
3528
3529 assert(mem_entry->is_object);
3530 object = vm_named_entry_to_vm_object(mem_entry);
3531 if (object == VM_OBJECT_NULL) {
3532 named_entry_unlock(mem_entry);
3533 return KERN_INVALID_ARGUMENT;
3534 }
3535
3536 offset = mem_entry->offset;
3537 data_offset = mem_entry->data_offset;
3538
3539 named_entry_unlock(mem_entry);
3540
3541 *offset_p = offset - vm_object_trunc_page(offset) + data_offset;
3542 return KERN_SUCCESS;
3543 }
3544
3545 kern_return_t
3546 mach_memory_entry_map_size(
3547 ipc_port_t entry_port,
3548 vm_map_t map,
3549 memory_object_offset_t offset,
3550 memory_object_offset_t size,
3551 mach_vm_size_t *map_size)
3552 {
3553 vm_named_entry_t mem_entry;
3554 vm_object_t object;
3555 vm_object_offset_t object_offset_start, object_offset_end;
3556 vm_map_copy_t copy_map, target_copy_map;
3557 vm_map_offset_t overmap_start, overmap_end, trimmed_start;
3558 kern_return_t kr;
3559
3560 if (!IP_VALID(entry_port) ||
3561 ip_kotype(entry_port) != IKOT_NAMED_ENTRY) {
3562 return KERN_INVALID_ARGUMENT;
3563 }
3564
3565 mem_entry = (vm_named_entry_t) entry_port->ip_kobject;
3566 named_entry_lock(mem_entry);
3567
3568 if (mem_entry->is_sub_map) {
3569 named_entry_unlock(mem_entry);
3570 return KERN_INVALID_ARGUMENT;
3571 }
3572
3573 if (mem_entry->is_object) {
3574 object = vm_named_entry_to_vm_object(mem_entry);
3575 if (object == VM_OBJECT_NULL) {
3576 named_entry_unlock(mem_entry);
3577 return KERN_INVALID_ARGUMENT;
3578 }
3579
3580 object_offset_start = mem_entry->offset;
3581 object_offset_start += mem_entry->data_offset;
3582 object_offset_start += offset;
3583 object_offset_end = object_offset_start + size;
3584 object_offset_start = vm_map_trunc_page(object_offset_start,
3585 VM_MAP_PAGE_MASK(map));
3586 object_offset_end = vm_map_round_page(object_offset_end,
3587 VM_MAP_PAGE_MASK(map));
3588
3589 named_entry_unlock(mem_entry);
3590
3591 *map_size = object_offset_end - object_offset_start;
3592 return KERN_SUCCESS;
3593 }
3594
3595 if (!mem_entry->is_copy) {
3596 panic("unsupported type of mem_entry %p\n", mem_entry);
3597 }
3598
3599 assert(mem_entry->is_copy);
3600 if (VM_MAP_COPY_PAGE_MASK(mem_entry->backing.copy) == VM_MAP_PAGE_MASK(map)) {
3601 *map_size = vm_map_round_page(mem_entry->offset + mem_entry->data_offset + offset + size, VM_MAP_PAGE_MASK(map)) - vm_map_trunc_page(mem_entry->offset + mem_entry->data_offset + offset, VM_MAP_PAGE_MASK(map));
3602 DEBUG4K_SHARE("map %p (%d) mem_entry %p offset 0x%llx + 0x%llx + 0x%llx size 0x%llx -> map_size 0x%llx\n", map, VM_MAP_PAGE_MASK(map), mem_entry, mem_entry->offset, mem_entry->data_offset, offset, size, *map_size);
3603 named_entry_unlock(mem_entry);
3604 return KERN_SUCCESS;
3605 }
3606
3607 DEBUG4K_SHARE("mem_entry %p copy %p (%d) map %p (%d) offset 0x%llx size 0x%llx\n", mem_entry, mem_entry->backing.copy, VM_MAP_COPY_PAGE_SHIFT(mem_entry->backing.copy), map, VM_MAP_PAGE_SHIFT(map), offset, size);
3608 copy_map = mem_entry->backing.copy;
3609 target_copy_map = VM_MAP_COPY_NULL;
3610 DEBUG4K_ADJUST("adjusting...\n");
3611 kr = vm_map_copy_adjust_to_target(copy_map,
3612 mem_entry->data_offset + offset,
3613 size,
3614 map,
3615 FALSE,
3616 &target_copy_map,
3617 &overmap_start,
3618 &overmap_end,
3619 &trimmed_start);
3620 if (kr == KERN_SUCCESS) {
3621 if (target_copy_map->size != copy_map->size) {
3622 DEBUG4K_ADJUST("copy %p (%d) map %p (%d) offset 0x%llx size 0x%llx overmap_start 0x%llx overmap_end 0x%llx trimmed_start 0x%llx map_size 0x%llx -> 0x%llx\n", copy_map, VM_MAP_COPY_PAGE_SHIFT(copy_map), map, VM_MAP_PAGE_SHIFT(map), (uint64_t)offset, (uint64_t)size, (uint64_t)overmap_start, (uint64_t)overmap_end, (uint64_t)trimmed_start, (uint64_t)copy_map->size, (uint64_t)target_copy_map->size);
3623 }
3624 *map_size = target_copy_map->size;
3625 if (target_copy_map != copy_map) {
3626 vm_map_copy_discard(target_copy_map);
3627 }
3628 target_copy_map = VM_MAP_COPY_NULL;
3629 }
3630 named_entry_unlock(mem_entry);
3631 return kr;
3632 }
3633
3634 /*
3635 * mach_memory_entry_port_release:
3636 *
3637 * Release a send right on a named entry port. This is the correct
3638 * way to destroy a named entry. When the last right on the port is
3639 * released, ipc_kobject_destroy() will call mach_destroy_memory_entry().
3640 */
3641 void
3642 mach_memory_entry_port_release(
3643 ipc_port_t port)
3644 {
3645 assert(ip_kotype(port) == IKOT_NAMED_ENTRY);
3646 ipc_port_release_send(port);
3647 }
3648
3649 /*
3650 * mach_destroy_memory_entry:
3651 *
3652 * Drops a reference on a memory entry and destroys the memory entry if
3653 * there are no more references on it.
3654 * NOTE: This routine should not be called to destroy a memory entry from the
3655 * kernel, as it will not release the Mach port associated with the memory
3656 * entry. The proper way to destroy a memory entry in the kernel is to
3657 * call mach_memort_entry_port_release() to release the kernel's send-right on
3658 * the memory entry's port. When the last send right is released, the memory
3659 * entry will be destroyed via ipc_kobject_destroy().
3660 */
3661 void
3662 mach_destroy_memory_entry(
3663 ipc_port_t port)
3664 {
3665 vm_named_entry_t named_entry;
3666 #if MACH_ASSERT
3667 assert(ip_kotype(port) == IKOT_NAMED_ENTRY);
3668 #endif /* MACH_ASSERT */
3669 named_entry = (vm_named_entry_t) ip_get_kobject(port);
3670
3671 named_entry_lock(named_entry);
3672 named_entry->ref_count -= 1;
3673
3674 if (named_entry->ref_count == 0) {
3675 if (named_entry->is_sub_map) {
3676 vm_map_deallocate(named_entry->backing.map);
3677 } else if (named_entry->is_copy) {
3678 vm_map_copy_discard(named_entry->backing.copy);
3679 } else if (named_entry->is_object) {
3680 assert(named_entry->backing.copy->cpy_hdr.nentries == 1);
3681 vm_map_copy_discard(named_entry->backing.copy);
3682 } else {
3683 assert(named_entry->backing.copy == VM_MAP_COPY_NULL);
3684 }
3685
3686 named_entry_unlock(named_entry);
3687 named_entry_lock_destroy(named_entry);
3688
3689 #if VM_NAMED_ENTRY_LIST
3690 lck_mtx_lock_spin(&vm_named_entry_list_lock_data);
3691 queue_remove(&vm_named_entry_list, named_entry,
3692 vm_named_entry_t, named_entry_list);
3693 assert(vm_named_entry_count > 0);
3694 vm_named_entry_count--;
3695 lck_mtx_unlock(&vm_named_entry_list_lock_data);
3696 #endif /* VM_NAMED_ENTRY_LIST */
3697
3698 kfree(named_entry, sizeof(struct vm_named_entry));
3699 } else {
3700 named_entry_unlock(named_entry);
3701 }
3702 }
3703
3704 /* Allow manipulation of individual page state. This is actually part of */
3705 /* the UPL regimen but takes place on the memory entry rather than on a UPL */
3706
3707 kern_return_t
3708 mach_memory_entry_page_op(
3709 ipc_port_t entry_port,
3710 vm_object_offset_t offset,
3711 int ops,
3712 ppnum_t *phys_entry,
3713 int *flags)
3714 {
3715 vm_named_entry_t mem_entry;
3716 vm_object_t object;
3717 kern_return_t kr;
3718
3719 if (!IP_VALID(entry_port) ||
3720 ip_kotype(entry_port) != IKOT_NAMED_ENTRY) {
3721 return KERN_INVALID_ARGUMENT;
3722 }
3723
3724 mem_entry = (vm_named_entry_t) ip_get_kobject(entry_port);
3725
3726 named_entry_lock(mem_entry);
3727
3728 if (mem_entry->is_sub_map ||
3729 mem_entry->is_copy) {
3730 named_entry_unlock(mem_entry);
3731 return KERN_INVALID_ARGUMENT;
3732 }
3733
3734 assert(mem_entry->is_object);
3735 object = vm_named_entry_to_vm_object(mem_entry);
3736 if (object == VM_OBJECT_NULL) {
3737 named_entry_unlock(mem_entry);
3738 return KERN_INVALID_ARGUMENT;
3739 }
3740
3741 vm_object_reference(object);
3742 named_entry_unlock(mem_entry);
3743
3744 kr = vm_object_page_op(object, offset, ops, phys_entry, flags);
3745
3746 vm_object_deallocate(object);
3747
3748 return kr;
3749 }
3750
3751 /*
3752 * mach_memory_entry_range_op offers performance enhancement over
3753 * mach_memory_entry_page_op for page_op functions which do not require page
3754 * level state to be returned from the call. Page_op was created to provide
3755 * a low-cost alternative to page manipulation via UPLs when only a single
3756 * page was involved. The range_op call establishes the ability in the _op
3757 * family of functions to work on multiple pages where the lack of page level
3758 * state handling allows the caller to avoid the overhead of the upl structures.
3759 */
3760
3761 kern_return_t
3762 mach_memory_entry_range_op(
3763 ipc_port_t entry_port,
3764 vm_object_offset_t offset_beg,
3765 vm_object_offset_t offset_end,
3766 int ops,
3767 int *range)
3768 {
3769 vm_named_entry_t mem_entry;
3770 vm_object_t object;
3771 kern_return_t kr;
3772
3773 if (!IP_VALID(entry_port) ||
3774 ip_kotype(entry_port) != IKOT_NAMED_ENTRY) {
3775 return KERN_INVALID_ARGUMENT;
3776 }
3777
3778 mem_entry = (vm_named_entry_t) ip_get_kobject(entry_port);
3779
3780 named_entry_lock(mem_entry);
3781
3782 if (mem_entry->is_sub_map ||
3783 mem_entry->is_copy) {
3784 named_entry_unlock(mem_entry);
3785 return KERN_INVALID_ARGUMENT;
3786 }
3787
3788 assert(mem_entry->is_object);
3789 object = vm_named_entry_to_vm_object(mem_entry);
3790 if (object == VM_OBJECT_NULL) {
3791 named_entry_unlock(mem_entry);
3792 return KERN_INVALID_ARGUMENT;
3793 }
3794
3795 vm_object_reference(object);
3796 named_entry_unlock(mem_entry);
3797
3798 kr = vm_object_range_op(object,
3799 offset_beg,
3800 offset_end,
3801 ops,
3802 (uint32_t *) range);
3803
3804 vm_object_deallocate(object);
3805
3806 return kr;
3807 }
3808
3809 /* ******* Temporary Internal calls to UPL for BSD ***** */
3810
3811 extern int kernel_upl_map(
3812 vm_map_t map,
3813 upl_t upl,
3814 vm_offset_t *dst_addr);
3815
3816 extern int kernel_upl_unmap(
3817 vm_map_t map,
3818 upl_t upl);
3819
3820 extern int kernel_upl_commit(
3821 upl_t upl,
3822 upl_page_info_t *pl,
3823 mach_msg_type_number_t count);
3824
3825 extern int kernel_upl_commit_range(
3826 upl_t upl,
3827 upl_offset_t offset,
3828 upl_size_t size,
3829 int flags,
3830 upl_page_info_array_t pl,
3831 mach_msg_type_number_t count);
3832
3833 extern int kernel_upl_abort(
3834 upl_t upl,
3835 int abort_type);
3836
3837 extern int kernel_upl_abort_range(
3838 upl_t upl,
3839 upl_offset_t offset,
3840 upl_size_t size,
3841 int abort_flags);
3842
3843
3844 kern_return_t
3845 kernel_upl_map(
3846 vm_map_t map,
3847 upl_t upl,
3848 vm_offset_t *dst_addr)
3849 {
3850 return vm_upl_map(map, upl, dst_addr);
3851 }
3852
3853
3854 kern_return_t
3855 kernel_upl_unmap(
3856 vm_map_t map,
3857 upl_t upl)
3858 {
3859 return vm_upl_unmap(map, upl);
3860 }
3861
3862 kern_return_t
3863 kernel_upl_commit(
3864 upl_t upl,
3865 upl_page_info_t *pl,
3866 mach_msg_type_number_t count)
3867 {
3868 kern_return_t kr;
3869
3870 kr = upl_commit(upl, pl, count);
3871 upl_deallocate(upl);
3872 return kr;
3873 }
3874
3875
3876 kern_return_t
3877 kernel_upl_commit_range(
3878 upl_t upl,
3879 upl_offset_t offset,
3880 upl_size_t size,
3881 int flags,
3882 upl_page_info_array_t pl,
3883 mach_msg_type_number_t count)
3884 {
3885 boolean_t finished = FALSE;
3886 kern_return_t kr;
3887
3888 if (flags & UPL_COMMIT_FREE_ON_EMPTY) {
3889 flags |= UPL_COMMIT_NOTIFY_EMPTY;
3890 }
3891
3892 if (flags & UPL_COMMIT_KERNEL_ONLY_FLAGS) {
3893 return KERN_INVALID_ARGUMENT;
3894 }
3895
3896 kr = upl_commit_range(upl, offset, size, flags, pl, count, &finished);
3897
3898 if ((flags & UPL_COMMIT_NOTIFY_EMPTY) && finished) {
3899 upl_deallocate(upl);
3900 }
3901
3902 return kr;
3903 }
3904
3905 kern_return_t
3906 kernel_upl_abort_range(
3907 upl_t upl,
3908 upl_offset_t offset,
3909 upl_size_t size,
3910 int abort_flags)
3911 {
3912 kern_return_t kr;
3913 boolean_t finished = FALSE;
3914
3915 if (abort_flags & UPL_COMMIT_FREE_ON_EMPTY) {
3916 abort_flags |= UPL_COMMIT_NOTIFY_EMPTY;
3917 }
3918
3919 kr = upl_abort_range(upl, offset, size, abort_flags, &finished);
3920
3921 if ((abort_flags & UPL_COMMIT_FREE_ON_EMPTY) && finished) {
3922 upl_deallocate(upl);
3923 }
3924
3925 return kr;
3926 }
3927
3928 kern_return_t
3929 kernel_upl_abort(
3930 upl_t upl,
3931 int abort_type)
3932 {
3933 kern_return_t kr;
3934
3935 kr = upl_abort(upl, abort_type);
3936 upl_deallocate(upl);
3937 return kr;
3938 }
3939
3940 /*
3941 * Now a kernel-private interface (for BootCache
3942 * use only). Need a cleaner way to create an
3943 * empty vm_map() and return a handle to it.
3944 */
3945
3946 kern_return_t
3947 vm_region_object_create(
3948 __unused vm_map_t target_map,
3949 vm_size_t size,
3950 ipc_port_t *object_handle)
3951 {
3952 vm_named_entry_t user_entry;
3953 ipc_port_t user_handle;
3954
3955 vm_map_t new_map;
3956
3957 if (mach_memory_entry_allocate(&user_entry, &user_handle)
3958 != KERN_SUCCESS) {
3959 return KERN_FAILURE;
3960 }
3961
3962 /* Create a named object based on a submap of specified size */
3963
3964 new_map = vm_map_create(PMAP_NULL, VM_MAP_MIN_ADDRESS,
3965 vm_map_round_page(size,
3966 VM_MAP_PAGE_MASK(target_map)),
3967 TRUE);
3968 vm_map_set_page_shift(new_map, VM_MAP_PAGE_SHIFT(target_map));
3969
3970 user_entry->backing.map = new_map;
3971 user_entry->internal = TRUE;
3972 user_entry->is_sub_map = TRUE;
3973 user_entry->offset = 0;
3974 user_entry->protection = VM_PROT_ALL;
3975 user_entry->size = size;
3976 assert(user_entry->ref_count == 1);
3977
3978 *object_handle = user_handle;
3979 return KERN_SUCCESS;
3980 }
3981
3982 ppnum_t vm_map_get_phys_page( /* forward */
3983 vm_map_t map,
3984 vm_offset_t offset);
3985
3986 ppnum_t
3987 vm_map_get_phys_page(
3988 vm_map_t map,
3989 vm_offset_t addr)
3990 {
3991 vm_object_offset_t offset;
3992 vm_object_t object;
3993 vm_map_offset_t map_offset;
3994 vm_map_entry_t entry;
3995 ppnum_t phys_page = 0;
3996
3997 map_offset = vm_map_trunc_page(addr, PAGE_MASK);
3998
3999 vm_map_lock(map);
4000 while (vm_map_lookup_entry(map, map_offset, &entry)) {
4001 if (VME_OBJECT(entry) == VM_OBJECT_NULL) {
4002 vm_map_unlock(map);
4003 return (ppnum_t) 0;
4004 }
4005 if (entry->is_sub_map) {
4006 vm_map_t old_map;
4007 vm_map_lock(VME_SUBMAP(entry));
4008 old_map = map;
4009 map = VME_SUBMAP(entry);
4010 map_offset = (VME_OFFSET(entry) +
4011 (map_offset - entry->vme_start));
4012 vm_map_unlock(old_map);
4013 continue;
4014 }
4015 if (VME_OBJECT(entry)->phys_contiguous) {
4016 /* These are not standard pageable memory mappings */
4017 /* If they are not present in the object they will */
4018 /* have to be picked up from the pager through the */
4019 /* fault mechanism. */
4020 if (VME_OBJECT(entry)->vo_shadow_offset == 0) {
4021 /* need to call vm_fault */
4022 vm_map_unlock(map);
4023 vm_fault(map, map_offset, VM_PROT_NONE,
4024 FALSE /* change_wiring */, VM_KERN_MEMORY_NONE,
4025 THREAD_UNINT, NULL, 0);
4026 vm_map_lock(map);
4027 continue;
4028 }
4029 offset = (VME_OFFSET(entry) +
4030 (map_offset - entry->vme_start));
4031 phys_page = (ppnum_t)
4032 ((VME_OBJECT(entry)->vo_shadow_offset
4033 + offset) >> PAGE_SHIFT);
4034 break;
4035 }
4036 offset = (VME_OFFSET(entry) + (map_offset - entry->vme_start));
4037 object = VME_OBJECT(entry);
4038 vm_object_lock(object);
4039 while (TRUE) {
4040 vm_page_t dst_page = vm_page_lookup(object, offset);
4041 if (dst_page == VM_PAGE_NULL) {
4042 if (object->shadow) {
4043 vm_object_t old_object;
4044 vm_object_lock(object->shadow);
4045 old_object = object;
4046 offset = offset + object->vo_shadow_offset;
4047 object = object->shadow;
4048 vm_object_unlock(old_object);
4049 } else {
4050 vm_object_unlock(object);
4051 break;
4052 }
4053 } else {
4054 phys_page = (ppnum_t)(VM_PAGE_GET_PHYS_PAGE(dst_page));
4055 vm_object_unlock(object);
4056 break;
4057 }
4058 }
4059 break;
4060 }
4061
4062 vm_map_unlock(map);
4063 return phys_page;
4064 }
4065
4066 #if 0
4067 kern_return_t kernel_object_iopl_request( /* forward */
4068 vm_named_entry_t named_entry,
4069 memory_object_offset_t offset,
4070 upl_size_t *upl_size,
4071 upl_t *upl_ptr,
4072 upl_page_info_array_t user_page_list,
4073 unsigned int *page_list_count,
4074 int *flags);
4075
4076 kern_return_t
4077 kernel_object_iopl_request(
4078 vm_named_entry_t named_entry,
4079 memory_object_offset_t offset,
4080 upl_size_t *upl_size,
4081 upl_t *upl_ptr,
4082 upl_page_info_array_t user_page_list,
4083 unsigned int *page_list_count,
4084 int *flags)
4085 {
4086 vm_object_t object;
4087 kern_return_t ret;
4088
4089 int caller_flags;
4090
4091 caller_flags = *flags;
4092
4093 if (caller_flags & ~UPL_VALID_FLAGS) {
4094 /*
4095 * For forward compatibility's sake,
4096 * reject any unknown flag.
4097 */
4098 return KERN_INVALID_VALUE;
4099 }
4100
4101 /* a few checks to make sure user is obeying rules */
4102 if (*upl_size == 0) {
4103 if (offset >= named_entry->size) {
4104 return KERN_INVALID_RIGHT;
4105 }
4106 *upl_size = (upl_size_t) (named_entry->size - offset);
4107 if (*upl_size != named_entry->size - offset) {
4108 return KERN_INVALID_ARGUMENT;
4109 }
4110 }
4111 if (caller_flags & UPL_COPYOUT_FROM) {
4112 if ((named_entry->protection & VM_PROT_READ)
4113 != VM_PROT_READ) {
4114 return KERN_INVALID_RIGHT;
4115 }
4116 } else {
4117 if ((named_entry->protection &
4118 (VM_PROT_READ | VM_PROT_WRITE))
4119 != (VM_PROT_READ | VM_PROT_WRITE)) {
4120 return KERN_INVALID_RIGHT;
4121 }
4122 }
4123 if (named_entry->size < (offset + *upl_size)) {
4124 return KERN_INVALID_ARGUMENT;
4125 }
4126
4127 /* the callers parameter offset is defined to be the */
4128 /* offset from beginning of named entry offset in object */
4129 offset = offset + named_entry->offset;
4130
4131 if (named_entry->is_sub_map ||
4132 named_entry->is_copy) {
4133 return KERN_INVALID_ARGUMENT;
4134 }
4135
4136 named_entry_lock(named_entry);
4137
4138 /* This is the case where we are going to operate */
4139 /* on an already known object. If the object is */
4140 /* not ready it is internal. An external */
4141 /* object cannot be mapped until it is ready */
4142 /* we can therefore avoid the ready check */
4143 /* in this case. */
4144 assert(named_entry->is_object);
4145 object = vm_named_entry_to_vm_object(named_entry);
4146 vm_object_reference(object);
4147 named_entry_unlock(named_entry);
4148
4149 if (!object->private) {
4150 if (*upl_size > MAX_UPL_TRANSFER_BYTES) {
4151 *upl_size = MAX_UPL_TRANSFER_BYTES;
4152 }
4153 if (object->phys_contiguous) {
4154 *flags = UPL_PHYS_CONTIG;
4155 } else {
4156 *flags = 0;
4157 }
4158 } else {
4159 *flags = UPL_DEV_MEMORY | UPL_PHYS_CONTIG;
4160 }
4161
4162 ret = vm_object_iopl_request(object,
4163 offset,
4164 *upl_size,
4165 upl_ptr,
4166 user_page_list,
4167 page_list_count,
4168 (upl_control_flags_t)(unsigned int)caller_flags);
4169 vm_object_deallocate(object);
4170 return ret;
4171 }
4172 #endif
4173
4174 /*
4175 * These symbols are looked up at runtime by vmware, VirtualBox,
4176 * despite not being exported in the symbol sets.
4177 */
4178
4179 #if defined(__x86_64__)
4180
4181 kern_return_t
4182 mach_vm_map(
4183 vm_map_t target_map,
4184 mach_vm_offset_t *address,
4185 mach_vm_size_t initial_size,
4186 mach_vm_offset_t mask,
4187 int flags,
4188 ipc_port_t port,
4189 vm_object_offset_t offset,
4190 boolean_t copy,
4191 vm_prot_t cur_protection,
4192 vm_prot_t max_protection,
4193 vm_inherit_t inheritance);
4194
4195 kern_return_t
4196 mach_vm_remap(
4197 vm_map_t target_map,
4198 mach_vm_offset_t *address,
4199 mach_vm_size_t size,
4200 mach_vm_offset_t mask,
4201 int flags,
4202 vm_map_t src_map,
4203 mach_vm_offset_t memory_address,
4204 boolean_t copy,
4205 vm_prot_t *cur_protection,
4206 vm_prot_t *max_protection,
4207 vm_inherit_t inheritance);
4208
4209 kern_return_t
4210 mach_vm_map(
4211 vm_map_t target_map,
4212 mach_vm_offset_t *address,
4213 mach_vm_size_t initial_size,
4214 mach_vm_offset_t mask,
4215 int flags,
4216 ipc_port_t port,
4217 vm_object_offset_t offset,
4218 boolean_t copy,
4219 vm_prot_t cur_protection,
4220 vm_prot_t max_protection,
4221 vm_inherit_t inheritance)
4222 {
4223 return mach_vm_map_external(target_map, address, initial_size, mask, flags, port,
4224 offset, copy, cur_protection, max_protection, inheritance);
4225 }
4226
4227 kern_return_t
4228 mach_vm_remap(
4229 vm_map_t target_map,
4230 mach_vm_offset_t *address,
4231 mach_vm_size_t size,
4232 mach_vm_offset_t mask,
4233 int flags,
4234 vm_map_t src_map,
4235 mach_vm_offset_t memory_address,
4236 boolean_t copy,
4237 vm_prot_t *cur_protection,
4238 vm_prot_t *max_protection,
4239 vm_inherit_t inheritance)
4240 {
4241 return mach_vm_remap_external(target_map, address, size, mask, flags, src_map, memory_address,
4242 copy, cur_protection, max_protection, inheritance);
4243 }
4244
4245 kern_return_t
4246 vm_map(
4247 vm_map_t target_map,
4248 vm_offset_t *address,
4249 vm_size_t size,
4250 vm_offset_t mask,
4251 int flags,
4252 ipc_port_t port,
4253 vm_offset_t offset,
4254 boolean_t copy,
4255 vm_prot_t cur_protection,
4256 vm_prot_t max_protection,
4257 vm_inherit_t inheritance);
4258
4259 kern_return_t
4260 vm_map(
4261 vm_map_t target_map,
4262 vm_offset_t *address,
4263 vm_size_t size,
4264 vm_offset_t mask,
4265 int flags,
4266 ipc_port_t port,
4267 vm_offset_t offset,
4268 boolean_t copy,
4269 vm_prot_t cur_protection,
4270 vm_prot_t max_protection,
4271 vm_inherit_t inheritance)
4272 {
4273 vm_tag_t tag;
4274
4275 VM_GET_FLAGS_ALIAS(flags, tag);
4276 return vm_map_kernel(target_map, address, size, mask,
4277 flags, VM_MAP_KERNEL_FLAGS_NONE, tag,
4278 port, offset, copy,
4279 cur_protection, max_protection, inheritance);
4280 }
4281
4282 #endif /* __x86_64__ */