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