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