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