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