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