]> git.saurik.com Git - apple/xnu.git/blame - osfmk/vm/memory_object.c
xnu-6153.141.1.tar.gz
[apple/xnu.git] / osfmk / vm / memory_object.c
CommitLineData
1c79356b 1/*
cb323159 2 * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 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.
0a7de745 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.
0a7de745 17 *
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
0a7de745 31/*
1c79356b
A
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
0a7de745 35 *
1c79356b
A
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.
0a7de745 41 *
1c79356b
A
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.
0a7de745 45 *
1c79356b 46 * Carnegie Mellon requests users of this software to return to
0a7de745 47 *
1c79356b
A
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
0a7de745 52 *
1c79356b
A
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/memory_object.c
60 * Author: Michael Wayne Young
61 *
62 * External memory management interface control functions.
63 */
64
1c79356b
A
65/*
66 * Interface dependencies:
67 */
68
0a7de745 69#include <mach/std_types.h> /* For pointer_t */
1c79356b
A
70#include <mach/mach_types.h>
71
0b4e3aa0 72#include <mach/mig.h>
1c79356b
A
73#include <mach/kern_return.h>
74#include <mach/memory_object.h>
75#include <mach/memory_object_default.h>
76#include <mach/memory_object_control_server.h>
0b4e3aa0 77#include <mach/host_priv_server.h>
1c79356b
A
78#include <mach/boolean.h>
79#include <mach/vm_prot.h>
80#include <mach/message.h>
81
1c79356b
A
82/*
83 * Implementation dependencies:
84 */
0a7de745 85#include <string.h> /* For memcpy() */
1c79356b 86
0b4e3aa0 87#include <kern/host.h>
0a7de745 88#include <kern/thread.h> /* For current_thread() */
0b4e3aa0
A
89#include <kern/ipc_mig.h>
90#include <kern/misc_protos.h>
91
92#include <vm/vm_object.h>
93#include <vm/vm_fault.h>
1c79356b
A
94#include <vm/memory_object.h>
95#include <vm/vm_page.h>
96#include <vm/vm_pageout.h>
0a7de745
A
97#include <vm/pmap.h> /* For pmap_clear_modify */
98#include <vm/vm_kern.h> /* For kernel_map, vm_move */
99#include <vm/vm_map.h> /* For vm_map_pageable */
100#include <vm/vm_purgeable_internal.h> /* Needed by some vm_page.h macros */
6d2010ae 101#include <vm/vm_shared_region.h>
1c79356b 102
1c79356b 103#include <vm/vm_external.h>
1c79356b 104
91447636
A
105#include <vm/vm_protos.h>
106
0a7de745 107memory_object_default_t memory_manager_default = MEMORY_OBJECT_DEFAULT_NULL;
cb323159 108decl_lck_mtx_data(, memory_manager_default_lock);
1c79356b 109
1c79356b
A
110
111/*
112 * Routine: memory_object_should_return_page
113 *
114 * Description:
115 * Determine whether the given page should be returned,
116 * based on the page's state and on the given return policy.
117 *
118 * We should return the page if one of the following is true:
119 *
120 * 1. Page is dirty and should_return is not RETURN_NONE.
121 * 2. Page is precious and should_return is RETURN_ALL.
122 * 3. Should_return is RETURN_ANYTHING.
123 *
d9a64523 124 * As a side effect, m->vmp_dirty will be made consistent
1c79356b
A
125 * with pmap_is_modified(m), if should_return is not
126 * MEMORY_OBJECT_RETURN_NONE.
127 */
128
0a7de745 129#define memory_object_should_return_page(m, should_return) \
1c79356b 130 (should_return != MEMORY_OBJECT_RETURN_NONE && \
d9a64523
A
131 (((m)->vmp_dirty || ((m)->vmp_dirty = pmap_is_modified(VM_PAGE_GET_PHYS_PAGE(m)))) || \
132 ((m)->vmp_precious && (should_return) == MEMORY_OBJECT_RETURN_ALL) || \
1c79356b
A
133 (should_return) == MEMORY_OBJECT_RETURN_ANYTHING))
134
0a7de745 135typedef int memory_object_lock_result_t;
1c79356b 136
0a7de745
A
137#define MEMORY_OBJECT_LOCK_RESULT_DONE 0
138#define MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK 1
139#define MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN 2
140#define MEMORY_OBJECT_LOCK_RESULT_MUST_FREE 3
1c79356b
A
141
142memory_object_lock_result_t memory_object_lock_page(
0a7de745
A
143 vm_page_t m,
144 memory_object_return_t should_return,
145 boolean_t should_flush,
146 vm_prot_t prot);
1c79356b
A
147
148/*
149 * Routine: memory_object_lock_page
150 *
151 * Description:
152 * Perform the appropriate lock operations on the
153 * given page. See the description of
154 * "memory_object_lock_request" for the meanings
155 * of the arguments.
156 *
157 * Returns an indication that the operation
158 * completed, blocked, or that the page must
159 * be cleaned.
160 */
161memory_object_lock_result_t
162memory_object_lock_page(
0a7de745
A
163 vm_page_t m,
164 memory_object_return_t should_return,
165 boolean_t should_flush,
166 vm_prot_t prot)
1c79356b 167{
0a7de745
A
168 if (m->vmp_busy || m->vmp_cleaning) {
169 return MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK;
170 }
b0d623f7 171
0a7de745 172 if (m->vmp_laundry) {
316670eb 173 vm_pageout_steal_laundry(m, FALSE);
0a7de745 174 }
6d2010ae 175
1c79356b
A
176 /*
177 * Don't worry about pages for which the kernel
178 * does not have any data.
179 */
d9a64523
A
180 if (m->vmp_absent || m->vmp_error || m->vmp_restart) {
181 if (m->vmp_error && should_flush && !VM_PAGE_WIRED(m)) {
6d2010ae
A
182 /*
183 * dump the page, pager wants us to
184 * clean it up and there is no
185 * relevant data to return
186 */
0a7de745 187 return MEMORY_OBJECT_LOCK_RESULT_MUST_FREE;
765c9de3 188 }
0a7de745 189 return MEMORY_OBJECT_LOCK_RESULT_DONE;
765c9de3 190 }
d9a64523 191 assert(!m->vmp_fictitious);
1c79356b 192
b0d623f7 193 if (VM_PAGE_WIRED(m)) {
6d2010ae
A
194 /*
195 * The page is wired... just clean or return the page if needed.
196 * Wired pages don't get flushed or disconnected from the pmap.
197 */
0a7de745
A
198 if (memory_object_should_return_page(m, should_return)) {
199 return MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN;
200 }
1c79356b 201
0a7de745
A
202 return MEMORY_OBJECT_LOCK_RESULT_DONE;
203 }
1c79356b 204
6d2010ae
A
205 if (should_flush) {
206 /*
0a7de745 207 * must do the pmap_disconnect before determining the
6d2010ae
A
208 * need to return the page... otherwise it's possible
209 * for the page to go from the clean to the dirty state
210 * after we've made our decision
211 */
39037602 212 if (pmap_disconnect(VM_PAGE_GET_PHYS_PAGE(m)) & VM_MEM_MODIFIED) {
316670eb
A
213 SET_PAGE_DIRTY(m, FALSE);
214 }
6d2010ae
A
215 } else {
216 /*
217 * If we are decreasing permission, do it now;
218 * let the fault handler take care of increases
219 * (pmap_page_protect may not increase protection).
220 */
0a7de745 221 if (prot != VM_PROT_NO_CHANGE) {
39037602 222 pmap_page_protect(VM_PAGE_GET_PHYS_PAGE(m), VM_PROT_ALL & ~prot);
0a7de745 223 }
1c79356b 224 }
1c79356b 225 /*
6d2010ae 226 * Handle returning dirty or precious pages
1c79356b 227 */
1c79356b 228 if (memory_object_should_return_page(m, should_return)) {
1c79356b 229 /*
6d2010ae
A
230 * we use to do a pmap_disconnect here in support
231 * of memory_object_lock_request, but that routine
232 * no longer requires this... in any event, in
233 * our world, it would turn into a big noop since
234 * we don't lock the page in any way and as soon
235 * as we drop the object lock, the page can be
236 * faulted back into an address space
237 *
238 * if (!should_flush)
39037602 239 * pmap_disconnect(VM_PAGE_GET_PHYS_PAGE(m));
1c79356b 240 */
0a7de745 241 return MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN;
1c79356b
A
242 }
243
244 /*
6d2010ae 245 * Handle flushing clean pages
1c79356b 246 */
0a7de745
A
247 if (should_flush) {
248 return MEMORY_OBJECT_LOCK_RESULT_MUST_FREE;
249 }
1c79356b 250
6d2010ae
A
251 /*
252 * we use to deactivate clean pages at this point,
253 * but we do not believe that an msync should change
254 * the 'age' of a page in the cache... here is the
255 * original comment and code concerning this...
256 *
257 * XXX Make clean but not flush a paging hint,
258 * and deactivate the pages. This is a hack
259 * because it overloads flush/clean with
260 * implementation-dependent meaning. This only
261 * happens to pages that are already clean.
262 *
263 * if (vm_page_deactivate_hint && (should_return != MEMORY_OBJECT_RETURN_NONE))
264 * return (MEMORY_OBJECT_LOCK_RESULT_MUST_DEACTIVATE);
265 */
1c79356b 266
0a7de745 267 return MEMORY_OBJECT_LOCK_RESULT_DONE;
1c79356b 268}
0b4e3aa0 269
6d2010ae 270
1c79356b 271
1c79356b
A
272/*
273 * Routine: memory_object_lock_request [user interface]
274 *
275 * Description:
276 * Control use of the data associated with the given
277 * memory object. For each page in the given range,
278 * perform the following operations, in order:
279 * 1) restrict access to the page (disallow
280 * forms specified by "prot");
281 * 2) return data to the manager (if "should_return"
282 * is RETURN_DIRTY and the page is dirty, or
0a7de745 283 * "should_return" is RETURN_ALL and the page
1c79356b
A
284 * is either dirty or precious); and,
285 * 3) flush the cached copy (if "should_flush"
286 * is asserted).
287 * The set of pages is defined by a starting offset
288 * ("offset") and size ("size"). Only pages with the
289 * same page alignment as the starting offset are
290 * considered.
291 *
292 * A single acknowledgement is sent (to the "reply_to"
293 * port) when these actions are complete. If successful,
294 * the naked send right for reply_to is consumed.
295 */
296
297kern_return_t
298memory_object_lock_request(
0a7de745
A
299 memory_object_control_t control,
300 memory_object_offset_t offset,
301 memory_object_size_t size,
302 memory_object_offset_t * resid_offset,
303 int * io_errno,
304 memory_object_return_t should_return,
305 int flags,
306 vm_prot_t prot)
1c79356b 307{
0a7de745 308 vm_object_t object;
1c79356b 309
0a7de745 310 /*
1c79356b
A
311 * Check for bogus arguments.
312 */
0b4e3aa0 313 object = memory_object_control_to_vm_object(control);
0a7de745
A
314 if (object == VM_OBJECT_NULL) {
315 return KERN_INVALID_ARGUMENT;
316 }
1c79356b 317
0a7de745
A
318 if ((prot & ~VM_PROT_ALL) != 0 && prot != VM_PROT_NO_CHANGE) {
319 return KERN_INVALID_ARGUMENT;
320 }
1c79356b 321
55e303ae 322 size = round_page_64(size);
1c79356b
A
323
324 /*
325 * Lock the object, and acquire a paging reference to
0b4e3aa0 326 * prevent the memory_object reference from being released.
1c79356b 327 */
1c79356b
A
328 vm_object_lock(object);
329 vm_object_paging_begin(object);
b0d623f7
A
330
331 if (flags & MEMORY_OBJECT_DATA_FLUSH_ALL) {
332 if ((should_return != MEMORY_OBJECT_RETURN_NONE) || offset || object->copy) {
333 flags &= ~MEMORY_OBJECT_DATA_FLUSH_ALL;
334 flags |= MEMORY_OBJECT_DATA_FLUSH;
335 }
336 }
1c79356b
A
337 offset -= object->paging_offset;
338
0a7de745 339 if (flags & MEMORY_OBJECT_DATA_FLUSH_ALL) {
b0d623f7 340 vm_object_reap_pages(object, REAP_DATA_FLUSH);
0a7de745 341 } else {
b0d623f7 342 (void)vm_object_update(object, offset, size, resid_offset,
0a7de745
A
343 io_errno, should_return, flags, prot);
344 }
1c79356b 345
1c79356b
A
346 vm_object_paging_end(object);
347 vm_object_unlock(object);
1c79356b 348
0a7de745 349 return KERN_SUCCESS;
1c79356b
A
350}
351
352/*
0b4e3aa0
A
353 * memory_object_release_name: [interface]
354 *
355 * Enforces name semantic on memory_object reference count decrement
356 * This routine should not be called unless the caller holds a name
357 * reference gained through the memory_object_named_create or the
358 * memory_object_rename call.
359 * If the TERMINATE_IDLE flag is set, the call will return if the
360 * reference count is not 1. i.e. idle with the only remaining reference
361 * being the name.
362 * If the decision is made to proceed the name field flag is set to
363 * false and the reference count is decremented. If the RESPECT_CACHE
0a7de745 364 * flag is set and the reference count has gone to zero, the
0b4e3aa0
A
365 * memory_object is checked to see if it is cacheable otherwise when
366 * the reference count is zero, it is simply terminated.
367 */
368
369kern_return_t
370memory_object_release_name(
0a7de745
A
371 memory_object_control_t control,
372 int flags)
0b4e3aa0 373{
0a7de745 374 vm_object_t object;
0b4e3aa0
A
375
376 object = memory_object_control_to_vm_object(control);
0a7de745
A
377 if (object == VM_OBJECT_NULL) {
378 return KERN_INVALID_ARGUMENT;
379 }
0b4e3aa0
A
380
381 return vm_object_release_name(object, flags);
382}
383
384
385
386/*
387 * Routine: memory_object_destroy [user interface]
388 * Purpose:
389 * Shut down a memory object, despite the
390 * presence of address map (or other) references
391 * to the vm_object.
392 */
393kern_return_t
394memory_object_destroy(
0a7de745
A
395 memory_object_control_t control,
396 kern_return_t reason)
0b4e3aa0 397{
0a7de745 398 vm_object_t object;
0b4e3aa0
A
399
400 object = memory_object_control_to_vm_object(control);
0a7de745
A
401 if (object == VM_OBJECT_NULL) {
402 return KERN_INVALID_ARGUMENT;
403 }
0b4e3aa0 404
0a7de745 405 return vm_object_destroy(object, reason);
0b4e3aa0
A
406}
407
408/*
409 * Routine: vm_object_sync
1c79356b
A
410 *
411 * Kernel internal function to synch out pages in a given
412 * range within an object to its memory manager. Much the
413 * same as memory_object_lock_request but page protection
414 * is not changed.
415 *
416 * If the should_flush and should_return flags are true pages
417 * are flushed, that is dirty & precious pages are written to
418 * the memory manager and then discarded. If should_return
419 * is false, only precious pages are returned to the memory
420 * manager.
421 *
422 * If should flush is false and should_return true, the memory
423 * manager's copy of the pages is updated. If should_return
424 * is also false, only the precious pages are updated. This
425 * last option is of limited utility.
426 *
427 * Returns:
428 * FALSE if no pages were returned to the pager
429 * TRUE otherwise.
430 */
431
432boolean_t
0b4e3aa0 433vm_object_sync(
0a7de745
A
434 vm_object_t object,
435 vm_object_offset_t offset,
436 vm_object_size_t size,
437 boolean_t should_flush,
438 boolean_t should_return,
439 boolean_t should_iosync)
1c79356b 440{
0a7de745 441 boolean_t rv;
91447636 442 int flags;
1c79356b 443
1c79356b
A
444 /*
445 * Lock the object, and acquire a paging reference to
446 * prevent the memory_object and control ports from
447 * being destroyed.
448 */
449 vm_object_lock(object);
450 vm_object_paging_begin(object);
451
39236c6e 452 if (should_flush) {
0a7de745 453 flags = MEMORY_OBJECT_DATA_FLUSH;
39236c6e
A
454 /*
455 * This flush is from an msync(), not a truncate(), so the
456 * contents of the file are not affected.
457 * MEMORY_OBECT_DATA_NO_CHANGE lets vm_object_update() know
458 * that the data is not changed and that there's no need to
459 * push the old contents to a copy object.
460 */
461 flags |= MEMORY_OBJECT_DATA_NO_CHANGE;
0a7de745
A
462 } else {
463 flags = 0;
464 }
91447636 465
0a7de745
A
466 if (should_iosync) {
467 flags |= MEMORY_OBJECT_IO_SYNC;
468 }
91447636
A
469
470 rv = vm_object_update(object, offset, (vm_object_size_t)size, NULL, NULL,
0a7de745
A
471 (should_return) ?
472 MEMORY_OBJECT_RETURN_ALL :
473 MEMORY_OBJECT_RETURN_NONE,
474 flags,
475 VM_PROT_NO_CHANGE);
1c79356b
A
476
477
478 vm_object_paging_end(object);
479 vm_object_unlock(object);
480 return rv;
481}
482
91447636
A
483
484
6d2010ae 485#define LIST_REQ_PAGEOUT_PAGES(object, data_cnt, po, ro, ioerr, iosync) \
0a7de745
A
486MACRO_BEGIN \
487 \
488 int upl_flags; \
489 memory_object_t pager; \
490 \
491 if ((pager = (object)->pager) != MEMORY_OBJECT_NULL) { \
492 vm_object_paging_begin(object); \
493 vm_object_unlock(object); \
494 \
495 if (iosync) \
496 upl_flags = UPL_MSYNC | UPL_IOSYNC; \
497 else \
498 upl_flags = UPL_MSYNC; \
499 \
500 (void) memory_object_data_return(pager, \
501 po, \
502 (memory_object_cluster_size_t)data_cnt, \
6d2010ae
A
503 ro, \
504 ioerr, \
0a7de745
A
505 FALSE, \
506 FALSE, \
507 upl_flags); \
508 \
509 vm_object_lock(object); \
510 vm_object_paging_end(object); \
511 } \
6d2010ae
A
512MACRO_END
513
39037602
A
514extern struct vnode *
515vnode_pager_lookup_vnode(memory_object_t);
91447636
A
516
517static int
518vm_object_update_extent(
0a7de745
A
519 vm_object_t object,
520 vm_object_offset_t offset,
521 vm_object_offset_t offset_end,
522 vm_object_offset_t *offset_resid,
523 int *io_errno,
524 boolean_t should_flush,
525 memory_object_return_t should_return,
526 boolean_t should_iosync,
527 vm_prot_t prot)
91447636 528{
0a7de745
A
529 vm_page_t m;
530 int retval = 0;
531 vm_object_offset_t paging_offset = 0;
532 vm_object_offset_t next_offset = offset;
533 memory_object_lock_result_t page_lock_result;
534 memory_object_cluster_size_t data_cnt = 0;
535 struct vm_page_delayed_work dw_array[DEFAULT_DELAYED_WORK_LIMIT];
536 struct vm_page_delayed_work *dwp;
537 int dw_count;
538 int dw_limit;
539 int dirty_count;
540
541 dwp = &dw_array[0];
542 dw_count = 0;
6d2010ae 543 dw_limit = DELAYED_WORK_LIMIT(DEFAULT_DELAYED_WORK_LIMIT);
4bd07ac2 544 dirty_count = 0;
91447636
A
545
546 for (;
0a7de745
A
547 offset < offset_end && object->resident_page_count;
548 offset += PAGE_SIZE_64) {
549 /*
b0d623f7 550 * Limit the number of pages to be cleaned at once to a contiguous
fe8ab488 551 * run, or at most MAX_UPL_TRANSFER_BYTES
91447636 552 */
b0d623f7 553 if (data_cnt) {
fe8ab488 554 if ((data_cnt >= MAX_UPL_TRANSFER_BYTES) || (next_offset != offset)) {
6d2010ae 555 if (dw_count) {
3e170ce0 556 vm_page_do_delayed_work(object, VM_KERN_MEMORY_NONE, &dw_array[0], dw_count);
6d2010ae
A
557 dwp = &dw_array[0];
558 dw_count = 0;
559 }
560 LIST_REQ_PAGEOUT_PAGES(object, data_cnt,
0a7de745 561 paging_offset, offset_resid, io_errno, should_iosync);
b0d623f7
A
562 data_cnt = 0;
563 }
91447636 564 }
91447636 565 while ((m = vm_page_lookup(object, offset)) != VM_PAGE_NULL) {
6d2010ae 566 dwp->dw_mask = 0;
0a7de745 567
6d2010ae
A
568 page_lock_result = memory_object_lock_page(m, should_return, should_flush, prot);
569
570 if (data_cnt && page_lock_result != MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN) {
571 /*
572 * End of a run of dirty/precious pages.
573 */
574 if (dw_count) {
3e170ce0 575 vm_page_do_delayed_work(object, VM_KERN_MEMORY_NONE, &dw_array[0], dw_count);
6d2010ae
A
576 dwp = &dw_array[0];
577 dw_count = 0;
578 }
579 LIST_REQ_PAGEOUT_PAGES(object, data_cnt,
0a7de745 580 paging_offset, offset_resid, io_errno, should_iosync);
6d2010ae
A
581 /*
582 * LIST_REQ_PAGEOUT_PAGES will drop the object lock which will
583 * allow the state of page 'm' to change... we need to re-lookup
584 * the current offset
585 */
586 data_cnt = 0;
587 continue;
588 }
589
590 switch (page_lock_result) {
6d2010ae
A
591 case MEMORY_OBJECT_LOCK_RESULT_DONE:
592 break;
593
594 case MEMORY_OBJECT_LOCK_RESULT_MUST_FREE:
0a7de745 595 if (m->vmp_dirty == TRUE) {
4bd07ac2 596 dirty_count++;
0a7de745 597 }
6d2010ae
A
598 dwp->dw_mask |= DW_vm_page_free;
599 break;
600
601 case MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK:
602 PAGE_SLEEP(object, m, THREAD_UNINT);
603 continue;
604
605 case MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN:
0a7de745 606 if (data_cnt == 0) {
6d2010ae 607 paging_offset = offset;
0a7de745 608 }
6d2010ae
A
609
610 data_cnt += PAGE_SIZE;
611 next_offset = offset + PAGE_SIZE_64;
612
6d2010ae
A
613 /*
614 * wired pages shouldn't be flushed and
615 * since they aren't on any queue,
616 * no need to remove them
617 */
618 if (!VM_PAGE_WIRED(m)) {
6d2010ae
A
619 if (should_flush) {
620 /*
621 * add additional state for the flush
622 */
d9a64523 623 m->vmp_free_when_done = TRUE;
6d2010ae
A
624 }
625 /*
626 * we use to remove the page from the queues at this
627 * point, but we do not believe that an msync
628 * should cause the 'age' of a page to be changed
629 *
630 * else
631 * dwp->dw_mask |= DW_VM_PAGE_QUEUES_REMOVE;
632 */
633 }
634 retval = 1;
635 break;
636 }
637 if (dwp->dw_mask) {
638 VM_PAGE_ADD_DELAYED_WORK(dwp, m, dw_count);
639
640 if (dw_count >= dw_limit) {
3e170ce0 641 vm_page_do_delayed_work(object, VM_KERN_MEMORY_NONE, &dw_array[0], dw_count);
6d2010ae
A
642 dwp = &dw_array[0];
643 dw_count = 0;
644 }
91447636
A
645 }
646 break;
647 }
648 }
0a7de745
A
649
650 if (object->pager) {
39037602 651 task_update_logical_writes(current_task(), (dirty_count * PAGE_SIZE), TASK_WRITE_INVALIDATED, vnode_pager_lookup_vnode(object->pager));
0a7de745 652 }
91447636
A
653 /*
654 * We have completed the scan for applicable pages.
655 * Clean any pages that have been saved.
656 */
0a7de745 657 if (dw_count) {
3e170ce0 658 vm_page_do_delayed_work(object, VM_KERN_MEMORY_NONE, &dw_array[0], dw_count);
0a7de745 659 }
6d2010ae 660
91447636 661 if (data_cnt) {
0a7de745
A
662 LIST_REQ_PAGEOUT_PAGES(object, data_cnt,
663 paging_offset, offset_resid, io_errno, should_iosync);
91447636 664 }
0a7de745 665 return retval;
91447636
A
666}
667
668
669
1c79356b 670/*
0b4e3aa0 671 * Routine: vm_object_update
1c79356b 672 * Description:
0b4e3aa0 673 * Work function for m_o_lock_request(), vm_o_sync().
1c79356b
A
674 *
675 * Called with object locked and paging ref taken.
676 */
677kern_return_t
0b4e3aa0 678vm_object_update(
0a7de745
A
679 vm_object_t object,
680 vm_object_offset_t offset,
681 vm_object_size_t size,
682 vm_object_offset_t *resid_offset,
683 int *io_errno,
684 memory_object_return_t should_return,
685 int flags,
686 vm_prot_t protection)
1c79356b 687{
0a7de745
A
688 vm_object_t copy_object = VM_OBJECT_NULL;
689 boolean_t data_returned = FALSE;
690 boolean_t update_cow;
691 boolean_t should_flush = (flags & MEMORY_OBJECT_DATA_FLUSH) ? TRUE : FALSE;
692 boolean_t should_iosync = (flags & MEMORY_OBJECT_IO_SYNC) ? TRUE : FALSE;
693 vm_fault_return_t result;
694 int num_of_extents;
695 int n;
696#define MAX_EXTENTS 8
697#define EXTENT_SIZE (1024 * 1024 * 256)
698#define RESIDENT_LIMIT (1024 * 32)
91447636 699 struct extent {
0a7de745
A
700 vm_object_offset_t e_base;
701 vm_object_offset_t e_min;
702 vm_object_offset_t e_max;
91447636 703 } extents[MAX_EXTENTS];
1c79356b
A
704
705 /*
706 * To avoid blocking while scanning for pages, save
707 * dirty pages to be cleaned all at once.
708 *
709 * XXXO A similar strategy could be used to limit the
710 * number of times that a scan must be restarted for
711 * other reasons. Those pages that would require blocking
712 * could be temporarily collected in another list, or
713 * their offsets could be recorded in a small array.
714 */
715
716 /*
717 * XXX NOTE: May want to consider converting this to a page list
718 * XXX vm_map_copy interface. Need to understand object
719 * XXX coalescing implications before doing so.
720 */
721
0a7de745
A
722 update_cow = ((flags & MEMORY_OBJECT_DATA_FLUSH)
723 && (!(flags & MEMORY_OBJECT_DATA_NO_CHANGE) &&
724 !(flags & MEMORY_OBJECT_DATA_PURGE)))
725 || (flags & MEMORY_OBJECT_COPY_SYNC);
726
2d21ac55 727 if (update_cow || (flags & (MEMORY_OBJECT_DATA_PURGE | MEMORY_OBJECT_DATA_SYNC))) {
0a7de745 728 int collisions = 0;
2d21ac55 729
0a7de745
A
730 while ((copy_object = object->copy) != VM_OBJECT_NULL) {
731 /*
2d21ac55
A
732 * need to do a try here since we're swimming upstream
733 * against the normal lock ordering... however, we need
734 * to hold the object stable until we gain control of the
735 * copy object so we have to be careful how we approach this
736 */
0a7de745
A
737 if (vm_object_lock_try(copy_object)) {
738 /*
739 * we 'won' the lock on the copy object...
740 * no need to hold the object lock any longer...
741 * take a real reference on the copy object because
742 * we're going to call vm_fault_page on it which may
743 * under certain conditions drop the lock and the paging
744 * reference we're about to take... the reference
745 * will keep the copy object from going away if that happens
746 */
747 vm_object_unlock(object);
748 vm_object_reference_locked(copy_object);
749 break;
2d21ac55
A
750 }
751 vm_object_unlock(object);
1c79356b 752
2d21ac55
A
753 collisions++;
754 mutex_pause(collisions);
755
756 vm_object_lock(object);
757 }
758 }
759 if ((copy_object != VM_OBJECT_NULL && update_cow) || (flags & MEMORY_OBJECT_DATA_SYNC)) {
0a7de745
A
760 vm_map_size_t i;
761 vm_map_size_t copy_size;
762 vm_map_offset_t copy_offset;
763 vm_prot_t prot;
764 vm_page_t page;
765 vm_page_t top_page;
766 kern_return_t error = 0;
d9a64523 767 struct vm_object_fault_info fault_info = {};
2d21ac55
A
768
769 if (copy_object != VM_OBJECT_NULL) {
0a7de745 770 /*
2d21ac55
A
771 * translate offset with respect to shadow's offset
772 */
0a7de745
A
773 copy_offset = (offset >= copy_object->vo_shadow_offset) ?
774 (vm_map_offset_t)(offset - copy_object->vo_shadow_offset) :
775 (vm_map_offset_t) 0;
2d21ac55 776
0a7de745
A
777 if (copy_offset > copy_object->vo_size) {
778 copy_offset = copy_object->vo_size;
779 }
2d21ac55
A
780
781 /*
782 * clip size with respect to shadow offset
783 */
6d2010ae 784 if (offset >= copy_object->vo_shadow_offset) {
0a7de745 785 copy_size = size;
6d2010ae 786 } else if (size >= copy_object->vo_shadow_offset - offset) {
0a7de745 787 copy_size = size - (copy_object->vo_shadow_offset - offset);
2d21ac55 788 } else {
0a7de745 789 copy_size = 0;
2d21ac55 790 }
0a7de745 791
6d2010ae 792 if (copy_offset + copy_size > copy_object->vo_size) {
0a7de745
A
793 if (copy_object->vo_size >= copy_offset) {
794 copy_size = copy_object->vo_size - copy_offset;
2d21ac55 795 } else {
0a7de745 796 copy_size = 0;
2d21ac55
A
797 }
798 }
0a7de745 799 copy_size += copy_offset;
1c79356b
A
800 } else {
801 copy_object = object;
802
803 copy_size = offset + size;
804 copy_offset = offset;
805 }
2d21ac55
A
806 fault_info.interruptible = THREAD_UNINT;
807 fault_info.behavior = VM_BEHAVIOR_SEQUENTIAL;
2d21ac55
A
808 fault_info.lo_offset = copy_offset;
809 fault_info.hi_offset = copy_size;
b0d623f7 810 fault_info.stealth = TRUE;
d9a64523
A
811 assert(fault_info.cs_bypass == FALSE);
812 assert(fault_info.pmap_cs_associated == FALSE);
1c79356b
A
813
814 vm_object_paging_begin(copy_object);
2d21ac55
A
815
816 for (i = copy_offset; i < copy_size; i += PAGE_SIZE) {
0a7de745 817RETRY_COW_OF_LOCK_REQUEST:
b0d623f7
A
818 fault_info.cluster_size = (vm_size_t) (copy_size - i);
819 assert(fault_info.cluster_size == copy_size - i);
2d21ac55 820
0a7de745 821 prot = VM_PROT_WRITE | VM_PROT_READ;
39236c6e 822 page = VM_PAGE_NULL;
0a7de745
A
823 result = vm_fault_page(copy_object, i,
824 VM_PROT_WRITE | VM_PROT_READ,
825 FALSE,
826 FALSE, /* page not looked up */
827 &prot,
828 &page,
829 &top_page,
830 (int *)0,
831 &error,
832 FALSE,
833 FALSE, &fault_info);
b0d623f7
A
834
835 switch (result) {
1c79356b 836 case VM_FAULT_SUCCESS:
2d21ac55 837 if (top_page) {
1c79356b 838 vm_fault_cleanup(
39037602 839 VM_PAGE_OBJECT(page), top_page);
1c79356b
A
840 vm_object_lock(copy_object);
841 vm_object_paging_begin(copy_object);
1c79356b 842 }
0a7de745 843 if ((!VM_PAGE_NON_SPECULATIVE_PAGEABLE(page))) {
b0d623f7 844 vm_page_lockspin_queues();
0a7de745
A
845
846 if ((!VM_PAGE_NON_SPECULATIVE_PAGEABLE(page))) {
b0d623f7 847 vm_page_deactivate(page);
39037602 848 }
b0d623f7
A
849 vm_page_unlock_queues();
850 }
2d21ac55 851 PAGE_WAKEUP_DONE(page);
1c79356b
A
852 break;
853 case VM_FAULT_RETRY:
0a7de745 854 prot = VM_PROT_WRITE | VM_PROT_READ;
1c79356b
A
855 vm_object_lock(copy_object);
856 vm_object_paging_begin(copy_object);
857 goto RETRY_COW_OF_LOCK_REQUEST;
858 case VM_FAULT_INTERRUPTED:
0a7de745 859 prot = VM_PROT_WRITE | VM_PROT_READ;
1c79356b
A
860 vm_object_lock(copy_object);
861 vm_object_paging_begin(copy_object);
862 goto RETRY_COW_OF_LOCK_REQUEST;
863 case VM_FAULT_MEMORY_SHORTAGE:
864 VM_PAGE_WAIT();
0a7de745 865 prot = VM_PROT_WRITE | VM_PROT_READ;
1c79356b
A
866 vm_object_lock(copy_object);
867 vm_object_paging_begin(copy_object);
868 goto RETRY_COW_OF_LOCK_REQUEST;
b0d623f7
A
869 case VM_FAULT_SUCCESS_NO_VM_PAGE:
870 /* success but no VM page: fail */
871 vm_object_paging_end(copy_object);
872 vm_object_unlock(copy_object);
0a7de745 873 /*FALLTHROUGH*/
1c79356b 874 case VM_FAULT_MEMORY_ERROR:
0a7de745
A
875 if (object != copy_object) {
876 vm_object_deallocate(copy_object);
877 }
1c79356b
A
878 vm_object_lock(object);
879 goto BYPASS_COW_COPYIN;
b0d623f7
A
880 default:
881 panic("vm_object_update: unexpected error 0x%x"
0a7de745 882 " from vm_fault_page()\n", result);
1c79356b 883 }
1c79356b
A
884 }
885 vm_object_paging_end(copy_object);
2d21ac55
A
886 }
887 if ((flags & (MEMORY_OBJECT_DATA_SYNC | MEMORY_OBJECT_COPY_SYNC))) {
0a7de745 888 if (copy_object != VM_OBJECT_NULL && copy_object != object) {
1c79356b 889 vm_object_unlock(copy_object);
0a7de745 890 vm_object_deallocate(copy_object);
1c79356b
A
891 vm_object_lock(object);
892 }
2d21ac55 893 return KERN_SUCCESS;
1c79356b 894 }
2d21ac55 895 if (copy_object != VM_OBJECT_NULL && copy_object != object) {
0a7de745 896 if ((flags & MEMORY_OBJECT_DATA_PURGE)) {
39037602 897 vm_object_lock_assert_exclusive(copy_object);
0a7de745 898 copy_object->shadow_severed = TRUE;
2d21ac55
A
899 copy_object->shadowed = FALSE;
900 copy_object->shadow = NULL;
901 /*
902 * delete the ref the COW was holding on the target object
903 */
904 vm_object_deallocate(object);
905 }
906 vm_object_unlock(copy_object);
0a7de745 907 vm_object_deallocate(copy_object);
2d21ac55 908 vm_object_lock(object);
1c79356b
A
909 }
910BYPASS_COW_COPYIN:
911
91447636
A
912 /*
913 * when we have a really large range to check relative
914 * to the number of actual resident pages, we'd like
915 * to use the resident page list to drive our checks
916 * however, the object lock will get dropped while processing
917 * the page which means the resident queue can change which
918 * means we can't walk the queue as we process the pages
919 * we also want to do the processing in offset order to allow
0a7de745 920 * 'runs' of pages to be collected if we're being told to
91447636 921 * flush to disk... the resident page queue is NOT ordered.
0a7de745 922 *
91447636
A
923 * a temporary solution (until we figure out how to deal with
924 * large address spaces more generically) is to pre-flight
925 * the resident page queue (if it's small enough) and develop
926 * a collection of extents (that encompass actual resident pages)
927 * to visit. This will at least allow us to deal with some of the
928 * more pathological cases in a more efficient manner. The current
929 * worst case (a single resident page at the end of an extremely large
930 * range) can take minutes to complete for ranges in the terrabyte
931 * category... since this routine is called when truncating a file,
932 * and we currently support files up to 16 Tbytes in size, this
933 * is not a theoretical problem
934 */
1c79356b 935
0a7de745
A
936 if ((object->resident_page_count < RESIDENT_LIMIT) &&
937 (atop_64(size) > (unsigned)(object->resident_page_count / (8 * MAX_EXTENTS)))) {
938 vm_page_t next;
939 vm_object_offset_t start;
940 vm_object_offset_t end;
941 vm_object_size_t e_mask;
91447636 942 vm_page_t m;
1c79356b 943
91447636
A
944 start = offset;
945 end = offset + size;
946 num_of_extents = 0;
947 e_mask = ~((vm_object_size_t)(EXTENT_SIZE - 1));
1c79356b 948
39037602 949 m = (vm_page_t) vm_page_queue_first(&object->memq);
1c79356b 950
39037602 951 while (!vm_page_queue_end(&object->memq, (vm_page_queue_entry_t) m)) {
d9a64523 952 next = (vm_page_t) vm_page_queue_next(&m->vmp_listq);
1c79356b 953
d9a64523 954 if ((m->vmp_offset >= start) && (m->vmp_offset < end)) {
0a7de745 955 /*
91447636
A
956 * this is a page we're interested in
957 * try to fit it into a current extent
1c79356b 958 */
0a7de745
A
959 for (n = 0; n < num_of_extents; n++) {
960 if ((m->vmp_offset & e_mask) == extents[n].e_base) {
961 /*
91447636
A
962 * use (PAGE_SIZE - 1) to determine the
963 * max offset so that we don't wrap if
964 * we're at the last page of the space
965 */
0a7de745
A
966 if (m->vmp_offset < extents[n].e_min) {
967 extents[n].e_min = m->vmp_offset;
968 } else if ((m->vmp_offset + (PAGE_SIZE - 1)) > extents[n].e_max) {
969 extents[n].e_max = m->vmp_offset + (PAGE_SIZE - 1);
970 }
971 break;
91447636
A
972 }
973 }
974 if (n == num_of_extents) {
0a7de745 975 /*
91447636
A
976 * didn't find a current extent that can encompass
977 * this page
978 */
0a7de745
A
979 if (n < MAX_EXTENTS) {
980 /*
981 * if we still have room,
91447636
A
982 * create a new extent
983 */
0a7de745 984 extents[n].e_base = m->vmp_offset & e_mask;
d9a64523
A
985 extents[n].e_min = m->vmp_offset;
986 extents[n].e_max = m->vmp_offset + (PAGE_SIZE - 1);
91447636
A
987
988 num_of_extents++;
989 } else {
990 /*
991 * no room to create a new extent...
992 * fall back to a single extent based
0a7de745 993 * on the min and max page offsets
91447636
A
994 * we find in the range we're interested in...
995 * first, look through the extent list and
996 * develop the overall min and max for the
997 * pages we've looked at up to this point
0a7de745
A
998 */
999 for (n = 1; n < num_of_extents; n++) {
1000 if (extents[n].e_min < extents[0].e_min) {
1001 extents[0].e_min = extents[n].e_min;
1002 }
1003 if (extents[n].e_max > extents[0].e_max) {
1004 extents[0].e_max = extents[n].e_max;
1005 }
91447636
A
1006 }
1007 /*
1008 * now setup to run through the remaining pages
1009 * to determine the overall min and max
1010 * offset for the specified range
1011 */
1012 extents[0].e_base = 0;
1013 e_mask = 0;
1014 num_of_extents = 1;
1015
1016 /*
1017 * by continuing, we'll reprocess the
1018 * page that forced us to abandon trying
1019 * to develop multiple extents
1020 */
1021 continue;
1022 }
1023 }
1c79356b 1024 }
91447636 1025 m = next;
1c79356b 1026 }
91447636 1027 } else {
0a7de745 1028 extents[0].e_min = offset;
91447636 1029 extents[0].e_max = offset + (size - 1);
1c79356b 1030
91447636
A
1031 num_of_extents = 1;
1032 }
1033 for (n = 0; n < num_of_extents; n++) {
0a7de745
A
1034 if (vm_object_update_extent(object, extents[n].e_min, extents[n].e_max, resid_offset, io_errno,
1035 should_flush, should_return, should_iosync, protection)) {
1036 data_returned = TRUE;
1037 }
1c79356b 1038 }
0a7de745 1039 return data_returned;
1c79356b
A
1040}
1041
91447636 1042
0b4e3aa0
A
1043static kern_return_t
1044vm_object_set_attributes_common(
0a7de745
A
1045 vm_object_t object,
1046 boolean_t may_cache,
5ba3f43e 1047 memory_object_copy_strategy_t copy_strategy)
1c79356b 1048{
0a7de745 1049 boolean_t object_became_ready;
1c79356b 1050
0a7de745
A
1051 if (object == VM_OBJECT_NULL) {
1052 return KERN_INVALID_ARGUMENT;
1053 }
1c79356b
A
1054
1055 /*
1056 * Verify the attributes of importance
1057 */
1058
0a7de745
A
1059 switch (copy_strategy) {
1060 case MEMORY_OBJECT_COPY_NONE:
1061 case MEMORY_OBJECT_COPY_DELAY:
1062 break;
1063 default:
1064 return KERN_INVALID_ARGUMENT;
1c79356b
A
1065 }
1066
0a7de745 1067 if (may_cache) {
1c79356b 1068 may_cache = TRUE;
0a7de745 1069 }
1c79356b
A
1070
1071 vm_object_lock(object);
1072
1073 /*
1074 * Copy the attributes
1075 */
1076 assert(!object->internal);
1077 object_became_ready = !object->pager_ready;
1078 object->copy_strategy = copy_strategy;
1079 object->can_persist = may_cache;
1c79356b
A
1080
1081 /*
1082 * Wake up anyone waiting for the ready attribute
1083 * to become asserted.
1084 */
1085
1086 if (object_became_ready) {
1087 object->pager_ready = TRUE;
1088 vm_object_wakeup(object, VM_OBJECT_EVENT_PAGER_READY);
1089 }
1090
1091 vm_object_unlock(object);
1092
0a7de745 1093 return KERN_SUCCESS;
1c79356b
A
1094}
1095
5ba3f43e
A
1096
1097kern_return_t
1098memory_object_synchronize_completed(
0a7de745
A
1099 __unused memory_object_control_t control,
1100 __unused memory_object_offset_t offset,
1101 __unused memory_object_size_t length)
5ba3f43e 1102{
0a7de745
A
1103 panic("memory_object_synchronize_completed no longer supported\n");
1104 return KERN_FAILURE;
5ba3f43e
A
1105}
1106
1107
1c79356b
A
1108/*
1109 * Set the memory object attribute as provided.
1110 *
0a7de745 1111 * XXX This routine cannot be completed until the vm_msync, clean
1c79356b 1112 * in place, and cluster work is completed. See ifdef notyet
0b4e3aa0 1113 * below and note that vm_object_set_attributes_common()
1c79356b
A
1114 * may have to be expanded.
1115 */
1116kern_return_t
1117memory_object_change_attributes(
0a7de745
A
1118 memory_object_control_t control,
1119 memory_object_flavor_t flavor,
1120 memory_object_info_t attributes,
1121 mach_msg_type_number_t count)
1c79356b 1122{
0a7de745
A
1123 vm_object_t object;
1124 kern_return_t result = KERN_SUCCESS;
1125 boolean_t may_cache;
1126 boolean_t invalidate;
1127 memory_object_copy_strategy_t copy_strategy;
1c79356b 1128
0b4e3aa0 1129 object = memory_object_control_to_vm_object(control);
0a7de745
A
1130 if (object == VM_OBJECT_NULL) {
1131 return KERN_INVALID_ARGUMENT;
1132 }
1c79356b
A
1133
1134 vm_object_lock(object);
0b4e3aa0 1135
1c79356b
A
1136 may_cache = object->can_persist;
1137 copy_strategy = object->copy_strategy;
1c79356b
A
1138#if notyet
1139 invalidate = object->invalidate;
1140#endif
0a7de745 1141 vm_object_unlock(object);
1c79356b
A
1142
1143 switch (flavor) {
0a7de745
A
1144 case OLD_MEMORY_OBJECT_BEHAVIOR_INFO:
1145 {
1146 old_memory_object_behave_info_t behave;
1c79356b 1147
0a7de745
A
1148 if (count != OLD_MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
1149 result = KERN_INVALID_ARGUMENT;
1150 break;
1151 }
1c79356b 1152
0a7de745 1153 behave = (old_memory_object_behave_info_t) attributes;
1c79356b 1154
1c79356b
A
1155 invalidate = behave->invalidate;
1156 copy_strategy = behave->copy_strategy;
1157
1158 break;
0a7de745 1159 }
1c79356b 1160
0a7de745
A
1161 case MEMORY_OBJECT_BEHAVIOR_INFO:
1162 {
1163 memory_object_behave_info_t behave;
1c79356b 1164
0a7de745
A
1165 if (count != MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
1166 result = KERN_INVALID_ARGUMENT;
1167 break;
1168 }
1c79356b 1169
0a7de745 1170 behave = (memory_object_behave_info_t) attributes;
1c79356b 1171
1c79356b
A
1172 invalidate = behave->invalidate;
1173 copy_strategy = behave->copy_strategy;
1c79356b 1174 break;
0a7de745 1175 }
1c79356b 1176
0a7de745
A
1177 case MEMORY_OBJECT_PERFORMANCE_INFO:
1178 {
1179 memory_object_perf_info_t perf;
1c79356b 1180
0a7de745
A
1181 if (count != MEMORY_OBJECT_PERF_INFO_COUNT) {
1182 result = KERN_INVALID_ARGUMENT;
1183 break;
1184 }
1c79356b 1185
0a7de745 1186 perf = (memory_object_perf_info_t) attributes;
1c79356b
A
1187
1188 may_cache = perf->may_cache;
1c79356b
A
1189
1190 break;
0a7de745 1191 }
1c79356b 1192
0a7de745
A
1193 case OLD_MEMORY_OBJECT_ATTRIBUTE_INFO:
1194 {
1195 old_memory_object_attr_info_t attr;
1c79356b 1196
0a7de745
A
1197 if (count != OLD_MEMORY_OBJECT_ATTR_INFO_COUNT) {
1198 result = KERN_INVALID_ARGUMENT;
1199 break;
1200 }
1c79356b
A
1201
1202 attr = (old_memory_object_attr_info_t) attributes;
1203
0a7de745
A
1204 may_cache = attr->may_cache;
1205 copy_strategy = attr->copy_strategy;
1c79356b
A
1206
1207 break;
0a7de745 1208 }
1c79356b 1209
0a7de745
A
1210 case MEMORY_OBJECT_ATTRIBUTE_INFO:
1211 {
1212 memory_object_attr_info_t attr;
1c79356b 1213
0a7de745
A
1214 if (count != MEMORY_OBJECT_ATTR_INFO_COUNT) {
1215 result = KERN_INVALID_ARGUMENT;
1216 break;
1217 }
1c79356b
A
1218
1219 attr = (memory_object_attr_info_t) attributes;
1220
1221 copy_strategy = attr->copy_strategy;
0a7de745 1222 may_cache = attr->may_cache_object;
1c79356b
A
1223
1224 break;
0a7de745 1225 }
1c79356b 1226
0a7de745 1227 default:
1c79356b
A
1228 result = KERN_INVALID_ARGUMENT;
1229 break;
1230 }
1231
0a7de745
A
1232 if (result != KERN_SUCCESS) {
1233 return result;
1234 }
1c79356b
A
1235
1236 if (copy_strategy == MEMORY_OBJECT_COPY_TEMPORARY) {
1237 copy_strategy = MEMORY_OBJECT_COPY_DELAY;
1c79356b
A
1238 }
1239
1240 /*
1c79356b
A
1241 * XXX may_cache may become a tri-valued variable to handle
1242 * XXX uncache if not in use.
1243 */
0a7de745
A
1244 return vm_object_set_attributes_common(object,
1245 may_cache,
1246 copy_strategy);
1c79356b
A
1247}
1248
1249kern_return_t
1250memory_object_get_attributes(
0a7de745
A
1251 memory_object_control_t control,
1252 memory_object_flavor_t flavor,
1253 memory_object_info_t attributes, /* pointer to OUT array */
1254 mach_msg_type_number_t *count) /* IN/OUT */
1c79356b 1255{
0a7de745
A
1256 kern_return_t ret = KERN_SUCCESS;
1257 vm_object_t object;
1c79356b 1258
0b4e3aa0 1259 object = memory_object_control_to_vm_object(control);
0a7de745
A
1260 if (object == VM_OBJECT_NULL) {
1261 return KERN_INVALID_ARGUMENT;
1262 }
1c79356b 1263
0a7de745 1264 vm_object_lock(object);
1c79356b
A
1265
1266 switch (flavor) {
0a7de745
A
1267 case OLD_MEMORY_OBJECT_BEHAVIOR_INFO:
1268 {
1269 old_memory_object_behave_info_t behave;
1c79356b
A
1270
1271 if (*count < OLD_MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
1272 ret = KERN_INVALID_ARGUMENT;
1273 break;
1274 }
1275
1276 behave = (old_memory_object_behave_info_t) attributes;
1277 behave->copy_strategy = object->copy_strategy;
5ba3f43e 1278 behave->temporary = FALSE;
0a7de745
A
1279#if notyet /* remove when vm_msync complies and clean in place fini */
1280 behave->invalidate = object->invalidate;
1c79356b
A
1281#else
1282 behave->invalidate = FALSE;
1283#endif
1284
1285 *count = OLD_MEMORY_OBJECT_BEHAVE_INFO_COUNT;
1286 break;
0a7de745 1287 }
1c79356b 1288
0a7de745
A
1289 case MEMORY_OBJECT_BEHAVIOR_INFO:
1290 {
1291 memory_object_behave_info_t behave;
1c79356b
A
1292
1293 if (*count < MEMORY_OBJECT_BEHAVE_INFO_COUNT) {
0a7de745
A
1294 ret = KERN_INVALID_ARGUMENT;
1295 break;
1296 }
1c79356b 1297
0a7de745
A
1298 behave = (memory_object_behave_info_t) attributes;
1299 behave->copy_strategy = object->copy_strategy;
5ba3f43e 1300 behave->temporary = FALSE;
0a7de745
A
1301#if notyet /* remove when vm_msync complies and clean in place fini */
1302 behave->invalidate = object->invalidate;
1c79356b
A
1303#else
1304 behave->invalidate = FALSE;
1305#endif
5ba3f43e 1306 behave->advisory_pageout = FALSE;
39236c6e 1307 behave->silent_overwrite = FALSE;
0a7de745 1308 *count = MEMORY_OBJECT_BEHAVE_INFO_COUNT;
1c79356b 1309 break;
0a7de745 1310 }
1c79356b 1311
0a7de745
A
1312 case MEMORY_OBJECT_PERFORMANCE_INFO:
1313 {
1314 memory_object_perf_info_t perf;
1c79356b
A
1315
1316 if (*count < MEMORY_OBJECT_PERF_INFO_COUNT) {
1317 ret = KERN_INVALID_ARGUMENT;
1318 break;
1319 }
1320
1321 perf = (memory_object_perf_info_t) attributes;
2d21ac55 1322 perf->cluster_size = PAGE_SIZE;
1c79356b
A
1323 perf->may_cache = object->can_persist;
1324
1325 *count = MEMORY_OBJECT_PERF_INFO_COUNT;
1326 break;
0a7de745 1327 }
1c79356b 1328
0a7de745
A
1329 case OLD_MEMORY_OBJECT_ATTRIBUTE_INFO:
1330 {
1331 old_memory_object_attr_info_t attr;
1c79356b 1332
0a7de745
A
1333 if (*count < OLD_MEMORY_OBJECT_ATTR_INFO_COUNT) {
1334 ret = KERN_INVALID_ARGUMENT;
1335 break;
1336 }
1c79356b 1337
0a7de745
A
1338 attr = (old_memory_object_attr_info_t) attributes;
1339 attr->may_cache = object->can_persist;
1340 attr->copy_strategy = object->copy_strategy;
1c79356b 1341
0a7de745
A
1342 *count = OLD_MEMORY_OBJECT_ATTR_INFO_COUNT;
1343 break;
1344 }
1c79356b 1345
0a7de745
A
1346 case MEMORY_OBJECT_ATTRIBUTE_INFO:
1347 {
1348 memory_object_attr_info_t attr;
1c79356b 1349
0a7de745
A
1350 if (*count < MEMORY_OBJECT_ATTR_INFO_COUNT) {
1351 ret = KERN_INVALID_ARGUMENT;
1352 break;
1353 }
1c79356b 1354
0a7de745
A
1355 attr = (memory_object_attr_info_t) attributes;
1356 attr->copy_strategy = object->copy_strategy;
2d21ac55 1357 attr->cluster_size = PAGE_SIZE;
0a7de745 1358 attr->may_cache_object = object->can_persist;
5ba3f43e 1359 attr->temporary = FALSE;
1c79356b 1360
0a7de745
A
1361 *count = MEMORY_OBJECT_ATTR_INFO_COUNT;
1362 break;
1363 }
1c79356b 1364
0a7de745 1365 default:
1c79356b
A
1366 ret = KERN_INVALID_ARGUMENT;
1367 break;
1368 }
1369
0a7de745 1370 vm_object_unlock(object);
1c79356b 1371
0a7de745 1372 return ret;
1c79356b
A
1373}
1374
1c79356b 1375
55e303ae
A
1376kern_return_t
1377memory_object_iopl_request(
0a7de745
A
1378 ipc_port_t port,
1379 memory_object_offset_t offset,
1380 upl_size_t *upl_size,
1381 upl_t *upl_ptr,
1382 upl_page_info_array_t user_page_list,
1383 unsigned int *page_list_count,
1384 upl_control_flags_t *flags,
1385 vm_tag_t tag)
55e303ae 1386{
0a7de745
A
1387 vm_object_t object;
1388 kern_return_t ret;
1389 upl_control_flags_t caller_flags;
55e303ae
A
1390
1391 caller_flags = *flags;
1392
91447636
A
1393 if (caller_flags & ~UPL_VALID_FLAGS) {
1394 /*
1395 * For forward compatibility's sake,
1396 * reject any unknown flag.
1397 */
1398 return KERN_INVALID_VALUE;
1399 }
1400
55e303ae 1401 if (ip_kotype(port) == IKOT_NAMED_ENTRY) {
0a7de745 1402 vm_named_entry_t named_entry;
55e303ae 1403
ea3f0419 1404 named_entry = (vm_named_entry_t) ip_get_kobject(port);
55e303ae 1405 /* a few checks to make sure user is obeying rules */
0a7de745
A
1406 if (*upl_size == 0) {
1407 if (offset >= named_entry->size) {
1408 return KERN_INVALID_RIGHT;
1409 }
b0d623f7 1410 *upl_size = (upl_size_t)(named_entry->size - offset);
0a7de745 1411 if (*upl_size != named_entry->size - offset) {
b0d623f7 1412 return KERN_INVALID_ARGUMENT;
0a7de745 1413 }
55e303ae 1414 }
0a7de745
A
1415 if (caller_flags & UPL_COPYOUT_FROM) {
1416 if ((named_entry->protection & VM_PROT_READ)
1417 != VM_PROT_READ) {
1418 return KERN_INVALID_RIGHT;
55e303ae
A
1419 }
1420 } else {
0a7de745
A
1421 if ((named_entry->protection &
1422 (VM_PROT_READ | VM_PROT_WRITE))
1423 != (VM_PROT_READ | VM_PROT_WRITE)) {
1424 return KERN_INVALID_RIGHT;
55e303ae
A
1425 }
1426 }
0a7de745
A
1427 if (named_entry->size < (offset + *upl_size)) {
1428 return KERN_INVALID_ARGUMENT;
1429 }
55e303ae
A
1430
1431 /* the callers parameter offset is defined to be the */
1432 /* offset from beginning of named entry offset in object */
1433 offset = offset + named_entry->offset;
1434
39236c6e 1435 if (named_entry->is_sub_map ||
0a7de745 1436 named_entry->is_copy) {
39236c6e 1437 return KERN_INVALID_ARGUMENT;
0a7de745
A
1438 }
1439
55e303ae
A
1440 named_entry_lock(named_entry);
1441
5ba3f43e
A
1442 object = named_entry->backing.object;
1443 vm_object_reference(object);
1444 named_entry_unlock(named_entry);
0c530ab8 1445 } else if (ip_kotype(port) == IKOT_MEM_OBJ_CONTROL) {
0a7de745 1446 memory_object_control_t control;
0c530ab8 1447 control = (memory_object_control_t) port;
0a7de745
A
1448 if (control == NULL) {
1449 return KERN_INVALID_ARGUMENT;
1450 }
55e303ae 1451 object = memory_object_control_to_vm_object(control);
0a7de745
A
1452 if (object == VM_OBJECT_NULL) {
1453 return KERN_INVALID_ARGUMENT;
1454 }
55e303ae 1455 vm_object_reference(object);
0c530ab8
A
1456 } else {
1457 return KERN_INVALID_ARGUMENT;
55e303ae 1458 }
0a7de745
A
1459 if (object == VM_OBJECT_NULL) {
1460 return KERN_INVALID_ARGUMENT;
1461 }
55e303ae
A
1462
1463 if (!object->private) {
55e303ae
A
1464 if (object->phys_contiguous) {
1465 *flags = UPL_PHYS_CONTIG;
1466 } else {
1467 *flags = 0;
1468 }
1469 } else {
1470 *flags = UPL_DEV_MEMORY | UPL_PHYS_CONTIG;
1471 }
1472
1473 ret = vm_object_iopl_request(object,
0a7de745
A
1474 offset,
1475 *upl_size,
1476 upl_ptr,
1477 user_page_list,
1478 page_list_count,
1479 caller_flags,
1480 tag);
55e303ae
A
1481 vm_object_deallocate(object);
1482 return ret;
1483}
1484
0a7de745 1485/*
0b4e3aa0
A
1486 * Routine: memory_object_upl_request [interface]
1487 * Purpose:
1488 * Cause the population of a portion of a vm_object.
1489 * Depending on the nature of the request, the pages
1490 * returned may be contain valid data or be uninitialized.
1491 *
1492 */
1c79356b 1493
0b4e3aa0
A
1494kern_return_t
1495memory_object_upl_request(
0a7de745
A
1496 memory_object_control_t control,
1497 memory_object_offset_t offset,
1498 upl_size_t size,
1499 upl_t *upl_ptr,
1500 upl_page_info_array_t user_page_list,
1501 unsigned int *page_list_count,
1502 int cntrl_flags,
1503 int tag)
0b4e3aa0 1504{
0a7de745 1505 vm_object_t object;
0b4e3aa0
A
1506
1507 object = memory_object_control_to_vm_object(control);
0a7de745
A
1508 if (object == VM_OBJECT_NULL) {
1509 return KERN_TERMINATED;
1510 }
0b4e3aa0
A
1511
1512 return vm_object_upl_request(object,
0a7de745
A
1513 offset,
1514 size,
1515 upl_ptr,
1516 user_page_list,
1517 page_list_count,
1518 (upl_control_flags_t)(unsigned int) cntrl_flags,
1519 tag);
0b4e3aa0
A
1520}
1521
0a7de745 1522/*
0b4e3aa0
A
1523 * Routine: memory_object_super_upl_request [interface]
1524 * Purpose:
1525 * Cause the population of a portion of a vm_object
1526 * in much the same way as memory_object_upl_request.
1527 * Depending on the nature of the request, the pages
1528 * returned may be contain valid data or be uninitialized.
1529 * However, the region may be expanded up to the super
1530 * cluster size provided.
1c79356b 1531 */
0b4e3aa0 1532
1c79356b 1533kern_return_t
0b4e3aa0
A
1534memory_object_super_upl_request(
1535 memory_object_control_t control,
0a7de745
A
1536 memory_object_offset_t offset,
1537 upl_size_t size,
1538 upl_size_t super_cluster,
1539 upl_t *upl,
1540 upl_page_info_t *user_page_list,
1541 unsigned int *page_list_count,
1542 int cntrl_flags,
1543 int tag)
1c79356b 1544{
0a7de745 1545 vm_object_t object;
0b4e3aa0
A
1546
1547 object = memory_object_control_to_vm_object(control);
0a7de745
A
1548 if (object == VM_OBJECT_NULL) {
1549 return KERN_INVALID_ARGUMENT;
1550 }
0b4e3aa0
A
1551
1552 return vm_object_super_upl_request(object,
0a7de745
A
1553 offset,
1554 size,
1555 super_cluster,
1556 upl,
1557 user_page_list,
1558 page_list_count,
1559 (upl_control_flags_t)(unsigned int) cntrl_flags,
1560 tag);
1c79356b
A
1561}
1562
2d21ac55 1563kern_return_t
d9a64523 1564memory_object_cluster_size(
0a7de745
A
1565 memory_object_control_t control,
1566 memory_object_offset_t *start,
1567 vm_size_t *length,
1568 uint32_t *io_streaming,
d9a64523 1569 memory_object_fault_info_t mo_fault_info)
2d21ac55 1570{
0a7de745
A
1571 vm_object_t object;
1572 vm_object_fault_info_t fault_info;
2d21ac55
A
1573
1574 object = memory_object_control_to_vm_object(control);
1575
0a7de745 1576 if (object == VM_OBJECT_NULL || object->paging_offset > *start) {
d9a64523 1577 return KERN_INVALID_ARGUMENT;
0a7de745 1578 }
2d21ac55
A
1579
1580 *start -= object->paging_offset;
1581
d9a64523
A
1582 fault_info = (vm_object_fault_info_t)(uintptr_t) mo_fault_info;
1583 vm_object_cluster_size(object,
0a7de745
A
1584 (vm_object_offset_t *)start,
1585 length,
1586 fault_info,
1587 io_streaming);
2d21ac55
A
1588
1589 *start += object->paging_offset;
1590
d9a64523 1591 return KERN_SUCCESS;
2d21ac55
A
1592}
1593
1594
1c79356b 1595/*
0b4e3aa0 1596 * Routine: host_default_memory_manager [interface]
1c79356b
A
1597 * Purpose:
1598 * set/get the default memory manager port and default cluster
1599 * size.
1600 *
1601 * If successful, consumes the supplied naked send right.
1602 */
1603kern_return_t
1604host_default_memory_manager(
0a7de745
A
1605 host_priv_t host_priv,
1606 memory_object_default_t *default_manager,
2d21ac55 1607 __unused memory_object_cluster_size_t cluster_size)
1c79356b 1608{
0b4e3aa0
A
1609 memory_object_default_t current_manager;
1610 memory_object_default_t new_manager;
1611 memory_object_default_t returned_manager;
2d21ac55 1612 kern_return_t result = KERN_SUCCESS;
1c79356b 1613
0a7de745
A
1614 if (host_priv == HOST_PRIV_NULL) {
1615 return KERN_INVALID_HOST;
1616 }
1c79356b
A
1617
1618 assert(host_priv == &realhost);
1619
1620 new_manager = *default_manager;
b0d623f7 1621 lck_mtx_lock(&memory_manager_default_lock);
1c79356b 1622 current_manager = memory_manager_default;
2d21ac55 1623 returned_manager = MEMORY_OBJECT_DEFAULT_NULL;
1c79356b 1624
0b4e3aa0 1625 if (new_manager == MEMORY_OBJECT_DEFAULT_NULL) {
1c79356b
A
1626 /*
1627 * Retrieve the current value.
1628 */
0b4e3aa0 1629 returned_manager = current_manager;
2d21ac55 1630 memory_object_default_reference(returned_manager);
1c79356b 1631 } else {
3e170ce0
A
1632 /*
1633 * Only allow the kernel to change the value.
1634 */
1635 extern task_t kernel_task;
1636 if (current_task() != kernel_task) {
1637 result = KERN_NO_ACCESS;
1638 goto out;
1639 }
2d21ac55
A
1640
1641 /*
1642 * If this is the first non-null manager, start
1643 * up the internal pager support.
1644 */
1645 if (current_manager == MEMORY_OBJECT_DEFAULT_NULL) {
1646 result = vm_pageout_internal_start();
0a7de745 1647 if (result != KERN_SUCCESS) {
2d21ac55 1648 goto out;
0a7de745 1649 }
2d21ac55
A
1650 }
1651
1c79356b
A
1652 /*
1653 * Retrieve the current value,
1654 * and replace it with the supplied value.
0b4e3aa0
A
1655 * We return the old reference to the caller
1656 * but we have to take a reference on the new
1657 * one.
1c79356b 1658 */
1c79356b
A
1659 returned_manager = current_manager;
1660 memory_manager_default = new_manager;
0b4e3aa0
A
1661 memory_object_default_reference(new_manager);
1662
1c79356b
A
1663 /*
1664 * In case anyone's been waiting for a memory
1665 * manager to be established, wake them up.
1666 */
1667
1668 thread_wakeup((event_t) &memory_manager_default);
b0d623f7
A
1669
1670 /*
1671 * Now that we have a default pager for anonymous memory,
1672 * reactivate all the throttled pages (i.e. dirty pages with
1673 * no pager).
1674 */
0a7de745 1675 if (current_manager == MEMORY_OBJECT_DEFAULT_NULL) {
b0d623f7
A
1676 vm_page_reactivate_all_throttled();
1677 }
1c79356b 1678 }
0a7de745 1679out:
b0d623f7 1680 lck_mtx_unlock(&memory_manager_default_lock);
1c79356b
A
1681
1682 *default_manager = returned_manager;
0a7de745 1683 return result;
1c79356b
A
1684}
1685
1686/*
1687 * Routine: memory_manager_default_reference
1688 * Purpose:
1689 * Returns a naked send right for the default
1690 * memory manager. The returned right is always
1691 * valid (not IP_NULL or IP_DEAD).
1692 */
1693
0b4e3aa0 1694__private_extern__ memory_object_default_t
2d21ac55 1695memory_manager_default_reference(void)
1c79356b 1696{
0b4e3aa0 1697 memory_object_default_t current_manager;
1c79356b 1698
b0d623f7 1699 lck_mtx_lock(&memory_manager_default_lock);
0b4e3aa0
A
1700 current_manager = memory_manager_default;
1701 while (current_manager == MEMORY_OBJECT_DEFAULT_NULL) {
9bccf70c
A
1702 wait_result_t res;
1703
b0d623f7 1704 res = lck_mtx_sleep(&memory_manager_default_lock,
0a7de745
A
1705 LCK_SLEEP_DEFAULT,
1706 (event_t) &memory_manager_default,
1707 THREAD_UNINT);
9bccf70c 1708 assert(res == THREAD_AWAKENED);
0b4e3aa0 1709 current_manager = memory_manager_default;
1c79356b 1710 }
0b4e3aa0 1711 memory_object_default_reference(current_manager);
b0d623f7 1712 lck_mtx_unlock(&memory_manager_default_lock);
1c79356b
A
1713
1714 return current_manager;
1715}
1716
1c79356b
A
1717/*
1718 * Routine: memory_manager_default_check
1719 *
1720 * Purpose:
1721 * Check whether a default memory manager has been set
1722 * up yet, or not. Returns KERN_SUCCESS if dmm exists,
1723 * and KERN_FAILURE if dmm does not exist.
1724 *
1725 * If there is no default memory manager, log an error,
1726 * but only the first time.
1727 *
1728 */
0b4e3aa0 1729__private_extern__ kern_return_t
1c79356b
A
1730memory_manager_default_check(void)
1731{
0b4e3aa0 1732 memory_object_default_t current;
1c79356b 1733
b0d623f7 1734 lck_mtx_lock(&memory_manager_default_lock);
1c79356b 1735 current = memory_manager_default;
0b4e3aa0 1736 if (current == MEMORY_OBJECT_DEFAULT_NULL) {
0a7de745
A
1737 static boolean_t logged; /* initialized to 0 */
1738 boolean_t complain = !logged;
1c79356b 1739 logged = TRUE;
b0d623f7 1740 lck_mtx_unlock(&memory_manager_default_lock);
0a7de745 1741 if (complain) {
1c79356b 1742 printf("Warning: No default memory manager\n");
0a7de745
A
1743 }
1744 return KERN_FAILURE;
1c79356b 1745 } else {
b0d623f7 1746 lck_mtx_unlock(&memory_manager_default_lock);
0a7de745 1747 return KERN_SUCCESS;
1c79356b
A
1748 }
1749}
1750
0b4e3aa0 1751__private_extern__ void
1c79356b
A
1752memory_manager_default_init(void)
1753{
0b4e3aa0 1754 memory_manager_default = MEMORY_OBJECT_DEFAULT_NULL;
b0d623f7 1755 lck_mtx_init(&memory_manager_default_lock, &vm_object_lck_grp, &vm_object_lck_attr);
1c79356b
A
1756}
1757
1758
1c79356b
A
1759
1760/* Allow manipulation of individual page state. This is actually part of */
1761/* the UPL regimen but takes place on the object rather than on a UPL */
1762
1763kern_return_t
1764memory_object_page_op(
0a7de745
A
1765 memory_object_control_t control,
1766 memory_object_offset_t offset,
1767 int ops,
1768 ppnum_t *phys_entry,
1769 int *flags)
1c79356b 1770{
0a7de745 1771 vm_object_t object;
0b4e3aa0
A
1772
1773 object = memory_object_control_to_vm_object(control);
0a7de745
A
1774 if (object == VM_OBJECT_NULL) {
1775 return KERN_INVALID_ARGUMENT;
1776 }
1c79356b 1777
0c530ab8 1778 return vm_object_page_op(object, offset, ops, phys_entry, flags);
1c79356b
A
1779}
1780
55e303ae 1781/*
0a7de745
A
1782 * memory_object_range_op offers performance enhancement over
1783 * memory_object_page_op for page_op functions which do not require page
1784 * level state to be returned from the call. Page_op was created to provide
1785 * a low-cost alternative to page manipulation via UPLs when only a single
1786 * page was involved. The range_op call establishes the ability in the _op
55e303ae
A
1787 * family of functions to work on multiple pages where the lack of page level
1788 * state handling allows the caller to avoid the overhead of the upl structures.
1789 */
1790
1791kern_return_t
1792memory_object_range_op(
0a7de745
A
1793 memory_object_control_t control,
1794 memory_object_offset_t offset_beg,
1795 memory_object_offset_t offset_end,
55e303ae
A
1796 int ops,
1797 int *range)
1798{
0a7de745 1799 vm_object_t object;
55e303ae
A
1800
1801 object = memory_object_control_to_vm_object(control);
0a7de745
A
1802 if (object == VM_OBJECT_NULL) {
1803 return KERN_INVALID_ARGUMENT;
1804 }
55e303ae 1805
0c530ab8 1806 return vm_object_range_op(object,
0a7de745
A
1807 offset_beg,
1808 offset_end,
1809 ops,
1810 (uint32_t *) range);
55e303ae
A
1811}
1812
91447636 1813
6d2010ae
A
1814void
1815memory_object_mark_used(
0a7de745 1816 memory_object_control_t control)
6d2010ae 1817{
0a7de745 1818 vm_object_t object;
6d2010ae 1819
0a7de745 1820 if (control == NULL) {
6d2010ae 1821 return;
0a7de745 1822 }
6d2010ae
A
1823
1824 object = memory_object_control_to_vm_object(control);
1825
0a7de745 1826 if (object != VM_OBJECT_NULL) {
6d2010ae 1827 vm_object_cache_remove(object);
0a7de745 1828 }
6d2010ae
A
1829}
1830
1831
1832void
1833memory_object_mark_unused(
0a7de745
A
1834 memory_object_control_t control,
1835 __unused boolean_t rage)
6d2010ae 1836{
0a7de745 1837 vm_object_t object;
6d2010ae 1838
0a7de745 1839 if (control == NULL) {
6d2010ae 1840 return;
0a7de745 1841 }
6d2010ae
A
1842
1843 object = memory_object_control_to_vm_object(control);
1844
0a7de745 1845 if (object != VM_OBJECT_NULL) {
6d2010ae 1846 vm_object_cache_add(object);
0a7de745 1847 }
6d2010ae
A
1848}
1849
fe8ab488
A
1850void
1851memory_object_mark_io_tracking(
1852 memory_object_control_t control)
1853{
1854 vm_object_t object;
1855
0a7de745 1856 if (control == NULL) {
fe8ab488 1857 return;
0a7de745 1858 }
fe8ab488
A
1859 object = memory_object_control_to_vm_object(control);
1860
1861 if (object != VM_OBJECT_NULL) {
1862 vm_object_lock(object);
1863 object->io_tracking = TRUE;
1864 vm_object_unlock(object);
1865 }
1866}
6d2010ae 1867
cb323159
A
1868void
1869memory_object_mark_trusted(
1870 memory_object_control_t control)
1871{
1872 vm_object_t object;
1873
1874 if (control == NULL) {
1875 return;
1876 }
1877 object = memory_object_control_to_vm_object(control);
1878
1879 if (object != VM_OBJECT_NULL) {
1880 vm_object_lock(object);
1881 object->pager_trusted = TRUE;
1882 vm_object_unlock(object);
1883 }
1884}
1885
39037602
A
1886#if CONFIG_SECLUDED_MEMORY
1887void
1888memory_object_mark_eligible_for_secluded(
1889 memory_object_control_t control,
0a7de745 1890 boolean_t eligible_for_secluded)
39037602
A
1891{
1892 vm_object_t object;
1893
0a7de745 1894 if (control == NULL) {
39037602 1895 return;
0a7de745 1896 }
39037602
A
1897 object = memory_object_control_to_vm_object(control);
1898
1899 if (object == VM_OBJECT_NULL) {
1900 return;
1901 }
1902
1903 vm_object_lock(object);
1904 if (eligible_for_secluded &&
1905 secluded_for_filecache && /* global boot-arg */
1906 !object->eligible_for_secluded) {
1907 object->eligible_for_secluded = TRUE;
1908 vm_page_secluded.eligible_for_secluded += object->resident_page_count;
1909 } else if (!eligible_for_secluded &&
0a7de745 1910 object->eligible_for_secluded) {
39037602
A
1911 object->eligible_for_secluded = FALSE;
1912 vm_page_secluded.eligible_for_secluded -= object->resident_page_count;
1913 if (object->resident_page_count) {
1914 /* XXX FBDP TODO: flush pages from secluded queue? */
1915 // printf("FBDP TODO: flush %d pages from %p from secluded queue\n", object->resident_page_count, object);
1916 }
1917 }
1918 vm_object_unlock(object);
1919}
1920#endif /* CONFIG_SECLUDED_MEMORY */
1921
91447636
A
1922kern_return_t
1923memory_object_pages_resident(
0a7de745
A
1924 memory_object_control_t control,
1925 boolean_t * has_pages_resident)
91447636 1926{
0a7de745 1927 vm_object_t object;
91447636
A
1928
1929 *has_pages_resident = FALSE;
1930
1931 object = memory_object_control_to_vm_object(control);
0a7de745
A
1932 if (object == VM_OBJECT_NULL) {
1933 return KERN_INVALID_ARGUMENT;
1934 }
91447636 1935
0a7de745 1936 if (object->resident_page_count) {
91447636 1937 *has_pages_resident = TRUE;
0a7de745
A
1938 }
1939
1940 return KERN_SUCCESS;
91447636
A
1941}
1942
2d21ac55
A
1943kern_return_t
1944memory_object_signed(
0a7de745
A
1945 memory_object_control_t control,
1946 boolean_t is_signed)
2d21ac55 1947{
0a7de745 1948 vm_object_t object;
2d21ac55
A
1949
1950 object = memory_object_control_to_vm_object(control);
0a7de745 1951 if (object == VM_OBJECT_NULL) {
2d21ac55 1952 return KERN_INVALID_ARGUMENT;
0a7de745 1953 }
2d21ac55
A
1954
1955 vm_object_lock(object);
1956 object->code_signed = is_signed;
1957 vm_object_unlock(object);
1958
1959 return KERN_SUCCESS;
1960}
91447636 1961
39236c6e
A
1962boolean_t
1963memory_object_is_signed(
0a7de745 1964 memory_object_control_t control)
39236c6e 1965{
0a7de745
A
1966 boolean_t is_signed;
1967 vm_object_t object;
39236c6e
A
1968
1969 object = memory_object_control_to_vm_object(control);
0a7de745 1970 if (object == VM_OBJECT_NULL) {
39236c6e 1971 return FALSE;
0a7de745 1972 }
39236c6e
A
1973
1974 vm_object_lock_shared(object);
1975 is_signed = object->code_signed;
1976 vm_object_unlock(object);
1977
1978 return is_signed;
1979}
1980
6d2010ae 1981boolean_t
d9a64523 1982memory_object_is_shared_cache(
0a7de745 1983 memory_object_control_t control)
6d2010ae 1984{
0a7de745 1985 vm_object_t object = VM_OBJECT_NULL;
6d2010ae
A
1986
1987 object = memory_object_control_to_vm_object(control);
0a7de745 1988 if (object == VM_OBJECT_NULL) {
6d2010ae 1989 return FALSE;
0a7de745 1990 }
6d2010ae 1991
d9a64523 1992 return object->object_is_shared_cache;
6d2010ae
A
1993}
1994
0b4e3aa0
A
1995static zone_t mem_obj_control_zone;
1996
1997__private_extern__ void
1998memory_object_control_bootstrap(void)
1999{
0a7de745 2000 int i;
0b4e3aa0 2001
0a7de745
A
2002 i = (vm_size_t) sizeof(struct memory_object_control);
2003 mem_obj_control_zone = zinit(i, 8192 * i, 4096, "mem_obj_control");
6d2010ae 2004 zone_change(mem_obj_control_zone, Z_CALLERACCT, FALSE);
0b4c1975 2005 zone_change(mem_obj_control_zone, Z_NOENCRYPT, TRUE);
0b4e3aa0
A
2006 return;
2007}
2008
2009__private_extern__ memory_object_control_t
2010memory_object_control_allocate(
0a7de745
A
2011 vm_object_t object)
2012{
0b4e3aa0
A
2013 memory_object_control_t control;
2014
2015 control = (memory_object_control_t)zalloc(mem_obj_control_zone);
0c530ab8
A
2016 if (control != MEMORY_OBJECT_CONTROL_NULL) {
2017 control->moc_object = object;
2018 control->moc_ikot = IKOT_MEM_OBJ_CONTROL; /* fake ip_kotype */
2019 }
0a7de745 2020 return control;
0b4e3aa0
A
2021}
2022
2023__private_extern__ void
2024memory_object_control_collapse(
0a7de745
A
2025 memory_object_control_t control,
2026 vm_object_t object)
2027{
0c530ab8 2028 assert((control->moc_object != VM_OBJECT_NULL) &&
0a7de745 2029 (control->moc_object != object));
0c530ab8 2030 control->moc_object = object;
0b4e3aa0
A
2031}
2032
2033__private_extern__ vm_object_t
2034memory_object_control_to_vm_object(
0a7de745 2035 memory_object_control_t control)
0b4e3aa0 2036{
0c530ab8 2037 if (control == MEMORY_OBJECT_CONTROL_NULL ||
0a7de745 2038 control->moc_ikot != IKOT_MEM_OBJ_CONTROL) {
0b4e3aa0 2039 return VM_OBJECT_NULL;
0a7de745 2040 }
0b4e3aa0 2041
0a7de745 2042 return control->moc_object;
0b4e3aa0
A
2043}
2044
5ba3f43e
A
2045__private_extern__ vm_object_t
2046memory_object_to_vm_object(
2047 memory_object_t mem_obj)
2048{
2049 memory_object_control_t mo_control;
2050
2051 if (mem_obj == MEMORY_OBJECT_NULL) {
2052 return VM_OBJECT_NULL;
2053 }
2054 mo_control = mem_obj->mo_control;
2055 if (mo_control == NULL) {
2056 return VM_OBJECT_NULL;
2057 }
2058 return memory_object_control_to_vm_object(mo_control);
2059}
2060
0b4e3aa0
A
2061memory_object_control_t
2062convert_port_to_mo_control(
0a7de745 2063 __unused mach_port_t port)
0b4e3aa0
A
2064{
2065 return MEMORY_OBJECT_CONTROL_NULL;
2066}
2067
2068
2069mach_port_t
2070convert_mo_control_to_port(
0a7de745 2071 __unused memory_object_control_t control)
0b4e3aa0
A
2072{
2073 return MACH_PORT_NULL;
2074}
2075
2076void
2077memory_object_control_reference(
0a7de745 2078 __unused memory_object_control_t control)
0b4e3aa0
A
2079{
2080 return;
2081}
2082
2083/*
2084 * We only every issue one of these references, so kill it
2085 * when that gets released (should switch the real reference
2086 * counting in true port-less EMMI).
2087 */
2088void
2089memory_object_control_deallocate(
0a7de745 2090 memory_object_control_t control)
0b4e3aa0 2091{
91447636 2092 zfree(mem_obj_control_zone, control);
0b4e3aa0
A
2093}
2094
2095void
2096memory_object_control_disable(
0a7de745 2097 memory_object_control_t control)
0b4e3aa0 2098{
0c530ab8
A
2099 assert(control->moc_object != VM_OBJECT_NULL);
2100 control->moc_object = VM_OBJECT_NULL;
0b4e3aa0
A
2101}
2102
2103void
2104memory_object_default_reference(
2105 memory_object_default_t dmm)
2106{
2107 ipc_port_make_send(dmm);
2108}
2109
2110void
2111memory_object_default_deallocate(
2112 memory_object_default_t dmm)
2113{
2114 ipc_port_release_send(dmm);
2115}
2116
2117memory_object_t
2118convert_port_to_memory_object(
0a7de745 2119 __unused mach_port_t port)
0b4e3aa0 2120{
0a7de745 2121 return MEMORY_OBJECT_NULL;
0b4e3aa0
A
2122}
2123
2124
2125mach_port_t
2126convert_memory_object_to_port(
0a7de745 2127 __unused memory_object_t object)
0b4e3aa0 2128{
0a7de745 2129 return MACH_PORT_NULL;
0b4e3aa0
A
2130}
2131
0b4e3aa0
A
2132
2133/* Routine memory_object_reference */
0a7de745
A
2134void
2135memory_object_reference(
0b4e3aa0
A
2136 memory_object_t memory_object)
2137{
0c530ab8
A
2138 (memory_object->mo_pager_ops->memory_object_reference)(
2139 memory_object);
0b4e3aa0
A
2140}
2141
2142/* Routine memory_object_deallocate */
0a7de745
A
2143void
2144memory_object_deallocate(
0b4e3aa0
A
2145 memory_object_t memory_object)
2146{
0c530ab8 2147 (memory_object->mo_pager_ops->memory_object_deallocate)(
0a7de745 2148 memory_object);
0b4e3aa0
A
2149}
2150
2151
2152/* Routine memory_object_init */
0a7de745
A
2153kern_return_t
2154memory_object_init
0b4e3aa0
A
2155(
2156 memory_object_t memory_object,
2157 memory_object_control_t memory_control,
91447636 2158 memory_object_cluster_size_t memory_object_page_size
0b4e3aa0
A
2159)
2160{
0c530ab8
A
2161 return (memory_object->mo_pager_ops->memory_object_init)(
2162 memory_object,
2163 memory_control,
2164 memory_object_page_size);
0b4e3aa0
A
2165}
2166
2167/* Routine memory_object_terminate */
0a7de745
A
2168kern_return_t
2169memory_object_terminate
0b4e3aa0
A
2170(
2171 memory_object_t memory_object
2172)
2173{
0c530ab8
A
2174 return (memory_object->mo_pager_ops->memory_object_terminate)(
2175 memory_object);
0b4e3aa0
A
2176}
2177
2178/* Routine memory_object_data_request */
0a7de745
A
2179kern_return_t
2180memory_object_data_request
0b4e3aa0
A
2181(
2182 memory_object_t memory_object,
2183 memory_object_offset_t offset,
91447636 2184 memory_object_cluster_size_t length,
2d21ac55
A
2185 vm_prot_t desired_access,
2186 memory_object_fault_info_t fault_info
0b4e3aa0
A
2187)
2188{
0c530ab8
A
2189 return (memory_object->mo_pager_ops->memory_object_data_request)(
2190 memory_object,
0a7de745 2191 offset,
0c530ab8 2192 length,
2d21ac55
A
2193 desired_access,
2194 fault_info);
0b4e3aa0
A
2195}
2196
2197/* Routine memory_object_data_return */
0a7de745
A
2198kern_return_t
2199memory_object_data_return
0b4e3aa0
A
2200(
2201 memory_object_t memory_object,
2202 memory_object_offset_t offset,
b0d623f7 2203 memory_object_cluster_size_t size,
91447636 2204 memory_object_offset_t *resid_offset,
0a7de745 2205 int *io_error,
0b4e3aa0 2206 boolean_t dirty,
91447636 2207 boolean_t kernel_copy,
0a7de745 2208 int upl_flags
0b4e3aa0
A
2209)
2210{
0c530ab8
A
2211 return (memory_object->mo_pager_ops->memory_object_data_return)(
2212 memory_object,
2213 offset,
2214 size,
2215 resid_offset,
2216 io_error,
2217 dirty,
2218 kernel_copy,
2219 upl_flags);
0b4e3aa0
A
2220}
2221
2222/* Routine memory_object_data_initialize */
0a7de745
A
2223kern_return_t
2224memory_object_data_initialize
0b4e3aa0
A
2225(
2226 memory_object_t memory_object,
2227 memory_object_offset_t offset,
b0d623f7 2228 memory_object_cluster_size_t size
0b4e3aa0
A
2229)
2230{
0c530ab8
A
2231 return (memory_object->mo_pager_ops->memory_object_data_initialize)(
2232 memory_object,
2233 offset,
2234 size);
0b4e3aa0
A
2235}
2236
2237/* Routine memory_object_data_unlock */
0a7de745
A
2238kern_return_t
2239memory_object_data_unlock
0b4e3aa0
A
2240(
2241 memory_object_t memory_object,
2242 memory_object_offset_t offset,
b0d623f7 2243 memory_object_size_t size,
0b4e3aa0
A
2244 vm_prot_t desired_access
2245)
2246{
0c530ab8
A
2247 return (memory_object->mo_pager_ops->memory_object_data_unlock)(
2248 memory_object,
2249 offset,
2250 size,
2251 desired_access);
0b4e3aa0
A
2252}
2253
2254/* Routine memory_object_synchronize */
0a7de745
A
2255kern_return_t
2256memory_object_synchronize
0b4e3aa0
A
2257(
2258 memory_object_t memory_object,
2259 memory_object_offset_t offset,
b0d623f7 2260 memory_object_size_t size,
0b4e3aa0
A
2261 vm_sync_t sync_flags
2262)
2263{
0a7de745 2264 panic("memory_object_syncrhonize no longer supported\n");
5ba3f43e 2265
0c530ab8
A
2266 return (memory_object->mo_pager_ops->memory_object_synchronize)(
2267 memory_object,
2268 offset,
2269 size,
2270 sync_flags);
0b4e3aa0
A
2271}
2272
593a1d5f
A
2273
2274/*
2275 * memory_object_map() is called by VM (in vm_map_enter() and its variants)
2276 * each time a "named" VM object gets mapped directly or indirectly
2277 * (copy-on-write mapping). A "named" VM object has an extra reference held
0a7de745 2278 * by the pager to keep it alive until the pager decides that the
593a1d5f
A
2279 * memory object (and its VM object) can be reclaimed.
2280 * VM calls memory_object_last_unmap() (in vm_object_deallocate()) when all
2281 * the mappings of that memory object have been removed.
2282 *
2283 * For a given VM object, calls to memory_object_map() and memory_object_unmap()
2284 * are serialized (through object->mapping_in_progress), to ensure that the
2285 * pager gets a consistent view of the mapping status of the memory object.
2286 *
2287 * This allows the pager to keep track of how many times a memory object
2288 * has been mapped and with which protections, to decide when it can be
2289 * reclaimed.
2290 */
2291
2292/* Routine memory_object_map */
0a7de745
A
2293kern_return_t
2294memory_object_map
593a1d5f
A
2295(
2296 memory_object_t memory_object,
2297 vm_prot_t prot
2298)
2299{
2300 return (memory_object->mo_pager_ops->memory_object_map)(
2301 memory_object,
2302 prot);
2303}
2304
2305/* Routine memory_object_last_unmap */
0a7de745
A
2306kern_return_t
2307memory_object_last_unmap
0b4e3aa0
A
2308(
2309 memory_object_t memory_object
2310)
2311{
593a1d5f 2312 return (memory_object->mo_pager_ops->memory_object_last_unmap)(
0c530ab8 2313 memory_object);
0b4e3aa0
A
2314}
2315
6d2010ae 2316/* Routine memory_object_data_reclaim */
0a7de745
A
2317kern_return_t
2318memory_object_data_reclaim
6d2010ae
A
2319(
2320 memory_object_t memory_object,
0a7de745 2321 boolean_t reclaim_backing_store
6d2010ae
A
2322)
2323{
0a7de745 2324 if (memory_object->mo_pager_ops->memory_object_data_reclaim == NULL) {
6d2010ae 2325 return KERN_NOT_SUPPORTED;
0a7de745 2326 }
6d2010ae
A
2327 return (memory_object->mo_pager_ops->memory_object_data_reclaim)(
2328 memory_object,
2329 reclaim_backing_store);
2330}
2331
91447636
A
2332upl_t
2333convert_port_to_upl(
0a7de745 2334 ipc_port_t port)
91447636
A
2335{
2336 upl_t upl;
2337
2338 ip_lock(port);
2339 if (!ip_active(port) || (ip_kotype(port) != IKOT_UPL)) {
0a7de745
A
2340 ip_unlock(port);
2341 return (upl_t)NULL;
91447636 2342 }
ea3f0419 2343 upl = (upl_t) ip_get_kobject(port);
91447636
A
2344 ip_unlock(port);
2345 upl_lock(upl);
0a7de745 2346 upl->ref_count += 1;
91447636
A
2347 upl_unlock(upl);
2348 return upl;
2349}
2350
2351mach_port_t
2352convert_upl_to_port(
0a7de745 2353 __unused upl_t upl)
91447636
A
2354{
2355 return MACH_PORT_NULL;
2356}
2357
2358__private_extern__ void
2359upl_no_senders(
0a7de745
A
2360 __unused ipc_port_t port,
2361 __unused mach_port_mscount_t mscount)
91447636
A
2362{
2363 return;
2364}