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