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