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