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