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