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