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