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