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