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