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