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