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