]> git.saurik.com Git - apple/xnu.git/blame - osfmk/vm/vm_resident.c
xnu-3789.21.4.tar.gz
[apple/xnu.git] / osfmk / vm / vm_resident.c
CommitLineData
1c79356b 1/*
b0d623f7 2 * Copyright (c) 2000-2009 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,1987 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_page.c
60 * Author: Avadis Tevanian, Jr., Michael Wayne Young
61 *
62 * Resident memory management module.
63 */
64
91447636 65#include <debug.h>
2d21ac55 66#include <libkern/OSAtomic.h>
3e170ce0 67#include <libkern/OSDebug.h>
91447636 68
9bccf70c 69#include <mach/clock_types.h>
1c79356b
A
70#include <mach/vm_prot.h>
71#include <mach/vm_statistics.h>
2d21ac55 72#include <mach/sdt.h>
1c79356b
A
73#include <kern/counters.h>
74#include <kern/sched_prim.h>
39037602 75#include <kern/policy_internal.h>
1c79356b
A
76#include <kern/task.h>
77#include <kern/thread.h>
b0d623f7 78#include <kern/kalloc.h>
1c79356b
A
79#include <kern/zalloc.h>
80#include <kern/xpr.h>
fe8ab488 81#include <kern/ledger.h>
1c79356b
A
82#include <vm/pmap.h>
83#include <vm/vm_init.h>
84#include <vm/vm_map.h>
85#include <vm/vm_page.h>
86#include <vm/vm_pageout.h>
87#include <vm/vm_kern.h> /* kernel_memory_allocate() */
88#include <kern/misc_protos.h>
89#include <zone_debug.h>
3e170ce0 90#include <mach_debug/zone_info.h>
1c79356b 91#include <vm/cpm.h>
6d2010ae 92#include <pexpert/pexpert.h>
55e303ae 93
91447636 94#include <vm/vm_protos.h>
2d21ac55
A
95#include <vm/memory_object.h>
96#include <vm/vm_purgeable_internal.h>
39236c6e 97#include <vm/vm_compressor.h>
2d21ac55 98
fe8ab488
A
99#if CONFIG_PHANTOM_CACHE
100#include <vm/vm_phantom_cache.h>
101#endif
102
b0d623f7
A
103#include <IOKit/IOHibernatePrivate.h>
104
b0d623f7
A
105#include <sys/kdebug.h>
106
39037602
A
107
108char vm_page_inactive_states[VM_PAGE_Q_STATE_ARRAY_SIZE];
109char vm_page_pageable_states[VM_PAGE_Q_STATE_ARRAY_SIZE];
110char vm_page_non_speculative_pageable_states[VM_PAGE_Q_STATE_ARRAY_SIZE];
111char vm_page_active_or_inactive_states[VM_PAGE_Q_STATE_ARRAY_SIZE];
112
113#if CONFIG_SECLUDED_MEMORY
114struct vm_page_secluded_data vm_page_secluded;
115#endif /* CONFIG_SECLUDED_MEMORY */
116
316670eb 117boolean_t hibernate_cleaning_in_progress = FALSE;
b0d623f7
A
118boolean_t vm_page_free_verify = TRUE;
119
6d2010ae
A
120uint32_t vm_lopage_free_count = 0;
121uint32_t vm_lopage_free_limit = 0;
122uint32_t vm_lopage_lowater = 0;
0b4c1975
A
123boolean_t vm_lopage_refill = FALSE;
124boolean_t vm_lopage_needed = FALSE;
125
b0d623f7
A
126lck_mtx_ext_t vm_page_queue_lock_ext;
127lck_mtx_ext_t vm_page_queue_free_lock_ext;
128lck_mtx_ext_t vm_purgeable_queue_lock_ext;
2d21ac55 129
0b4c1975
A
130int speculative_age_index = 0;
131int speculative_steal_index = 0;
2d21ac55
A
132struct vm_speculative_age_q vm_page_queue_speculative[VM_PAGE_MAX_SPECULATIVE_AGE_Q + 1];
133
0b4e3aa0 134
b0d623f7
A
135__private_extern__ void vm_page_init_lck_grp(void);
136
6d2010ae
A
137static void vm_page_free_prepare(vm_page_t page);
138static vm_page_t vm_page_grab_fictitious_common(ppnum_t phys_addr);
139
3e170ce0 140static void vm_tag_init(void);
b0d623f7 141
3e170ce0 142uint64_t vm_min_kernel_and_kext_address = VM_MIN_KERNEL_AND_KEXT_ADDRESS;
39037602
A
143uint32_t vm_packed_from_vm_pages_array_mask = VM_PACKED_FROM_VM_PAGES_ARRAY;
144uint32_t vm_packed_pointer_shift = VM_PACKED_POINTER_SHIFT;
b0d623f7 145
1c79356b
A
146/*
147 * Associated with page of user-allocatable memory is a
148 * page structure.
149 */
150
151/*
152 * These variables record the values returned by vm_page_bootstrap,
153 * for debugging purposes. The implementation of pmap_steal_memory
154 * and pmap_startup here also uses them internally.
155 */
156
157vm_offset_t virtual_space_start;
158vm_offset_t virtual_space_end;
7ddcb079 159uint32_t vm_page_pages;
1c79356b
A
160
161/*
162 * The vm_page_lookup() routine, which provides for fast
163 * (virtual memory object, offset) to page lookup, employs
164 * the following hash table. The vm_page_{insert,remove}
165 * routines install and remove associations in the table.
166 * [This table is often called the virtual-to-physical,
167 * or VP, table.]
168 */
169typedef struct {
fe8ab488 170 vm_page_packed_t page_list;
1c79356b
A
171#if MACH_PAGE_HASH_STATS
172 int cur_count; /* current count */
173 int hi_count; /* high water mark */
174#endif /* MACH_PAGE_HASH_STATS */
175} vm_page_bucket_t;
176
b0d623f7
A
177
178#define BUCKETS_PER_LOCK 16
179
1c79356b
A
180vm_page_bucket_t *vm_page_buckets; /* Array of buckets */
181unsigned int vm_page_bucket_count = 0; /* How big is array? */
182unsigned int vm_page_hash_mask; /* Mask for hash function */
183unsigned int vm_page_hash_shift; /* Shift for hash function */
2d21ac55 184uint32_t vm_page_bucket_hash; /* Basic bucket hash */
b0d623f7
A
185unsigned int vm_page_bucket_lock_count = 0; /* How big is array of locks? */
186
187lck_spin_t *vm_page_bucket_locks;
3e170ce0
A
188lck_spin_t vm_objects_wired_lock;
189lck_spin_t vm_allocation_sites_lock;
1c79356b 190
15129b1c
A
191#if VM_PAGE_BUCKETS_CHECK
192boolean_t vm_page_buckets_check_ready = FALSE;
193#if VM_PAGE_FAKE_BUCKETS
194vm_page_bucket_t *vm_page_fake_buckets; /* decoy buckets */
195vm_map_offset_t vm_page_fake_buckets_start, vm_page_fake_buckets_end;
196#endif /* VM_PAGE_FAKE_BUCKETS */
197#endif /* VM_PAGE_BUCKETS_CHECK */
91447636 198
3e170ce0
A
199
200
1c79356b
A
201#if MACH_PAGE_HASH_STATS
202/* This routine is only for debug. It is intended to be called by
203 * hand by a developer using a kernel debugger. This routine prints
204 * out vm_page_hash table statistics to the kernel debug console.
205 */
206void
207hash_debug(void)
208{
209 int i;
210 int numbuckets = 0;
211 int highsum = 0;
212 int maxdepth = 0;
213
214 for (i = 0; i < vm_page_bucket_count; i++) {
215 if (vm_page_buckets[i].hi_count) {
216 numbuckets++;
217 highsum += vm_page_buckets[i].hi_count;
218 if (vm_page_buckets[i].hi_count > maxdepth)
219 maxdepth = vm_page_buckets[i].hi_count;
220 }
221 }
222 printf("Total number of buckets: %d\n", vm_page_bucket_count);
223 printf("Number used buckets: %d = %d%%\n",
224 numbuckets, 100*numbuckets/vm_page_bucket_count);
225 printf("Number unused buckets: %d = %d%%\n",
226 vm_page_bucket_count - numbuckets,
227 100*(vm_page_bucket_count-numbuckets)/vm_page_bucket_count);
228 printf("Sum of bucket max depth: %d\n", highsum);
229 printf("Average bucket depth: %d.%2d\n",
230 highsum/vm_page_bucket_count,
231 highsum%vm_page_bucket_count);
232 printf("Maximum bucket depth: %d\n", maxdepth);
233}
234#endif /* MACH_PAGE_HASH_STATS */
235
236/*
237 * The virtual page size is currently implemented as a runtime
238 * variable, but is constant once initialized using vm_set_page_size.
239 * This initialization must be done in the machine-dependent
240 * bootstrap sequence, before calling other machine-independent
241 * initializations.
242 *
243 * All references to the virtual page size outside this
244 * module must use the PAGE_SIZE, PAGE_MASK and PAGE_SHIFT
245 * constants.
246 */
55e303ae
A
247vm_size_t page_size = PAGE_SIZE;
248vm_size_t page_mask = PAGE_MASK;
2d21ac55 249int page_shift = PAGE_SHIFT;
1c79356b
A
250
251/*
252 * Resident page structures are initialized from
253 * a template (see vm_page_alloc).
254 *
255 * When adding a new field to the virtual memory
256 * object structure, be sure to add initialization
257 * (see vm_page_bootstrap).
258 */
259struct vm_page vm_page_template;
260
2d21ac55 261vm_page_t vm_pages = VM_PAGE_NULL;
39037602
A
262vm_page_t vm_page_array_beginning_addr;
263vm_page_t vm_page_array_ending_addr;
264
2d21ac55 265unsigned int vm_pages_count = 0;
0b4c1975 266ppnum_t vm_page_lowest = 0;
2d21ac55 267
1c79356b
A
268/*
269 * Resident pages that represent real memory
2d21ac55
A
270 * are allocated from a set of free lists,
271 * one per color.
1c79356b 272 */
2d21ac55
A
273unsigned int vm_colors;
274unsigned int vm_color_mask; /* mask is == (vm_colors-1) */
275unsigned int vm_cache_geometry_colors = 0; /* set by hw dependent code during startup */
fe8ab488 276unsigned int vm_free_magazine_refill_limit = 0;
39037602
A
277
278
279struct vm_page_queue_free_head {
280 vm_page_queue_head_t qhead;
281} __attribute__((aligned(VM_PACKED_POINTER_ALIGNMENT)));
282
283struct vm_page_queue_free_head vm_page_queue_free[MAX_COLORS];
284
285
1c79356b 286unsigned int vm_page_free_wanted;
2d21ac55 287unsigned int vm_page_free_wanted_privileged;
39037602
A
288#if CONFIG_SECLUDED_MEMORY
289unsigned int vm_page_free_wanted_secluded;
290#endif /* CONFIG_SECLUDED_MEMORY */
91447636 291unsigned int vm_page_free_count;
1c79356b 292
1c79356b
A
293/*
294 * Occasionally, the virtual memory system uses
295 * resident page structures that do not refer to
296 * real pages, for example to leave a page with
297 * important state information in the VP table.
298 *
299 * These page structures are allocated the way
300 * most other kernel structures are.
301 */
39037602 302zone_t vm_page_array_zone;
1c79356b 303zone_t vm_page_zone;
b0d623f7
A
304vm_locks_array_t vm_page_locks;
305decl_lck_mtx_data(,vm_page_alloc_lock)
316670eb
A
306lck_mtx_ext_t vm_page_alloc_lock_ext;
307
9bccf70c 308unsigned int io_throttle_zero_fill;
1c79356b 309
b0d623f7
A
310unsigned int vm_page_local_q_count = 0;
311unsigned int vm_page_local_q_soft_limit = 250;
312unsigned int vm_page_local_q_hard_limit = 500;
313struct vplq *vm_page_local_q = NULL;
314
316670eb
A
315/* N.B. Guard and fictitious pages must not
316 * be assigned a zero phys_page value.
317 */
1c79356b
A
318/*
319 * Fictitious pages don't have a physical address,
55e303ae 320 * but we must initialize phys_page to something.
1c79356b
A
321 * For debugging, this should be a strange value
322 * that the pmap module can recognize in assertions.
323 */
b0d623f7 324ppnum_t vm_page_fictitious_addr = (ppnum_t) -1;
1c79356b 325
2d21ac55
A
326/*
327 * Guard pages are not accessible so they don't
328 * need a physical address, but we need to enter
329 * one in the pmap.
330 * Let's make it recognizable and make sure that
331 * we don't use a real physical page with that
332 * physical address.
333 */
b0d623f7 334ppnum_t vm_page_guard_addr = (ppnum_t) -2;
2d21ac55 335
1c79356b
A
336/*
337 * Resident page structures are also chained on
338 * queues that are used by the page replacement
339 * system (pageout daemon). These queues are
340 * defined here, but are shared by the pageout
9bccf70c 341 * module. The inactive queue is broken into
39236c6e 342 * file backed and anonymous for convenience as the
9bccf70c 343 * pageout daemon often assignes a higher
39236c6e 344 * importance to anonymous pages (less likely to pick)
1c79356b 345 */
39037602
A
346vm_page_queue_head_t vm_page_queue_active __attribute__((aligned(VM_PACKED_POINTER_ALIGNMENT)));
347vm_page_queue_head_t vm_page_queue_inactive __attribute__((aligned(VM_PACKED_POINTER_ALIGNMENT)));
348#if CONFIG_SECLUDED_MEMORY
349vm_page_queue_head_t vm_page_queue_secluded __attribute__((aligned(VM_PACKED_POINTER_ALIGNMENT)));
350#endif /* CONFIG_SECLUDED_MEMORY */
351vm_page_queue_head_t vm_page_queue_anonymous __attribute__((aligned(VM_PACKED_POINTER_ALIGNMENT))); /* inactive memory queue for anonymous pages */
352vm_page_queue_head_t vm_page_queue_throttled __attribute__((aligned(VM_PACKED_POINTER_ALIGNMENT)));
2d21ac55 353
3e170ce0
A
354queue_head_t vm_objects_wired;
355
39037602
A
356#if CONFIG_BACKGROUND_QUEUE
357vm_page_queue_head_t vm_page_queue_background __attribute__((aligned(VM_PACKED_POINTER_ALIGNMENT)));
358uint32_t vm_page_background_limit;
359uint32_t vm_page_background_target;
360uint32_t vm_page_background_count;
361uint64_t vm_page_background_promoted_count;
362
363uint32_t vm_page_background_internal_count;
364uint32_t vm_page_background_external_count;
365
366uint32_t vm_page_background_mode;
367uint32_t vm_page_background_exclude_external;
368#endif
369
91447636
A
370unsigned int vm_page_active_count;
371unsigned int vm_page_inactive_count;
39037602
A
372#if CONFIG_SECLUDED_MEMORY
373unsigned int vm_page_secluded_count;
374unsigned int vm_page_secluded_count_free;
375unsigned int vm_page_secluded_count_inuse;
376#endif /* CONFIG_SECLUDED_MEMORY */
316670eb 377unsigned int vm_page_anonymous_count;
2d21ac55
A
378unsigned int vm_page_throttled_count;
379unsigned int vm_page_speculative_count;
3e170ce0 380
91447636 381unsigned int vm_page_wire_count;
3e170ce0 382unsigned int vm_page_stolen_count;
0b4c1975 383unsigned int vm_page_wire_count_initial;
3e170ce0 384unsigned int vm_page_pages_initial;
91447636 385unsigned int vm_page_gobble_count = 0;
fe8ab488
A
386
387#define VM_PAGE_WIRE_COUNT_WARNING 0
388#define VM_PAGE_GOBBLE_COUNT_WARNING 0
91447636
A
389
390unsigned int vm_page_purgeable_count = 0; /* # of pages purgeable now */
b0d623f7 391unsigned int vm_page_purgeable_wired_count = 0; /* # of purgeable pages that are wired now */
91447636 392uint64_t vm_page_purged_count = 0; /* total count of purged pages */
1c79356b 393
fe8ab488 394unsigned int vm_page_xpmapped_external_count = 0;
39236c6e
A
395unsigned int vm_page_external_count = 0;
396unsigned int vm_page_internal_count = 0;
397unsigned int vm_page_pageable_external_count = 0;
398unsigned int vm_page_pageable_internal_count = 0;
399
b0d623f7 400#if DEVELOPMENT || DEBUG
2d21ac55
A
401unsigned int vm_page_speculative_recreated = 0;
402unsigned int vm_page_speculative_created = 0;
403unsigned int vm_page_speculative_used = 0;
b0d623f7 404#endif
2d21ac55 405
39037602 406vm_page_queue_head_t vm_page_queue_cleaned __attribute__((aligned(VM_PACKED_POINTER_ALIGNMENT)));
316670eb
A
407
408unsigned int vm_page_cleaned_count = 0;
409unsigned int vm_pageout_enqueued_cleaned = 0;
410
0c530ab8 411uint64_t max_valid_dma_address = 0xffffffffffffffffULL;
0b4c1975 412ppnum_t max_valid_low_ppnum = 0xffffffff;
0c530ab8
A
413
414
1c79356b
A
415/*
416 * Several page replacement parameters are also
417 * shared with this module, so that page allocation
418 * (done here in vm_page_alloc) can trigger the
419 * pageout daemon.
420 */
91447636
A
421unsigned int vm_page_free_target = 0;
422unsigned int vm_page_free_min = 0;
b0d623f7 423unsigned int vm_page_throttle_limit = 0;
91447636 424unsigned int vm_page_inactive_target = 0;
39037602
A
425#if CONFIG_SECLUDED_MEMORY
426unsigned int vm_page_secluded_target = 0;
427#endif /* CONFIG_SECLUDED_MEMORY */
39236c6e 428unsigned int vm_page_anonymous_min = 0;
2d21ac55 429unsigned int vm_page_inactive_min = 0;
91447636 430unsigned int vm_page_free_reserved = 0;
b0d623f7 431unsigned int vm_page_throttle_count = 0;
1c79356b 432
316670eb 433
1c79356b
A
434/*
435 * The VM system has a couple of heuristics for deciding
436 * that pages are "uninteresting" and should be placed
437 * on the inactive queue as likely candidates for replacement.
438 * These variables let the heuristics be controlled at run-time
439 * to make experimentation easier.
440 */
441
442boolean_t vm_page_deactivate_hint = TRUE;
443
b0d623f7
A
444struct vm_page_stats_reusable vm_page_stats_reusable;
445
1c79356b
A
446/*
447 * vm_set_page_size:
448 *
449 * Sets the page size, perhaps based upon the memory
450 * size. Must be called before any use of page-size
451 * dependent functions.
452 *
453 * Sets page_shift and page_mask from page_size.
454 */
455void
456vm_set_page_size(void)
457{
fe8ab488
A
458 page_size = PAGE_SIZE;
459 page_mask = PAGE_MASK;
460 page_shift = PAGE_SHIFT;
1c79356b
A
461
462 if ((page_mask & page_size) != 0)
463 panic("vm_set_page_size: page size not a power of two");
464
465 for (page_shift = 0; ; page_shift++)
91447636 466 if ((1U << page_shift) == page_size)
1c79356b 467 break;
1c79356b
A
468}
469
fe8ab488
A
470#define COLOR_GROUPS_TO_STEAL 4
471
2d21ac55
A
472
473/* Called once during statup, once the cache geometry is known.
474 */
475static void
476vm_page_set_colors( void )
477{
478 unsigned int n, override;
479
593a1d5f 480 if ( PE_parse_boot_argn("colors", &override, sizeof (override)) ) /* colors specified as a boot-arg? */
2d21ac55
A
481 n = override;
482 else if ( vm_cache_geometry_colors ) /* do we know what the cache geometry is? */
483 n = vm_cache_geometry_colors;
484 else n = DEFAULT_COLORS; /* use default if all else fails */
485
486 if ( n == 0 )
487 n = 1;
488 if ( n > MAX_COLORS )
489 n = MAX_COLORS;
490
491 /* the count must be a power of 2 */
b0d623f7 492 if ( ( n & (n - 1)) != 0 )
2d21ac55
A
493 panic("vm_page_set_colors");
494
495 vm_colors = n;
496 vm_color_mask = n - 1;
fe8ab488
A
497
498 vm_free_magazine_refill_limit = vm_colors * COLOR_GROUPS_TO_STEAL;
2d21ac55
A
499}
500
501
b0d623f7
A
502lck_grp_t vm_page_lck_grp_free;
503lck_grp_t vm_page_lck_grp_queue;
504lck_grp_t vm_page_lck_grp_local;
505lck_grp_t vm_page_lck_grp_purge;
506lck_grp_t vm_page_lck_grp_alloc;
507lck_grp_t vm_page_lck_grp_bucket;
508lck_grp_attr_t vm_page_lck_grp_attr;
509lck_attr_t vm_page_lck_attr;
510
511
512__private_extern__ void
513vm_page_init_lck_grp(void)
514{
515 /*
516 * initialze the vm_page lock world
517 */
518 lck_grp_attr_setdefault(&vm_page_lck_grp_attr);
519 lck_grp_init(&vm_page_lck_grp_free, "vm_page_free", &vm_page_lck_grp_attr);
520 lck_grp_init(&vm_page_lck_grp_queue, "vm_page_queue", &vm_page_lck_grp_attr);
521 lck_grp_init(&vm_page_lck_grp_local, "vm_page_queue_local", &vm_page_lck_grp_attr);
522 lck_grp_init(&vm_page_lck_grp_purge, "vm_page_purge", &vm_page_lck_grp_attr);
523 lck_grp_init(&vm_page_lck_grp_alloc, "vm_page_alloc", &vm_page_lck_grp_attr);
524 lck_grp_init(&vm_page_lck_grp_bucket, "vm_page_bucket", &vm_page_lck_grp_attr);
525 lck_attr_setdefault(&vm_page_lck_attr);
316670eb 526 lck_mtx_init_ext(&vm_page_alloc_lock, &vm_page_alloc_lock_ext, &vm_page_lck_grp_alloc, &vm_page_lck_attr);
39236c6e
A
527
528 vm_compressor_init_locks();
b0d623f7
A
529}
530
531void
532vm_page_init_local_q()
533{
534 unsigned int num_cpus;
535 unsigned int i;
536 struct vplq *t_local_q;
537
538 num_cpus = ml_get_max_cpus();
539
540 /*
541 * no point in this for a uni-processor system
542 */
543 if (num_cpus >= 2) {
544 t_local_q = (struct vplq *)kalloc(num_cpus * sizeof(struct vplq));
545
546 for (i = 0; i < num_cpus; i++) {
547 struct vpl *lq;
548
549 lq = &t_local_q[i].vpl_un.vpl;
550 VPL_LOCK_INIT(lq, &vm_page_lck_grp_local, &vm_page_lck_attr);
39037602 551 vm_page_queue_init(&lq->vpl_queue);
b0d623f7 552 lq->vpl_count = 0;
39236c6e
A
553 lq->vpl_internal_count = 0;
554 lq->vpl_external_count = 0;
b0d623f7
A
555 }
556 vm_page_local_q_count = num_cpus;
557
558 vm_page_local_q = (struct vplq *)t_local_q;
559 }
560}
561
562
1c79356b
A
563/*
564 * vm_page_bootstrap:
565 *
566 * Initializes the resident memory module.
567 *
568 * Allocates memory for the page cells, and
569 * for the object/offset-to-page hash table headers.
570 * Each page cell is initialized and placed on the free list.
571 * Returns the range of available kernel virtual memory.
572 */
573
574void
575vm_page_bootstrap(
576 vm_offset_t *startp,
577 vm_offset_t *endp)
578{
39037602 579 vm_page_t m;
91447636 580 unsigned int i;
1c79356b
A
581 unsigned int log1;
582 unsigned int log2;
583 unsigned int size;
584
585 /*
586 * Initialize the vm_page template.
587 */
588
589 m = &vm_page_template;
b0d623f7 590 bzero(m, sizeof (*m));
1c79356b 591
39037602
A
592#if CONFIG_BACKGROUND_QUEUE
593 m->vm_page_backgroundq.next = 0;
594 m->vm_page_backgroundq.prev = 0;
595 m->vm_page_in_background = FALSE;
596 m->vm_page_on_backgroundq = FALSE;
597#endif
598
599 VM_PAGE_ZERO_PAGEQ_ENTRY(m);
600 m->listq.next = 0;
601 m->listq.prev = 0;
602 m->next_m = 0;
91447636 603
39037602 604 m->vm_page_object = 0; /* reset later */
b0d623f7
A
605 m->offset = (vm_object_offset_t) -1; /* reset later */
606
607 m->wire_count = 0;
39037602 608 m->vm_page_q_state = VM_PAGE_NOT_ON_Q;
1c79356b 609 m->laundry = FALSE;
1c79356b 610 m->reference = FALSE;
b0d623f7
A
611 m->gobbled = FALSE;
612 m->private = FALSE;
b0d623f7
A
613 m->__unused_pageq_bits = 0;
614
39037602 615 VM_PAGE_SET_PHYS_PAGE(m, 0); /* reset later */
1c79356b
A
616 m->busy = TRUE;
617 m->wanted = FALSE;
618 m->tabled = FALSE;
15129b1c 619 m->hashed = FALSE;
1c79356b 620 m->fictitious = FALSE;
b0d623f7
A
621 m->pmapped = FALSE;
622 m->wpmapped = FALSE;
39037602 623 m->free_when_done = FALSE;
1c79356b
A
624 m->absent = FALSE;
625 m->error = FALSE;
626 m->dirty = FALSE;
627 m->cleaning = FALSE;
628 m->precious = FALSE;
629 m->clustered = FALSE;
b0d623f7 630 m->overwriting = FALSE;
1c79356b 631 m->restart = FALSE;
b0d623f7 632 m->unusual = FALSE;
91447636 633 m->encrypted = FALSE;
2d21ac55 634 m->encrypted_cleaning = FALSE;
b0d623f7
A
635 m->cs_validated = FALSE;
636 m->cs_tainted = FALSE;
c18c124e 637 m->cs_nx = FALSE;
b0d623f7 638 m->no_cache = FALSE;
b0d623f7 639 m->reusable = FALSE;
6d2010ae 640 m->slid = FALSE;
39236c6e 641 m->xpmapped = FALSE;
15129b1c 642 m->written_by_kernel = FALSE;
b0d623f7 643 m->__unused_object_bits = 0;
1c79356b 644
1c79356b
A
645 /*
646 * Initialize the page queues.
647 */
b0d623f7
A
648 vm_page_init_lck_grp();
649
650 lck_mtx_init_ext(&vm_page_queue_free_lock, &vm_page_queue_free_lock_ext, &vm_page_lck_grp_free, &vm_page_lck_attr);
651 lck_mtx_init_ext(&vm_page_queue_lock, &vm_page_queue_lock_ext, &vm_page_lck_grp_queue, &vm_page_lck_attr);
652 lck_mtx_init_ext(&vm_purgeable_queue_lock, &vm_purgeable_queue_lock_ext, &vm_page_lck_grp_purge, &vm_page_lck_attr);
2d21ac55
A
653
654 for (i = 0; i < PURGEABLE_Q_TYPE_MAX; i++) {
655 int group;
656
657 purgeable_queues[i].token_q_head = 0;
658 purgeable_queues[i].token_q_tail = 0;
659 for (group = 0; group < NUM_VOLATILE_GROUPS; group++)
660 queue_init(&purgeable_queues[i].objq[group]);
661
662 purgeable_queues[i].type = i;
663 purgeable_queues[i].new_pages = 0;
664#if MACH_ASSERT
665 purgeable_queues[i].debug_count_tokens = 0;
666 purgeable_queues[i].debug_count_objects = 0;
667#endif
668 };
fe8ab488
A
669 purgeable_nonvolatile_count = 0;
670 queue_init(&purgeable_nonvolatile_queue);
2d21ac55
A
671
672 for (i = 0; i < MAX_COLORS; i++ )
39037602
A
673 vm_page_queue_init(&vm_page_queue_free[i].qhead);
674
675 vm_page_queue_init(&vm_lopage_queue_free);
676 vm_page_queue_init(&vm_page_queue_active);
677 vm_page_queue_init(&vm_page_queue_inactive);
678#if CONFIG_SECLUDED_MEMORY
679 vm_page_queue_init(&vm_page_queue_secluded);
680#endif /* CONFIG_SECLUDED_MEMORY */
681 vm_page_queue_init(&vm_page_queue_cleaned);
682 vm_page_queue_init(&vm_page_queue_throttled);
683 vm_page_queue_init(&vm_page_queue_anonymous);
3e170ce0 684 queue_init(&vm_objects_wired);
1c79356b 685
2d21ac55 686 for ( i = 0; i <= VM_PAGE_MAX_SPECULATIVE_AGE_Q; i++ ) {
39037602 687 vm_page_queue_init(&vm_page_queue_speculative[i].age_q);
2d21ac55
A
688
689 vm_page_queue_speculative[i].age_ts.tv_sec = 0;
690 vm_page_queue_speculative[i].age_ts.tv_nsec = 0;
691 }
39037602
A
692#if CONFIG_BACKGROUND_QUEUE
693 vm_page_queue_init(&vm_page_queue_background);
694
695 vm_page_background_count = 0;
696 vm_page_background_internal_count = 0;
697 vm_page_background_external_count = 0;
698 vm_page_background_promoted_count = 0;
699
700 vm_page_background_target = (unsigned int)(atop_64(max_mem) / 25);
701
702 if (vm_page_background_target > VM_PAGE_BACKGROUND_TARGET_MAX)
703 vm_page_background_target = VM_PAGE_BACKGROUND_TARGET_MAX;
704 vm_page_background_limit = vm_page_background_target + 256;
705
706 vm_page_background_mode = VM_PAGE_BG_LEVEL_1;
707 vm_page_background_exclude_external = 0;
708
709 PE_parse_boot_argn("vm_page_bg_mode", &vm_page_background_mode, sizeof(vm_page_background_mode));
710 PE_parse_boot_argn("vm_page_bg_exclude_external", &vm_page_background_exclude_external, sizeof(vm_page_background_exclude_external));
711 PE_parse_boot_argn("vm_page_bg_target", &vm_page_background_target, sizeof(vm_page_background_target));
712 PE_parse_boot_argn("vm_page_bg_limit", &vm_page_background_limit, sizeof(vm_page_background_limit));
713
714 if (vm_page_background_mode > VM_PAGE_BG_LEVEL_3)
715 vm_page_background_mode = VM_PAGE_BG_LEVEL_1;
716
717 if (vm_page_background_limit <= vm_page_background_target)
718 vm_page_background_limit = vm_page_background_target + 256;
719#endif
1c79356b 720 vm_page_free_wanted = 0;
2d21ac55 721 vm_page_free_wanted_privileged = 0;
39037602
A
722#if CONFIG_SECLUDED_MEMORY
723 vm_page_free_wanted_secluded = 0;
724#endif /* CONFIG_SECLUDED_MEMORY */
2d21ac55
A
725
726 vm_page_set_colors();
727
39037602
A
728 bzero(vm_page_inactive_states, sizeof(vm_page_inactive_states));
729 vm_page_inactive_states[VM_PAGE_ON_INACTIVE_INTERNAL_Q] = 1;
730 vm_page_inactive_states[VM_PAGE_ON_INACTIVE_EXTERNAL_Q] = 1;
731 vm_page_inactive_states[VM_PAGE_ON_INACTIVE_CLEANED_Q] = 1;
732
733 bzero(vm_page_pageable_states, sizeof(vm_page_pageable_states));
734 vm_page_pageable_states[VM_PAGE_ON_INACTIVE_INTERNAL_Q] = 1;
735 vm_page_pageable_states[VM_PAGE_ON_INACTIVE_EXTERNAL_Q] = 1;
736 vm_page_pageable_states[VM_PAGE_ON_INACTIVE_CLEANED_Q] = 1;
737 vm_page_pageable_states[VM_PAGE_ON_ACTIVE_Q] = 1;
738 vm_page_pageable_states[VM_PAGE_ON_SPECULATIVE_Q] = 1;
739 vm_page_pageable_states[VM_PAGE_ON_THROTTLED_Q] = 1;
740#if CONFIG_SECLUDED_MEMORY
741 vm_page_pageable_states[VM_PAGE_ON_SECLUDED_Q] = 1;
742#endif /* CONFIG_SECLUDED_MEMORY */
743
744 bzero(vm_page_non_speculative_pageable_states, sizeof(vm_page_non_speculative_pageable_states));
745 vm_page_non_speculative_pageable_states[VM_PAGE_ON_INACTIVE_INTERNAL_Q] = 1;
746 vm_page_non_speculative_pageable_states[VM_PAGE_ON_INACTIVE_EXTERNAL_Q] = 1;
747 vm_page_non_speculative_pageable_states[VM_PAGE_ON_INACTIVE_CLEANED_Q] = 1;
748 vm_page_non_speculative_pageable_states[VM_PAGE_ON_ACTIVE_Q] = 1;
749 vm_page_non_speculative_pageable_states[VM_PAGE_ON_THROTTLED_Q] = 1;
750#if CONFIG_SECLUDED_MEMORY
751 vm_page_non_speculative_pageable_states[VM_PAGE_ON_SECLUDED_Q] = 1;
752#endif /* CONFIG_SECLUDED_MEMORY */
753
754 bzero(vm_page_active_or_inactive_states, sizeof(vm_page_active_or_inactive_states));
755 vm_page_active_or_inactive_states[VM_PAGE_ON_INACTIVE_INTERNAL_Q] = 1;
756 vm_page_active_or_inactive_states[VM_PAGE_ON_INACTIVE_EXTERNAL_Q] = 1;
757 vm_page_active_or_inactive_states[VM_PAGE_ON_INACTIVE_CLEANED_Q] = 1;
758 vm_page_active_or_inactive_states[VM_PAGE_ON_ACTIVE_Q] = 1;
759#if CONFIG_SECLUDED_MEMORY
760 vm_page_active_or_inactive_states[VM_PAGE_ON_SECLUDED_Q] = 1;
761#endif /* CONFIG_SECLUDED_MEMORY */
762
1c79356b
A
763
764 /*
765 * Steal memory for the map and zone subsystems.
766 */
39037602
A
767#if CONFIG_GZALLOC
768 gzalloc_configure();
769#endif
770 kernel_debug_string_early("vm_map_steal_memory");
316670eb 771 vm_map_steal_memory();
1c79356b
A
772
773 /*
774 * Allocate (and initialize) the virtual-to-physical
775 * table hash buckets.
776 *
777 * The number of buckets should be a power of two to
778 * get a good hash function. The following computation
779 * chooses the first power of two that is greater
780 * than the number of physical pages in the system.
781 */
782
1c79356b
A
783 if (vm_page_bucket_count == 0) {
784 unsigned int npages = pmap_free_pages();
785
786 vm_page_bucket_count = 1;
787 while (vm_page_bucket_count < npages)
788 vm_page_bucket_count <<= 1;
789 }
b0d623f7 790 vm_page_bucket_lock_count = (vm_page_bucket_count + BUCKETS_PER_LOCK - 1) / BUCKETS_PER_LOCK;
1c79356b
A
791
792 vm_page_hash_mask = vm_page_bucket_count - 1;
793
794 /*
795 * Calculate object shift value for hashing algorithm:
796 * O = log2(sizeof(struct vm_object))
797 * B = log2(vm_page_bucket_count)
798 * hash shifts the object left by
799 * B/2 - O
800 */
801 size = vm_page_bucket_count;
802 for (log1 = 0; size > 1; log1++)
803 size /= 2;
804 size = sizeof(struct vm_object);
805 for (log2 = 0; size > 1; log2++)
806 size /= 2;
807 vm_page_hash_shift = log1/2 - log2 + 1;
55e303ae
A
808
809 vm_page_bucket_hash = 1 << ((log1 + 1) >> 1); /* Get (ceiling of sqrt of table size) */
810 vm_page_bucket_hash |= 1 << ((log1 + 1) >> 2); /* Get (ceiling of quadroot of table size) */
811 vm_page_bucket_hash |= 1; /* Set bit and add 1 - always must be 1 to insure unique series */
1c79356b
A
812
813 if (vm_page_hash_mask & vm_page_bucket_count)
814 printf("vm_page_bootstrap: WARNING -- strange page hash\n");
815
15129b1c
A
816#if VM_PAGE_BUCKETS_CHECK
817#if VM_PAGE_FAKE_BUCKETS
818 /*
819 * Allocate a decoy set of page buckets, to detect
820 * any stomping there.
821 */
822 vm_page_fake_buckets = (vm_page_bucket_t *)
823 pmap_steal_memory(vm_page_bucket_count *
824 sizeof(vm_page_bucket_t));
825 vm_page_fake_buckets_start = (vm_map_offset_t) vm_page_fake_buckets;
826 vm_page_fake_buckets_end =
827 vm_map_round_page((vm_page_fake_buckets_start +
828 (vm_page_bucket_count *
829 sizeof (vm_page_bucket_t))),
830 PAGE_MASK);
831 char *cp;
832 for (cp = (char *)vm_page_fake_buckets_start;
833 cp < (char *)vm_page_fake_buckets_end;
834 cp++) {
835 *cp = 0x5a;
836 }
837#endif /* VM_PAGE_FAKE_BUCKETS */
838#endif /* VM_PAGE_BUCKETS_CHECK */
839
39037602 840 kernel_debug_string_early("vm_page_buckets");
1c79356b
A
841 vm_page_buckets = (vm_page_bucket_t *)
842 pmap_steal_memory(vm_page_bucket_count *
843 sizeof(vm_page_bucket_t));
844
39037602 845 kernel_debug_string_early("vm_page_bucket_locks");
b0d623f7
A
846 vm_page_bucket_locks = (lck_spin_t *)
847 pmap_steal_memory(vm_page_bucket_lock_count *
848 sizeof(lck_spin_t));
849
1c79356b 850 for (i = 0; i < vm_page_bucket_count; i++) {
39037602 851 vm_page_bucket_t *bucket = &vm_page_buckets[i];
1c79356b 852
fe8ab488 853 bucket->page_list = VM_PAGE_PACK_PTR(VM_PAGE_NULL);
1c79356b
A
854#if MACH_PAGE_HASH_STATS
855 bucket->cur_count = 0;
856 bucket->hi_count = 0;
857#endif /* MACH_PAGE_HASH_STATS */
858 }
859
b0d623f7
A
860 for (i = 0; i < vm_page_bucket_lock_count; i++)
861 lck_spin_init(&vm_page_bucket_locks[i], &vm_page_lck_grp_bucket, &vm_page_lck_attr);
862
3e170ce0
A
863 lck_spin_init(&vm_objects_wired_lock, &vm_page_lck_grp_bucket, &vm_page_lck_attr);
864 lck_spin_init(&vm_allocation_sites_lock, &vm_page_lck_grp_bucket, &vm_page_lck_attr);
865 vm_tag_init();
866
15129b1c
A
867#if VM_PAGE_BUCKETS_CHECK
868 vm_page_buckets_check_ready = TRUE;
869#endif /* VM_PAGE_BUCKETS_CHECK */
870
1c79356b
A
871 /*
872 * Machine-dependent code allocates the resident page table.
873 * It uses vm_page_init to initialize the page frames.
874 * The code also returns to us the virtual space available
875 * to the kernel. We don't trust the pmap module
876 * to get the alignment right.
877 */
878
39037602 879 kernel_debug_string_early("pmap_startup");
1c79356b 880 pmap_startup(&virtual_space_start, &virtual_space_end);
91447636
A
881 virtual_space_start = round_page(virtual_space_start);
882 virtual_space_end = trunc_page(virtual_space_end);
1c79356b
A
883
884 *startp = virtual_space_start;
885 *endp = virtual_space_end;
886
887 /*
888 * Compute the initial "wire" count.
889 * Up until now, the pages which have been set aside are not under
890 * the VM system's control, so although they aren't explicitly
891 * wired, they nonetheless can't be moved. At this moment,
892 * all VM managed pages are "free", courtesy of pmap_startup.
893 */
b0d623f7 894 assert((unsigned int) atop_64(max_mem) == atop_64(max_mem));
0b4c1975 895 vm_page_wire_count = ((unsigned int) atop_64(max_mem)) - vm_page_free_count - vm_lopage_free_count; /* initial value */
39037602
A
896#if CONFIG_SECLUDED_MEMORY
897 vm_page_wire_count -= vm_page_secluded_count;
898#endif
0b4c1975 899 vm_page_wire_count_initial = vm_page_wire_count;
3e170ce0 900 vm_page_pages_initial = vm_page_pages;
91447636 901
2d21ac55
A
902 printf("vm_page_bootstrap: %d free pages and %d wired pages\n",
903 vm_page_free_count, vm_page_wire_count);
904
39037602 905 kernel_debug_string_early("vm_page_bootstrap complete");
91447636 906 simple_lock_init(&vm_paging_lock, 0);
1c79356b
A
907}
908
909#ifndef MACHINE_PAGES
910/*
911 * We implement pmap_steal_memory and pmap_startup with the help
912 * of two simpler functions, pmap_virtual_space and pmap_next_page.
913 */
914
91447636 915void *
1c79356b
A
916pmap_steal_memory(
917 vm_size_t size)
918{
55e303ae
A
919 vm_offset_t addr, vaddr;
920 ppnum_t phys_page;
1c79356b
A
921
922 /*
923 * We round the size to a round multiple.
924 */
925
926 size = (size + sizeof (void *) - 1) &~ (sizeof (void *) - 1);
927
928 /*
929 * If this is the first call to pmap_steal_memory,
930 * we have to initialize ourself.
931 */
932
933 if (virtual_space_start == virtual_space_end) {
934 pmap_virtual_space(&virtual_space_start, &virtual_space_end);
935
936 /*
937 * The initial values must be aligned properly, and
938 * we don't trust the pmap module to do it right.
939 */
940
91447636
A
941 virtual_space_start = round_page(virtual_space_start);
942 virtual_space_end = trunc_page(virtual_space_end);
1c79356b
A
943 }
944
945 /*
946 * Allocate virtual memory for this request.
947 */
948
949 addr = virtual_space_start;
950 virtual_space_start += size;
951
6d2010ae 952 //kprintf("pmap_steal_memory: %08lX - %08lX; size=%08lX\n", (long)addr, (long)virtual_space_start, (long)size); /* (TEST/DEBUG) */
1c79356b
A
953
954 /*
955 * Allocate and map physical pages to back new virtual pages.
956 */
957
91447636 958 for (vaddr = round_page(addr);
1c79356b
A
959 vaddr < addr + size;
960 vaddr += PAGE_SIZE) {
b0d623f7 961
0b4c1975 962 if (!pmap_next_page_hi(&phys_page))
39037602 963 panic("pmap_steal_memory() size: 0x%llx\n", (uint64_t)size);
1c79356b
A
964
965 /*
966 * XXX Logically, these mappings should be wired,
967 * but some pmap modules barf if they are.
968 */
b0d623f7
A
969#if defined(__LP64__)
970 pmap_pre_expand(kernel_pmap, vaddr);
971#endif
1c79356b 972
55e303ae 973 pmap_enter(kernel_pmap, vaddr, phys_page,
316670eb 974 VM_PROT_READ|VM_PROT_WRITE, VM_PROT_NONE,
9bccf70c 975 VM_WIMG_USE_DEFAULT, FALSE);
1c79356b
A
976 /*
977 * Account for newly stolen memory
978 */
979 vm_page_wire_count++;
3e170ce0 980 vm_page_stolen_count++;
1c79356b
A
981 }
982
91447636 983 return (void *) addr;
1c79356b
A
984}
985
39037602
A
986#if CONFIG_SECLUDED_MEMORY
987/* boot-args to control secluded memory */
988unsigned int secluded_mem_mb = 0; /* # of MBs of RAM to seclude */
989int secluded_for_iokit = 1; /* IOKit can use secluded memory */
990int secluded_for_apps = 1; /* apps can use secluded memory */
991int secluded_for_filecache = 2; /* filecache can use seclude memory */
992#if 11
993int secluded_for_fbdp = 0;
994#endif
995int secluded_aging_policy = SECLUDED_AGING_BEFORE_ACTIVE;
996#endif /* CONFIG_SECLUDED_MEMORY */
997
998
999
1000
fe8ab488 1001void vm_page_release_startup(vm_page_t mem);
1c79356b
A
1002void
1003pmap_startup(
1004 vm_offset_t *startp,
1005 vm_offset_t *endp)
1006{
55e303ae 1007 unsigned int i, npages, pages_initialized, fill, fillval;
55e303ae
A
1008 ppnum_t phys_page;
1009 addr64_t tmpaddr;
1c79356b 1010
fe8ab488 1011#if defined(__LP64__)
fe8ab488
A
1012 /*
1013 * make sure we are aligned on a 64 byte boundary
1014 * for VM_PAGE_PACK_PTR (it clips off the low-order
1015 * 6 bits of the pointer)
1016 */
1017 if (virtual_space_start != virtual_space_end)
1018 virtual_space_start = round_page(virtual_space_start);
1019#endif
1020
1c79356b
A
1021 /*
1022 * We calculate how many page frames we will have
1023 * and then allocate the page structures in one chunk.
1024 */
1025
55e303ae 1026 tmpaddr = (addr64_t)pmap_free_pages() * (addr64_t)PAGE_SIZE; /* Get the amount of memory left */
b0d623f7 1027 tmpaddr = tmpaddr + (addr64_t)(round_page(virtual_space_start) - virtual_space_start); /* Account for any slop */
2d21ac55 1028 npages = (unsigned int)(tmpaddr / (addr64_t)(PAGE_SIZE + sizeof(*vm_pages))); /* Figure size of all vm_page_ts, including enough to hold the vm_page_ts */
1c79356b 1029
2d21ac55 1030 vm_pages = (vm_page_t) pmap_steal_memory(npages * sizeof *vm_pages);
1c79356b
A
1031
1032 /*
1033 * Initialize the page frames.
1034 */
39037602
A
1035 kernel_debug_string_early("Initialize the page frames");
1036
1037 vm_page_array_beginning_addr = &vm_pages[0];
1038 vm_page_array_ending_addr = &vm_pages[npages];
1039
1040
1c79356b 1041 for (i = 0, pages_initialized = 0; i < npages; i++) {
55e303ae 1042 if (!pmap_next_page(&phys_page))
1c79356b 1043 break;
0b4c1975
A
1044 if (pages_initialized == 0 || phys_page < vm_page_lowest)
1045 vm_page_lowest = phys_page;
1c79356b 1046
0b4c1975 1047 vm_page_init(&vm_pages[i], phys_page, FALSE);
1c79356b
A
1048 vm_page_pages++;
1049 pages_initialized++;
1050 }
2d21ac55 1051 vm_pages_count = pages_initialized;
1c79356b 1052
fe8ab488
A
1053#if defined(__LP64__)
1054
39037602 1055 if ((vm_page_t)(VM_PAGE_UNPACK_PTR(VM_PAGE_PACK_PTR(&vm_pages[0]))) != &vm_pages[0])
fe8ab488
A
1056 panic("VM_PAGE_PACK_PTR failed on &vm_pages[0] - %p", (void *)&vm_pages[0]);
1057
39037602 1058 if ((vm_page_t)(VM_PAGE_UNPACK_PTR(VM_PAGE_PACK_PTR(&vm_pages[vm_pages_count-1]))) != &vm_pages[vm_pages_count-1])
fe8ab488
A
1059 panic("VM_PAGE_PACK_PTR failed on &vm_pages[vm_pages_count-1] - %p", (void *)&vm_pages[vm_pages_count-1]);
1060#endif
39037602 1061 kernel_debug_string_early("page fill/release");
0c530ab8
A
1062 /*
1063 * Check if we want to initialize pages to a known value
1064 */
1065 fill = 0; /* Assume no fill */
593a1d5f 1066 if (PE_parse_boot_argn("fill", &fillval, sizeof (fillval))) fill = 1; /* Set fill */
316670eb
A
1067#if DEBUG
1068 /* This slows down booting the DEBUG kernel, particularly on
1069 * large memory systems, but is worthwhile in deterministically
1070 * trapping uninitialized memory usage.
1071 */
1072 if (fill == 0) {
1073 fill = 1;
1074 fillval = 0xDEB8F177;
1075 }
1076#endif
1077 if (fill)
1078 kprintf("Filling vm_pages with pattern: 0x%x\n", fillval);
39037602
A
1079
1080#if CONFIG_SECLUDED_MEMORY
1081 /* default: no secluded mem */
1082 secluded_mem_mb = 0;
1083 if (max_mem > 1*1024*1024*1024) {
1084 /* default to 90MB for devices with > 1GB of RAM */
1085 secluded_mem_mb = 90;
1086 }
1087 /* override with value from device tree, if provided */
1088 PE_get_default("kern.secluded_mem_mb",
1089 &secluded_mem_mb, sizeof(secluded_mem_mb));
1090 /* override with value from boot-args, if provided */
1091 PE_parse_boot_argn("secluded_mem_mb",
1092 &secluded_mem_mb,
1093 sizeof (secluded_mem_mb));
1094
1095 vm_page_secluded_target = (unsigned int)
1096 ((secluded_mem_mb * 1024ULL * 1024ULL) / PAGE_SIZE);
1097 PE_parse_boot_argn("secluded_for_iokit",
1098 &secluded_for_iokit,
1099 sizeof (secluded_for_iokit));
1100 PE_parse_boot_argn("secluded_for_apps",
1101 &secluded_for_apps,
1102 sizeof (secluded_for_apps));
1103 PE_parse_boot_argn("secluded_for_filecache",
1104 &secluded_for_filecache,
1105 sizeof (secluded_for_filecache));
1106#if 11
1107 PE_parse_boot_argn("secluded_for_fbdp",
1108 &secluded_for_fbdp,
1109 sizeof (secluded_for_fbdp));
1110#endif
1111 PE_parse_boot_argn("secluded_aging_policy",
1112 &secluded_aging_policy,
1113 sizeof (secluded_aging_policy));
1114#endif /* CONFIG_SECLUDED_MEMORY */
1115
0c530ab8
A
1116 // -debug code remove
1117 if (2 == vm_himemory_mode) {
1118 // free low -> high so high is preferred
0b4c1975 1119 for (i = 1; i <= pages_initialized; i++) {
39037602 1120 if(fill) fillPage(VM_PAGE_GET_PHYS_PAGE(&vm_pages[i - 1]), fillval); /* Fill the page with a know value if requested at boot */
fe8ab488 1121 vm_page_release_startup(&vm_pages[i - 1]);
0c530ab8
A
1122 }
1123 }
1124 else
1125 // debug code remove-
1126
1c79356b
A
1127 /*
1128 * Release pages in reverse order so that physical pages
1129 * initially get allocated in ascending addresses. This keeps
1130 * the devices (which must address physical memory) happy if
1131 * they require several consecutive pages.
1132 */
0b4c1975 1133 for (i = pages_initialized; i > 0; i--) {
39037602 1134 if(fill) fillPage(VM_PAGE_GET_PHYS_PAGE(&vm_pages[i - 1]), fillval); /* Fill the page with a know value if requested at boot */
fe8ab488 1135 vm_page_release_startup(&vm_pages[i - 1]);
1c79356b
A
1136 }
1137
fe8ab488
A
1138 VM_CHECK_MEMORYSTATUS;
1139
55e303ae
A
1140#if 0
1141 {
1142 vm_page_t xx, xxo, xxl;
2d21ac55 1143 int i, j, k, l;
55e303ae
A
1144
1145 j = 0; /* (BRINGUP) */
1146 xxl = 0;
1147
2d21ac55 1148 for( i = 0; i < vm_colors; i++ ) {
39037602 1149 queue_iterate(&vm_page_queue_free[i].qhead,
2d21ac55
A
1150 xx,
1151 vm_page_t,
1152 pageq) { /* BRINGUP */
1153 j++; /* (BRINGUP) */
1154 if(j > vm_page_free_count) { /* (BRINGUP) */
1155 panic("pmap_startup: too many pages, xx = %08X, xxl = %08X\n", xx, xxl);
55e303ae 1156 }
2d21ac55
A
1157
1158 l = vm_page_free_count - j; /* (BRINGUP) */
1159 k = 0; /* (BRINGUP) */
1160
1161 if(((j - 1) & 0xFFFF) == 0) kprintf("checking number %d of %d\n", j, vm_page_free_count);
1162
39037602 1163 for(xxo = xx->pageq.next; xxo != &vm_page_queue_free[i].qhead; xxo = xxo->pageq.next) { /* (BRINGUP) */
2d21ac55
A
1164 k++;
1165 if(k > l) panic("pmap_startup: too many in secondary check %d %d\n", k, l);
1166 if((xx->phys_page & 0xFFFFFFFF) == (xxo->phys_page & 0xFFFFFFFF)) { /* (BRINGUP) */
1167 panic("pmap_startup: duplicate physaddr, xx = %08X, xxo = %08X\n", xx, xxo);
1168 }
1169 }
1170
1171 xxl = xx;
55e303ae
A
1172 }
1173 }
1174
1175 if(j != vm_page_free_count) { /* (BRINGUP) */
1176 panic("pmap_startup: vm_page_free_count does not match, calc = %d, vm_page_free_count = %08X\n", j, vm_page_free_count);
1177 }
1178 }
1179#endif
1180
1181
1c79356b
A
1182 /*
1183 * We have to re-align virtual_space_start,
1184 * because pmap_steal_memory has been using it.
1185 */
1186
b0d623f7 1187 virtual_space_start = round_page(virtual_space_start);
1c79356b
A
1188
1189 *startp = virtual_space_start;
1190 *endp = virtual_space_end;
1191}
1192#endif /* MACHINE_PAGES */
1193
1194/*
1195 * Routine: vm_page_module_init
1196 * Purpose:
1197 * Second initialization pass, to be done after
1198 * the basic VM system is ready.
1199 */
1200void
1201vm_page_module_init(void)
1202{
39037602
A
1203 uint64_t vm_page_zone_pages, vm_page_array_zone_data_size;
1204 vm_size_t vm_page_with_ppnum_size;
1c79356b 1205
39037602
A
1206 vm_page_array_zone = zinit((vm_size_t) sizeof(struct vm_page),
1207 0, PAGE_SIZE, "vm pages array");
1c79356b 1208
39037602
A
1209 zone_change(vm_page_array_zone, Z_CALLERACCT, FALSE);
1210 zone_change(vm_page_array_zone, Z_EXPAND, FALSE);
1211 zone_change(vm_page_array_zone, Z_EXHAUST, TRUE);
1212 zone_change(vm_page_array_zone, Z_FOREIGN, TRUE);
1213 zone_change(vm_page_array_zone, Z_GZALLOC_EXEMPT, TRUE);
3e170ce0
A
1214 /*
1215 * Adjust zone statistics to account for the real pages allocated
1216 * in vm_page_create(). [Q: is this really what we want?]
1217 */
39037602
A
1218 vm_page_array_zone->count += vm_page_pages;
1219 vm_page_array_zone->sum_count += vm_page_pages;
1220 vm_page_array_zone_data_size = vm_page_pages * vm_page_array_zone->elem_size;
1221 vm_page_array_zone->cur_size += vm_page_array_zone_data_size;
1222 vm_page_zone_pages = ((round_page(vm_page_array_zone_data_size)) / PAGE_SIZE);
1223 OSAddAtomic64(vm_page_zone_pages, &(vm_page_array_zone->page_count));
3e170ce0
A
1224 /* since zone accounts for these, take them out of stolen */
1225 VM_PAGE_MOVE_STOLEN(vm_page_zone_pages);
39037602
A
1226
1227 vm_page_with_ppnum_size = (sizeof(struct vm_page_with_ppnum) + (VM_PACKED_POINTER_ALIGNMENT-1)) & ~(VM_PACKED_POINTER_ALIGNMENT - 1);
1228
1229 vm_page_zone = zinit(vm_page_with_ppnum_size,
1230 0, PAGE_SIZE, "vm pages");
1231
1232 zone_change(vm_page_zone, Z_CALLERACCT, FALSE);
1233 zone_change(vm_page_zone, Z_EXPAND, FALSE);
1234 zone_change(vm_page_zone, Z_EXHAUST, TRUE);
1235 zone_change(vm_page_zone, Z_FOREIGN, TRUE);
1236 zone_change(vm_page_zone, Z_GZALLOC_EXEMPT, TRUE);
1c79356b
A
1237}
1238
1239/*
1240 * Routine: vm_page_create
1241 * Purpose:
1242 * After the VM system is up, machine-dependent code
1243 * may stumble across more physical memory. For example,
1244 * memory that it was reserving for a frame buffer.
1245 * vm_page_create turns this memory into available pages.
1246 */
1247
1248void
1249vm_page_create(
55e303ae
A
1250 ppnum_t start,
1251 ppnum_t end)
1c79356b 1252{
55e303ae
A
1253 ppnum_t phys_page;
1254 vm_page_t m;
1c79356b 1255
55e303ae
A
1256 for (phys_page = start;
1257 phys_page < end;
1258 phys_page++) {
6d2010ae 1259 while ((m = (vm_page_t) vm_page_grab_fictitious_common(phys_page))
1c79356b
A
1260 == VM_PAGE_NULL)
1261 vm_page_more_fictitious();
1262
6d2010ae 1263 m->fictitious = FALSE;
0b4c1975 1264 pmap_clear_noencrypt(phys_page);
6d2010ae 1265
1c79356b 1266 vm_page_pages++;
39037602 1267 vm_page_release(m, FALSE);
1c79356b
A
1268 }
1269}
1270
1271/*
1272 * vm_page_hash:
1273 *
1274 * Distributes the object/offset key pair among hash buckets.
1275 *
55e303ae 1276 * NOTE: The bucket count must be a power of 2
1c79356b
A
1277 */
1278#define vm_page_hash(object, offset) (\
b0d623f7 1279 ( (natural_t)((uintptr_t)object * vm_page_bucket_hash) + ((uint32_t)atop_64(offset) ^ vm_page_bucket_hash))\
1c79356b
A
1280 & vm_page_hash_mask)
1281
2d21ac55 1282
1c79356b
A
1283/*
1284 * vm_page_insert: [ internal use only ]
1285 *
1286 * Inserts the given mem entry into the object/object-page
1287 * table and object list.
1288 *
1289 * The object must be locked.
1290 */
1c79356b
A
1291void
1292vm_page_insert(
2d21ac55
A
1293 vm_page_t mem,
1294 vm_object_t object,
1295 vm_object_offset_t offset)
1296{
3e170ce0
A
1297 vm_page_insert_internal(mem, object, offset, VM_KERN_MEMORY_NONE, FALSE, TRUE, FALSE, FALSE, NULL);
1298}
1299
1300void
1301vm_page_insert_wired(
1302 vm_page_t mem,
1303 vm_object_t object,
1304 vm_object_offset_t offset,
1305 vm_tag_t tag)
1306{
1307 vm_page_insert_internal(mem, object, offset, tag, FALSE, TRUE, FALSE, FALSE, NULL);
2d21ac55
A
1308}
1309
4a3eedf9 1310void
2d21ac55
A
1311vm_page_insert_internal(
1312 vm_page_t mem,
1313 vm_object_t object,
1314 vm_object_offset_t offset,
3e170ce0 1315 vm_tag_t tag,
b0d623f7 1316 boolean_t queues_lock_held,
316670eb 1317 boolean_t insert_in_hash,
3e170ce0
A
1318 boolean_t batch_pmap_op,
1319 boolean_t batch_accounting,
1320 uint64_t *delayed_ledger_update)
1c79356b 1321{
fe8ab488
A
1322 vm_page_bucket_t *bucket;
1323 lck_spin_t *bucket_lock;
1324 int hash_id;
1325 task_t owner;
1c79356b
A
1326
1327 XPR(XPR_VM_PAGE,
1328 "vm_page_insert, object 0x%X offset 0x%X page 0x%X\n",
b0d623f7 1329 object, offset, mem, 0,0);
316670eb
A
1330#if 0
1331 /*
1332 * we may not hold the page queue lock
1333 * so this check isn't safe to make
1334 */
1c79356b 1335 VM_PAGE_CHECK(mem);
316670eb 1336#endif
1c79356b 1337
39236c6e
A
1338 assert(page_aligned(offset));
1339
3e170ce0
A
1340 assert(!VM_PAGE_WIRED(mem) || mem->private || mem->fictitious || (tag != VM_KERN_MEMORY_NONE));
1341
fe8ab488
A
1342 /* the vm_submap_object is only a placeholder for submaps */
1343 assert(object != vm_submap_object);
2d21ac55
A
1344
1345 vm_object_lock_assert_exclusive(object);
39037602 1346 LCK_MTX_ASSERT(&vm_page_queue_lock,
b0d623f7
A
1347 queues_lock_held ? LCK_MTX_ASSERT_OWNED
1348 : LCK_MTX_ASSERT_NOTOWNED);
39037602
A
1349 if (queues_lock_held == FALSE)
1350 assert(!VM_PAGE_PAGEABLE(mem));
3e170ce0 1351
b0d623f7 1352 if (insert_in_hash == TRUE) {
15129b1c 1353#if DEBUG || VM_PAGE_CHECK_BUCKETS
39037602 1354 if (mem->tabled || mem->vm_page_object)
b0d623f7
A
1355 panic("vm_page_insert: page %p for (obj=%p,off=0x%llx) "
1356 "already in (obj=%p,off=0x%llx)",
39037602 1357 mem, object, offset, VM_PAGE_OBJECT(mem), mem->offset);
91447636 1358#endif
6d2010ae 1359 assert(!object->internal || offset < object->vo_size);
b0d623f7
A
1360 assert(vm_page_lookup(object, offset) == VM_PAGE_NULL);
1361
1362 /*
1363 * Record the object/offset pair in this page
1364 */
1c79356b 1365
39037602 1366 mem->vm_page_object = VM_PAGE_PACK_OBJECT(object);
b0d623f7 1367 mem->offset = offset;
1c79356b 1368
39037602
A
1369#if CONFIG_SECLUDED_MEMORY
1370 if (object->eligible_for_secluded) {
1371 vm_page_secluded.eligible_for_secluded++;
1372 }
1373#endif /* CONFIG_SECLUDED_MEMORY */
1374
b0d623f7
A
1375 /*
1376 * Insert it into the object_object/offset hash table
1377 */
1378 hash_id = vm_page_hash(object, offset);
1379 bucket = &vm_page_buckets[hash_id];
1380 bucket_lock = &vm_page_bucket_locks[hash_id / BUCKETS_PER_LOCK];
1381
1382 lck_spin_lock(bucket_lock);
1c79356b 1383
fe8ab488
A
1384 mem->next_m = bucket->page_list;
1385 bucket->page_list = VM_PAGE_PACK_PTR(mem);
39037602 1386 assert(mem == (vm_page_t)(VM_PAGE_UNPACK_PTR(bucket->page_list)));
fe8ab488 1387
1c79356b 1388#if MACH_PAGE_HASH_STATS
b0d623f7
A
1389 if (++bucket->cur_count > bucket->hi_count)
1390 bucket->hi_count = bucket->cur_count;
1c79356b 1391#endif /* MACH_PAGE_HASH_STATS */
15129b1c 1392 mem->hashed = TRUE;
b0d623f7
A
1393 lck_spin_unlock(bucket_lock);
1394 }
6d2010ae 1395
316670eb
A
1396 {
1397 unsigned int cache_attr;
6d2010ae
A
1398
1399 cache_attr = object->wimg_bits & VM_WIMG_MASK;
1400
1401 if (cache_attr != VM_WIMG_USE_DEFAULT) {
316670eb 1402 PMAP_SET_CACHE_ATTR(mem, object, cache_attr, batch_pmap_op);
6d2010ae
A
1403 }
1404 }
1c79356b
A
1405 /*
1406 * Now link into the object's list of backed pages.
1407 */
39037602 1408 vm_page_queue_enter(&object->memq, mem, vm_page_t, listq);
3e170ce0 1409 object->memq_hint = mem;
1c79356b
A
1410 mem->tabled = TRUE;
1411
1412 /*
1413 * Show that the object has one more resident page.
1414 */
1415
1416 object->resident_page_count++;
b0d623f7 1417 if (VM_PAGE_WIRED(mem)) {
39037602
A
1418 assert(mem->wire_count > 0);
1419
3e170ce0
A
1420 if (!mem->private && !mem->fictitious)
1421 {
1422 if (!object->wired_page_count)
1423 {
1424 assert(VM_KERN_MEMORY_NONE != tag);
1425 object->wire_tag = tag;
1426 VM_OBJECT_WIRED(object);
1427 }
1428 }
1429 object->wired_page_count++;
b0d623f7
A
1430 }
1431 assert(object->resident_page_count >= object->wired_page_count);
91447636 1432
3e170ce0
A
1433 if (batch_accounting == FALSE) {
1434 if (object->internal) {
1435 OSAddAtomic(1, &vm_page_internal_count);
1436 } else {
1437 OSAddAtomic(1, &vm_page_external_count);
1438 }
39236c6e
A
1439 }
1440
1441 /*
1442 * It wouldn't make sense to insert a "reusable" page in
1443 * an object (the page would have been marked "reusable" only
1444 * at the time of a madvise(MADV_FREE_REUSABLE) if it was already
1445 * in the object at that time).
1446 * But a page could be inserted in a "all_reusable" object, if
1447 * something faults it in (a vm_read() from another task or a
1448 * "use-after-free" issue in user space, for example). It can
1449 * also happen if we're relocating a page from that object to
1450 * a different physical page during a physically-contiguous
1451 * allocation.
1452 */
b0d623f7 1453 assert(!mem->reusable);
39037602 1454 if (object->all_reusable) {
39236c6e
A
1455 OSAddAtomic(+1, &vm_page_stats_reusable.reusable_count);
1456 }
2d21ac55 1457
fe8ab488
A
1458 if (object->purgable == VM_PURGABLE_DENY) {
1459 owner = TASK_NULL;
1460 } else {
1461 owner = object->vo_purgeable_owner;
1462 }
1463 if (owner &&
1464 (object->purgable == VM_PURGABLE_NONVOLATILE ||
1465 VM_PAGE_WIRED(mem))) {
3e170ce0
A
1466
1467 if (delayed_ledger_update)
1468 *delayed_ledger_update += PAGE_SIZE;
1469 else {
1470 /* more non-volatile bytes */
1471 ledger_credit(owner->ledger,
1472 task_ledgers.purgeable_nonvolatile,
1473 PAGE_SIZE);
1474 /* more footprint */
1475 ledger_credit(owner->ledger,
1476 task_ledgers.phys_footprint,
1477 PAGE_SIZE);
1478 }
fe8ab488
A
1479
1480 } else if (owner &&
1481 (object->purgable == VM_PURGABLE_VOLATILE ||
1482 object->purgable == VM_PURGABLE_EMPTY)) {
1483 assert(! VM_PAGE_WIRED(mem));
1484 /* more volatile bytes */
1485 ledger_credit(owner->ledger,
1486 task_ledgers.purgeable_volatile,
1487 PAGE_SIZE);
1488 }
1489
b0d623f7
A
1490 if (object->purgable == VM_PURGABLE_VOLATILE) {
1491 if (VM_PAGE_WIRED(mem)) {
fe8ab488 1492 OSAddAtomic(+1, &vm_page_purgeable_wired_count);
b0d623f7 1493 } else {
fe8ab488 1494 OSAddAtomic(+1, &vm_page_purgeable_count);
b0d623f7 1495 }
593a1d5f 1496 } else if (object->purgable == VM_PURGABLE_EMPTY &&
39037602 1497 mem->vm_page_q_state == VM_PAGE_ON_THROTTLED_Q) {
b0d623f7
A
1498 /*
1499 * This page belongs to a purged VM object but hasn't
1500 * been purged (because it was "busy").
1501 * It's in the "throttled" queue and hence not
1502 * visible to vm_pageout_scan(). Move it to a pageable
1503 * queue, so that it can eventually be reclaimed, instead
1504 * of lingering in the "empty" object.
1505 */
593a1d5f 1506 if (queues_lock_held == FALSE)
b0d623f7 1507 vm_page_lockspin_queues();
593a1d5f 1508 vm_page_deactivate(mem);
2d21ac55
A
1509 if (queues_lock_held == FALSE)
1510 vm_page_unlock_queues();
91447636 1511 }
fe8ab488
A
1512
1513#if VM_OBJECT_TRACKING_OP_MODIFIED
1514 if (vm_object_tracking_inited &&
1515 object->internal &&
1516 object->resident_page_count == 0 &&
1517 object->pager == NULL &&
1518 object->shadow != NULL &&
1519 object->shadow->copy == object) {
1520 void *bt[VM_OBJECT_TRACKING_BTDEPTH];
1521 int numsaved = 0;
1522
1523 numsaved =OSBacktrace(bt, VM_OBJECT_TRACKING_BTDEPTH);
1524 btlog_add_entry(vm_object_tracking_btlog,
1525 object,
1526 VM_OBJECT_TRACKING_OP_MODIFIED,
1527 bt,
1528 numsaved);
1529 }
1530#endif /* VM_OBJECT_TRACKING_OP_MODIFIED */
1c79356b
A
1531}
1532
1533/*
1534 * vm_page_replace:
1535 *
1536 * Exactly like vm_page_insert, except that we first
1537 * remove any existing page at the given offset in object.
1538 *
b0d623f7 1539 * The object must be locked.
1c79356b 1540 */
1c79356b
A
1541void
1542vm_page_replace(
39037602
A
1543 vm_page_t mem,
1544 vm_object_t object,
1545 vm_object_offset_t offset)
1c79356b 1546{
0c530ab8
A
1547 vm_page_bucket_t *bucket;
1548 vm_page_t found_m = VM_PAGE_NULL;
b0d623f7
A
1549 lck_spin_t *bucket_lock;
1550 int hash_id;
1c79356b 1551
316670eb
A
1552#if 0
1553 /*
1554 * we don't hold the page queue lock
1555 * so this check isn't safe to make
1556 */
1c79356b 1557 VM_PAGE_CHECK(mem);
316670eb 1558#endif
2d21ac55 1559 vm_object_lock_assert_exclusive(object);
15129b1c 1560#if DEBUG || VM_PAGE_CHECK_BUCKETS
39037602 1561 if (mem->tabled || mem->vm_page_object)
91447636
A
1562 panic("vm_page_replace: page %p for (obj=%p,off=0x%llx) "
1563 "already in (obj=%p,off=0x%llx)",
39037602 1564 mem, object, offset, VM_PAGE_OBJECT(mem), mem->offset);
91447636 1565#endif
39037602
A
1566 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_NOTOWNED);
1567
1568 assert(!VM_PAGE_PAGEABLE(mem));
1569
1c79356b
A
1570 /*
1571 * Record the object/offset pair in this page
1572 */
39037602 1573 mem->vm_page_object = VM_PAGE_PACK_OBJECT(object);
1c79356b
A
1574 mem->offset = offset;
1575
1576 /*
1577 * Insert it into the object_object/offset hash table,
1578 * replacing any page that might have been there.
1579 */
1580
b0d623f7
A
1581 hash_id = vm_page_hash(object, offset);
1582 bucket = &vm_page_buckets[hash_id];
1583 bucket_lock = &vm_page_bucket_locks[hash_id / BUCKETS_PER_LOCK];
1584
1585 lck_spin_lock(bucket_lock);
0c530ab8 1586
fe8ab488
A
1587 if (bucket->page_list) {
1588 vm_page_packed_t *mp = &bucket->page_list;
39037602 1589 vm_page_t m = (vm_page_t)(VM_PAGE_UNPACK_PTR(*mp));
0c530ab8 1590
1c79356b 1591 do {
39037602
A
1592 /*
1593 * compare packed object pointers
1594 */
1595 if (m->vm_page_object == mem->vm_page_object && m->offset == offset) {
1c79356b 1596 /*
0c530ab8 1597 * Remove old page from hash list
1c79356b 1598 */
fe8ab488 1599 *mp = m->next_m;
15129b1c 1600 m->hashed = FALSE;
1c79356b 1601
0c530ab8 1602 found_m = m;
1c79356b
A
1603 break;
1604 }
fe8ab488 1605 mp = &m->next_m;
39037602 1606 } while ((m = (vm_page_t)(VM_PAGE_UNPACK_PTR(*mp))));
0c530ab8 1607
fe8ab488 1608 mem->next_m = bucket->page_list;
1c79356b 1609 } else {
39037602 1610 mem->next_m = VM_PAGE_PACK_PTR(NULL);
1c79356b 1611 }
0c530ab8
A
1612 /*
1613 * insert new page at head of hash list
1614 */
fe8ab488 1615 bucket->page_list = VM_PAGE_PACK_PTR(mem);
15129b1c 1616 mem->hashed = TRUE;
0c530ab8 1617
b0d623f7 1618 lck_spin_unlock(bucket_lock);
1c79356b 1619
0c530ab8
A
1620 if (found_m) {
1621 /*
1622 * there was already a page at the specified
1623 * offset for this object... remove it from
1624 * the object and free it back to the free list
1625 */
b0d623f7 1626 vm_page_free_unlocked(found_m, FALSE);
91447636 1627 }
3e170ce0 1628 vm_page_insert_internal(mem, object, offset, VM_KERN_MEMORY_NONE, FALSE, FALSE, FALSE, FALSE, NULL);
1c79356b
A
1629}
1630
1631/*
1632 * vm_page_remove: [ internal use only ]
1633 *
1634 * Removes the given mem entry from the object/offset-page
1635 * table and the object page list.
1636 *
b0d623f7 1637 * The object must be locked.
1c79356b
A
1638 */
1639
1640void
1641vm_page_remove(
b0d623f7
A
1642 vm_page_t mem,
1643 boolean_t remove_from_hash)
1c79356b 1644{
b0d623f7
A
1645 vm_page_bucket_t *bucket;
1646 vm_page_t this;
1647 lck_spin_t *bucket_lock;
1648 int hash_id;
fe8ab488 1649 task_t owner;
39037602
A
1650 vm_object_t m_object;
1651
1652 m_object = VM_PAGE_OBJECT(mem);
1c79356b
A
1653
1654 XPR(XPR_VM_PAGE,
1655 "vm_page_remove, object 0x%X offset 0x%X page 0x%X\n",
39037602 1656 m_object, mem->offset,
b0d623f7
A
1657 mem, 0,0);
1658
39037602 1659 vm_object_lock_assert_exclusive(m_object);
1c79356b
A
1660 assert(mem->tabled);
1661 assert(!mem->cleaning);
316670eb 1662 assert(!mem->laundry);
39037602
A
1663
1664 if (VM_PAGE_PAGEABLE(mem)) {
1665 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
1666 }
316670eb
A
1667#if 0
1668 /*
1669 * we don't hold the page queue lock
1670 * so this check isn't safe to make
1671 */
1c79356b 1672 VM_PAGE_CHECK(mem);
316670eb 1673#endif
b0d623f7
A
1674 if (remove_from_hash == TRUE) {
1675 /*
1676 * Remove from the object_object/offset hash table
1677 */
39037602 1678 hash_id = vm_page_hash(m_object, mem->offset);
b0d623f7
A
1679 bucket = &vm_page_buckets[hash_id];
1680 bucket_lock = &vm_page_bucket_locks[hash_id / BUCKETS_PER_LOCK];
91447636 1681
b0d623f7 1682 lck_spin_lock(bucket_lock);
1c79356b 1683
39037602 1684 if ((this = (vm_page_t)(VM_PAGE_UNPACK_PTR(bucket->page_list))) == mem) {
b0d623f7 1685 /* optimize for common case */
1c79356b 1686
fe8ab488 1687 bucket->page_list = mem->next_m;
b0d623f7 1688 } else {
fe8ab488 1689 vm_page_packed_t *prev;
1c79356b 1690
fe8ab488 1691 for (prev = &this->next_m;
39037602 1692 (this = (vm_page_t)(VM_PAGE_UNPACK_PTR(*prev))) != mem;
fe8ab488 1693 prev = &this->next_m)
b0d623f7 1694 continue;
fe8ab488 1695 *prev = this->next_m;
b0d623f7 1696 }
1c79356b 1697#if MACH_PAGE_HASH_STATS
b0d623f7 1698 bucket->cur_count--;
1c79356b 1699#endif /* MACH_PAGE_HASH_STATS */
15129b1c 1700 mem->hashed = FALSE;
b0d623f7
A
1701 lck_spin_unlock(bucket_lock);
1702 }
1c79356b
A
1703 /*
1704 * Now remove from the object's list of backed pages.
1705 */
1706
3e170ce0 1707 vm_page_remove_internal(mem);
1c79356b
A
1708
1709 /*
1710 * And show that the object has one fewer resident
1711 * page.
1712 */
1713
39037602
A
1714 assert(m_object->resident_page_count > 0);
1715 m_object->resident_page_count--;
6d2010ae 1716
39037602 1717 if (m_object->internal) {
fe8ab488 1718#if DEBUG
39236c6e 1719 assert(vm_page_internal_count);
fe8ab488
A
1720#endif /* DEBUG */
1721
39236c6e
A
1722 OSAddAtomic(-1, &vm_page_internal_count);
1723 } else {
1724 assert(vm_page_external_count);
1725 OSAddAtomic(-1, &vm_page_external_count);
fe8ab488
A
1726
1727 if (mem->xpmapped) {
1728 assert(vm_page_xpmapped_external_count);
1729 OSAddAtomic(-1, &vm_page_xpmapped_external_count);
1730 }
39236c6e 1731 }
39037602
A
1732 if (!m_object->internal && (m_object->objq.next || m_object->objq.prev)) {
1733 if (m_object->resident_page_count == 0)
1734 vm_object_cache_remove(m_object);
6d2010ae
A
1735 }
1736
b0d623f7 1737 if (VM_PAGE_WIRED(mem)) {
39037602
A
1738 assert(mem->wire_count > 0);
1739 assert(m_object->wired_page_count > 0);
1740 m_object->wired_page_count--;
1741 if (!m_object->wired_page_count) {
1742 VM_OBJECT_UNWIRED(m_object);
3e170ce0 1743 }
b0d623f7 1744 }
39037602
A
1745 assert(m_object->resident_page_count >=
1746 m_object->wired_page_count);
b0d623f7 1747 if (mem->reusable) {
39037602
A
1748 assert(m_object->reusable_page_count > 0);
1749 m_object->reusable_page_count--;
1750 assert(m_object->reusable_page_count <=
1751 m_object->resident_page_count);
b0d623f7
A
1752 mem->reusable = FALSE;
1753 OSAddAtomic(-1, &vm_page_stats_reusable.reusable_count);
1754 vm_page_stats_reusable.reused_remove++;
39037602 1755 } else if (m_object->all_reusable) {
b0d623f7
A
1756 OSAddAtomic(-1, &vm_page_stats_reusable.reusable_count);
1757 vm_page_stats_reusable.reused_remove++;
1758 }
1c79356b 1759
39037602 1760 if (m_object->purgable == VM_PURGABLE_DENY) {
fe8ab488
A
1761 owner = TASK_NULL;
1762 } else {
39037602 1763 owner = m_object->vo_purgeable_owner;
fe8ab488
A
1764 }
1765 if (owner &&
39037602 1766 (m_object->purgable == VM_PURGABLE_NONVOLATILE ||
fe8ab488
A
1767 VM_PAGE_WIRED(mem))) {
1768 /* less non-volatile bytes */
1769 ledger_debit(owner->ledger,
1770 task_ledgers.purgeable_nonvolatile,
1771 PAGE_SIZE);
1772 /* less footprint */
1773 ledger_debit(owner->ledger,
1774 task_ledgers.phys_footprint,
1775 PAGE_SIZE);
1776 } else if (owner &&
39037602
A
1777 (m_object->purgable == VM_PURGABLE_VOLATILE ||
1778 m_object->purgable == VM_PURGABLE_EMPTY)) {
fe8ab488
A
1779 assert(! VM_PAGE_WIRED(mem));
1780 /* less volatile bytes */
1781 ledger_debit(owner->ledger,
1782 task_ledgers.purgeable_volatile,
1783 PAGE_SIZE);
1784 }
39037602 1785 if (m_object->purgable == VM_PURGABLE_VOLATILE) {
b0d623f7
A
1786 if (VM_PAGE_WIRED(mem)) {
1787 assert(vm_page_purgeable_wired_count > 0);
1788 OSAddAtomic(-1, &vm_page_purgeable_wired_count);
1789 } else {
1790 assert(vm_page_purgeable_count > 0);
1791 OSAddAtomic(-1, &vm_page_purgeable_count);
1792 }
91447636 1793 }
39037602
A
1794 if (m_object->set_cache_attr == TRUE)
1795 pmap_set_cache_attributes(VM_PAGE_GET_PHYS_PAGE(mem), 0);
6d2010ae 1796
1c79356b 1797 mem->tabled = FALSE;
39037602 1798 mem->vm_page_object = 0;
91447636 1799 mem->offset = (vm_object_offset_t) -1;
1c79356b
A
1800}
1801
b0d623f7 1802
1c79356b
A
1803/*
1804 * vm_page_lookup:
1805 *
1806 * Returns the page associated with the object/offset
1807 * pair specified; if none is found, VM_PAGE_NULL is returned.
1808 *
1809 * The object must be locked. No side effects.
1810 */
1811
3e170ce0
A
1812#define VM_PAGE_HASH_LOOKUP_THRESHOLD 10
1813
1814#if DEBUG_VM_PAGE_LOOKUP
2d21ac55 1815
3e170ce0
A
1816struct {
1817 uint64_t vpl_total;
1818 uint64_t vpl_empty_obj;
1819 uint64_t vpl_bucket_NULL;
1820 uint64_t vpl_hit_hint;
1821 uint64_t vpl_hit_hint_next;
1822 uint64_t vpl_hit_hint_prev;
1823 uint64_t vpl_fast;
1824 uint64_t vpl_slow;
1825 uint64_t vpl_hit;
1826 uint64_t vpl_miss;
1827
1828 uint64_t vpl_fast_elapsed;
1829 uint64_t vpl_slow_elapsed;
1830} vm_page_lookup_stats __attribute__((aligned(8)));
1831
1832#endif
1833
1834#define KDP_VM_PAGE_WALK_MAX 1000
1835
1836vm_page_t
1837kdp_vm_page_lookup(
1838 vm_object_t object,
1839 vm_object_offset_t offset)
1840{
1841 vm_page_t cur_page;
1842 int num_traversed = 0;
1843
1844 if (not_in_kdp) {
1845 panic("panic: kdp_vm_page_lookup done outside of kernel debugger");
1846 }
1847
39037602 1848 vm_page_queue_iterate(&object->memq, cur_page, vm_page_t, listq) {
3e170ce0
A
1849 if (cur_page->offset == offset) {
1850 return cur_page;
1851 }
1852 num_traversed++;
1853
1854 if (num_traversed >= KDP_VM_PAGE_WALK_MAX) {
1855 return VM_PAGE_NULL;
1856 }
1857 }
1858
1859 return VM_PAGE_NULL;
1860}
91447636 1861
1c79356b
A
1862vm_page_t
1863vm_page_lookup(
b0d623f7
A
1864 vm_object_t object,
1865 vm_object_offset_t offset)
1c79356b 1866{
b0d623f7
A
1867 vm_page_t mem;
1868 vm_page_bucket_t *bucket;
39037602 1869 vm_page_queue_entry_t qe;
3e170ce0 1870 lck_spin_t *bucket_lock = NULL;
b0d623f7 1871 int hash_id;
3e170ce0
A
1872#if DEBUG_VM_PAGE_LOOKUP
1873 uint64_t start, elapsed;
91447636 1874
3e170ce0
A
1875 OSAddAtomic64(1, &vm_page_lookup_stats.vpl_total);
1876#endif
2d21ac55 1877 vm_object_lock_assert_held(object);
3e170ce0
A
1878
1879 if (object->resident_page_count == 0) {
1880#if DEBUG_VM_PAGE_LOOKUP
1881 OSAddAtomic64(1, &vm_page_lookup_stats.vpl_empty_obj);
1882#endif
1883 return (VM_PAGE_NULL);
1884 }
1885
91447636 1886 mem = object->memq_hint;
2d21ac55 1887
91447636 1888 if (mem != VM_PAGE_NULL) {
39037602 1889 assert(VM_PAGE_OBJECT(mem) == object);
2d21ac55 1890
91447636 1891 if (mem->offset == offset) {
3e170ce0
A
1892#if DEBUG_VM_PAGE_LOOKUP
1893 OSAddAtomic64(1, &vm_page_lookup_stats.vpl_hit_hint);
1894#endif
1895 return (mem);
91447636 1896 }
39037602 1897 qe = (vm_page_queue_entry_t)vm_page_queue_next(&mem->listq);
2d21ac55 1898
39037602 1899 if (! vm_page_queue_end(&object->memq, qe)) {
91447636
A
1900 vm_page_t next_page;
1901
39037602
A
1902 next_page = (vm_page_t)((uintptr_t)qe);
1903 assert(VM_PAGE_OBJECT(next_page) == object);
2d21ac55 1904
91447636 1905 if (next_page->offset == offset) {
91447636 1906 object->memq_hint = next_page; /* new hint */
3e170ce0
A
1907#if DEBUG_VM_PAGE_LOOKUP
1908 OSAddAtomic64(1, &vm_page_lookup_stats.vpl_hit_hint_next);
1909#endif
1910 return (next_page);
91447636
A
1911 }
1912 }
39037602 1913 qe = (vm_page_queue_entry_t)vm_page_queue_prev(&mem->listq);
2d21ac55 1914
39037602 1915 if (! vm_page_queue_end(&object->memq, qe)) {
91447636
A
1916 vm_page_t prev_page;
1917
39037602
A
1918 prev_page = (vm_page_t)((uintptr_t)qe);
1919 assert(VM_PAGE_OBJECT(prev_page) == object);
2d21ac55 1920
91447636 1921 if (prev_page->offset == offset) {
91447636 1922 object->memq_hint = prev_page; /* new hint */
3e170ce0
A
1923#if DEBUG_VM_PAGE_LOOKUP
1924 OSAddAtomic64(1, &vm_page_lookup_stats.vpl_hit_hint_prev);
1925#endif
1926 return (prev_page);
91447636
A
1927 }
1928 }
1929 }
1c79356b 1930 /*
2d21ac55 1931 * Search the hash table for this object/offset pair
1c79356b 1932 */
b0d623f7
A
1933 hash_id = vm_page_hash(object, offset);
1934 bucket = &vm_page_buckets[hash_id];
1c79356b 1935
2d21ac55
A
1936 /*
1937 * since we hold the object lock, we are guaranteed that no
1938 * new pages can be inserted into this object... this in turn
1939 * guarantess that the page we're looking for can't exist
1940 * if the bucket it hashes to is currently NULL even when looked
1941 * at outside the scope of the hash bucket lock... this is a
1942 * really cheap optimiztion to avoid taking the lock
1943 */
fe8ab488 1944 if (!bucket->page_list) {
3e170ce0
A
1945#if DEBUG_VM_PAGE_LOOKUP
1946 OSAddAtomic64(1, &vm_page_lookup_stats.vpl_bucket_NULL);
1947#endif
2d21ac55
A
1948 return (VM_PAGE_NULL);
1949 }
0c530ab8 1950
3e170ce0
A
1951#if DEBUG_VM_PAGE_LOOKUP
1952 start = mach_absolute_time();
1953#endif
1954 if (object->resident_page_count <= VM_PAGE_HASH_LOOKUP_THRESHOLD) {
316670eb 1955 /*
3e170ce0
A
1956 * on average, it's roughly 3 times faster to run a short memq list
1957 * than to take the spin lock and go through the hash list
316670eb 1958 */
39037602 1959 mem = (vm_page_t)vm_page_queue_first(&object->memq);
3e170ce0 1960
39037602 1961 while (!vm_page_queue_end(&object->memq, (vm_page_queue_entry_t)mem)) {
3e170ce0
A
1962
1963 if (mem->offset == offset)
1964 break;
1965
39037602 1966 mem = (vm_page_t)vm_page_queue_next(&mem->listq);
3e170ce0 1967 }
39037602 1968 if (vm_page_queue_end(&object->memq, (vm_page_queue_entry_t)mem))
3e170ce0
A
1969 mem = NULL;
1970 } else {
39037602
A
1971 vm_page_object_t packed_object;
1972
1973 packed_object = VM_PAGE_PACK_OBJECT(object);
3e170ce0
A
1974
1975 bucket_lock = &vm_page_bucket_locks[hash_id / BUCKETS_PER_LOCK];
1976
1977 lck_spin_lock(bucket_lock);
1978
39037602
A
1979 for (mem = (vm_page_t)(VM_PAGE_UNPACK_PTR(bucket->page_list));
1980 mem != VM_PAGE_NULL;
1981 mem = (vm_page_t)(VM_PAGE_UNPACK_PTR(mem->next_m))) {
3e170ce0
A
1982#if 0
1983 /*
1984 * we don't hold the page queue lock
1985 * so this check isn't safe to make
1986 */
1987 VM_PAGE_CHECK(mem);
316670eb 1988#endif
39037602 1989 if ((mem->vm_page_object == packed_object) && (mem->offset == offset))
3e170ce0
A
1990 break;
1991 }
1992 lck_spin_unlock(bucket_lock);
1c79356b 1993 }
55e303ae 1994
3e170ce0
A
1995#if DEBUG_VM_PAGE_LOOKUP
1996 elapsed = mach_absolute_time() - start;
1997
1998 if (bucket_lock) {
1999 OSAddAtomic64(1, &vm_page_lookup_stats.vpl_slow);
2000 OSAddAtomic64(elapsed, &vm_page_lookup_stats.vpl_slow_elapsed);
2001 } else {
2002 OSAddAtomic64(1, &vm_page_lookup_stats.vpl_fast);
2003 OSAddAtomic64(elapsed, &vm_page_lookup_stats.vpl_fast_elapsed);
2004 }
2005 if (mem != VM_PAGE_NULL)
2006 OSAddAtomic64(1, &vm_page_lookup_stats.vpl_hit);
2007 else
2008 OSAddAtomic64(1, &vm_page_lookup_stats.vpl_miss);
2009#endif
91447636 2010 if (mem != VM_PAGE_NULL) {
39037602 2011 assert(VM_PAGE_OBJECT(mem) == object);
91447636 2012
3e170ce0
A
2013 object->memq_hint = mem;
2014 }
2015 return (mem);
91447636
A
2016}
2017
2018
1c79356b
A
2019/*
2020 * vm_page_rename:
2021 *
2022 * Move the given memory entry from its
2023 * current object to the specified target object/offset.
2024 *
2025 * The object must be locked.
2026 */
2027void
2028vm_page_rename(
39037602
A
2029 vm_page_t mem,
2030 vm_object_t new_object,
2031 vm_object_offset_t new_offset,
2032 boolean_t encrypted_ok)
1c79356b 2033{
39037602
A
2034 boolean_t internal_to_external, external_to_internal;
2035 vm_tag_t tag;
2036 vm_object_t m_object;
39236c6e 2037
39037602 2038 m_object = VM_PAGE_OBJECT(mem);
2d21ac55 2039
39037602
A
2040 assert(m_object != new_object);
2041 assert(m_object);
3e170ce0 2042
91447636
A
2043 /*
2044 * ENCRYPTED SWAP:
2045 * The encryption key is based on the page's memory object
2046 * (aka "pager") and paging offset. Moving the page to
2047 * another VM object changes its "pager" and "paging_offset"
2d21ac55
A
2048 * so it has to be decrypted first, or we would lose the key.
2049 *
2050 * One exception is VM object collapsing, where we transfer pages
2051 * from one backing object to its parent object. This operation also
2052 * transfers the paging information, so the <pager,paging_offset> info
2053 * should remain consistent. The caller (vm_object_do_collapse())
2054 * sets "encrypted_ok" in this case.
91447636 2055 */
2d21ac55 2056 if (!encrypted_ok && mem->encrypted) {
91447636
A
2057 panic("vm_page_rename: page %p is encrypted\n", mem);
2058 }
2d21ac55 2059
b0d623f7
A
2060 XPR(XPR_VM_PAGE,
2061 "vm_page_rename, new object 0x%X, offset 0x%X page 0x%X\n",
2062 new_object, new_offset,
2063 mem, 0,0);
2064
1c79356b
A
2065 /*
2066 * Changes to mem->object require the page lock because
2067 * the pageout daemon uses that lock to get the object.
2068 */
b0d623f7 2069 vm_page_lockspin_queues();
1c79356b 2070
39236c6e
A
2071 internal_to_external = FALSE;
2072 external_to_internal = FALSE;
2073
39037602 2074 if (mem->vm_page_q_state == VM_PAGE_ON_ACTIVE_LOCAL_Q) {
39236c6e
A
2075 /*
2076 * it's much easier to get the vm_page_pageable_xxx accounting correct
2077 * if we first move the page to the active queue... it's going to end
2078 * up there anyway, and we don't do vm_page_rename's frequently enough
2079 * for this to matter.
2080 */
39037602 2081 vm_page_queues_remove(mem, FALSE);
39236c6e
A
2082 vm_page_activate(mem);
2083 }
39037602
A
2084 if (VM_PAGE_PAGEABLE(mem)) {
2085 if (m_object->internal && !new_object->internal) {
39236c6e
A
2086 internal_to_external = TRUE;
2087 }
39037602 2088 if (!m_object->internal && new_object->internal) {
39236c6e
A
2089 external_to_internal = TRUE;
2090 }
2091 }
2092
39037602 2093 tag = m_object->wire_tag;
b0d623f7 2094 vm_page_remove(mem, TRUE);
3e170ce0 2095 vm_page_insert_internal(mem, new_object, new_offset, tag, TRUE, TRUE, FALSE, FALSE, NULL);
1c79356b 2096
39236c6e
A
2097 if (internal_to_external) {
2098 vm_page_pageable_internal_count--;
2099 vm_page_pageable_external_count++;
2100 } else if (external_to_internal) {
2101 vm_page_pageable_external_count--;
2102 vm_page_pageable_internal_count++;
2103 }
2104
1c79356b
A
2105 vm_page_unlock_queues();
2106}
2107
2108/*
2109 * vm_page_init:
2110 *
2111 * Initialize the fields in a new page.
2112 * This takes a structure with random values and initializes it
2113 * so that it can be given to vm_page_release or vm_page_insert.
2114 */
2115void
2116vm_page_init(
2117 vm_page_t mem,
0b4c1975
A
2118 ppnum_t phys_page,
2119 boolean_t lopage)
1c79356b 2120{
91447636 2121 assert(phys_page);
7ddcb079
A
2122
2123#if DEBUG
2124 if ((phys_page != vm_page_fictitious_addr) && (phys_page != vm_page_guard_addr)) {
2125 if (!(pmap_valid_page(phys_page))) {
2126 panic("vm_page_init: non-DRAM phys_page 0x%x\n", phys_page);
2127 }
2128 }
2129#endif
1c79356b 2130 *mem = vm_page_template;
39037602
A
2131
2132 VM_PAGE_SET_PHYS_PAGE(mem, phys_page);
6d2010ae
A
2133#if 0
2134 /*
2135 * we're leaving this turned off for now... currently pages
2136 * come off the free list and are either immediately dirtied/referenced
2137 * due to zero-fill or COW faults, or are used to read or write files...
2138 * in the file I/O case, the UPL mechanism takes care of clearing
2139 * the state of the HW ref/mod bits in a somewhat fragile way.
2140 * Since we may change the way this works in the future (to toughen it up),
2141 * I'm leaving this as a reminder of where these bits could get cleared
2142 */
2143
2144 /*
2145 * make sure both the h/w referenced and modified bits are
2146 * clear at this point... we are especially dependent on
2147 * not finding a 'stale' h/w modified in a number of spots
2148 * once this page goes back into use
2149 */
2150 pmap_clear_refmod(phys_page, VM_MEM_MODIFIED | VM_MEM_REFERENCED);
2151#endif
0b4c1975 2152 mem->lopage = lopage;
1c79356b
A
2153}
2154
2155/*
2156 * vm_page_grab_fictitious:
2157 *
2158 * Remove a fictitious page from the free list.
2159 * Returns VM_PAGE_NULL if there are no free pages.
2160 */
2161int c_vm_page_grab_fictitious = 0;
6d2010ae 2162int c_vm_page_grab_fictitious_failed = 0;
1c79356b
A
2163int c_vm_page_release_fictitious = 0;
2164int c_vm_page_more_fictitious = 0;
2165
2166vm_page_t
2d21ac55 2167vm_page_grab_fictitious_common(
b0d623f7 2168 ppnum_t phys_addr)
1c79356b 2169{
6d2010ae
A
2170 vm_page_t m;
2171
2172 if ((m = (vm_page_t)zget(vm_page_zone))) {
1c79356b 2173
0b4c1975 2174 vm_page_init(m, phys_addr, FALSE);
1c79356b 2175 m->fictitious = TRUE;
1c79356b 2176
6d2010ae
A
2177 c_vm_page_grab_fictitious++;
2178 } else
2179 c_vm_page_grab_fictitious_failed++;
2180
1c79356b
A
2181 return m;
2182}
2183
2d21ac55
A
2184vm_page_t
2185vm_page_grab_fictitious(void)
2186{
2187 return vm_page_grab_fictitious_common(vm_page_fictitious_addr);
2188}
2189
2190vm_page_t
2191vm_page_grab_guard(void)
2192{
2193 return vm_page_grab_fictitious_common(vm_page_guard_addr);
2194}
2195
6d2010ae 2196
1c79356b
A
2197/*
2198 * vm_page_release_fictitious:
2199 *
6d2010ae 2200 * Release a fictitious page to the zone pool
1c79356b 2201 */
1c79356b
A
2202void
2203vm_page_release_fictitious(
6d2010ae 2204 vm_page_t m)
1c79356b 2205{
39037602 2206 assert((m->vm_page_q_state == VM_PAGE_NOT_ON_Q) || (m->vm_page_q_state == VM_PAGE_IS_WIRED));
1c79356b 2207 assert(m->fictitious);
39037602
A
2208 assert(VM_PAGE_GET_PHYS_PAGE(m) == vm_page_fictitious_addr ||
2209 VM_PAGE_GET_PHYS_PAGE(m) == vm_page_guard_addr);
1c79356b
A
2210
2211 c_vm_page_release_fictitious++;
6d2010ae 2212
91447636 2213 zfree(vm_page_zone, m);
1c79356b
A
2214}
2215
2216/*
2217 * vm_page_more_fictitious:
2218 *
6d2010ae 2219 * Add more fictitious pages to the zone.
1c79356b
A
2220 * Allowed to block. This routine is way intimate
2221 * with the zones code, for several reasons:
2222 * 1. we need to carve some page structures out of physical
2223 * memory before zones work, so they _cannot_ come from
2224 * the zone_map.
2225 * 2. the zone needs to be collectable in order to prevent
2226 * growth without bound. These structures are used by
2227 * the device pager (by the hundreds and thousands), as
2228 * private pages for pageout, and as blocking pages for
2229 * pagein. Temporary bursts in demand should not result in
2230 * permanent allocation of a resource.
2231 * 3. To smooth allocation humps, we allocate single pages
2232 * with kernel_memory_allocate(), and cram them into the
6d2010ae 2233 * zone.
1c79356b
A
2234 */
2235
2236void vm_page_more_fictitious(void)
2237{
6d2010ae
A
2238 vm_offset_t addr;
2239 kern_return_t retval;
1c79356b
A
2240
2241 c_vm_page_more_fictitious++;
2242
1c79356b
A
2243 /*
2244 * Allocate a single page from the zone_map. Do not wait if no physical
2245 * pages are immediately available, and do not zero the space. We need
2246 * our own blocking lock here to prevent having multiple,
2247 * simultaneous requests from piling up on the zone_map lock. Exactly
2248 * one (of our) threads should be potentially waiting on the map lock.
2249 * If winner is not vm-privileged, then the page allocation will fail,
2250 * and it will temporarily block here in the vm_page_wait().
2251 */
b0d623f7 2252 lck_mtx_lock(&vm_page_alloc_lock);
1c79356b
A
2253 /*
2254 * If another thread allocated space, just bail out now.
2255 */
2256 if (zone_free_count(vm_page_zone) > 5) {
2257 /*
2258 * The number "5" is a small number that is larger than the
2259 * number of fictitious pages that any single caller will
2260 * attempt to allocate. Otherwise, a thread will attempt to
2261 * acquire a fictitious page (vm_page_grab_fictitious), fail,
2262 * release all of the resources and locks already acquired,
2263 * and then call this routine. This routine finds the pages
2264 * that the caller released, so fails to allocate new space.
2265 * The process repeats infinitely. The largest known number
2266 * of fictitious pages required in this manner is 2. 5 is
2267 * simply a somewhat larger number.
2268 */
b0d623f7 2269 lck_mtx_unlock(&vm_page_alloc_lock);
1c79356b
A
2270 return;
2271 }
2272
91447636
A
2273 retval = kernel_memory_allocate(zone_map,
2274 &addr, PAGE_SIZE, VM_PROT_ALL,
3e170ce0 2275 KMA_KOBJECT|KMA_NOPAGEWAIT, VM_KERN_MEMORY_ZONE);
91447636 2276 if (retval != KERN_SUCCESS) {
1c79356b 2277 /*
6d2010ae 2278 * No page was available. Drop the
1c79356b
A
2279 * lock to give another thread a chance at it, and
2280 * wait for the pageout daemon to make progress.
2281 */
b0d623f7 2282 lck_mtx_unlock(&vm_page_alloc_lock);
1c79356b
A
2283 vm_page_wait(THREAD_UNINT);
2284 return;
2285 }
39236c6e 2286
7ddcb079 2287 zcram(vm_page_zone, addr, PAGE_SIZE);
6d2010ae 2288
b0d623f7 2289 lck_mtx_unlock(&vm_page_alloc_lock);
1c79356b
A
2290}
2291
1c79356b
A
2292
2293/*
2294 * vm_pool_low():
2295 *
2296 * Return true if it is not likely that a non-vm_privileged thread
2297 * can get memory without blocking. Advisory only, since the
2298 * situation may change under us.
2299 */
2300int
2301vm_pool_low(void)
2302{
2303 /* No locking, at worst we will fib. */
b0d623f7 2304 return( vm_page_free_count <= vm_page_free_reserved );
1c79356b
A
2305}
2306
0c530ab8 2307
39037602
A
2308#if CONFIG_BACKGROUND_QUEUE
2309
2310void
2311vm_page_update_background_state(vm_page_t mem)
2312{
2313 if (vm_page_background_mode == VM_PAGE_BG_DISABLED)
2314 return;
2315
2316 if (mem->vm_page_in_background == FALSE)
2317 return;
2318
2319#if BACKGROUNDQ_BASED_ON_QOS
2320 if (proc_get_effective_thread_policy(current_thread(), TASK_POLICY_QOS) <= THREAD_QOS_LEGACY)
2321 return;
2322#else
2323 task_t my_task;
2324
2325 my_task = current_task();
2326
2327 if (my_task) {
2328 if (proc_get_effective_task_policy(my_task, TASK_POLICY_DARWIN_BG))
2329 return;
2330 }
2331#endif
2332 vm_page_lockspin_queues();
2333
2334 mem->vm_page_in_background = FALSE;
2335 vm_page_background_promoted_count++;
2336
2337 vm_page_remove_from_backgroundq(mem);
2338
2339 vm_page_unlock_queues();
2340}
2341
2342
2343void
2344vm_page_assign_background_state(vm_page_t mem)
2345{
2346 if (vm_page_background_mode == VM_PAGE_BG_DISABLED)
2347 return;
2348
2349#if BACKGROUNDQ_BASED_ON_QOS
2350 if (proc_get_effective_thread_policy(current_thread(), TASK_POLICY_QOS) <= THREAD_QOS_LEGACY)
2351 mem->vm_page_in_background = TRUE;
2352 else
2353 mem->vm_page_in_background = FALSE;
2354#else
2355 task_t my_task;
2356
2357 my_task = current_task();
2358
2359 if (my_task)
2360 mem->vm_page_in_background = proc_get_effective_task_policy(my_task, TASK_POLICY_DARWIN_BG);
2361#endif
2362}
2363
2364
2365void
2366vm_page_remove_from_backgroundq(
2367 vm_page_t mem)
2368{
2369 vm_object_t m_object;
2370
2371 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
2372
2373 if (mem->vm_page_on_backgroundq) {
2374 vm_page_queue_remove(&vm_page_queue_background, mem, vm_page_t, vm_page_backgroundq);
2375
2376 mem->vm_page_backgroundq.next = 0;
2377 mem->vm_page_backgroundq.prev = 0;
2378 mem->vm_page_on_backgroundq = FALSE;
2379
2380 vm_page_background_count--;
2381
2382 m_object = VM_PAGE_OBJECT(mem);
2383
2384 if (m_object->internal)
2385 vm_page_background_internal_count--;
2386 else
2387 vm_page_background_external_count--;
2388 } else {
2389 assert(VM_PAGE_UNPACK_PTR(mem->vm_page_backgroundq.next) == (uintptr_t)NULL &&
2390 VM_PAGE_UNPACK_PTR(mem->vm_page_backgroundq.prev) == (uintptr_t)NULL);
2391 }
2392}
2393
2394
2395void
2396vm_page_add_to_backgroundq(
2397 vm_page_t mem,
2398 boolean_t first)
2399{
2400 vm_object_t m_object;
2401
2402 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
2403
2404 if (vm_page_background_mode == VM_PAGE_BG_DISABLED)
2405 return;
2406
2407 if (mem->vm_page_on_backgroundq == FALSE) {
2408
2409 m_object = VM_PAGE_OBJECT(mem);
2410
2411 if (vm_page_background_exclude_external && !m_object->internal)
2412 return;
2413
2414 if (first == TRUE)
2415 vm_page_queue_enter_first(&vm_page_queue_background, mem, vm_page_t, vm_page_backgroundq);
2416 else
2417 vm_page_queue_enter(&vm_page_queue_background, mem, vm_page_t, vm_page_backgroundq);
2418 mem->vm_page_on_backgroundq = TRUE;
2419
2420 vm_page_background_count++;
2421
2422 if (m_object->internal)
2423 vm_page_background_internal_count++;
2424 else
2425 vm_page_background_external_count++;
2426 }
2427}
2428
2429#endif
0c530ab8
A
2430
2431/*
2432 * this is an interface to support bring-up of drivers
2433 * on platforms with physical memory > 4G...
2434 */
fe8ab488 2435int vm_himemory_mode = 2;
0c530ab8
A
2436
2437
2438/*
2439 * this interface exists to support hardware controllers
2440 * incapable of generating DMAs with more than 32 bits
2441 * of address on platforms with physical memory > 4G...
2442 */
0b4c1975
A
2443unsigned int vm_lopages_allocated_q = 0;
2444unsigned int vm_lopages_allocated_cpm_success = 0;
2445unsigned int vm_lopages_allocated_cpm_failed = 0;
39037602 2446vm_page_queue_head_t vm_lopage_queue_free __attribute__((aligned(VM_PACKED_POINTER_ALIGNMENT)));
0c530ab8
A
2447
2448vm_page_t
2449vm_page_grablo(void)
2450{
0b4c1975 2451 vm_page_t mem;
0c530ab8 2452
0b4c1975 2453 if (vm_lopage_needed == FALSE)
0c530ab8
A
2454 return (vm_page_grab());
2455
b0d623f7 2456 lck_mtx_lock_spin(&vm_page_queue_free_lock);
0c530ab8 2457
39037602
A
2458 if ( !vm_page_queue_empty(&vm_lopage_queue_free)) {
2459 vm_page_queue_remove_first(&vm_lopage_queue_free,
0b4c1975
A
2460 mem,
2461 vm_page_t,
2462 pageq);
2463 assert(vm_lopage_free_count);
39037602
A
2464 assert(mem->vm_page_q_state == VM_PAGE_ON_FREE_LOPAGE_Q);
2465 mem->vm_page_q_state = VM_PAGE_NOT_ON_Q;
0c530ab8 2466
0b4c1975
A
2467 vm_lopage_free_count--;
2468 vm_lopages_allocated_q++;
2469
2470 if (vm_lopage_free_count < vm_lopage_lowater)
2471 vm_lopage_refill = TRUE;
0c530ab8 2472
0b4c1975 2473 lck_mtx_unlock(&vm_page_queue_free_lock);
39037602
A
2474
2475#if CONFIG_BACKGROUND_QUEUE
2476 vm_page_assign_background_state(mem);
2477#endif
2d21ac55 2478 } else {
0b4c1975
A
2479 lck_mtx_unlock(&vm_page_queue_free_lock);
2480
2481 if (cpm_allocate(PAGE_SIZE, &mem, atop(0xffffffff), 0, FALSE, KMA_LOMEM) != KERN_SUCCESS) {
2482
2483 lck_mtx_lock_spin(&vm_page_queue_free_lock);
2484 vm_lopages_allocated_cpm_failed++;
2485 lck_mtx_unlock(&vm_page_queue_free_lock);
2486
2487 return (VM_PAGE_NULL);
2488 }
39037602
A
2489 assert(mem->vm_page_q_state == VM_PAGE_NOT_ON_Q);
2490
0b4c1975
A
2491 mem->busy = TRUE;
2492
2493 vm_page_lockspin_queues();
2494
2495 mem->gobbled = FALSE;
2496 vm_page_gobble_count--;
2497 vm_page_wire_count--;
2498
2499 vm_lopages_allocated_cpm_success++;
2500 vm_page_unlock_queues();
0c530ab8 2501 }
0b4c1975 2502 assert(mem->busy);
0b4c1975
A
2503 assert(!mem->pmapped);
2504 assert(!mem->wpmapped);
39037602 2505 assert(!pmap_is_noencrypt(VM_PAGE_GET_PHYS_PAGE(mem)));
0b4c1975 2506
39037602 2507 VM_PAGE_ZERO_PAGEQ_ENTRY(mem);
0c530ab8
A
2508
2509 return (mem);
2510}
2511
6d2010ae 2512
1c79356b
A
2513/*
2514 * vm_page_grab:
2515 *
2d21ac55
A
2516 * first try to grab a page from the per-cpu free list...
2517 * this must be done while pre-emption is disabled... if
2518 * a page is available, we're done...
2519 * if no page is available, grab the vm_page_queue_free_lock
2520 * and see if current number of free pages would allow us
2521 * to grab at least 1... if not, return VM_PAGE_NULL as before...
2522 * if there are pages available, disable preemption and
2523 * recheck the state of the per-cpu free list... we could
2524 * have been preempted and moved to a different cpu, or
2525 * some other thread could have re-filled it... if still
2526 * empty, figure out how many pages we can steal from the
2527 * global free queue and move to the per-cpu queue...
2528 * return 1 of these pages when done... only wakeup the
2529 * pageout_scan thread if we moved pages from the global
2530 * list... no need for the wakeup if we've satisfied the
2531 * request from the per-cpu queue.
1c79356b
A
2532 */
2533
39037602
A
2534#if CONFIG_SECLUDED_MEMORY
2535vm_page_t vm_page_grab_secluded(void);
2536#endif /* CONFIG_SECLUDED_MEMORY */
1c79356b
A
2537
2538vm_page_t
39037602 2539vm_page_grab(void)
1c79356b 2540{
39037602
A
2541 return vm_page_grab_options(0);
2542}
2d21ac55 2543
39037602
A
2544vm_page_t
2545vm_page_grab_options(
2546 int grab_options)
2547{
2548 vm_page_t mem;
2d21ac55
A
2549
2550 disable_preemption();
2551
2552 if ((mem = PROCESSOR_DATA(current_processor(), free_pages))) {
2553return_page_from_cpu_list:
39037602
A
2554 assert(mem->vm_page_q_state == VM_PAGE_ON_FREE_LOCAL_Q);
2555
2d21ac55 2556 PROCESSOR_DATA(current_processor(), page_grab_count) += 1;
39037602 2557 PROCESSOR_DATA(current_processor(), free_pages) = mem->snext;
2d21ac55
A
2558
2559 enable_preemption();
39037602
A
2560 VM_PAGE_ZERO_PAGEQ_ENTRY(mem);
2561 mem->vm_page_q_state = VM_PAGE_NOT_ON_Q;
2d21ac55 2562
39037602 2563 assert(mem->listq.next == 0 && mem->listq.prev == 0);
2d21ac55 2564 assert(mem->tabled == FALSE);
39037602 2565 assert(mem->vm_page_object == 0);
2d21ac55 2566 assert(!mem->laundry);
39037602 2567 assert(pmap_verify_free(VM_PAGE_GET_PHYS_PAGE(mem)));
2d21ac55
A
2568 assert(mem->busy);
2569 assert(!mem->encrypted);
2570 assert(!mem->pmapped);
4a3eedf9 2571 assert(!mem->wpmapped);
39037602 2572 assert(!pmap_is_noencrypt(VM_PAGE_GET_PHYS_PAGE(mem)));
2d21ac55 2573
39037602
A
2574#if CONFIG_BACKGROUND_QUEUE
2575 vm_page_assign_background_state(mem);
2576#endif
2d21ac55
A
2577 return mem;
2578 }
2579 enable_preemption();
2580
1c79356b 2581
1c79356b
A
2582 /*
2583 * Optionally produce warnings if the wire or gobble
2584 * counts exceed some threshold.
2585 */
fe8ab488
A
2586#if VM_PAGE_WIRE_COUNT_WARNING
2587 if (vm_page_wire_count >= VM_PAGE_WIRE_COUNT_WARNING) {
1c79356b
A
2588 printf("mk: vm_page_grab(): high wired page count of %d\n",
2589 vm_page_wire_count);
1c79356b 2590 }
fe8ab488
A
2591#endif
2592#if VM_PAGE_GOBBLE_COUNT_WARNING
2593 if (vm_page_gobble_count >= VM_PAGE_GOBBLE_COUNT_WARNING) {
1c79356b
A
2594 printf("mk: vm_page_grab(): high gobbled page count of %d\n",
2595 vm_page_gobble_count);
1c79356b 2596 }
fe8ab488 2597#endif
39037602 2598
b0d623f7
A
2599 lck_mtx_lock_spin(&vm_page_queue_free_lock);
2600
1c79356b
A
2601 /*
2602 * Only let privileged threads (involved in pageout)
2603 * dip into the reserved pool.
2604 */
1c79356b 2605 if ((vm_page_free_count < vm_page_free_reserved) &&
91447636 2606 !(current_thread()->options & TH_OPT_VMPRIV)) {
39037602 2607 /* no page for us in the free queue... */
b0d623f7 2608 lck_mtx_unlock(&vm_page_queue_free_lock);
1c79356b 2609 mem = VM_PAGE_NULL;
39037602
A
2610
2611#if CONFIG_SECLUDED_MEMORY
2612 /* ... but can we try and grab from the secluded queue? */
2613 if (vm_page_secluded_count > 0 &&
2614 ((grab_options & VM_PAGE_GRAB_SECLUDED) ||
2615 task_can_use_secluded_mem(current_task()))) {
2616 mem = vm_page_grab_secluded();
2617 if (grab_options & VM_PAGE_GRAB_SECLUDED) {
2618 vm_page_secluded.grab_for_iokit++;
2619 if (mem) {
2620 vm_page_secluded.grab_for_iokit_success++;
2621 }
2622 }
2623 if (mem) {
2624 VM_CHECK_MEMORYSTATUS;
2625 return mem;
2626 }
2627 }
2628#else /* CONFIG_SECLUDED_MEMORY */
2629 (void) grab_options;
2630#endif /* CONFIG_SECLUDED_MEMORY */
1c79356b 2631 }
2d21ac55
A
2632 else {
2633 vm_page_t head;
2634 vm_page_t tail;
2635 unsigned int pages_to_steal;
2636 unsigned int color;
1c79356b 2637
2d21ac55 2638 while ( vm_page_free_count == 0 ) {
1c79356b 2639
b0d623f7 2640 lck_mtx_unlock(&vm_page_queue_free_lock);
2d21ac55
A
2641 /*
2642 * must be a privileged thread to be
2643 * in this state since a non-privileged
2644 * thread would have bailed if we were
2645 * under the vm_page_free_reserved mark
2646 */
2647 VM_PAGE_WAIT();
b0d623f7 2648 lck_mtx_lock_spin(&vm_page_queue_free_lock);
2d21ac55
A
2649 }
2650
2651 disable_preemption();
2652
2653 if ((mem = PROCESSOR_DATA(current_processor(), free_pages))) {
b0d623f7 2654 lck_mtx_unlock(&vm_page_queue_free_lock);
2d21ac55
A
2655
2656 /*
2657 * we got preempted and moved to another processor
2658 * or we got preempted and someone else ran and filled the cache
2659 */
2660 goto return_page_from_cpu_list;
2661 }
2662 if (vm_page_free_count <= vm_page_free_reserved)
2663 pages_to_steal = 1;
2664 else {
fe8ab488
A
2665 if (vm_free_magazine_refill_limit <= (vm_page_free_count - vm_page_free_reserved))
2666 pages_to_steal = vm_free_magazine_refill_limit;
2667 else
2d21ac55
A
2668 pages_to_steal = (vm_page_free_count - vm_page_free_reserved);
2669 }
2670 color = PROCESSOR_DATA(current_processor(), start_color);
2671 head = tail = NULL;
2672
fe8ab488
A
2673 vm_page_free_count -= pages_to_steal;
2674
2d21ac55 2675 while (pages_to_steal--) {
2d21ac55 2676
39037602 2677 while (vm_page_queue_empty(&vm_page_queue_free[color].qhead))
2d21ac55
A
2678 color = (color + 1) & vm_color_mask;
2679
39037602 2680 vm_page_queue_remove_first(&vm_page_queue_free[color].qhead,
2d21ac55
A
2681 mem,
2682 vm_page_t,
2683 pageq);
39037602 2684 assert(mem->vm_page_q_state == VM_PAGE_ON_FREE_Q);
6d2010ae 2685
39037602
A
2686 VM_PAGE_ZERO_PAGEQ_ENTRY(mem);
2687
2d21ac55
A
2688 color = (color + 1) & vm_color_mask;
2689
2690 if (head == NULL)
2691 head = mem;
2692 else
39037602 2693 tail->snext = mem;
2d21ac55
A
2694 tail = mem;
2695
39037602 2696 assert(mem->listq.next == 0 && mem->listq.prev == 0);
2d21ac55 2697 assert(mem->tabled == FALSE);
39037602 2698 assert(mem->vm_page_object == 0);
2d21ac55 2699 assert(!mem->laundry);
2d21ac55 2700
39037602
A
2701 mem->vm_page_q_state = VM_PAGE_ON_FREE_LOCAL_Q;
2702
2703 assert(pmap_verify_free(VM_PAGE_GET_PHYS_PAGE(mem)));
2d21ac55 2704 assert(mem->busy);
2d21ac55
A
2705 assert(!mem->encrypted);
2706 assert(!mem->pmapped);
4a3eedf9 2707 assert(!mem->wpmapped);
39037602 2708 assert(!pmap_is_noencrypt(VM_PAGE_GET_PHYS_PAGE(mem)));
2d21ac55 2709 }
fe8ab488
A
2710 lck_mtx_unlock(&vm_page_queue_free_lock);
2711
39037602 2712 PROCESSOR_DATA(current_processor(), free_pages) = head->snext;
2d21ac55
A
2713 PROCESSOR_DATA(current_processor(), start_color) = color;
2714
2715 /*
2716 * satisfy this request
2717 */
2718 PROCESSOR_DATA(current_processor(), page_grab_count) += 1;
2719 mem = head;
39037602
A
2720 assert(mem->vm_page_q_state == VM_PAGE_ON_FREE_LOCAL_Q);
2721
2722 VM_PAGE_ZERO_PAGEQ_ENTRY(mem);
2723 mem->vm_page_q_state = VM_PAGE_NOT_ON_Q;
91447636 2724
2d21ac55
A
2725 enable_preemption();
2726 }
1c79356b
A
2727 /*
2728 * Decide if we should poke the pageout daemon.
2729 * We do this if the free count is less than the low
2730 * water mark, or if the free count is less than the high
2731 * water mark (but above the low water mark) and the inactive
2732 * count is less than its target.
2733 *
2734 * We don't have the counts locked ... if they change a little,
2735 * it doesn't really matter.
2736 */
1c79356b 2737 if ((vm_page_free_count < vm_page_free_min) ||
316670eb
A
2738 ((vm_page_free_count < vm_page_free_target) &&
2739 ((vm_page_inactive_count + vm_page_speculative_count) < vm_page_inactive_min)))
2740 thread_wakeup((event_t) &vm_page_free_wanted);
39037602
A
2741#if CONFIG_BACKGROUND_QUEUE
2742 if (vm_page_background_mode == VM_PAGE_BG_LEVEL_3 && (vm_page_background_count > vm_page_background_limit))
2743 thread_wakeup((event_t) &vm_page_free_wanted);
2744#endif
2d21ac55 2745
6d2010ae 2746 VM_CHECK_MEMORYSTATUS;
39037602
A
2747
2748 if (mem) {
2749// dbgLog(VM_PAGE_GET_PHYS_PAGE(mem), vm_page_free_count, vm_page_wire_count, 4); /* (TEST/DEBUG) */
2750
2751#if CONFIG_BACKGROUND_QUEUE
2752 vm_page_assign_background_state(mem);
2753#endif
2754 }
2755 return mem;
2756}
2757
2758#if CONFIG_SECLUDED_MEMORY
2759vm_page_t
2760vm_page_grab_secluded(void)
2761{
2762 vm_page_t mem;
2763 vm_object_t object;
2764 int refmod_state;
2765
2766 if (vm_page_secluded_count == 0) {
2767 /* no secluded pages to grab... */
2768 return VM_PAGE_NULL;
2769 }
2770
2771 /* secluded queue is protected by the VM page queue lock */
2772 vm_page_lock_queues();
2773
2774 if (vm_page_secluded_count == 0) {
2775 /* no secluded pages to grab... */
2776 vm_page_unlock_queues();
2777 return VM_PAGE_NULL;
2778 }
2779
2780#if 00
2781 /* can we grab from the secluded queue? */
2782 if (vm_page_secluded_count > vm_page_secluded_target ||
2783 (vm_page_secluded_count > 0 &&
2784 task_can_use_secluded_mem(current_task()))) {
2785 /* OK */
2786 } else {
2787 /* can't grab from secluded queue... */
2788 vm_page_unlock_queues();
2789 return VM_PAGE_NULL;
2790 }
2791#endif
2792
2793 /* we can grab a page from secluded queue! */
2794 assert((vm_page_secluded_count_free +
2795 vm_page_secluded_count_inuse) ==
2796 vm_page_secluded_count);
2797 if (current_task()->task_can_use_secluded_mem) {
2798 assert(num_tasks_can_use_secluded_mem > 0);
2799 }
2800 assert(!vm_page_queue_empty(&vm_page_queue_secluded));
2801 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
2802 vm_page_queue_remove_first(&vm_page_queue_secluded,
2803 mem,
2804 vm_page_t,
2805 pageq);
2806 assert(mem->vm_page_q_state == VM_PAGE_ON_SECLUDED_Q);
2807
2808 VM_PAGE_ZERO_PAGEQ_ENTRY(mem);
2809 mem->vm_page_q_state = VM_PAGE_NOT_ON_Q;
2810 vm_page_secluded_count--;
2811
2812 object = VM_PAGE_OBJECT(mem);
2813
2814 assert(!mem->fictitious);
2815 assert(!VM_PAGE_WIRED(mem));
2816 if (object == VM_OBJECT_NULL) {
2817 /* free for grab! */
2818 assert(mem->busy);
2819 vm_page_secluded_count_free--;
2820 vm_page_unlock_queues();
2821 vm_page_secluded.grab_success_free++;
2822 return mem;
2823 }
2824
2825 vm_page_secluded_count_inuse--;
2826 assert(!object->internal);
2827// vm_page_pageable_external_count--;
2828
2829 if (!vm_object_lock_try(object)) {
2830// printf("SECLUDED: page %p: object %p locked\n", mem, object);
2831 vm_page_secluded.grab_failure_locked++;
2832 reactivate_secluded_page:
2833 vm_page_activate(mem);
2834 vm_page_unlock_queues();
2835 return VM_PAGE_NULL;
2836 }
2837 if (mem->busy ||
2838 mem->cleaning ||
2839 mem->laundry) {
2840 /* can't steal page in this state... */
2841 vm_object_unlock(object);
2842 vm_page_secluded.grab_failure_state++;
2843 goto reactivate_secluded_page;
2844 }
2845
2846 mem->busy = TRUE;
2847 refmod_state = pmap_disconnect(VM_PAGE_GET_PHYS_PAGE(mem));
2848 if (refmod_state & VM_MEM_REFERENCED) {
2849 mem->reference = TRUE;
2850 }
2851 if (refmod_state & VM_MEM_MODIFIED) {
2852 SET_PAGE_DIRTY(mem, FALSE);
2853 }
2854 if (mem->dirty || mem->precious) {
2855 /* can't grab a dirty page; re-activate */
2856// printf("SECLUDED: dirty page %p\n", mem);
743345f9 2857 PAGE_WAKEUP_DONE(mem);
39037602
A
2858 vm_page_secluded.grab_failure_dirty++;
2859 vm_object_unlock(object);
2860 goto reactivate_secluded_page;
2861 }
2862 if (mem->reference) {
2863 /* it's been used but we do need to grab a page... */
2864 }
743345f9
A
2865 /* page could still be on vm_page_queue_background... */
2866 vm_page_free_prepare_queues(mem);
2867
39037602
A
2868 vm_page_unlock_queues();
2869
2870 /* finish what vm_page_free() would have done... */
2871 vm_page_free_prepare_object(mem, TRUE);
2872 vm_object_unlock(object);
2873 object = VM_OBJECT_NULL;
2874 if (vm_page_free_verify) {
2875 assert(pmap_verify_free(VM_PAGE_GET_PHYS_PAGE(mem)));
2876 }
2877 pmap_clear_noencrypt(VM_PAGE_GET_PHYS_PAGE(mem));
2878 assert(mem->busy);
2879 vm_page_secluded.grab_success_other++;
1c79356b
A
2880
2881 return mem;
2882}
39037602 2883#endif /* CONFIG_SECLUDED_MEMORY */
1c79356b
A
2884
2885/*
2886 * vm_page_release:
2887 *
2888 * Return a page to the free list.
2889 */
2890
2891void
2892vm_page_release(
39037602
A
2893 vm_page_t mem,
2894 boolean_t page_queues_locked)
1c79356b 2895{
2d21ac55 2896 unsigned int color;
b0d623f7
A
2897 int need_wakeup = 0;
2898 int need_priv_wakeup = 0;
39037602
A
2899#if CONFIG_SECLUDED_MEMORY
2900 int need_secluded_wakeup = 0;
2901#endif /* CONFIG_SECLUDED_MEMORY */
55e303ae 2902
39037602
A
2903 if (page_queues_locked) {
2904 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
2905 } else {
2906 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_NOTOWNED);
2907 }
6d2010ae 2908
1c79356b 2909 assert(!mem->private && !mem->fictitious);
b0d623f7 2910 if (vm_page_free_verify) {
39037602 2911 assert(pmap_verify_free(VM_PAGE_GET_PHYS_PAGE(mem)));
b0d623f7 2912 }
39037602 2913// dbgLog(VM_PAGE_GET_PHYS_PAGE(mem), vm_page_free_count, vm_page_wire_count, 5); /* (TEST/DEBUG) */
1c79356b 2914
39037602 2915 pmap_clear_noencrypt(VM_PAGE_GET_PHYS_PAGE(mem));
7ddcb079 2916
b0d623f7 2917 lck_mtx_lock_spin(&vm_page_queue_free_lock);
6d2010ae 2918
39037602 2919 assert(mem->vm_page_q_state == VM_PAGE_NOT_ON_Q);
2d21ac55 2920 assert(mem->busy);
91447636 2921 assert(!mem->laundry);
39037602
A
2922 assert(mem->vm_page_object == 0);
2923 assert(mem->pageq.next == 0 && mem->pageq.prev == 0);
2924 assert(mem->listq.next == 0 && mem->listq.prev == 0);
2925#if CONFIG_BACKGROUND_QUEUE
2926 assert(mem->vm_page_backgroundq.next == 0 &&
2927 mem->vm_page_backgroundq.prev == 0 &&
2928 mem->vm_page_on_backgroundq == FALSE);
2929#endif
6d2010ae 2930 if ((mem->lopage == TRUE || vm_lopage_refill == TRUE) &&
0b4c1975 2931 vm_lopage_free_count < vm_lopage_free_limit &&
39037602 2932 VM_PAGE_GET_PHYS_PAGE(mem) < max_valid_low_ppnum) {
0c530ab8
A
2933 /*
2934 * this exists to support hardware controllers
2935 * incapable of generating DMAs with more than 32 bits
2936 * of address on platforms with physical memory > 4G...
2937 */
39037602
A
2938 vm_page_queue_enter_first(&vm_lopage_queue_free,
2939 mem,
2940 vm_page_t,
2941 pageq);
0c530ab8 2942 vm_lopage_free_count++;
0b4c1975
A
2943
2944 if (vm_lopage_free_count >= vm_lopage_free_limit)
2945 vm_lopage_refill = FALSE;
2946
39037602 2947 mem->vm_page_q_state = VM_PAGE_ON_FREE_LOPAGE_Q;
0b4c1975 2948 mem->lopage = TRUE;
39037602
A
2949#if CONFIG_SECLUDED_MEMORY
2950 } else if (vm_page_free_count > vm_page_free_reserved &&
2951 vm_page_secluded_count < vm_page_secluded_target &&
2952 num_tasks_can_use_secluded_mem == 0) {
2953 /*
2954 * XXX FBDP TODO: also avoid refilling secluded queue
2955 * when some IOKit objects are already grabbing from it...
2956 */
2957 if (!page_queues_locked) {
2958 if (!vm_page_trylock_queues()) {
2959 /* take locks in right order */
2960 lck_mtx_unlock(&vm_page_queue_free_lock);
2961 vm_page_lock_queues();
2962 lck_mtx_lock_spin(&vm_page_queue_free_lock);
2963 }
2964 }
6d2010ae 2965 mem->lopage = FALSE;
39037602
A
2966 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
2967 vm_page_queue_enter_first(&vm_page_queue_secluded,
2968 mem,
2969 vm_page_t,
2970 pageq);
2971 mem->vm_page_q_state = VM_PAGE_ON_SECLUDED_Q;
2972 vm_page_secluded_count++;
2973 vm_page_secluded_count_free++;
2974 if (!page_queues_locked) {
2975 vm_page_unlock_queues();
2976 }
2977 LCK_MTX_ASSERT(&vm_page_queue_free_lock, LCK_MTX_ASSERT_OWNED);
2978 if (vm_page_free_wanted_secluded > 0) {
2979 vm_page_free_wanted_secluded--;
2980 need_secluded_wakeup = 1;
2981 }
2982#endif /* CONFIG_SECLUDED_MEMORY */
2983 } else {
2984 mem->lopage = FALSE;
2985 mem->vm_page_q_state = VM_PAGE_ON_FREE_Q;
0b4c1975 2986
39037602
A
2987 color = VM_PAGE_GET_PHYS_PAGE(mem) & vm_color_mask;
2988 vm_page_queue_enter_first(&vm_page_queue_free[color].qhead,
2989 mem,
2990 vm_page_t,
2991 pageq);
0c530ab8
A
2992 vm_page_free_count++;
2993 /*
2994 * Check if we should wake up someone waiting for page.
2995 * But don't bother waking them unless they can allocate.
2996 *
2997 * We wakeup only one thread, to prevent starvation.
2998 * Because the scheduling system handles wait queues FIFO,
2999 * if we wakeup all waiting threads, one greedy thread
3000 * can starve multiple niceguy threads. When the threads
3001 * all wakeup, the greedy threads runs first, grabs the page,
3002 * and waits for another page. It will be the first to run
3003 * when the next page is freed.
3004 *
3005 * However, there is a slight danger here.
3006 * The thread we wake might not use the free page.
3007 * Then the other threads could wait indefinitely
3008 * while the page goes unused. To forestall this,
3009 * the pageout daemon will keep making free pages
3010 * as long as vm_page_free_wanted is non-zero.
3011 */
1c79356b 3012
b0d623f7
A
3013 assert(vm_page_free_count > 0);
3014 if (vm_page_free_wanted_privileged > 0) {
2d21ac55 3015 vm_page_free_wanted_privileged--;
b0d623f7 3016 need_priv_wakeup = 1;
39037602
A
3017#if CONFIG_SECLUDED_MEMORY
3018 } else if (vm_page_free_wanted_secluded > 0 &&
3019 vm_page_free_count > vm_page_free_reserved) {
3020 vm_page_free_wanted_secluded--;
3021 need_secluded_wakeup = 1;
3022#endif /* CONFIG_SECLUDED_MEMORY */
b0d623f7
A
3023 } else if (vm_page_free_wanted > 0 &&
3024 vm_page_free_count > vm_page_free_reserved) {
0c530ab8 3025 vm_page_free_wanted--;
b0d623f7 3026 need_wakeup = 1;
0c530ab8 3027 }
1c79356b 3028 }
b0d623f7
A
3029 lck_mtx_unlock(&vm_page_queue_free_lock);
3030
3031 if (need_priv_wakeup)
3032 thread_wakeup_one((event_t) &vm_page_free_wanted_privileged);
39037602
A
3033#if CONFIG_SECLUDED_MEMORY
3034 else if (need_secluded_wakeup)
3035 thread_wakeup_one((event_t) &vm_page_free_wanted_secluded);
3036#endif /* CONFIG_SECLUDED_MEMORY */
b0d623f7
A
3037 else if (need_wakeup)
3038 thread_wakeup_one((event_t) &vm_page_free_count);
2d21ac55 3039
6d2010ae 3040 VM_CHECK_MEMORYSTATUS;
1c79356b
A
3041}
3042
fe8ab488
A
3043/*
3044 * This version of vm_page_release() is used only at startup
3045 * when we are single-threaded and pages are being released
3046 * for the first time. Hence, no locking or unnecessary checks are made.
3047 * Note: VM_CHECK_MEMORYSTATUS invoked by the caller.
3048 */
3049void
3050vm_page_release_startup(
39037602 3051 vm_page_t mem)
fe8ab488 3052{
39037602 3053 vm_page_queue_t queue_free;
fe8ab488
A
3054
3055 if (vm_lopage_free_count < vm_lopage_free_limit &&
39037602 3056 VM_PAGE_GET_PHYS_PAGE(mem) < max_valid_low_ppnum) {
fe8ab488 3057 mem->lopage = TRUE;
39037602 3058 mem->vm_page_q_state = VM_PAGE_ON_FREE_LOPAGE_Q;
fe8ab488
A
3059 vm_lopage_free_count++;
3060 queue_free = &vm_lopage_queue_free;
39037602
A
3061#if CONFIG_SECLUDED_MEMORY
3062 } else if (vm_page_secluded_count < vm_page_secluded_target) {
3063 mem->lopage = FALSE;
3064 mem->vm_page_q_state = VM_PAGE_ON_SECLUDED_Q;
3065 vm_page_secluded_count++;
3066 vm_page_secluded_count_free++;
3067 queue_free = &vm_page_queue_secluded;
3068#endif /* CONFIG_SECLUDED_MEMORY */
3069 } else {
fe8ab488 3070 mem->lopage = FALSE;
39037602 3071 mem->vm_page_q_state = VM_PAGE_ON_FREE_Q;
fe8ab488 3072 vm_page_free_count++;
39037602 3073 queue_free = &vm_page_queue_free[VM_PAGE_GET_PHYS_PAGE(mem) & vm_color_mask].qhead;
fe8ab488 3074 }
39037602 3075 vm_page_queue_enter_first(queue_free, mem, vm_page_t, pageq);
fe8ab488
A
3076}
3077
1c79356b
A
3078/*
3079 * vm_page_wait:
3080 *
3081 * Wait for a page to become available.
3082 * If there are plenty of free pages, then we don't sleep.
3083 *
3084 * Returns:
3085 * TRUE: There may be another page, try again
3086 * FALSE: We were interrupted out of our wait, don't try again
3087 */
3088
3089boolean_t
3090vm_page_wait(
3091 int interruptible )
3092{
3093 /*
3094 * We can't use vm_page_free_reserved to make this
3095 * determination. Consider: some thread might
3096 * need to allocate two pages. The first allocation
3097 * succeeds, the second fails. After the first page is freed,
3098 * a call to vm_page_wait must really block.
3099 */
9bccf70c 3100 kern_return_t wait_result;
9bccf70c 3101 int need_wakeup = 0;
2d21ac55 3102 int is_privileged = current_thread()->options & TH_OPT_VMPRIV;
1c79356b 3103
b0d623f7 3104 lck_mtx_lock_spin(&vm_page_queue_free_lock);
2d21ac55
A
3105
3106 if (is_privileged && vm_page_free_count) {
b0d623f7 3107 lck_mtx_unlock(&vm_page_queue_free_lock);
2d21ac55
A
3108 return TRUE;
3109 }
2d21ac55 3110
39037602 3111 if (vm_page_free_count >= vm_page_free_target) {
b0d623f7 3112 lck_mtx_unlock(&vm_page_queue_free_lock);
39037602
A
3113 return TRUE;
3114 }
9bccf70c 3115
39037602
A
3116 if (is_privileged) {
3117 if (vm_page_free_wanted_privileged++ == 0)
3118 need_wakeup = 1;
3119 wait_result = assert_wait((event_t)&vm_page_free_wanted_privileged, interruptible);
3120#if CONFIG_SECLUDED_MEMORY
3121 } else if (secluded_for_apps &&
3122 task_can_use_secluded_mem(current_task())) {
3123#if 00
3124 /* XXX FBDP: need pageq lock for this... */
3125 /* XXX FBDP: might wait even if pages available, */
3126 /* XXX FBDP: hopefully not for too long... */
3127 if (vm_page_secluded_count > 0) {
3128 lck_mtx_unlock(&vm_page_queue_free_lock);
3129 return TRUE;
39236c6e 3130 }
39037602
A
3131#endif
3132 if (vm_page_free_wanted_secluded++ == 0) {
3133 need_wakeup = 1;
3134 }
3135 wait_result = assert_wait(
3136 (event_t)&vm_page_free_wanted_secluded,
3137 interruptible);
3138#endif /* CONFIG_SECLUDED_MEMORY */
1c79356b 3139 } else {
39037602
A
3140 if (vm_page_free_wanted++ == 0)
3141 need_wakeup = 1;
3142 wait_result = assert_wait((event_t)&vm_page_free_count,
3143 interruptible);
3144 }
3145 lck_mtx_unlock(&vm_page_queue_free_lock);
3146 counter(c_vm_page_wait_block++);
3147
3148 if (need_wakeup)
3149 thread_wakeup((event_t)&vm_page_free_wanted);
3150
3151 if (wait_result == THREAD_WAITING) {
3152 VM_DEBUG_EVENT(vm_page_wait_block, VM_PAGE_WAIT_BLOCK, DBG_FUNC_START,
3153 vm_page_free_wanted_privileged,
3154 vm_page_free_wanted,
3155#if CONFIG_SECLUDED_MEMORY
3156 vm_page_free_wanted_secluded,
3157#else /* CONFIG_SECLUDED_MEMORY */
3158 0,
3159#endif /* CONFIG_SECLUDED_MEMORY */
3160 0);
3161 wait_result = thread_block(THREAD_CONTINUE_NULL);
3162 VM_DEBUG_EVENT(vm_page_wait_block,
3163 VM_PAGE_WAIT_BLOCK, DBG_FUNC_END, 0, 0, 0, 0);
1c79356b 3164 }
39037602
A
3165
3166 return (wait_result == THREAD_AWAKENED);
1c79356b
A
3167}
3168
3169/*
3170 * vm_page_alloc:
3171 *
3172 * Allocate and return a memory cell associated
3173 * with this VM object/offset pair.
3174 *
3175 * Object must be locked.
3176 */
3177
3178vm_page_t
3179vm_page_alloc(
3180 vm_object_t object,
3181 vm_object_offset_t offset)
3182{
39037602
A
3183 vm_page_t mem;
3184 int grab_options;
1c79356b 3185
2d21ac55 3186 vm_object_lock_assert_exclusive(object);
39037602
A
3187 grab_options = 0;
3188#if CONFIG_SECLUDED_MEMORY
3189 if (object->can_grab_secluded) {
3190 grab_options |= VM_PAGE_GRAB_SECLUDED;
3191 }
3192#endif /* CONFIG_SECLUDED_MEMORY */
3193 mem = vm_page_grab_options(grab_options);
1c79356b
A
3194 if (mem == VM_PAGE_NULL)
3195 return VM_PAGE_NULL;
3196
3197 vm_page_insert(mem, object, offset);
3198
3199 return(mem);
3200}
3201
2d21ac55
A
3202/*
3203 * vm_page_alloc_guard:
3204 *
b0d623f7 3205 * Allocate a fictitious page which will be used
2d21ac55
A
3206 * as a guard page. The page will be inserted into
3207 * the object and returned to the caller.
3208 */
3209
3210vm_page_t
3211vm_page_alloc_guard(
3212 vm_object_t object,
3213 vm_object_offset_t offset)
3214{
39037602 3215 vm_page_t mem;
2d21ac55
A
3216
3217 vm_object_lock_assert_exclusive(object);
3218 mem = vm_page_grab_guard();
3219 if (mem == VM_PAGE_NULL)
3220 return VM_PAGE_NULL;
3221
3222 vm_page_insert(mem, object, offset);
3223
3224 return(mem);
3225}
3226
3227
1c79356b
A
3228counter(unsigned int c_laundry_pages_freed = 0;)
3229
1c79356b 3230/*
6d2010ae 3231 * vm_page_free_prepare:
1c79356b 3232 *
6d2010ae
A
3233 * Removes page from any queue it may be on
3234 * and disassociates it from its VM object.
1c79356b
A
3235 *
3236 * Object and page queues must be locked prior to entry.
3237 */
b0d623f7 3238static void
2d21ac55 3239vm_page_free_prepare(
6d2010ae 3240 vm_page_t mem)
b0d623f7
A
3241{
3242 vm_page_free_prepare_queues(mem);
3243 vm_page_free_prepare_object(mem, TRUE);
3244}
3245
3246
3247void
3248vm_page_free_prepare_queues(
3249 vm_page_t mem)
1c79356b 3250{
39037602
A
3251 vm_object_t m_object;
3252
2d21ac55 3253 VM_PAGE_CHECK(mem);
39037602
A
3254
3255 assert(mem->vm_page_q_state != VM_PAGE_ON_FREE_Q);
1c79356b 3256 assert(!mem->cleaning);
39037602 3257 m_object = VM_PAGE_OBJECT(mem);
fe8ab488 3258
39037602
A
3259 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
3260 if (m_object) {
3261 vm_object_lock_assert_exclusive(m_object);
b0d623f7 3262 }
2d21ac55
A
3263 if (mem->laundry) {
3264 /*
3265 * We may have to free a page while it's being laundered
3266 * if we lost its pager (due to a forced unmount, for example).
316670eb
A
3267 * We need to call vm_pageout_steal_laundry() before removing
3268 * the page from its VM object, so that we can remove it
3269 * from its pageout queue and adjust the laundry accounting
2d21ac55 3270 */
316670eb 3271 vm_pageout_steal_laundry(mem, TRUE);
2d21ac55
A
3272 counter(++c_laundry_pages_freed);
3273 }
39236c6e 3274
39037602 3275 vm_page_queues_remove(mem, TRUE);
b0d623f7
A
3276
3277 if (VM_PAGE_WIRED(mem)) {
39037602
A
3278 assert(mem->wire_count > 0);
3279
3280 if (m_object) {
3281 assert(m_object->wired_page_count > 0);
3282 m_object->wired_page_count--;
3283 if (!m_object->wired_page_count) {
3284 VM_OBJECT_UNWIRED(m_object);
3e170ce0
A
3285 }
3286
39037602
A
3287 assert(m_object->resident_page_count >=
3288 m_object->wired_page_count);
6d2010ae 3289
39037602 3290 if (m_object->purgable == VM_PURGABLE_VOLATILE) {
6d2010ae
A
3291 OSAddAtomic(+1, &vm_page_purgeable_count);
3292 assert(vm_page_purgeable_wired_count > 0);
3293 OSAddAtomic(-1, &vm_page_purgeable_wired_count);
3294 }
39037602
A
3295 if ((m_object->purgable == VM_PURGABLE_VOLATILE ||
3296 m_object->purgable == VM_PURGABLE_EMPTY) &&
3297 m_object->vo_purgeable_owner != TASK_NULL) {
fe8ab488
A
3298 task_t owner;
3299
39037602 3300 owner = m_object->vo_purgeable_owner;
fe8ab488
A
3301 /*
3302 * While wired, this page was accounted
3303 * as "non-volatile" but it should now
3304 * be accounted as "volatile".
3305 */
3306 /* one less "non-volatile"... */
3307 ledger_debit(owner->ledger,
3308 task_ledgers.purgeable_nonvolatile,
3309 PAGE_SIZE);
3310 /* ... and "phys_footprint" */
3311 ledger_debit(owner->ledger,
3312 task_ledgers.phys_footprint,
3313 PAGE_SIZE);
3314 /* one more "volatile" */
3315 ledger_credit(owner->ledger,
3316 task_ledgers.purgeable_volatile,
3317 PAGE_SIZE);
3318 }
b0d623f7 3319 }
1c79356b
A
3320 if (!mem->private && !mem->fictitious)
3321 vm_page_wire_count--;
39037602
A
3322
3323 mem->vm_page_q_state = VM_PAGE_NOT_ON_Q;
1c79356b
A
3324 mem->wire_count = 0;
3325 assert(!mem->gobbled);
3326 } else if (mem->gobbled) {
3327 if (!mem->private && !mem->fictitious)
3328 vm_page_wire_count--;
3329 vm_page_gobble_count--;
3330 }
b0d623f7
A
3331}
3332
3333
3334void
3335vm_page_free_prepare_object(
3336 vm_page_t mem,
3337 boolean_t remove_from_hash)
3338{
b0d623f7
A
3339 if (mem->tabled)
3340 vm_page_remove(mem, remove_from_hash); /* clears tabled, object, offset */
1c79356b 3341
b0d623f7 3342 PAGE_WAKEUP(mem); /* clears wanted */
1c79356b
A
3343
3344 if (mem->private) {
3345 mem->private = FALSE;
3346 mem->fictitious = TRUE;
39037602 3347 VM_PAGE_SET_PHYS_PAGE(mem, vm_page_fictitious_addr);
1c79356b 3348 }
6d2010ae 3349 if ( !mem->fictitious) {
39037602 3350 vm_page_init(mem, VM_PAGE_GET_PHYS_PAGE(mem), mem->lopage);
1c79356b
A
3351 }
3352}
3353
b0d623f7 3354
6d2010ae
A
3355/*
3356 * vm_page_free:
3357 *
3358 * Returns the given page to the free list,
3359 * disassociating it with any VM object.
3360 *
3361 * Object and page queues must be locked prior to entry.
3362 */
2d21ac55
A
3363void
3364vm_page_free(
3365 vm_page_t mem)
3366{
b0d623f7 3367 vm_page_free_prepare(mem);
6d2010ae 3368
b0d623f7
A
3369 if (mem->fictitious) {
3370 vm_page_release_fictitious(mem);
3371 } else {
39037602
A
3372 vm_page_release(mem,
3373 TRUE); /* page queues are locked */
b0d623f7
A
3374 }
3375}
3376
3377
3378void
3379vm_page_free_unlocked(
3380 vm_page_t mem,
3381 boolean_t remove_from_hash)
3382{
3383 vm_page_lockspin_queues();
3384 vm_page_free_prepare_queues(mem);
3385 vm_page_unlock_queues();
3386
3387 vm_page_free_prepare_object(mem, remove_from_hash);
3388
2d21ac55
A
3389 if (mem->fictitious) {
3390 vm_page_release_fictitious(mem);
3391 } else {
39037602 3392 vm_page_release(mem, FALSE); /* page queues are not locked */
2d21ac55
A
3393 }
3394}
55e303ae 3395
316670eb 3396
2d21ac55
A
3397/*
3398 * Free a list of pages. The list can be up to several hundred pages,
3399 * as blocked up by vm_pageout_scan().
b0d623f7 3400 * The big win is not having to take the free list lock once
316670eb 3401 * per page.
2d21ac55 3402 */
55e303ae
A
3403void
3404vm_page_free_list(
316670eb 3405 vm_page_t freeq,
b0d623f7 3406 boolean_t prepare_object)
55e303ae 3407{
316670eb 3408 vm_page_t mem;
2d21ac55 3409 vm_page_t nxt;
316670eb
A
3410 vm_page_t local_freeq;
3411 int pg_count;
2d21ac55 3412
316670eb 3413 while (freeq) {
55e303ae 3414
316670eb
A
3415 pg_count = 0;
3416 local_freeq = VM_PAGE_NULL;
3417 mem = freeq;
b0d623f7 3418
316670eb
A
3419 /*
3420 * break up the processing into smaller chunks so
3421 * that we can 'pipeline' the pages onto the
3422 * free list w/o introducing too much
3423 * contention on the global free queue lock
3424 */
3425 while (mem && pg_count < 64) {
3426
39037602
A
3427 assert(mem->vm_page_q_state == VM_PAGE_NOT_ON_Q);
3428#if CONFIG_BACKGROUND_QUEUE
3429 assert(mem->vm_page_backgroundq.next == 0 &&
3430 mem->vm_page_backgroundq.prev == 0 &&
3431 mem->vm_page_on_backgroundq == FALSE);
3432#endif
3433 nxt = mem->snext;
3434 mem->snext = NULL;
3435 assert(mem->pageq.prev == 0);
316670eb 3436
316670eb 3437 if (vm_page_free_verify && !mem->fictitious && !mem->private) {
39037602 3438 assert(pmap_verify_free(VM_PAGE_GET_PHYS_PAGE(mem)));
316670eb
A
3439 }
3440 if (prepare_object == TRUE)
3441 vm_page_free_prepare_object(mem, TRUE);
b0d623f7 3442
316670eb
A
3443 if (!mem->fictitious) {
3444 assert(mem->busy);
55e303ae 3445
316670eb
A
3446 if ((mem->lopage == TRUE || vm_lopage_refill == TRUE) &&
3447 vm_lopage_free_count < vm_lopage_free_limit &&
39037602
A
3448 VM_PAGE_GET_PHYS_PAGE(mem) < max_valid_low_ppnum) {
3449 vm_page_release(mem, FALSE); /* page queues are not locked */
3450#if CONFIG_SECLUDED_MEMORY
3451 } else if (vm_page_secluded_count < vm_page_secluded_target &&
3452 num_tasks_can_use_secluded_mem == 0) {
3453 vm_page_release(mem,
3454 FALSE); /* page queues are not locked */
3455#endif /* CONFIG_SECLUDED_MEMORY */
316670eb
A
3456 } else {
3457 /*
3458 * IMPORTANT: we can't set the page "free" here
3459 * because that would make the page eligible for
3460 * a physically-contiguous allocation (see
3461 * vm_page_find_contiguous()) right away (we don't
3462 * hold the vm_page_queue_free lock). That would
3463 * cause trouble because the page is not actually
3464 * in the free queue yet...
3465 */
39037602 3466 mem->snext = local_freeq;
316670eb
A
3467 local_freeq = mem;
3468 pg_count++;
935ed37a 3469
39037602 3470 pmap_clear_noencrypt(VM_PAGE_GET_PHYS_PAGE(mem));
935ed37a 3471 }
316670eb 3472 } else {
39037602
A
3473 assert(VM_PAGE_GET_PHYS_PAGE(mem) == vm_page_fictitious_addr ||
3474 VM_PAGE_GET_PHYS_PAGE(mem) == vm_page_guard_addr);
316670eb 3475 vm_page_release_fictitious(mem);
2d21ac55 3476 }
316670eb 3477 mem = nxt;
55e303ae 3478 }
316670eb
A
3479 freeq = mem;
3480
3481 if ( (mem = local_freeq) ) {
3482 unsigned int avail_free_count;
3483 unsigned int need_wakeup = 0;
3484 unsigned int need_priv_wakeup = 0;
39037602
A
3485#if CONFIG_SECLUDED_MEMORY
3486 unsigned int need_wakeup_secluded = 0;
3487#endif /* CONFIG_SECLUDED_MEMORY */
2d21ac55 3488
316670eb 3489 lck_mtx_lock_spin(&vm_page_queue_free_lock);
55e303ae 3490
316670eb
A
3491 while (mem) {
3492 int color;
3493
39037602 3494 nxt = mem->snext;
2d21ac55 3495
39037602 3496 assert(mem->vm_page_q_state == VM_PAGE_NOT_ON_Q);
b0d623f7 3497 assert(mem->busy);
39037602
A
3498 mem->lopage = FALSE;
3499 mem->vm_page_q_state = VM_PAGE_ON_FREE_Q;
3500
3501 color = VM_PAGE_GET_PHYS_PAGE(mem) & vm_color_mask;
3502 vm_page_queue_enter_first(&vm_page_queue_free[color].qhead,
3503 mem,
3504 vm_page_t,
3505 pageq);
316670eb 3506 mem = nxt;
2d21ac55 3507 }
316670eb
A
3508 vm_page_free_count += pg_count;
3509 avail_free_count = vm_page_free_count;
3510
3511 if (vm_page_free_wanted_privileged > 0 && avail_free_count > 0) {
3512
3513 if (avail_free_count < vm_page_free_wanted_privileged) {
3514 need_priv_wakeup = avail_free_count;
3515 vm_page_free_wanted_privileged -= avail_free_count;
3516 avail_free_count = 0;
3517 } else {
3518 need_priv_wakeup = vm_page_free_wanted_privileged;
316670eb 3519 avail_free_count -= vm_page_free_wanted_privileged;
39037602 3520 vm_page_free_wanted_privileged = 0;
316670eb 3521 }
b0d623f7 3522 }
39037602
A
3523#if CONFIG_SECLUDED_MEMORY
3524 if (vm_page_free_wanted_secluded > 0 &&
3525 avail_free_count > vm_page_free_reserved) {
3526 unsigned int available_pages;
3527 available_pages = (avail_free_count -
3528 vm_page_free_reserved);
3529 if (available_pages <
3530 vm_page_free_wanted_secluded) {
3531 need_wakeup_secluded = available_pages;
3532 vm_page_free_wanted_secluded -=
3533 available_pages;
3534 avail_free_count -= available_pages;
3535 } else {
3536 need_wakeup_secluded =
3537 vm_page_free_wanted_secluded;
3538 avail_free_count -=
3539 vm_page_free_wanted_secluded;
3540 vm_page_free_wanted_secluded = 0;
3541 }
3542 }
3543#endif /* CONFIG_SECLUDED_MEMORY */
316670eb
A
3544 if (vm_page_free_wanted > 0 && avail_free_count > vm_page_free_reserved) {
3545 unsigned int available_pages;
55e303ae 3546
316670eb 3547 available_pages = avail_free_count - vm_page_free_reserved;
55e303ae 3548
316670eb
A
3549 if (available_pages >= vm_page_free_wanted) {
3550 need_wakeup = vm_page_free_wanted;
3551 vm_page_free_wanted = 0;
3552 } else {
3553 need_wakeup = available_pages;
3554 vm_page_free_wanted -= available_pages;
3555 }
3556 }
3557 lck_mtx_unlock(&vm_page_queue_free_lock);
55e303ae 3558
316670eb
A
3559 if (need_priv_wakeup != 0) {
3560 /*
3561 * There shouldn't be that many VM-privileged threads,
3562 * so let's wake them all up, even if we don't quite
3563 * have enough pages to satisfy them all.
3564 */
3565 thread_wakeup((event_t)&vm_page_free_wanted_privileged);
3566 }
39037602
A
3567#if CONFIG_SECLUDED_MEMORY
3568 if (need_wakeup_secluded != 0 &&
3569 vm_page_free_wanted_secluded == 0) {
3570 thread_wakeup((event_t)
3571 &vm_page_free_wanted_secluded);
3572 } else {
3573 for (;
3574 need_wakeup_secluded != 0;
3575 need_wakeup_secluded--) {
3576 thread_wakeup_one(
3577 (event_t)
3578 &vm_page_free_wanted_secluded);
3579 }
3580 }
3581#endif /* CONFIG_SECLUDED_MEMORY */
316670eb
A
3582 if (need_wakeup != 0 && vm_page_free_wanted == 0) {
3583 /*
3584 * We don't expect to have any more waiters
3585 * after this, so let's wake them all up at
3586 * once.
3587 */
3588 thread_wakeup((event_t) &vm_page_free_count);
3589 } else for (; need_wakeup != 0; need_wakeup--) {
3590 /*
3591 * Wake up one waiter per page we just released.
3592 */
3593 thread_wakeup_one((event_t) &vm_page_free_count);
55e303ae 3594 }
2d21ac55 3595
316670eb 3596 VM_CHECK_MEMORYSTATUS;
b0d623f7 3597 }
55e303ae
A
3598 }
3599}
3600
3601
1c79356b
A
3602/*
3603 * vm_page_wire:
3604 *
3605 * Mark this page as wired down by yet
3606 * another map, removing it from paging queues
3607 * as necessary.
3608 *
3609 * The page's object and the page queues must be locked.
3610 */
3e170ce0
A
3611
3612
1c79356b
A
3613void
3614vm_page_wire(
39037602 3615 vm_page_t mem,
3e170ce0
A
3616 vm_tag_t tag,
3617 boolean_t check_memorystatus)
1c79356b 3618{
39037602
A
3619 vm_object_t m_object;
3620
3621 m_object = VM_PAGE_OBJECT(mem);
1c79356b 3622
39037602 3623// dbgLog(current_thread(), mem->offset, m_object, 1); /* (TEST/DEBUG) */
1c79356b
A
3624
3625 VM_PAGE_CHECK(mem);
39037602
A
3626 if (m_object) {
3627 vm_object_lock_assert_exclusive(m_object);
b0d623f7
A
3628 } else {
3629 /*
3630 * In theory, the page should be in an object before it
3631 * gets wired, since we need to hold the object lock
3632 * to update some fields in the page structure.
3633 * However, some code (i386 pmap, for example) might want
3634 * to wire a page before it gets inserted into an object.
3635 * That's somewhat OK, as long as nobody else can get to
3636 * that page and update it at the same time.
3637 */
3638 }
39037602 3639 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
b0d623f7 3640 if ( !VM_PAGE_WIRED(mem)) {
316670eb 3641
39037602
A
3642 if (mem->laundry)
3643 vm_pageout_steal_laundry(mem, TRUE);
3644
3645 vm_page_queues_remove(mem, TRUE);
3646
3647 assert(mem->wire_count == 0);
3648 mem->vm_page_q_state = VM_PAGE_IS_WIRED;
b0d623f7 3649
39037602 3650 if (m_object) {
3e170ce0
A
3651
3652 if (!mem->private && !mem->fictitious)
3653 {
39037602 3654 if (!m_object->wired_page_count)
3e170ce0
A
3655 {
3656 assert(VM_KERN_MEMORY_NONE != tag);
39037602
A
3657 m_object->wire_tag = tag;
3658 VM_OBJECT_WIRED(m_object);
3e170ce0
A
3659 }
3660 }
39037602 3661 m_object->wired_page_count++;
3e170ce0 3662
39037602
A
3663 assert(m_object->resident_page_count >=
3664 m_object->wired_page_count);
3665 if (m_object->purgable == VM_PURGABLE_VOLATILE) {
b0d623f7
A
3666 assert(vm_page_purgeable_count > 0);
3667 OSAddAtomic(-1, &vm_page_purgeable_count);
3668 OSAddAtomic(1, &vm_page_purgeable_wired_count);
3669 }
39037602
A
3670 if ((m_object->purgable == VM_PURGABLE_VOLATILE ||
3671 m_object->purgable == VM_PURGABLE_EMPTY) &&
3672 m_object->vo_purgeable_owner != TASK_NULL) {
fe8ab488
A
3673 task_t owner;
3674
39037602 3675 owner = m_object->vo_purgeable_owner;
fe8ab488
A
3676 /* less volatile bytes */
3677 ledger_debit(owner->ledger,
3678 task_ledgers.purgeable_volatile,
3679 PAGE_SIZE);
3680 /* more not-quite-volatile bytes */
3681 ledger_credit(owner->ledger,
3682 task_ledgers.purgeable_nonvolatile,
3683 PAGE_SIZE);
3684 /* more footprint */
3685 ledger_credit(owner->ledger,
3686 task_ledgers.phys_footprint,
3687 PAGE_SIZE);
3688 }
39037602 3689 if (m_object->all_reusable) {
b0d623f7
A
3690 /*
3691 * Wired pages are not counted as "re-usable"
3692 * in "all_reusable" VM objects, so nothing
3693 * to do here.
3694 */
3695 } else if (mem->reusable) {
3696 /*
3697 * This page is not "re-usable" when it's
3698 * wired, so adjust its state and the
3699 * accounting.
3700 */
39037602 3701 vm_object_reuse_pages(m_object,
b0d623f7
A
3702 mem->offset,
3703 mem->offset+PAGE_SIZE_64,
3704 FALSE);
3705 }
3706 }
3707 assert(!mem->reusable);
3708
1c79356b
A
3709 if (!mem->private && !mem->fictitious && !mem->gobbled)
3710 vm_page_wire_count++;
3711 if (mem->gobbled)
3712 vm_page_gobble_count--;
3713 mem->gobbled = FALSE;
593a1d5f 3714
3e170ce0
A
3715 if (check_memorystatus == TRUE) {
3716 VM_CHECK_MEMORYSTATUS;
3717 }
91447636
A
3718 /*
3719 * ENCRYPTED SWAP:
3720 * The page could be encrypted, but
3721 * We don't have to decrypt it here
3722 * because we don't guarantee that the
3723 * data is actually valid at this point.
3724 * The page will get decrypted in
3725 * vm_fault_wire() if needed.
3726 */
1c79356b
A
3727 }
3728 assert(!mem->gobbled);
39037602 3729 assert(mem->vm_page_q_state == VM_PAGE_IS_WIRED);
1c79356b 3730 mem->wire_count++;
39037602
A
3731 if (__improbable(mem->wire_count == 0)) {
3732 panic("vm_page_wire(%p): wire_count overflow", mem);
3733 }
b0d623f7 3734 VM_PAGE_CHECK(mem);
1c79356b
A
3735}
3736
1c79356b
A
3737/*
3738 * vm_page_unwire:
3739 *
3740 * Release one wiring of this page, potentially
3741 * enabling it to be paged again.
3742 *
3743 * The page's object and the page queues must be locked.
3744 */
3745void
3746vm_page_unwire(
0b4c1975
A
3747 vm_page_t mem,
3748 boolean_t queueit)
1c79356b 3749{
39037602
A
3750 vm_object_t m_object;
3751
3752 m_object = VM_PAGE_OBJECT(mem);
1c79356b 3753
39037602 3754// dbgLog(current_thread(), mem->offset, m_object, 0); /* (TEST/DEBUG) */
1c79356b
A
3755
3756 VM_PAGE_CHECK(mem);
b0d623f7 3757 assert(VM_PAGE_WIRED(mem));
39037602 3758 assert(mem->wire_count > 0);
4bd07ac2 3759 assert(!mem->gobbled);
39037602
A
3760 assert(m_object != VM_OBJECT_NULL);
3761 vm_object_lock_assert_exclusive(m_object);
3762 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
1c79356b 3763 if (--mem->wire_count == 0) {
39037602
A
3764 mem->vm_page_q_state = VM_PAGE_NOT_ON_Q;
3765
4bd07ac2
A
3766 if (!mem->private && !mem->fictitious) {
3767 vm_page_wire_count--;
3768 }
39037602
A
3769 assert(m_object->wired_page_count > 0);
3770 m_object->wired_page_count--;
3771 if (!m_object->wired_page_count) {
3772 VM_OBJECT_UNWIRED(m_object);
3e170ce0 3773 }
39037602
A
3774 assert(m_object->resident_page_count >=
3775 m_object->wired_page_count);
3776 if (m_object->purgable == VM_PURGABLE_VOLATILE) {
b0d623f7
A
3777 OSAddAtomic(+1, &vm_page_purgeable_count);
3778 assert(vm_page_purgeable_wired_count > 0);
3779 OSAddAtomic(-1, &vm_page_purgeable_wired_count);
3780 }
39037602
A
3781 if ((m_object->purgable == VM_PURGABLE_VOLATILE ||
3782 m_object->purgable == VM_PURGABLE_EMPTY) &&
3783 m_object->vo_purgeable_owner != TASK_NULL) {
fe8ab488
A
3784 task_t owner;
3785
39037602 3786 owner = m_object->vo_purgeable_owner;
fe8ab488
A
3787 /* more volatile bytes */
3788 ledger_credit(owner->ledger,
3789 task_ledgers.purgeable_volatile,
3790 PAGE_SIZE);
3791 /* less not-quite-volatile bytes */
3792 ledger_debit(owner->ledger,
3793 task_ledgers.purgeable_nonvolatile,
3794 PAGE_SIZE);
3795 /* less footprint */
3796 ledger_debit(owner->ledger,
3797 task_ledgers.phys_footprint,
3798 PAGE_SIZE);
3799 }
39037602
A
3800 assert(m_object != kernel_object);
3801 assert(mem->pageq.next == 0 && mem->pageq.prev == 0);
0b4c1975
A
3802
3803 if (queueit == TRUE) {
39037602 3804 if (m_object->purgable == VM_PURGABLE_EMPTY) {
0b4c1975
A
3805 vm_page_deactivate(mem);
3806 } else {
3807 vm_page_activate(mem);
3808 }
2d21ac55 3809 }
593a1d5f 3810
6d2010ae
A
3811 VM_CHECK_MEMORYSTATUS;
3812
1c79356b 3813 }
b0d623f7 3814 VM_PAGE_CHECK(mem);
1c79356b
A
3815}
3816
3817/*
3818 * vm_page_deactivate:
3819 *
3820 * Returns the given page to the inactive list,
3821 * indicating that no physical maps have access
3822 * to this page. [Used by the physical mapping system.]
3823 *
3824 * The page queues must be locked.
3825 */
3826void
3827vm_page_deactivate(
b0d623f7
A
3828 vm_page_t m)
3829{
3830 vm_page_deactivate_internal(m, TRUE);
3831}
3832
3833
3834void
3835vm_page_deactivate_internal(
3836 vm_page_t m,
3837 boolean_t clear_hw_reference)
1c79356b 3838{
39037602
A
3839 vm_object_t m_object;
3840
3841 m_object = VM_PAGE_OBJECT(m);
2d21ac55 3842
1c79356b 3843 VM_PAGE_CHECK(m);
39037602
A
3844 assert(m_object != kernel_object);
3845 assert(VM_PAGE_GET_PHYS_PAGE(m) != vm_page_guard_addr);
1c79356b 3846
39037602
A
3847// dbgLog(VM_PAGE_GET_PHYS_PAGE(m), vm_page_free_count, vm_page_wire_count, 6); /* (TEST/DEBUG) */
3848 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
1c79356b
A
3849 /*
3850 * This page is no longer very interesting. If it was
3851 * interesting (active or inactive/referenced), then we
3852 * clear the reference bit and (re)enter it in the
3853 * inactive queue. Note wired pages should not have
3854 * their reference bit cleared.
3855 */
6d2010ae 3856 assert ( !(m->absent && !m->unusual));
0b4c1975 3857
1c79356b 3858 if (m->gobbled) { /* can this happen? */
b0d623f7 3859 assert( !VM_PAGE_WIRED(m));
2d21ac55 3860
1c79356b
A
3861 if (!m->private && !m->fictitious)
3862 vm_page_wire_count--;
3863 vm_page_gobble_count--;
3864 m->gobbled = FALSE;
3865 }
316670eb
A
3866 /*
3867 * if this page is currently on the pageout queue, we can't do the
3e170ce0 3868 * vm_page_queues_remove (which doesn't handle the pageout queue case)
316670eb
A
3869 * and we can't remove it manually since we would need the object lock
3870 * (which is not required here) to decrement the activity_in_progress
3871 * reference which is held on the object while the page is in the pageout queue...
3872 * just let the normal laundry processing proceed
39037602
A
3873 */
3874 if (m->laundry || m->private || m->fictitious ||
3875 (m->vm_page_q_state == VM_PAGE_USED_BY_COMPRESSOR) ||
3876 (m->vm_page_q_state == VM_PAGE_ON_PAGEOUT_Q) ||
3877 VM_PAGE_WIRED(m)) {
3878 return;
3879 }
6d2010ae 3880 if (!m->absent && clear_hw_reference == TRUE)
39037602 3881 pmap_clear_reference(VM_PAGE_GET_PHYS_PAGE(m));
2d21ac55
A
3882
3883 m->reference = FALSE;
2d21ac55
A
3884 m->no_cache = FALSE;
3885
39037602
A
3886 if ( !VM_PAGE_INACTIVE(m)) {
3887 vm_page_queues_remove(m, FALSE);
0b4e3aa0 3888
39037602
A
3889 if (!VM_DYNAMIC_PAGING_ENABLED() &&
3890 m->dirty && m_object->internal &&
3891 (m_object->purgable == VM_PURGABLE_DENY ||
3892 m_object->purgable == VM_PURGABLE_NONVOLATILE ||
3893 m_object->purgable == VM_PURGABLE_VOLATILE)) {
3e170ce0 3894 vm_page_check_pageable_safe(m);
39037602
A
3895 vm_page_queue_enter(&vm_page_queue_throttled, m, vm_page_t, pageq);
3896 m->vm_page_q_state = VM_PAGE_ON_THROTTLED_Q;
2d21ac55 3897 vm_page_throttled_count++;
9bccf70c 3898 } else {
39037602 3899 if (m_object->named && m_object->ref_count == 1) {
2d21ac55 3900 vm_page_speculate(m, FALSE);
b0d623f7 3901#if DEVELOPMENT || DEBUG
2d21ac55 3902 vm_page_speculative_recreated++;
b0d623f7 3903#endif
2d21ac55 3904 } else {
3e170ce0 3905 vm_page_enqueue_inactive(m, FALSE);
2d21ac55 3906 }
9bccf70c 3907 }
1c79356b
A
3908 }
3909}
3910
316670eb
A
3911/*
3912 * vm_page_enqueue_cleaned
3913 *
3914 * Put the page on the cleaned queue, mark it cleaned, etc.
3915 * Being on the cleaned queue (and having m->clean_queue set)
3916 * does ** NOT ** guarantee that the page is clean!
3917 *
3918 * Call with the queues lock held.
3919 */
3920
3921void vm_page_enqueue_cleaned(vm_page_t m)
3922{
39037602
A
3923 vm_object_t m_object;
3924
3925 m_object = VM_PAGE_OBJECT(m);
3926
3927 assert(VM_PAGE_GET_PHYS_PAGE(m) != vm_page_guard_addr);
3928 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
316670eb 3929 assert( !(m->absent && !m->unusual));
39037602 3930 assert( !VM_PAGE_WIRED(m));
316670eb
A
3931
3932 if (m->gobbled) {
316670eb
A
3933 if (!m->private && !m->fictitious)
3934 vm_page_wire_count--;
3935 vm_page_gobble_count--;
3936 m->gobbled = FALSE;
3937 }
3938 /*
3939 * if this page is currently on the pageout queue, we can't do the
3e170ce0 3940 * vm_page_queues_remove (which doesn't handle the pageout queue case)
316670eb
A
3941 * and we can't remove it manually since we would need the object lock
3942 * (which is not required here) to decrement the activity_in_progress
3943 * reference which is held on the object while the page is in the pageout queue...
3944 * just let the normal laundry processing proceed
3945 */
39037602
A
3946 if (m->laundry || m->private || m->fictitious ||
3947 (m->vm_page_q_state == VM_PAGE_ON_INACTIVE_CLEANED_Q) ||
3948 (m->vm_page_q_state == VM_PAGE_ON_PAGEOUT_Q)) {
3949 return;
3950 }
3951 vm_page_queues_remove(m, FALSE);
316670eb 3952
3e170ce0 3953 vm_page_check_pageable_safe(m);
39037602
A
3954 vm_page_queue_enter(&vm_page_queue_cleaned, m, vm_page_t, pageq);
3955 m->vm_page_q_state = VM_PAGE_ON_INACTIVE_CLEANED_Q;
316670eb
A
3956 vm_page_cleaned_count++;
3957
316670eb 3958 vm_page_inactive_count++;
39037602 3959 if (m_object->internal) {
39236c6e
A
3960 vm_page_pageable_internal_count++;
3961 } else {
3962 vm_page_pageable_external_count++;
3963 }
39037602
A
3964#if CONFIG_BACKGROUND_QUEUE
3965 if (m->vm_page_in_background)
3966 vm_page_add_to_backgroundq(m, TRUE);
3967#endif
316670eb
A
3968 vm_pageout_enqueued_cleaned++;
3969}
3970
1c79356b
A
3971/*
3972 * vm_page_activate:
3973 *
3974 * Put the specified page on the active list (if appropriate).
3975 *
3976 * The page queues must be locked.
3977 */
3978
3979void
3980vm_page_activate(
39037602 3981 vm_page_t m)
1c79356b 3982{
39037602
A
3983 vm_object_t m_object;
3984
3985 m_object = VM_PAGE_OBJECT(m);
3986
1c79356b 3987 VM_PAGE_CHECK(m);
2d21ac55 3988#ifdef FIXME_4778297
39037602 3989 assert(m_object != kernel_object);
91447636 3990#endif
39037602
A
3991 assert(VM_PAGE_GET_PHYS_PAGE(m) != vm_page_guard_addr);
3992 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
6d2010ae 3993 assert( !(m->absent && !m->unusual));
0b4c1975 3994
1c79356b 3995 if (m->gobbled) {
b0d623f7 3996 assert( !VM_PAGE_WIRED(m));
1c79356b
A
3997 if (!m->private && !m->fictitious)
3998 vm_page_wire_count--;
3999 vm_page_gobble_count--;
4000 m->gobbled = FALSE;
4001 }
316670eb
A
4002 /*
4003 * if this page is currently on the pageout queue, we can't do the
3e170ce0 4004 * vm_page_queues_remove (which doesn't handle the pageout queue case)
316670eb
A
4005 * and we can't remove it manually since we would need the object lock
4006 * (which is not required here) to decrement the activity_in_progress
4007 * reference which is held on the object while the page is in the pageout queue...
4008 * just let the normal laundry processing proceed
4009 */
39037602
A
4010 if (m->laundry || m->private || m->fictitious ||
4011 (m->vm_page_q_state == VM_PAGE_USED_BY_COMPRESSOR) ||
4012 (m->vm_page_q_state == VM_PAGE_ON_PAGEOUT_Q))
1c79356b
A
4013 return;
4014
2d21ac55 4015#if DEBUG
39037602 4016 if (m->vm_page_q_state == VM_PAGE_ON_ACTIVE_Q)
2d21ac55
A
4017 panic("vm_page_activate: already active");
4018#endif
4019
39037602 4020 if (m->vm_page_q_state == VM_PAGE_ON_SPECULATIVE_Q) {
2d21ac55
A
4021 DTRACE_VM2(pgrec, int, 1, (uint64_t *), NULL);
4022 DTRACE_VM2(pgfrec, int, 1, (uint64_t *), NULL);
4023 }
316670eb 4024
39037602 4025 vm_page_queues_remove(m, FALSE);
2d21ac55 4026
b0d623f7 4027 if ( !VM_PAGE_WIRED(m)) {
3e170ce0 4028 vm_page_check_pageable_safe(m);
39037602
A
4029 if (!VM_DYNAMIC_PAGING_ENABLED() &&
4030 m->dirty && m_object->internal &&
4031 (m_object->purgable == VM_PURGABLE_DENY ||
4032 m_object->purgable == VM_PURGABLE_NONVOLATILE ||
4033 m_object->purgable == VM_PURGABLE_VOLATILE)) {
4034 vm_page_queue_enter(&vm_page_queue_throttled, m, vm_page_t, pageq);
4035 m->vm_page_q_state = VM_PAGE_ON_THROTTLED_Q;
2d21ac55 4036 vm_page_throttled_count++;
9bccf70c 4037 } else {
39037602
A
4038#if CONFIG_SECLUDED_MEMORY
4039 if (secluded_for_filecache &&
4040 vm_page_secluded_target != 0 &&
4041 num_tasks_can_use_secluded_mem == 0 &&
4042 m_object->eligible_for_secluded &&
4043 ((secluded_aging_policy == SECLUDED_AGING_FIFO) ||
4044 (secluded_aging_policy ==
4045 SECLUDED_AGING_ALONG_ACTIVE) ||
4046 (secluded_aging_policy ==
4047 SECLUDED_AGING_BEFORE_ACTIVE))) {
4048 vm_page_queue_enter(&vm_page_queue_secluded, m,
4049 vm_page_t, pageq);
4050 m->vm_page_q_state = VM_PAGE_ON_SECLUDED_Q;
4051 vm_page_secluded_count++;
4052 vm_page_secluded_count_inuse++;
4053 assert(!m_object->internal);
4054// vm_page_pageable_external_count++;
4055 } else
4056#endif /* CONFIG_SECLUDED_MEMORY */
4057 vm_page_enqueue_active(m, FALSE);
9bccf70c 4058 }
2d21ac55
A
4059 m->reference = TRUE;
4060 m->no_cache = FALSE;
1c79356b 4061 }
b0d623f7 4062 VM_PAGE_CHECK(m);
2d21ac55
A
4063}
4064
4065
4066/*
4067 * vm_page_speculate:
4068 *
4069 * Put the specified page on the speculative list (if appropriate).
4070 *
4071 * The page queues must be locked.
4072 */
4073void
4074vm_page_speculate(
4075 vm_page_t m,
4076 boolean_t new)
4077{
4078 struct vm_speculative_age_q *aq;
39037602
A
4079 vm_object_t m_object;
4080
4081 m_object = VM_PAGE_OBJECT(m);
2d21ac55
A
4082
4083 VM_PAGE_CHECK(m);
3e170ce0
A
4084 vm_page_check_pageable_safe(m);
4085
39037602
A
4086 assert(VM_PAGE_GET_PHYS_PAGE(m) != vm_page_guard_addr);
4087 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
6d2010ae 4088 assert( !(m->absent && !m->unusual));
39037602 4089 assert(m_object->internal == FALSE);
b0d623f7 4090
316670eb
A
4091 /*
4092 * if this page is currently on the pageout queue, we can't do the
3e170ce0 4093 * vm_page_queues_remove (which doesn't handle the pageout queue case)
316670eb
A
4094 * and we can't remove it manually since we would need the object lock
4095 * (which is not required here) to decrement the activity_in_progress
4096 * reference which is held on the object while the page is in the pageout queue...
4097 * just let the normal laundry processing proceed
4098 */
39037602
A
4099 if (m->laundry || m->private || m->fictitious ||
4100 (m->vm_page_q_state == VM_PAGE_USED_BY_COMPRESSOR) ||
4101 (m->vm_page_q_state == VM_PAGE_ON_PAGEOUT_Q))
6d2010ae 4102 return;
0b4c1975 4103
39037602 4104 vm_page_queues_remove(m, FALSE);
b0d623f7
A
4105
4106 if ( !VM_PAGE_WIRED(m)) {
2d21ac55 4107 mach_timespec_t ts;
b0d623f7
A
4108 clock_sec_t sec;
4109 clock_nsec_t nsec;
2d21ac55 4110
b0d623f7
A
4111 clock_get_system_nanotime(&sec, &nsec);
4112 ts.tv_sec = (unsigned int) sec;
4113 ts.tv_nsec = nsec;
2d21ac55
A
4114
4115 if (vm_page_speculative_count == 0) {
4116
4117 speculative_age_index = VM_PAGE_MIN_SPECULATIVE_AGE_Q;
4118 speculative_steal_index = VM_PAGE_MIN_SPECULATIVE_AGE_Q;
4119
4120 aq = &vm_page_queue_speculative[speculative_age_index];
4121
4122 /*
4123 * set the timer to begin a new group
4124 */
6d2010ae
A
4125 aq->age_ts.tv_sec = vm_page_speculative_q_age_ms / 1000;
4126 aq->age_ts.tv_nsec = (vm_page_speculative_q_age_ms % 1000) * 1000 * NSEC_PER_USEC;
2d21ac55
A
4127
4128 ADD_MACH_TIMESPEC(&aq->age_ts, &ts);
4129 } else {
4130 aq = &vm_page_queue_speculative[speculative_age_index];
4131
4132 if (CMP_MACH_TIMESPEC(&ts, &aq->age_ts) >= 0) {
4133
4134 speculative_age_index++;
4135
4136 if (speculative_age_index > VM_PAGE_MAX_SPECULATIVE_AGE_Q)
4137 speculative_age_index = VM_PAGE_MIN_SPECULATIVE_AGE_Q;
4138 if (speculative_age_index == speculative_steal_index) {
4139 speculative_steal_index = speculative_age_index + 1;
4140
4141 if (speculative_steal_index > VM_PAGE_MAX_SPECULATIVE_AGE_Q)
4142 speculative_steal_index = VM_PAGE_MIN_SPECULATIVE_AGE_Q;
4143 }
4144 aq = &vm_page_queue_speculative[speculative_age_index];
4145
39037602 4146 if (!vm_page_queue_empty(&aq->age_q))
2d21ac55
A
4147 vm_page_speculate_ageit(aq);
4148
6d2010ae
A
4149 aq->age_ts.tv_sec = vm_page_speculative_q_age_ms / 1000;
4150 aq->age_ts.tv_nsec = (vm_page_speculative_q_age_ms % 1000) * 1000 * NSEC_PER_USEC;
2d21ac55
A
4151
4152 ADD_MACH_TIMESPEC(&aq->age_ts, &ts);
4153 }
4154 }
39037602
A
4155 vm_page_enqueue_tail(&aq->age_q, &m->pageq);
4156 m->vm_page_q_state = VM_PAGE_ON_SPECULATIVE_Q;
2d21ac55 4157 vm_page_speculative_count++;
39037602 4158 vm_page_pageable_external_count++;
2d21ac55
A
4159
4160 if (new == TRUE) {
39037602 4161 vm_object_lock_assert_exclusive(m_object);
6d2010ae 4162
39037602 4163 m_object->pages_created++;
b0d623f7 4164#if DEVELOPMENT || DEBUG
2d21ac55 4165 vm_page_speculative_created++;
b0d623f7 4166#endif
2d21ac55
A
4167 }
4168 }
b0d623f7 4169 VM_PAGE_CHECK(m);
2d21ac55
A
4170}
4171
4172
4173/*
4174 * move pages from the specified aging bin to
4175 * the speculative bin that pageout_scan claims from
4176 *
4177 * The page queues must be locked.
4178 */
4179void
4180vm_page_speculate_ageit(struct vm_speculative_age_q *aq)
4181{
4182 struct vm_speculative_age_q *sq;
4183 vm_page_t t;
4184
4185 sq = &vm_page_queue_speculative[VM_PAGE_SPECULATIVE_AGED_Q];
4186
39037602 4187 if (vm_page_queue_empty(&sq->age_q)) {
2d21ac55
A
4188 sq->age_q.next = aq->age_q.next;
4189 sq->age_q.prev = aq->age_q.prev;
4190
39037602
A
4191 t = (vm_page_t)VM_PAGE_UNPACK_PTR(sq->age_q.next);
4192 t->pageq.prev = VM_PAGE_PACK_PTR(&sq->age_q);
2d21ac55 4193
39037602
A
4194 t = (vm_page_t)VM_PAGE_UNPACK_PTR(sq->age_q.prev);
4195 t->pageq.next = VM_PAGE_PACK_PTR(&sq->age_q);
2d21ac55 4196 } else {
39037602 4197 t = (vm_page_t)VM_PAGE_UNPACK_PTR(sq->age_q.prev);
2d21ac55
A
4198 t->pageq.next = aq->age_q.next;
4199
39037602 4200 t = (vm_page_t)VM_PAGE_UNPACK_PTR(aq->age_q.next);
2d21ac55
A
4201 t->pageq.prev = sq->age_q.prev;
4202
39037602
A
4203 t = (vm_page_t)VM_PAGE_UNPACK_PTR(aq->age_q.prev);
4204 t->pageq.next = VM_PAGE_PACK_PTR(&sq->age_q);
2d21ac55
A
4205
4206 sq->age_q.prev = aq->age_q.prev;
1c79356b 4207 }
39037602 4208 vm_page_queue_init(&aq->age_q);
2d21ac55
A
4209}
4210
4211
4212void
4213vm_page_lru(
4214 vm_page_t m)
4215{
4216 VM_PAGE_CHECK(m);
39037602
A
4217 assert(VM_PAGE_OBJECT(m) != kernel_object);
4218 assert(VM_PAGE_GET_PHYS_PAGE(m) != vm_page_guard_addr);
2d21ac55 4219
39037602 4220 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
316670eb
A
4221 /*
4222 * if this page is currently on the pageout queue, we can't do the
3e170ce0 4223 * vm_page_queues_remove (which doesn't handle the pageout queue case)
316670eb
A
4224 * and we can't remove it manually since we would need the object lock
4225 * (which is not required here) to decrement the activity_in_progress
4226 * reference which is held on the object while the page is in the pageout queue...
4227 * just let the normal laundry processing proceed
4228 */
39037602
A
4229 if (m->laundry || m->private ||
4230 (m->vm_page_q_state == VM_PAGE_USED_BY_COMPRESSOR) ||
4231 (m->vm_page_q_state == VM_PAGE_ON_PAGEOUT_Q) ||
4232 VM_PAGE_WIRED(m))
2d21ac55
A
4233 return;
4234
4235 m->no_cache = FALSE;
4236
39037602 4237 vm_page_queues_remove(m, FALSE);
2d21ac55 4238
3e170ce0 4239 vm_page_enqueue_inactive(m, FALSE);
1c79356b
A
4240}
4241
2d21ac55 4242
b0d623f7
A
4243void
4244vm_page_reactivate_all_throttled(void)
4245{
4246 vm_page_t first_throttled, last_throttled;
4247 vm_page_t first_active;
4248 vm_page_t m;
4249 int extra_active_count;
39236c6e 4250 int extra_internal_count, extra_external_count;
39037602 4251 vm_object_t m_object;
b0d623f7 4252
39037602 4253 if (!VM_DYNAMIC_PAGING_ENABLED())
6d2010ae
A
4254 return;
4255
b0d623f7 4256 extra_active_count = 0;
39236c6e
A
4257 extra_internal_count = 0;
4258 extra_external_count = 0;
b0d623f7 4259 vm_page_lock_queues();
39037602 4260 if (! vm_page_queue_empty(&vm_page_queue_throttled)) {
b0d623f7
A
4261 /*
4262 * Switch "throttled" pages to "active".
4263 */
39037602 4264 vm_page_queue_iterate(&vm_page_queue_throttled, m, vm_page_t, pageq) {
b0d623f7 4265 VM_PAGE_CHECK(m);
39037602
A
4266 assert(m->vm_page_q_state == VM_PAGE_ON_THROTTLED_Q);
4267
4268 m_object = VM_PAGE_OBJECT(m);
6d2010ae
A
4269
4270 extra_active_count++;
39037602 4271 if (m_object->internal) {
39236c6e
A
4272 extra_internal_count++;
4273 } else {
4274 extra_external_count++;
4275 }
6d2010ae 4276
39037602 4277 m->vm_page_q_state = VM_PAGE_ON_ACTIVE_Q;
b0d623f7 4278 VM_PAGE_CHECK(m);
39037602
A
4279#if CONFIG_BACKGROUND_QUEUE
4280 if (m->vm_page_in_background)
4281 vm_page_add_to_backgroundq(m, FALSE);
4282#endif
b0d623f7
A
4283 }
4284
4285 /*
4286 * Transfer the entire throttled queue to a regular LRU page queues.
4287 * We insert it at the head of the active queue, so that these pages
4288 * get re-evaluated by the LRU algorithm first, since they've been
4289 * completely out of it until now.
4290 */
39037602
A
4291 first_throttled = (vm_page_t) vm_page_queue_first(&vm_page_queue_throttled);
4292 last_throttled = (vm_page_t) vm_page_queue_last(&vm_page_queue_throttled);
4293 first_active = (vm_page_t) vm_page_queue_first(&vm_page_queue_active);
4294 if (vm_page_queue_empty(&vm_page_queue_active)) {
4295 vm_page_queue_active.prev = VM_PAGE_CONVERT_TO_QUEUE_ENTRY(last_throttled);
b0d623f7 4296 } else {
39037602 4297 first_active->pageq.prev = VM_PAGE_CONVERT_TO_QUEUE_ENTRY(last_throttled);
b0d623f7 4298 }
39037602
A
4299 vm_page_queue_active.next = VM_PAGE_CONVERT_TO_QUEUE_ENTRY(first_throttled);
4300 first_throttled->pageq.prev = VM_PAGE_CONVERT_TO_QUEUE_ENTRY(&vm_page_queue_active);
4301 last_throttled->pageq.next = VM_PAGE_CONVERT_TO_QUEUE_ENTRY(first_active);
b0d623f7
A
4302
4303#if DEBUG
4304 printf("reactivated %d throttled pages\n", vm_page_throttled_count);
4305#endif
39037602 4306 vm_page_queue_init(&vm_page_queue_throttled);
b0d623f7
A
4307 /*
4308 * Adjust the global page counts.
4309 */
4310 vm_page_active_count += extra_active_count;
39236c6e
A
4311 vm_page_pageable_internal_count += extra_internal_count;
4312 vm_page_pageable_external_count += extra_external_count;
b0d623f7
A
4313 vm_page_throttled_count = 0;
4314 }
4315 assert(vm_page_throttled_count == 0);
39037602 4316 assert(vm_page_queue_empty(&vm_page_queue_throttled));
b0d623f7
A
4317 vm_page_unlock_queues();
4318}
4319
4320
4321/*
4322 * move pages from the indicated local queue to the global active queue
4323 * its ok to fail if we're below the hard limit and force == FALSE
4324 * the nolocks == TRUE case is to allow this function to be run on
4325 * the hibernate path
4326 */
4327
4328void
4329vm_page_reactivate_local(uint32_t lid, boolean_t force, boolean_t nolocks)
4330{
4331 struct vpl *lq;
4332 vm_page_t first_local, last_local;
4333 vm_page_t first_active;
4334 vm_page_t m;
4335 uint32_t count = 0;
4336
4337 if (vm_page_local_q == NULL)
4338 return;
4339
4340 lq = &vm_page_local_q[lid].vpl_un.vpl;
4341
4342 if (nolocks == FALSE) {
4343 if (lq->vpl_count < vm_page_local_q_hard_limit && force == FALSE) {
4344 if ( !vm_page_trylockspin_queues())
4345 return;
4346 } else
4347 vm_page_lockspin_queues();
4348
4349 VPL_LOCK(&lq->vpl_lock);
4350 }
4351 if (lq->vpl_count) {
4352 /*
4353 * Switch "local" pages to "active".
4354 */
39037602 4355 assert(!vm_page_queue_empty(&lq->vpl_queue));
b0d623f7 4356
39037602 4357 vm_page_queue_iterate(&lq->vpl_queue, m, vm_page_t, pageq) {
b0d623f7 4358 VM_PAGE_CHECK(m);
3e170ce0 4359 vm_page_check_pageable_safe(m);
39037602 4360 assert(m->vm_page_q_state == VM_PAGE_ON_ACTIVE_LOCAL_Q);
b0d623f7
A
4361 assert(!m->fictitious);
4362
4363 if (m->local_id != lid)
4364 panic("vm_page_reactivate_local: found vm_page_t(%p) with wrong cpuid", m);
4365
4366 m->local_id = 0;
39037602 4367 m->vm_page_q_state = VM_PAGE_ON_ACTIVE_Q;
b0d623f7 4368 VM_PAGE_CHECK(m);
39037602
A
4369#if CONFIG_BACKGROUND_QUEUE
4370 if (m->vm_page_in_background)
4371 vm_page_add_to_backgroundq(m, FALSE);
4372#endif
b0d623f7
A
4373 count++;
4374 }
4375 if (count != lq->vpl_count)
4376 panic("vm_page_reactivate_local: count = %d, vm_page_local_count = %d\n", count, lq->vpl_count);
4377
4378 /*
4379 * Transfer the entire local queue to a regular LRU page queues.
4380 */
39037602
A
4381 first_local = (vm_page_t) vm_page_queue_first(&lq->vpl_queue);
4382 last_local = (vm_page_t) vm_page_queue_last(&lq->vpl_queue);
4383 first_active = (vm_page_t) vm_page_queue_first(&vm_page_queue_active);
b0d623f7 4384
39037602
A
4385 if (vm_page_queue_empty(&vm_page_queue_active)) {
4386 vm_page_queue_active.prev = VM_PAGE_CONVERT_TO_QUEUE_ENTRY(last_local);
b0d623f7 4387 } else {
39037602 4388 first_active->pageq.prev = VM_PAGE_CONVERT_TO_QUEUE_ENTRY(last_local);
b0d623f7 4389 }
39037602
A
4390 vm_page_queue_active.next = VM_PAGE_CONVERT_TO_QUEUE_ENTRY(first_local);
4391 first_local->pageq.prev = VM_PAGE_CONVERT_TO_QUEUE_ENTRY(&vm_page_queue_active);
4392 last_local->pageq.next = VM_PAGE_CONVERT_TO_QUEUE_ENTRY(first_active);
b0d623f7 4393
39037602 4394 vm_page_queue_init(&lq->vpl_queue);
b0d623f7
A
4395 /*
4396 * Adjust the global page counts.
4397 */
4398 vm_page_active_count += lq->vpl_count;
39236c6e
A
4399 vm_page_pageable_internal_count += lq->vpl_internal_count;
4400 vm_page_pageable_external_count += lq->vpl_external_count;
b0d623f7 4401 lq->vpl_count = 0;
39236c6e
A
4402 lq->vpl_internal_count = 0;
4403 lq->vpl_external_count = 0;
b0d623f7 4404 }
39037602 4405 assert(vm_page_queue_empty(&lq->vpl_queue));
b0d623f7
A
4406
4407 if (nolocks == FALSE) {
4408 VPL_UNLOCK(&lq->vpl_lock);
4409 vm_page_unlock_queues();
4410 }
4411}
4412
1c79356b
A
4413/*
4414 * vm_page_part_zero_fill:
4415 *
4416 * Zero-fill a part of the page.
4417 */
39236c6e 4418#define PMAP_ZERO_PART_PAGE_IMPLEMENTED
1c79356b
A
4419void
4420vm_page_part_zero_fill(
4421 vm_page_t m,
4422 vm_offset_t m_pa,
4423 vm_size_t len)
4424{
1c79356b 4425
316670eb
A
4426#if 0
4427 /*
4428 * we don't hold the page queue lock
4429 * so this check isn't safe to make
4430 */
1c79356b 4431 VM_PAGE_CHECK(m);
316670eb
A
4432#endif
4433
1c79356b 4434#ifdef PMAP_ZERO_PART_PAGE_IMPLEMENTED
39037602 4435 pmap_zero_part_page(VM_PAGE_GET_PHYS_PAGE(m), m_pa, len);
1c79356b 4436#else
39236c6e 4437 vm_page_t tmp;
1c79356b
A
4438 while (1) {
4439 tmp = vm_page_grab();
4440 if (tmp == VM_PAGE_NULL) {
4441 vm_page_wait(THREAD_UNINT);
4442 continue;
4443 }
4444 break;
4445 }
4446 vm_page_zero_fill(tmp);
4447 if(m_pa != 0) {
4448 vm_page_part_copy(m, 0, tmp, 0, m_pa);
4449 }
4450 if((m_pa + len) < PAGE_SIZE) {
4451 vm_page_part_copy(m, m_pa + len, tmp,
4452 m_pa + len, PAGE_SIZE - (m_pa + len));
4453 }
4454 vm_page_copy(tmp,m);
b0d623f7 4455 VM_PAGE_FREE(tmp);
1c79356b
A
4456#endif
4457
4458}
4459
4460/*
4461 * vm_page_zero_fill:
4462 *
4463 * Zero-fill the specified page.
4464 */
4465void
4466vm_page_zero_fill(
4467 vm_page_t m)
4468{
4469 XPR(XPR_VM_PAGE,
39037602
A
4470 "vm_page_zero_fill, object 0x%X offset 0x%X page 0x%X\n",
4471 VM_PAGE_OBJECT(m), m->offset, m, 0,0);
316670eb
A
4472#if 0
4473 /*
4474 * we don't hold the page queue lock
4475 * so this check isn't safe to make
4476 */
1c79356b 4477 VM_PAGE_CHECK(m);
316670eb 4478#endif
1c79356b 4479
39037602
A
4480// dbgTrace(0xAEAEAEAE, VM_PAGE_GET_PHYS_PAGE(m), 0); /* (BRINGUP) */
4481 pmap_zero_page(VM_PAGE_GET_PHYS_PAGE(m));
1c79356b
A
4482}
4483
4484/*
4485 * vm_page_part_copy:
4486 *
4487 * copy part of one page to another
4488 */
4489
4490void
4491vm_page_part_copy(
4492 vm_page_t src_m,
4493 vm_offset_t src_pa,
4494 vm_page_t dst_m,
4495 vm_offset_t dst_pa,
4496 vm_size_t len)
4497{
316670eb
A
4498#if 0
4499 /*
4500 * we don't hold the page queue lock
4501 * so this check isn't safe to make
4502 */
1c79356b
A
4503 VM_PAGE_CHECK(src_m);
4504 VM_PAGE_CHECK(dst_m);
316670eb 4505#endif
39037602
A
4506 pmap_copy_part_page(VM_PAGE_GET_PHYS_PAGE(src_m), src_pa,
4507 VM_PAGE_GET_PHYS_PAGE(dst_m), dst_pa, len);
1c79356b
A
4508}
4509
4510/*
4511 * vm_page_copy:
4512 *
4513 * Copy one page to another
91447636
A
4514 *
4515 * ENCRYPTED SWAP:
4516 * The source page should not be encrypted. The caller should
4517 * make sure the page is decrypted first, if necessary.
1c79356b
A
4518 */
4519
2d21ac55
A
4520int vm_page_copy_cs_validations = 0;
4521int vm_page_copy_cs_tainted = 0;
4522
1c79356b
A
4523void
4524vm_page_copy(
4525 vm_page_t src_m,
4526 vm_page_t dest_m)
4527{
39037602
A
4528 vm_object_t src_m_object;
4529
4530 src_m_object = VM_PAGE_OBJECT(src_m);
4531
1c79356b 4532 XPR(XPR_VM_PAGE,
39037602
A
4533 "vm_page_copy, object 0x%X offset 0x%X to object 0x%X offset 0x%X\n",
4534 src_m_object, src_m->offset,
4535 VM_PAGE_OBJECT(dest_m), dest_m->offset,
4536 0);
316670eb
A
4537#if 0
4538 /*
4539 * we don't hold the page queue lock
4540 * so this check isn't safe to make
4541 */
1c79356b
A
4542 VM_PAGE_CHECK(src_m);
4543 VM_PAGE_CHECK(dest_m);
316670eb 4544#endif
39037602 4545 vm_object_lock_assert_held(src_m_object);
1c79356b 4546
91447636
A
4547 /*
4548 * ENCRYPTED SWAP:
4549 * The source page should not be encrypted at this point.
4550 * The destination page will therefore not contain encrypted
4551 * data after the copy.
4552 */
4553 if (src_m->encrypted) {
4554 panic("vm_page_copy: source page %p is encrypted\n", src_m);
4555 }
4556 dest_m->encrypted = FALSE;
4557
39037602
A
4558 if (src_m_object != VM_OBJECT_NULL &&
4559 src_m_object->code_signed) {
2d21ac55 4560 /*
4a3eedf9 4561 * We're copying a page from a code-signed object.
2d21ac55
A
4562 * Whoever ends up mapping the copy page might care about
4563 * the original page's integrity, so let's validate the
4564 * source page now.
4565 */
4566 vm_page_copy_cs_validations++;
4567 vm_page_validate_cs(src_m);
39037602
A
4568#if DEVELOPMENT || DEBUG
4569 DTRACE_VM4(codesigned_copy,
4570 vm_object_t, src_m_object,
4571 vm_object_offset_t, src_m->offset,
4572 int, src_m->cs_validated,
4573 int, src_m->cs_tainted);
4574#endif /* DEVELOPMENT || DEBUG */
4575
2d21ac55 4576 }
6d2010ae
A
4577
4578 if (vm_page_is_slideable(src_m)) {
4579 boolean_t was_busy = src_m->busy;
4580 src_m->busy = TRUE;
4581 (void) vm_page_slide(src_m, 0);
4582 assert(src_m->busy);
316670eb 4583 if (!was_busy) {
6d2010ae
A
4584 PAGE_WAKEUP_DONE(src_m);
4585 }
4586 }
4587
2d21ac55 4588 /*
b0d623f7
A
4589 * Propagate the cs_tainted bit to the copy page. Do not propagate
4590 * the cs_validated bit.
2d21ac55 4591 */
2d21ac55
A
4592 dest_m->cs_tainted = src_m->cs_tainted;
4593 if (dest_m->cs_tainted) {
2d21ac55
A
4594 vm_page_copy_cs_tainted++;
4595 }
6d2010ae
A
4596 dest_m->slid = src_m->slid;
4597 dest_m->error = src_m->error; /* sliding src_m might have failed... */
39037602 4598 pmap_copy_page(VM_PAGE_GET_PHYS_PAGE(src_m), VM_PAGE_GET_PHYS_PAGE(dest_m));
1c79356b
A
4599}
4600
2d21ac55 4601#if MACH_ASSERT
b0d623f7
A
4602static void
4603_vm_page_print(
4604 vm_page_t p)
4605{
4606 printf("vm_page %p: \n", p);
39037602
A
4607 printf(" pageq: next=%p prev=%p\n",
4608 (vm_page_t)VM_PAGE_UNPACK_PTR(p->pageq.next),
4609 (vm_page_t)VM_PAGE_UNPACK_PTR(p->pageq.prev));
4610 printf(" listq: next=%p prev=%p\n",
4611 (vm_page_t)(VM_PAGE_UNPACK_PTR(p->listq.next)),
4612 (vm_page_t)(VM_PAGE_UNPACK_PTR(p->listq.prev)));
4613 printf(" next=%p\n", (vm_page_t)(VM_PAGE_UNPACK_PTR(p->next_m)));
4614 printf(" object=%p offset=0x%llx\n",VM_PAGE_OBJECT(p), p->offset);
b0d623f7 4615 printf(" wire_count=%u\n", p->wire_count);
39037602 4616 printf(" q_state=%u\n", p->vm_page_q_state);
b0d623f7 4617
39037602
A
4618 printf(" %slaundry, %sref, %sgobbled, %sprivate\n",
4619 (p->laundry ? "" : "!"),
b0d623f7
A
4620 (p->reference ? "" : "!"),
4621 (p->gobbled ? "" : "!"),
39037602 4622 (p->private ? "" : "!"));
b0d623f7 4623 printf(" %sbusy, %swanted, %stabled, %sfictitious, %spmapped, %swpmapped\n",
39037602
A
4624 (p->busy ? "" : "!"),
4625 (p->wanted ? "" : "!"),
4626 (p->tabled ? "" : "!"),
4627 (p->fictitious ? "" : "!"),
4628 (p->pmapped ? "" : "!"),
4629 (p->wpmapped ? "" : "!"));
4630 printf(" %sfree_when_done, %sabsent, %serror, %sdirty, %scleaning, %sprecious, %sclustered\n",
4631 (p->free_when_done ? "" : "!"),
b0d623f7
A
4632 (p->absent ? "" : "!"),
4633 (p->error ? "" : "!"),
4634 (p->dirty ? "" : "!"),
4635 (p->cleaning ? "" : "!"),
4636 (p->precious ? "" : "!"),
4637 (p->clustered ? "" : "!"));
4638 printf(" %soverwriting, %srestart, %sunusual, %sencrypted, %sencrypted_cleaning\n",
4639 (p->overwriting ? "" : "!"),
4640 (p->restart ? "" : "!"),
4641 (p->unusual ? "" : "!"),
4642 (p->encrypted ? "" : "!"),
4643 (p->encrypted_cleaning ? "" : "!"));
c18c124e 4644 printf(" %scs_validated, %scs_tainted, %scs_nx, %sno_cache\n",
b0d623f7
A
4645 (p->cs_validated ? "" : "!"),
4646 (p->cs_tainted ? "" : "!"),
c18c124e 4647 (p->cs_nx ? "" : "!"),
b0d623f7 4648 (p->no_cache ? "" : "!"));
b0d623f7 4649
39037602 4650 printf("phys_page=0x%x\n", VM_PAGE_GET_PHYS_PAGE(p));
b0d623f7
A
4651}
4652
1c79356b
A
4653/*
4654 * Check that the list of pages is ordered by
4655 * ascending physical address and has no holes.
4656 */
2d21ac55 4657static int
1c79356b
A
4658vm_page_verify_contiguous(
4659 vm_page_t pages,
4660 unsigned int npages)
4661{
39037602 4662 vm_page_t m;
1c79356b 4663 unsigned int page_count;
91447636 4664 vm_offset_t prev_addr;
1c79356b 4665
39037602 4666 prev_addr = VM_PAGE_GET_PHYS_PAGE(pages);
1c79356b
A
4667 page_count = 1;
4668 for (m = NEXT_PAGE(pages); m != VM_PAGE_NULL; m = NEXT_PAGE(m)) {
39037602 4669 if (VM_PAGE_GET_PHYS_PAGE(m) != prev_addr + 1) {
b0d623f7 4670 printf("m %p prev_addr 0x%lx, current addr 0x%x\n",
39037602 4671 m, (long)prev_addr, VM_PAGE_GET_PHYS_PAGE(m));
6d2010ae 4672 printf("pages %p page_count %d npages %d\n", pages, page_count, npages);
1c79356b
A
4673 panic("vm_page_verify_contiguous: not contiguous!");
4674 }
39037602 4675 prev_addr = VM_PAGE_GET_PHYS_PAGE(m);
1c79356b
A
4676 ++page_count;
4677 }
4678 if (page_count != npages) {
2d21ac55 4679 printf("pages %p actual count 0x%x but requested 0x%x\n",
1c79356b
A
4680 pages, page_count, npages);
4681 panic("vm_page_verify_contiguous: count error");
4682 }
4683 return 1;
4684}
1c79356b
A
4685
4686
2d21ac55
A
4687/*
4688 * Check the free lists for proper length etc.
4689 */
fe8ab488 4690static boolean_t vm_page_verify_this_free_list_enabled = FALSE;
b0d623f7
A
4691static unsigned int
4692vm_page_verify_free_list(
39037602 4693 vm_page_queue_head_t *vm_page_queue,
b0d623f7
A
4694 unsigned int color,
4695 vm_page_t look_for_page,
4696 boolean_t expect_page)
4697{
4698 unsigned int npages;
4699 vm_page_t m;
4700 vm_page_t prev_m;
4701 boolean_t found_page;
4702
fe8ab488
A
4703 if (! vm_page_verify_this_free_list_enabled)
4704 return 0;
4705
b0d623f7
A
4706 found_page = FALSE;
4707 npages = 0;
39037602
A
4708 prev_m = (vm_page_t)((uintptr_t)vm_page_queue);
4709
4710 vm_page_queue_iterate(vm_page_queue,
4711 m,
4712 vm_page_t,
4713 pageq) {
6d2010ae 4714
b0d623f7
A
4715 if (m == look_for_page) {
4716 found_page = TRUE;
4717 }
39037602 4718 if ((vm_page_t)VM_PAGE_UNPACK_PTR(m->pageq.prev) != prev_m)
b0d623f7 4719 panic("vm_page_verify_free_list(color=%u, npages=%u): page %p corrupted prev ptr %p instead of %p\n",
39037602 4720 color, npages, m, (vm_page_t)VM_PAGE_UNPACK_PTR(m->pageq.prev), prev_m);
b0d623f7
A
4721 if ( ! m->busy )
4722 panic("vm_page_verify_free_list(color=%u, npages=%u): page %p not busy\n",
4723 color, npages, m);
6d2010ae 4724 if (color != (unsigned int) -1) {
39037602 4725 if ((VM_PAGE_GET_PHYS_PAGE(m) & vm_color_mask) != color)
6d2010ae 4726 panic("vm_page_verify_free_list(color=%u, npages=%u): page %p wrong color %u instead of %u\n",
39037602
A
4727 color, npages, m, VM_PAGE_GET_PHYS_PAGE(m) & vm_color_mask, color);
4728 if (m->vm_page_q_state != VM_PAGE_ON_FREE_Q)
4729 panic("vm_page_verify_free_list(color=%u, npages=%u): page %p - expecting q_state == VM_PAGE_ON_FREE_Q, found %d\n",
4730 color, npages, m, m->vm_page_q_state);
4731 } else {
4732 if (m->vm_page_q_state != VM_PAGE_ON_FREE_LOCAL_Q)
4733 panic("vm_page_verify_free_list(npages=%u): local page %p - expecting q_state == VM_PAGE_ON_FREE_LOCAL_Q, found %d\n",
4734 npages, m, m->vm_page_q_state);
6d2010ae 4735 }
b0d623f7
A
4736 ++npages;
4737 prev_m = m;
4738 }
4739 if (look_for_page != VM_PAGE_NULL) {
4740 unsigned int other_color;
4741
4742 if (expect_page && !found_page) {
4743 printf("vm_page_verify_free_list(color=%u, npages=%u): page %p not found phys=%u\n",
39037602 4744 color, npages, look_for_page, VM_PAGE_GET_PHYS_PAGE(look_for_page));
b0d623f7
A
4745 _vm_page_print(look_for_page);
4746 for (other_color = 0;
4747 other_color < vm_colors;
4748 other_color++) {
4749 if (other_color == color)
4750 continue;
39037602 4751 vm_page_verify_free_list(&vm_page_queue_free[other_color].qhead,
6d2010ae 4752 other_color, look_for_page, FALSE);
b0d623f7 4753 }
6d2010ae 4754 if (color == (unsigned int) -1) {
d1ecb069
A
4755 vm_page_verify_free_list(&vm_lopage_queue_free,
4756 (unsigned int) -1, look_for_page, FALSE);
4757 }
b0d623f7
A
4758 panic("vm_page_verify_free_list(color=%u)\n", color);
4759 }
4760 if (!expect_page && found_page) {
4761 printf("vm_page_verify_free_list(color=%u, npages=%u): page %p found phys=%u\n",
39037602 4762 color, npages, look_for_page, VM_PAGE_GET_PHYS_PAGE(look_for_page));
b0d623f7
A
4763 }
4764 }
4765 return npages;
4766}
4767
fe8ab488 4768static boolean_t vm_page_verify_all_free_lists_enabled = FALSE;
2d21ac55
A
4769static void
4770vm_page_verify_free_lists( void )
4771{
d1ecb069 4772 unsigned int color, npages, nlopages;
fe8ab488 4773 boolean_t toggle = TRUE;
b0d623f7 4774
fe8ab488 4775 if (! vm_page_verify_all_free_lists_enabled)
b0d623f7
A
4776 return;
4777
2d21ac55 4778 npages = 0;
b0d623f7
A
4779
4780 lck_mtx_lock(&vm_page_queue_free_lock);
fe8ab488
A
4781
4782 if (vm_page_verify_this_free_list_enabled == TRUE) {
4783 /*
4784 * This variable has been set globally for extra checking of
4785 * each free list Q. Since we didn't set it, we don't own it
4786 * and we shouldn't toggle it.
4787 */
4788 toggle = FALSE;
4789 }
4790
4791 if (toggle == TRUE) {
4792 vm_page_verify_this_free_list_enabled = TRUE;
4793 }
2d21ac55
A
4794
4795 for( color = 0; color < vm_colors; color++ ) {
39037602 4796 npages += vm_page_verify_free_list(&vm_page_queue_free[color].qhead,
6d2010ae 4797 color, VM_PAGE_NULL, FALSE);
2d21ac55 4798 }
d1ecb069
A
4799 nlopages = vm_page_verify_free_list(&vm_lopage_queue_free,
4800 (unsigned int) -1,
4801 VM_PAGE_NULL, FALSE);
4802 if (npages != vm_page_free_count || nlopages != vm_lopage_free_count)
4803 panic("vm_page_verify_free_lists: "
4804 "npages %u free_count %d nlopages %u lo_free_count %u",
4805 npages, vm_page_free_count, nlopages, vm_lopage_free_count);
6d2010ae 4806
fe8ab488
A
4807 if (toggle == TRUE) {
4808 vm_page_verify_this_free_list_enabled = FALSE;
4809 }
4810
b0d623f7 4811 lck_mtx_unlock(&vm_page_queue_free_lock);
2d21ac55 4812}
2d21ac55 4813
b0d623f7 4814#endif /* MACH_ASSERT */
2d21ac55 4815
91447636 4816
3e170ce0
A
4817
4818
4819
4820extern boolean_t (* volatile consider_buffer_cache_collect)(int);
4821
1c79356b 4822/*
2d21ac55 4823 * CONTIGUOUS PAGE ALLOCATION
2d21ac55
A
4824 *
4825 * Find a region large enough to contain at least n pages
1c79356b
A
4826 * of contiguous physical memory.
4827 *
2d21ac55
A
4828 * This is done by traversing the vm_page_t array in a linear fashion
4829 * we assume that the vm_page_t array has the avaiable physical pages in an
4830 * ordered, ascending list... this is currently true of all our implementations
4831 * and must remain so... there can be 'holes' in the array... we also can
4832 * no longer tolerate the vm_page_t's in the list being 'freed' and reclaimed
4833 * which use to happen via 'vm_page_convert'... that function was no longer
4834 * being called and was removed...
4835 *
4836 * The basic flow consists of stabilizing some of the interesting state of
4837 * a vm_page_t behind the vm_page_queue and vm_page_free locks... we start our
4838 * sweep at the beginning of the array looking for pages that meet our criterea
4839 * for a 'stealable' page... currently we are pretty conservative... if the page
4840 * meets this criterea and is physically contiguous to the previous page in the 'run'
4841 * we keep developing it. If we hit a page that doesn't fit, we reset our state
4842 * and start to develop a new run... if at this point we've already considered
4843 * at least MAX_CONSIDERED_BEFORE_YIELD pages, we'll drop the 2 locks we hold,
4844 * and mutex_pause (which will yield the processor), to keep the latency low w/r
4845 * to other threads trying to acquire free pages (or move pages from q to q),
4846 * and then continue from the spot we left off... we only make 1 pass through the
4847 * array. Once we have a 'run' that is long enough, we'll go into the loop which
4848 * which steals the pages from the queues they're currently on... pages on the free
4849 * queue can be stolen directly... pages that are on any of the other queues
4850 * must be removed from the object they are tabled on... this requires taking the
4851 * object lock... we do this as a 'try' to prevent deadlocks... if the 'try' fails
4852 * or if the state of the page behind the vm_object lock is no longer viable, we'll
4853 * dump the pages we've currently stolen back to the free list, and pick up our
4854 * scan from the point where we aborted the 'current' run.
4855 *
4856 *
1c79356b 4857 * Requirements:
2d21ac55 4858 * - neither vm_page_queue nor vm_free_list lock can be held on entry
1c79356b 4859 *
2d21ac55 4860 * Returns a pointer to a list of gobbled/wired pages or VM_PAGE_NULL.
1c79356b 4861 *
e5568f75 4862 * Algorithm:
1c79356b 4863 */
2d21ac55
A
4864
4865#define MAX_CONSIDERED_BEFORE_YIELD 1000
4866
4867
4868#define RESET_STATE_OF_RUN() \
4869 MACRO_BEGIN \
4870 prevcontaddr = -2; \
b0d623f7 4871 start_pnum = -1; \
2d21ac55
A
4872 free_considered = 0; \
4873 substitute_needed = 0; \
4874 npages = 0; \
4875 MACRO_END
4876
b0d623f7
A
4877/*
4878 * Can we steal in-use (i.e. not free) pages when searching for
4879 * physically-contiguous pages ?
4880 */
4881#define VM_PAGE_FIND_CONTIGUOUS_CAN_STEAL 1
4882
4883static unsigned int vm_page_find_contiguous_last_idx = 0, vm_page_lomem_find_contiguous_last_idx = 0;
4884#if DEBUG
4885int vm_page_find_contig_debug = 0;
4886#endif
2d21ac55 4887
1c79356b
A
4888static vm_page_t
4889vm_page_find_contiguous(
2d21ac55
A
4890 unsigned int contig_pages,
4891 ppnum_t max_pnum,
b0d623f7
A
4892 ppnum_t pnum_mask,
4893 boolean_t wire,
4894 int flags)
1c79356b 4895{
2d21ac55 4896 vm_page_t m = NULL;
e5568f75 4897 ppnum_t prevcontaddr;
b0d623f7
A
4898 ppnum_t start_pnum;
4899 unsigned int npages, considered, scanned;
4900 unsigned int page_idx, start_idx, last_idx, orig_last_idx;
4901 unsigned int idx_last_contig_page_found = 0;
2d21ac55
A
4902 int free_considered, free_available;
4903 int substitute_needed;
3e170ce0 4904 boolean_t wrapped, zone_gc_called = FALSE;
593a1d5f 4905#if DEBUG
b0d623f7
A
4906 clock_sec_t tv_start_sec, tv_end_sec;
4907 clock_usec_t tv_start_usec, tv_end_usec;
593a1d5f 4908#endif
3e170ce0 4909
2d21ac55
A
4910 int yielded = 0;
4911 int dumped_run = 0;
4912 int stolen_pages = 0;
39236c6e 4913 int compressed_pages = 0;
3e170ce0 4914
1c79356b 4915
2d21ac55 4916 if (contig_pages == 0)
1c79356b
A
4917 return VM_PAGE_NULL;
4918
3e170ce0
A
4919full_scan_again:
4920
2d21ac55
A
4921#if MACH_ASSERT
4922 vm_page_verify_free_lists();
593a1d5f
A
4923#endif
4924#if DEBUG
2d21ac55
A
4925 clock_get_system_microtime(&tv_start_sec, &tv_start_usec);
4926#endif
39236c6e
A
4927 PAGE_REPLACEMENT_ALLOWED(TRUE);
4928
2d21ac55 4929 vm_page_lock_queues();
3e170ce0
A
4930
4931
b0d623f7 4932 lck_mtx_lock(&vm_page_queue_free_lock);
2d21ac55
A
4933
4934 RESET_STATE_OF_RUN();
1c79356b 4935
b0d623f7 4936 scanned = 0;
2d21ac55
A
4937 considered = 0;
4938 free_available = vm_page_free_count - vm_page_free_reserved;
e5568f75 4939
b0d623f7
A
4940 wrapped = FALSE;
4941
4942 if(flags & KMA_LOMEM)
4943 idx_last_contig_page_found = vm_page_lomem_find_contiguous_last_idx;
4944 else
4945 idx_last_contig_page_found = vm_page_find_contiguous_last_idx;
4946
4947 orig_last_idx = idx_last_contig_page_found;
4948 last_idx = orig_last_idx;
4949
4950 for (page_idx = last_idx, start_idx = last_idx;
2d21ac55
A
4951 npages < contig_pages && page_idx < vm_pages_count;
4952 page_idx++) {
b0d623f7
A
4953retry:
4954 if (wrapped &&
4955 npages == 0 &&
4956 page_idx >= orig_last_idx) {
4957 /*
4958 * We're back where we started and we haven't
4959 * found any suitable contiguous range. Let's
4960 * give up.
4961 */
4962 break;
4963 }
4964 scanned++;
2d21ac55 4965 m = &vm_pages[page_idx];
e5568f75 4966
b0d623f7
A
4967 assert(!m->fictitious);
4968 assert(!m->private);
4969
39037602 4970 if (max_pnum && VM_PAGE_GET_PHYS_PAGE(m) > max_pnum) {
2d21ac55
A
4971 /* no more low pages... */
4972 break;
e5568f75 4973 }
39037602 4974 if (!npages & ((VM_PAGE_GET_PHYS_PAGE(m) & pnum_mask) != 0)) {
b0d623f7
A
4975 /*
4976 * not aligned
4977 */
4978 RESET_STATE_OF_RUN();
4979
4980 } else if (VM_PAGE_WIRED(m) || m->gobbled ||
39037602
A
4981 m->encrypted_cleaning || m->laundry || m->wanted ||
4982 m->cleaning || m->overwriting || m->free_when_done) {
2d21ac55
A
4983 /*
4984 * page is in a transient state
4985 * or a state we don't want to deal
4986 * with, so don't consider it which
4987 * means starting a new run
4988 */
4989 RESET_STATE_OF_RUN();
1c79356b 4990
39037602
A
4991 } else if ((m->vm_page_q_state == VM_PAGE_NOT_ON_Q) ||
4992 (m->vm_page_q_state == VM_PAGE_ON_FREE_LOCAL_Q) ||
4993 (m->vm_page_q_state == VM_PAGE_ON_FREE_LOPAGE_Q) ||
4994 (m->vm_page_q_state == VM_PAGE_ON_PAGEOUT_Q)) {
2d21ac55 4995 /*
39037602
A
4996 * page needs to be on one of our queues (other then the pageout or special free queues)
4997 * or it needs to belong to the compressor pool (which is now indicated
4998 * by vm_page_q_state == VM_PAGE_USED_BY_COMPRESSOR and falls out
4999 * from the check for VM_PAGE_NOT_ON_Q)
2d21ac55
A
5000 * in order for it to be stable behind the
5001 * locks we hold at this point...
5002 * if not, don't consider it which
5003 * means starting a new run
5004 */
5005 RESET_STATE_OF_RUN();
5006
39037602 5007 } else if ((m->vm_page_q_state != VM_PAGE_ON_FREE_Q) && (!m->tabled || m->busy)) {
2d21ac55
A
5008 /*
5009 * pages on the free list are always 'busy'
5010 * so we couldn't test for 'busy' in the check
5011 * for the transient states... pages that are
5012 * 'free' are never 'tabled', so we also couldn't
5013 * test for 'tabled'. So we check here to make
5014 * sure that a non-free page is not busy and is
5015 * tabled on an object...
5016 * if not, don't consider it which
5017 * means starting a new run
5018 */
5019 RESET_STATE_OF_RUN();
5020
5021 } else {
39037602
A
5022 if (VM_PAGE_GET_PHYS_PAGE(m) != prevcontaddr + 1) {
5023 if ((VM_PAGE_GET_PHYS_PAGE(m) & pnum_mask) != 0) {
b0d623f7
A
5024 RESET_STATE_OF_RUN();
5025 goto did_consider;
5026 } else {
5027 npages = 1;
5028 start_idx = page_idx;
39037602 5029 start_pnum = VM_PAGE_GET_PHYS_PAGE(m);
b0d623f7 5030 }
2d21ac55
A
5031 } else {
5032 npages++;
e5568f75 5033 }
39037602 5034 prevcontaddr = VM_PAGE_GET_PHYS_PAGE(m);
b0d623f7
A
5035
5036 VM_PAGE_CHECK(m);
39037602 5037 if (m->vm_page_q_state == VM_PAGE_ON_FREE_Q) {
2d21ac55 5038 free_considered++;
b0d623f7
A
5039 } else {
5040 /*
5041 * This page is not free.
5042 * If we can't steal used pages,
5043 * we have to give up this run
5044 * and keep looking.
5045 * Otherwise, we might need to
5046 * move the contents of this page
5047 * into a substitute page.
5048 */
5049#if VM_PAGE_FIND_CONTIGUOUS_CAN_STEAL
39236c6e 5050 if (m->pmapped || m->dirty || m->precious) {
b0d623f7
A
5051 substitute_needed++;
5052 }
5053#else
5054 RESET_STATE_OF_RUN();
5055#endif
2d21ac55 5056 }
b0d623f7 5057
2d21ac55
A
5058 if ((free_considered + substitute_needed) > free_available) {
5059 /*
5060 * if we let this run continue
5061 * we will end up dropping the vm_page_free_count
5062 * below the reserve limit... we need to abort
5063 * this run, but we can at least re-consider this
5064 * page... thus the jump back to 'retry'
5065 */
5066 RESET_STATE_OF_RUN();
5067
5068 if (free_available && considered <= MAX_CONSIDERED_BEFORE_YIELD) {
5069 considered++;
5070 goto retry;
e5568f75 5071 }
2d21ac55
A
5072 /*
5073 * free_available == 0
5074 * so can't consider any free pages... if
5075 * we went to retry in this case, we'd
5076 * get stuck looking at the same page
5077 * w/o making any forward progress
5078 * we also want to take this path if we've already
5079 * reached our limit that controls the lock latency
5080 */
e5568f75 5081 }
2d21ac55 5082 }
b0d623f7 5083did_consider:
2d21ac55 5084 if (considered > MAX_CONSIDERED_BEFORE_YIELD && npages <= 1) {
39236c6e
A
5085
5086 PAGE_REPLACEMENT_ALLOWED(FALSE);
5087
b0d623f7 5088 lck_mtx_unlock(&vm_page_queue_free_lock);
2d21ac55 5089 vm_page_unlock_queues();
e5568f75 5090
2d21ac55
A
5091 mutex_pause(0);
5092
39236c6e
A
5093 PAGE_REPLACEMENT_ALLOWED(TRUE);
5094
2d21ac55 5095 vm_page_lock_queues();
b0d623f7 5096 lck_mtx_lock(&vm_page_queue_free_lock);
2d21ac55
A
5097
5098 RESET_STATE_OF_RUN();
1c79356b 5099 /*
2d21ac55
A
5100 * reset our free page limit since we
5101 * dropped the lock protecting the vm_page_free_queue
1c79356b 5102 */
2d21ac55
A
5103 free_available = vm_page_free_count - vm_page_free_reserved;
5104 considered = 0;
3e170ce0 5105
2d21ac55 5106 yielded++;
3e170ce0 5107
2d21ac55
A
5108 goto retry;
5109 }
5110 considered++;
5111 }
5112 m = VM_PAGE_NULL;
5113
b0d623f7
A
5114 if (npages != contig_pages) {
5115 if (!wrapped) {
5116 /*
5117 * We didn't find a contiguous range but we didn't
5118 * start from the very first page.
5119 * Start again from the very first page.
5120 */
5121 RESET_STATE_OF_RUN();
5122 if( flags & KMA_LOMEM)
5123 idx_last_contig_page_found = vm_page_lomem_find_contiguous_last_idx = 0;
5124 else
5125 idx_last_contig_page_found = vm_page_find_contiguous_last_idx = 0;
5126 last_idx = 0;
5127 page_idx = last_idx;
5128 wrapped = TRUE;
5129 goto retry;
5130 }
5131 lck_mtx_unlock(&vm_page_queue_free_lock);
5132 } else {
2d21ac55
A
5133 vm_page_t m1;
5134 vm_page_t m2;
5135 unsigned int cur_idx;
5136 unsigned int tmp_start_idx;
5137 vm_object_t locked_object = VM_OBJECT_NULL;
5138 boolean_t abort_run = FALSE;
5139
b0d623f7
A
5140 assert(page_idx - start_idx == contig_pages);
5141
2d21ac55
A
5142 tmp_start_idx = start_idx;
5143
5144 /*
5145 * first pass through to pull the free pages
5146 * off of the free queue so that in case we
5147 * need substitute pages, we won't grab any
5148 * of the free pages in the run... we'll clear
5149 * the 'free' bit in the 2nd pass, and even in
5150 * an abort_run case, we'll collect all of the
5151 * free pages in this run and return them to the free list
5152 */
5153 while (start_idx < page_idx) {
5154
5155 m1 = &vm_pages[start_idx++];
5156
b0d623f7 5157#if !VM_PAGE_FIND_CONTIGUOUS_CAN_STEAL
39037602 5158 assert(m1->vm_page_q_state == VM_PAGE_ON_FREE_Q);
b0d623f7
A
5159#endif
5160
39037602 5161 if (m1->vm_page_q_state == VM_PAGE_ON_FREE_Q) {
0b4c1975 5162 unsigned int color;
2d21ac55 5163
39037602 5164 color = VM_PAGE_GET_PHYS_PAGE(m1) & vm_color_mask;
b0d623f7 5165#if MACH_ASSERT
39037602 5166 vm_page_verify_free_list(&vm_page_queue_free[color].qhead, color, m1, TRUE);
b0d623f7 5167#endif
39037602
A
5168 vm_page_queue_remove(&vm_page_queue_free[color].qhead,
5169 m1,
5170 vm_page_t,
5171 pageq);
5172
5173 VM_PAGE_ZERO_PAGEQ_ENTRY(m1);
0b4c1975 5174#if MACH_ASSERT
39037602 5175 vm_page_verify_free_list(&vm_page_queue_free[color].qhead, color, VM_PAGE_NULL, FALSE);
0b4c1975 5176#endif
b0d623f7
A
5177 /*
5178 * Clear the "free" bit so that this page
5179 * does not get considered for another
5180 * concurrent physically-contiguous allocation.
5181 */
39037602 5182 m1->vm_page_q_state = VM_PAGE_NOT_ON_Q;
b0d623f7 5183 assert(m1->busy);
0b4c1975
A
5184
5185 vm_page_free_count--;
2d21ac55
A
5186 }
5187 }
b0d623f7
A
5188 if( flags & KMA_LOMEM)
5189 vm_page_lomem_find_contiguous_last_idx = page_idx;
5190 else
5191 vm_page_find_contiguous_last_idx = page_idx;
5192
2d21ac55
A
5193 /*
5194 * we can drop the free queue lock at this point since
5195 * we've pulled any 'free' candidates off of the list
5196 * we need it dropped so that we can do a vm_page_grab
5197 * when substituing for pmapped/dirty pages
5198 */
b0d623f7 5199 lck_mtx_unlock(&vm_page_queue_free_lock);
2d21ac55
A
5200
5201 start_idx = tmp_start_idx;
5202 cur_idx = page_idx - 1;
5203
5204 while (start_idx++ < page_idx) {
5205 /*
5206 * must go through the list from back to front
5207 * so that the page list is created in the
5208 * correct order - low -> high phys addresses
5209 */
5210 m1 = &vm_pages[cur_idx--];
5211
39037602 5212 if (m1->vm_page_object == 0) {
2d21ac55 5213 /*
b0d623f7 5214 * page has already been removed from
2d21ac55
A
5215 * the free list in the 1st pass
5216 */
39037602 5217 assert(m1->vm_page_q_state == VM_PAGE_NOT_ON_Q);
b0d623f7 5218 assert(m1->offset == (vm_object_offset_t) -1);
2d21ac55
A
5219 assert(m1->busy);
5220 assert(!m1->wanted);
5221 assert(!m1->laundry);
e5568f75 5222 } else {
2d21ac55 5223 vm_object_t object;
39236c6e
A
5224 int refmod;
5225 boolean_t disconnected, reusable;
2d21ac55
A
5226
5227 if (abort_run == TRUE)
5228 continue;
5229
39037602
A
5230 assert(m1->vm_page_q_state != VM_PAGE_NOT_ON_Q);
5231
5232 object = VM_PAGE_OBJECT(m1);
2d21ac55
A
5233
5234 if (object != locked_object) {
5235 if (locked_object) {
5236 vm_object_unlock(locked_object);
5237 locked_object = VM_OBJECT_NULL;
5238 }
5239 if (vm_object_lock_try(object))
5240 locked_object = object;
5241 }
5242 if (locked_object == VM_OBJECT_NULL ||
b0d623f7 5243 (VM_PAGE_WIRED(m1) || m1->gobbled ||
39037602
A
5244 m1->encrypted_cleaning || m1->laundry || m1->wanted ||
5245 m1->cleaning || m1->overwriting || m1->free_when_done || m1->busy) ||
5246 (m1->vm_page_q_state == VM_PAGE_ON_PAGEOUT_Q)) {
2d21ac55
A
5247
5248 if (locked_object) {
5249 vm_object_unlock(locked_object);
5250 locked_object = VM_OBJECT_NULL;
5251 }
5252 tmp_start_idx = cur_idx;
5253 abort_run = TRUE;
5254 continue;
5255 }
39236c6e
A
5256
5257 disconnected = FALSE;
5258 reusable = FALSE;
5259
5260 if ((m1->reusable ||
39037602
A
5261 object->all_reusable) &&
5262 (m1->vm_page_q_state == VM_PAGE_ON_INACTIVE_INTERNAL_Q) &&
39236c6e
A
5263 !m1->dirty &&
5264 !m1->reference) {
5265 /* reusable page... */
39037602 5266 refmod = pmap_disconnect(VM_PAGE_GET_PHYS_PAGE(m1));
39236c6e
A
5267 disconnected = TRUE;
5268 if (refmod == 0) {
5269 /*
5270 * ... not reused: can steal
5271 * without relocating contents.
5272 */
5273 reusable = TRUE;
5274 }
5275 }
5276
5277 if ((m1->pmapped &&
5278 ! reusable) ||
5279 m1->dirty ||
5280 m1->precious) {
2d21ac55
A
5281 vm_object_offset_t offset;
5282
5283 m2 = vm_page_grab();
5284
5285 if (m2 == VM_PAGE_NULL) {
5286 if (locked_object) {
5287 vm_object_unlock(locked_object);
5288 locked_object = VM_OBJECT_NULL;
5289 }
5290 tmp_start_idx = cur_idx;
5291 abort_run = TRUE;
5292 continue;
5293 }
39236c6e
A
5294 if (! disconnected) {
5295 if (m1->pmapped)
39037602 5296 refmod = pmap_disconnect(VM_PAGE_GET_PHYS_PAGE(m1));
39236c6e
A
5297 else
5298 refmod = 0;
5299 }
5300
5301 /* copy the page's contents */
39037602 5302 pmap_copy_page(VM_PAGE_GET_PHYS_PAGE(m1), VM_PAGE_GET_PHYS_PAGE(m2));
39236c6e
A
5303 /* copy the page's state */
5304 assert(!VM_PAGE_WIRED(m1));
39037602
A
5305 assert(m1->vm_page_q_state != VM_PAGE_ON_FREE_Q);
5306 assert(m1->vm_page_q_state != VM_PAGE_ON_PAGEOUT_Q);
39236c6e
A
5307 assert(!m1->laundry);
5308 m2->reference = m1->reference;
5309 assert(!m1->gobbled);
5310 assert(!m1->private);
5311 m2->no_cache = m1->no_cache;
fe8ab488 5312 m2->xpmapped = 0;
39236c6e
A
5313 assert(!m1->busy);
5314 assert(!m1->wanted);
5315 assert(!m1->fictitious);
5316 m2->pmapped = m1->pmapped; /* should flush cache ? */
5317 m2->wpmapped = m1->wpmapped;
39037602 5318 assert(!m1->free_when_done);
39236c6e
A
5319 m2->absent = m1->absent;
5320 m2->error = m1->error;
5321 m2->dirty = m1->dirty;
5322 assert(!m1->cleaning);
5323 m2->precious = m1->precious;
5324 m2->clustered = m1->clustered;
5325 assert(!m1->overwriting);
5326 m2->restart = m1->restart;
5327 m2->unusual = m1->unusual;
5328 m2->encrypted = m1->encrypted;
5329 assert(!m1->encrypted_cleaning);
5330 m2->cs_validated = m1->cs_validated;
5331 m2->cs_tainted = m1->cs_tainted;
c18c124e 5332 m2->cs_nx = m1->cs_nx;
39236c6e
A
5333
5334 /*
5335 * If m1 had really been reusable,
5336 * we would have just stolen it, so
5337 * let's not propagate it's "reusable"
5338 * bit and assert that m2 is not
5339 * marked as "reusable".
5340 */
5341 // m2->reusable = m1->reusable;
5342 assert(!m2->reusable);
5343
39037602 5344 // assert(!m1->lopage);
39236c6e 5345 m2->slid = m1->slid;
39037602
A
5346
5347 if (m1->vm_page_q_state == VM_PAGE_USED_BY_COMPRESSOR)
5348 m2->vm_page_q_state = VM_PAGE_USED_BY_COMPRESSOR;
39236c6e 5349
15129b1c
A
5350 /*
5351 * page may need to be flushed if
5352 * it is marshalled into a UPL
5353 * that is going to be used by a device
5354 * that doesn't support coherency
5355 */
5356 m2->written_by_kernel = TRUE;
5357
39236c6e
A
5358 /*
5359 * make sure we clear the ref/mod state
5360 * from the pmap layer... else we risk
5361 * inheriting state from the last time
5362 * this page was used...
5363 */
39037602 5364 pmap_clear_refmod(VM_PAGE_GET_PHYS_PAGE(m2), VM_MEM_MODIFIED | VM_MEM_REFERENCED);
2d21ac55
A
5365
5366 if (refmod & VM_MEM_REFERENCED)
5367 m2->reference = TRUE;
316670eb
A
5368 if (refmod & VM_MEM_MODIFIED) {
5369 SET_PAGE_DIRTY(m2, TRUE);
5370 }
2d21ac55
A
5371 offset = m1->offset;
5372
5373 /*
5374 * completely cleans up the state
5375 * of the page so that it is ready
5376 * to be put onto the free list, or
5377 * for this purpose it looks like it
5378 * just came off of the free list
5379 */
5380 vm_page_free_prepare(m1);
5381
5382 /*
39236c6e
A
5383 * now put the substitute page
5384 * on the object
2d21ac55 5385 */
3e170ce0 5386 vm_page_insert_internal(m2, locked_object, offset, VM_KERN_MEMORY_NONE, TRUE, TRUE, FALSE, FALSE, NULL);
2d21ac55 5387
39037602 5388 if (m2->vm_page_q_state == VM_PAGE_USED_BY_COMPRESSOR) {
39236c6e
A
5389 m2->pmapped = TRUE;
5390 m2->wpmapped = TRUE;
2d21ac55 5391
39236c6e
A
5392 PMAP_ENTER(kernel_pmap, m2->offset, m2,
5393 VM_PROT_READ | VM_PROT_WRITE, VM_PROT_NONE, 0, TRUE);
3e170ce0 5394
39236c6e 5395 compressed_pages++;
3e170ce0 5396
39236c6e
A
5397 } else {
5398 if (m2->reference)
5399 vm_page_activate(m2);
5400 else
5401 vm_page_deactivate(m2);
5402 }
2d21ac55
A
5403 PAGE_WAKEUP_DONE(m2);
5404
5405 } else {
39037602 5406 assert(m1->vm_page_q_state != VM_PAGE_USED_BY_COMPRESSOR);
39236c6e 5407
2d21ac55
A
5408 /*
5409 * completely cleans up the state
5410 * of the page so that it is ready
5411 * to be put onto the free list, or
5412 * for this purpose it looks like it
5413 * just came off of the free list
5414 */
5415 vm_page_free_prepare(m1);
5416 }
3e170ce0 5417
2d21ac55 5418 stolen_pages++;
3e170ce0 5419
1c79356b 5420 }
39037602
A
5421#if CONFIG_BACKGROUND_QUEUE
5422 vm_page_assign_background_state(m1);
5423#endif
5424 VM_PAGE_ZERO_PAGEQ_ENTRY(m1);
5425 m1->snext = m;
2d21ac55 5426 m = m1;
e5568f75 5427 }
2d21ac55
A
5428 if (locked_object) {
5429 vm_object_unlock(locked_object);
5430 locked_object = VM_OBJECT_NULL;
1c79356b
A
5431 }
5432
2d21ac55
A
5433 if (abort_run == TRUE) {
5434 if (m != VM_PAGE_NULL) {
b0d623f7 5435 vm_page_free_list(m, FALSE);
2d21ac55 5436 }
3e170ce0 5437
2d21ac55 5438 dumped_run++;
3e170ce0 5439
2d21ac55
A
5440 /*
5441 * want the index of the last
5442 * page in this run that was
5443 * successfully 'stolen', so back
5444 * it up 1 for the auto-decrement on use
5445 * and 1 more to bump back over this page
5446 */
5447 page_idx = tmp_start_idx + 2;
b0d623f7
A
5448 if (page_idx >= vm_pages_count) {
5449 if (wrapped)
5450 goto done_scanning;
5451 page_idx = last_idx = 0;
5452 wrapped = TRUE;
5453 }
5454 abort_run = FALSE;
5455
2d21ac55 5456 /*
b0d623f7
A
5457 * We didn't find a contiguous range but we didn't
5458 * start from the very first page.
5459 * Start again from the very first page.
2d21ac55 5460 */
b0d623f7
A
5461 RESET_STATE_OF_RUN();
5462
5463 if( flags & KMA_LOMEM)
5464 idx_last_contig_page_found = vm_page_lomem_find_contiguous_last_idx = page_idx;
5465 else
5466 idx_last_contig_page_found = vm_page_find_contiguous_last_idx = page_idx;
5467
5468 last_idx = page_idx;
2d21ac55 5469
b0d623f7
A
5470 lck_mtx_lock(&vm_page_queue_free_lock);
5471 /*
5472 * reset our free page limit since we
5473 * dropped the lock protecting the vm_page_free_queue
5474 */
5475 free_available = vm_page_free_count - vm_page_free_reserved;
2d21ac55
A
5476 goto retry;
5477 }
e5568f75 5478
e5568f75 5479 for (m1 = m; m1 != VM_PAGE_NULL; m1 = NEXT_PAGE(m1)) {
2d21ac55 5480
39037602
A
5481 assert(m1->vm_page_q_state == VM_PAGE_NOT_ON_Q);
5482 assert(m1->wire_count == 0);
5483
5484 if (wire == TRUE) {
2d21ac55 5485 m1->wire_count++;
39037602
A
5486 m1->vm_page_q_state = VM_PAGE_IS_WIRED;
5487 } else
2d21ac55 5488 m1->gobbled = TRUE;
e5568f75 5489 }
2d21ac55
A
5490 if (wire == FALSE)
5491 vm_page_gobble_count += npages;
5492
5493 /*
5494 * gobbled pages are also counted as wired pages
5495 */
e5568f75 5496 vm_page_wire_count += npages;
e5568f75 5497
2d21ac55
A
5498 assert(vm_page_verify_contiguous(m, npages));
5499 }
5500done_scanning:
39236c6e
A
5501 PAGE_REPLACEMENT_ALLOWED(FALSE);
5502
2d21ac55
A
5503 vm_page_unlock_queues();
5504
593a1d5f 5505#if DEBUG
2d21ac55
A
5506 clock_get_system_microtime(&tv_end_sec, &tv_end_usec);
5507
5508 tv_end_sec -= tv_start_sec;
5509 if (tv_end_usec < tv_start_usec) {
5510 tv_end_sec--;
5511 tv_end_usec += 1000000;
1c79356b 5512 }
2d21ac55
A
5513 tv_end_usec -= tv_start_usec;
5514 if (tv_end_usec >= 1000000) {
5515 tv_end_sec++;
5516 tv_end_sec -= 1000000;
5517 }
b0d623f7 5518 if (vm_page_find_contig_debug) {
39236c6e
A
5519 printf("%s(num=%d,low=%d): found %d pages at 0x%llx in %ld.%06ds... started at %d... scanned %d pages... yielded %d times... dumped run %d times... stole %d pages... stole %d compressed pages\n",
5520 __func__, contig_pages, max_pnum, npages, (vm_object_offset_t)start_pnum << PAGE_SHIFT,
5521 (long)tv_end_sec, tv_end_usec, orig_last_idx,
5522 scanned, yielded, dumped_run, stolen_pages, compressed_pages);
b0d623f7 5523 }
e5568f75 5524
593a1d5f
A
5525#endif
5526#if MACH_ASSERT
2d21ac55
A
5527 vm_page_verify_free_lists();
5528#endif
3e170ce0
A
5529 if (m == NULL && zone_gc_called == FALSE) {
5530 printf("%s(num=%d,low=%d): found %d pages at 0x%llx...scanned %d pages... yielded %d times... dumped run %d times... stole %d pages... stole %d compressed pages... wired count is %d\n",
5531 __func__, contig_pages, max_pnum, npages, (vm_object_offset_t)start_pnum << PAGE_SHIFT,
5532 scanned, yielded, dumped_run, stolen_pages, compressed_pages, vm_page_wire_count);
5533
5534 if (consider_buffer_cache_collect != NULL) {
5535 (void)(*consider_buffer_cache_collect)(1);
5536 }
5537
39037602 5538 consider_zone_gc();
3e170ce0
A
5539
5540 zone_gc_called = TRUE;
5541
5542 printf("vm_page_find_contiguous: zone_gc called... wired count is %d\n", vm_page_wire_count);
5543 goto full_scan_again;
5544 }
5545
e5568f75 5546 return m;
1c79356b
A
5547}
5548
5549/*
5550 * Allocate a list of contiguous, wired pages.
5551 */
5552kern_return_t
5553cpm_allocate(
5554 vm_size_t size,
5555 vm_page_t *list,
2d21ac55 5556 ppnum_t max_pnum,
b0d623f7
A
5557 ppnum_t pnum_mask,
5558 boolean_t wire,
5559 int flags)
1c79356b 5560{
91447636
A
5561 vm_page_t pages;
5562 unsigned int npages;
1c79356b 5563
6d2010ae 5564 if (size % PAGE_SIZE != 0)
1c79356b
A
5565 return KERN_INVALID_ARGUMENT;
5566
b0d623f7
A
5567 npages = (unsigned int) (size / PAGE_SIZE);
5568 if (npages != size / PAGE_SIZE) {
5569 /* 32-bit overflow */
5570 return KERN_INVALID_ARGUMENT;
5571 }
1c79356b 5572
1c79356b
A
5573 /*
5574 * Obtain a pointer to a subset of the free
5575 * list large enough to satisfy the request;
5576 * the region will be physically contiguous.
5577 */
b0d623f7 5578 pages = vm_page_find_contiguous(npages, max_pnum, pnum_mask, wire, flags);
e5568f75 5579
2d21ac55 5580 if (pages == VM_PAGE_NULL)
1c79356b 5581 return KERN_NO_SPACE;
1c79356b 5582 /*
2d21ac55 5583 * determine need for wakeups
1c79356b 5584 */
2d21ac55 5585 if ((vm_page_free_count < vm_page_free_min) ||
316670eb
A
5586 ((vm_page_free_count < vm_page_free_target) &&
5587 ((vm_page_inactive_count + vm_page_speculative_count) < vm_page_inactive_min)))
5588 thread_wakeup((event_t) &vm_page_free_wanted);
2d21ac55 5589
6d2010ae
A
5590 VM_CHECK_MEMORYSTATUS;
5591
1c79356b
A
5592 /*
5593 * The CPM pages should now be available and
5594 * ordered by ascending physical address.
5595 */
5596 assert(vm_page_verify_contiguous(pages, npages));
5597
5598 *list = pages;
5599 return KERN_SUCCESS;
5600}
6d2010ae
A
5601
5602
5603unsigned int vm_max_delayed_work_limit = DEFAULT_DELAYED_WORK_LIMIT;
5604
5605/*
5606 * when working on a 'run' of pages, it is necessary to hold
5607 * the vm_page_queue_lock (a hot global lock) for certain operations
5608 * on the page... however, the majority of the work can be done
5609 * while merely holding the object lock... in fact there are certain
5610 * collections of pages that don't require any work brokered by the
5611 * vm_page_queue_lock... to mitigate the time spent behind the global
5612 * lock, go to a 2 pass algorithm... collect pages up to DELAYED_WORK_LIMIT
5613 * while doing all of the work that doesn't require the vm_page_queue_lock...
5614 * then call vm_page_do_delayed_work to acquire the vm_page_queue_lock and do the
5615 * necessary work for each page... we will grab the busy bit on the page
5616 * if it's not already held so that vm_page_do_delayed_work can drop the object lock
5617 * if it can't immediately take the vm_page_queue_lock in order to compete
5618 * for the locks in the same order that vm_pageout_scan takes them.
5619 * the operation names are modeled after the names of the routines that
5620 * need to be called in order to make the changes very obvious in the
5621 * original loop
5622 */
5623
5624void
5625vm_page_do_delayed_work(
5626 vm_object_t object,
3e170ce0 5627 vm_tag_t tag,
6d2010ae
A
5628 struct vm_page_delayed_work *dwp,
5629 int dw_count)
5630{
5631 int j;
5632 vm_page_t m;
5633 vm_page_t local_free_q = VM_PAGE_NULL;
6d2010ae
A
5634
5635 /*
5636 * pageout_scan takes the vm_page_lock_queues first
5637 * then tries for the object lock... to avoid what
5638 * is effectively a lock inversion, we'll go to the
5639 * trouble of taking them in that same order... otherwise
5640 * if this object contains the majority of the pages resident
5641 * in the UBC (or a small set of large objects actively being
5642 * worked on contain the majority of the pages), we could
5643 * cause the pageout_scan thread to 'starve' in its attempt
5644 * to find pages to move to the free queue, since it has to
5645 * successfully acquire the object lock of any candidate page
5646 * before it can steal/clean it.
5647 */
5648 if (!vm_page_trylockspin_queues()) {
5649 vm_object_unlock(object);
5650
5651 vm_page_lockspin_queues();
5652
5653 for (j = 0; ; j++) {
5654 if (!vm_object_lock_avoid(object) &&
5655 _vm_object_lock_try(object))
5656 break;
5657 vm_page_unlock_queues();
5658 mutex_pause(j);
5659 vm_page_lockspin_queues();
5660 }
6d2010ae
A
5661 }
5662 for (j = 0; j < dw_count; j++, dwp++) {
5663
5664 m = dwp->dw_m;
5665
6d2010ae
A
5666 if (dwp->dw_mask & DW_vm_pageout_throttle_up)
5667 vm_pageout_throttle_up(m);
fe8ab488
A
5668#if CONFIG_PHANTOM_CACHE
5669 if (dwp->dw_mask & DW_vm_phantom_cache_update)
5670 vm_phantom_cache_update(m);
5671#endif
6d2010ae 5672 if (dwp->dw_mask & DW_vm_page_wire)
3e170ce0 5673 vm_page_wire(m, tag, FALSE);
6d2010ae
A
5674 else if (dwp->dw_mask & DW_vm_page_unwire) {
5675 boolean_t queueit;
5676
fe8ab488 5677 queueit = (dwp->dw_mask & (DW_vm_page_free | DW_vm_page_deactivate_internal)) ? FALSE : TRUE;
6d2010ae
A
5678
5679 vm_page_unwire(m, queueit);
5680 }
5681 if (dwp->dw_mask & DW_vm_page_free) {
5682 vm_page_free_prepare_queues(m);
5683
39037602 5684 assert(m->pageq.next == 0 && m->pageq.prev == 0);
6d2010ae
A
5685 /*
5686 * Add this page to our list of reclaimed pages,
5687 * to be freed later.
5688 */
39037602 5689 m->snext = local_free_q;
6d2010ae
A
5690 local_free_q = m;
5691 } else {
5692 if (dwp->dw_mask & DW_vm_page_deactivate_internal)
5693 vm_page_deactivate_internal(m, FALSE);
5694 else if (dwp->dw_mask & DW_vm_page_activate) {
39037602 5695 if (m->vm_page_q_state != VM_PAGE_ON_ACTIVE_Q) {
6d2010ae
A
5696 vm_page_activate(m);
5697 }
5698 }
5699 else if (dwp->dw_mask & DW_vm_page_speculate)
5700 vm_page_speculate(m, TRUE);
316670eb
A
5701 else if (dwp->dw_mask & DW_enqueue_cleaned) {
5702 /*
5703 * if we didn't hold the object lock and did this,
5704 * we might disconnect the page, then someone might
5705 * soft fault it back in, then we would put it on the
5706 * cleaned queue, and so we would have a referenced (maybe even dirty)
5707 * page on that queue, which we don't want
5708 */
39037602 5709 int refmod_state = pmap_disconnect(VM_PAGE_GET_PHYS_PAGE(m));
316670eb
A
5710
5711 if ((refmod_state & VM_MEM_REFERENCED)) {
5712 /*
5713 * this page has been touched since it got cleaned; let's activate it
5714 * if it hasn't already been
5715 */
5716 vm_pageout_enqueued_cleaned++;
5717 vm_pageout_cleaned_reactivated++;
5718 vm_pageout_cleaned_commit_reactivated++;
5719
39037602 5720 if (m->vm_page_q_state != VM_PAGE_ON_ACTIVE_Q)
316670eb
A
5721 vm_page_activate(m);
5722 } else {
5723 m->reference = FALSE;
5724 vm_page_enqueue_cleaned(m);
5725 }
5726 }
6d2010ae
A
5727 else if (dwp->dw_mask & DW_vm_page_lru)
5728 vm_page_lru(m);
316670eb 5729 else if (dwp->dw_mask & DW_VM_PAGE_QUEUES_REMOVE) {
39037602
A
5730 if (m->vm_page_q_state != VM_PAGE_ON_PAGEOUT_Q)
5731 vm_page_queues_remove(m, TRUE);
316670eb 5732 }
6d2010ae
A
5733 if (dwp->dw_mask & DW_set_reference)
5734 m->reference = TRUE;
5735 else if (dwp->dw_mask & DW_clear_reference)
5736 m->reference = FALSE;
5737
5738 if (dwp->dw_mask & DW_move_page) {
39037602
A
5739 if (m->vm_page_q_state != VM_PAGE_ON_PAGEOUT_Q) {
5740 vm_page_queues_remove(m, FALSE);
6d2010ae 5741
39037602 5742 assert(VM_PAGE_OBJECT(m) != kernel_object);
6d2010ae 5743
3e170ce0 5744 vm_page_enqueue_inactive(m, FALSE);
316670eb 5745 }
6d2010ae
A
5746 }
5747 if (dwp->dw_mask & DW_clear_busy)
5748 m->busy = FALSE;
5749
5750 if (dwp->dw_mask & DW_PAGE_WAKEUP)
5751 PAGE_WAKEUP(m);
5752 }
5753 }
5754 vm_page_unlock_queues();
5755
5756 if (local_free_q)
5757 vm_page_free_list(local_free_q, TRUE);
5758
5759 VM_CHECK_MEMORYSTATUS;
5760
5761}
5762
0b4c1975
A
5763kern_return_t
5764vm_page_alloc_list(
5765 int page_count,
5766 int flags,
5767 vm_page_t *list)
5768{
5769 vm_page_t lo_page_list = VM_PAGE_NULL;
5770 vm_page_t mem;
5771 int i;
5772
5773 if ( !(flags & KMA_LOMEM))
5774 panic("vm_page_alloc_list: called w/o KMA_LOMEM");
5775
5776 for (i = 0; i < page_count; i++) {
5777
5778 mem = vm_page_grablo();
5779
5780 if (mem == VM_PAGE_NULL) {
5781 if (lo_page_list)
5782 vm_page_free_list(lo_page_list, FALSE);
5783
5784 *list = VM_PAGE_NULL;
5785
5786 return (KERN_RESOURCE_SHORTAGE);
5787 }
39037602 5788 mem->snext = lo_page_list;
0b4c1975
A
5789 lo_page_list = mem;
5790 }
5791 *list = lo_page_list;
5792
5793 return (KERN_SUCCESS);
5794}
5795
5796void
5797vm_page_set_offset(vm_page_t page, vm_object_offset_t offset)
5798{
5799 page->offset = offset;
5800}
5801
5802vm_page_t
5803vm_page_get_next(vm_page_t page)
5804{
39037602 5805 return (page->snext);
0b4c1975
A
5806}
5807
5808vm_object_offset_t
5809vm_page_get_offset(vm_page_t page)
5810{
5811 return (page->offset);
5812}
5813
5814ppnum_t
5815vm_page_get_phys_page(vm_page_t page)
5816{
39037602 5817 return (VM_PAGE_GET_PHYS_PAGE(page));
0b4c1975
A
5818}
5819
5820
b0d623f7
A
5821/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5822
d1ecb069
A
5823#if HIBERNATION
5824
b0d623f7
A
5825static vm_page_t hibernate_gobble_queue;
5826
0b4c1975 5827static int hibernate_drain_pageout_queue(struct vm_pageout_queue *);
39236c6e 5828static int hibernate_flush_dirty_pages(int);
39037602 5829static int hibernate_flush_queue(vm_page_queue_head_t *, int);
0b4c1975
A
5830
5831void hibernate_flush_wait(void);
5832void hibernate_mark_in_progress(void);
5833void hibernate_clear_in_progress(void);
5834
39236c6e
A
5835void hibernate_free_range(int, int);
5836void hibernate_hash_insert_page(vm_page_t);
5837uint32_t hibernate_mark_as_unneeded(addr64_t, addr64_t, hibernate_page_list_t *, hibernate_page_list_t *);
5838void hibernate_rebuild_vm_structs(void);
5839uint32_t hibernate_teardown_vm_structs(hibernate_page_list_t *, hibernate_page_list_t *);
5840ppnum_t hibernate_lookup_paddr(unsigned int);
0b4c1975
A
5841
5842struct hibernate_statistics {
5843 int hibernate_considered;
5844 int hibernate_reentered_on_q;
5845 int hibernate_found_dirty;
5846 int hibernate_skipped_cleaning;
5847 int hibernate_skipped_transient;
5848 int hibernate_skipped_precious;
39236c6e 5849 int hibernate_skipped_external;
0b4c1975
A
5850 int hibernate_queue_nolock;
5851 int hibernate_queue_paused;
5852 int hibernate_throttled;
5853 int hibernate_throttle_timeout;
5854 int hibernate_drained;
5855 int hibernate_drain_timeout;
5856 int cd_lock_failed;
5857 int cd_found_precious;
5858 int cd_found_wired;
5859 int cd_found_busy;
5860 int cd_found_unusual;
5861 int cd_found_cleaning;
5862 int cd_found_laundry;
5863 int cd_found_dirty;
39236c6e 5864 int cd_found_xpmapped;
8a3053a0 5865 int cd_skipped_xpmapped;
0b4c1975
A
5866 int cd_local_free;
5867 int cd_total_free;
5868 int cd_vm_page_wire_count;
39236c6e 5869 int cd_vm_struct_pages_unneeded;
0b4c1975
A
5870 int cd_pages;
5871 int cd_discarded;
5872 int cd_count_wire;
5873} hibernate_stats;
5874
5875
8a3053a0
A
5876/*
5877 * clamp the number of 'xpmapped' pages we'll sweep into the hibernation image
5878 * so that we don't overrun the estimated image size, which would
5879 * result in a hibernation failure.
5880 */
5881#define HIBERNATE_XPMAPPED_LIMIT 40000
5882
0b4c1975
A
5883
5884static int
5885hibernate_drain_pageout_queue(struct vm_pageout_queue *q)
5886{
5887 wait_result_t wait_result;
5888
5889 vm_page_lock_queues();
5890
39037602 5891 while ( !vm_page_queue_empty(&q->pgo_pending) ) {
0b4c1975
A
5892
5893 q->pgo_draining = TRUE;
5894
5895 assert_wait_timeout((event_t) (&q->pgo_laundry+1), THREAD_INTERRUPTIBLE, 5000, 1000*NSEC_PER_USEC);
5896
5897 vm_page_unlock_queues();
5898
5899 wait_result = thread_block(THREAD_CONTINUE_NULL);
5900
39037602 5901 if (wait_result == THREAD_TIMED_OUT && !vm_page_queue_empty(&q->pgo_pending)) {
0b4c1975 5902 hibernate_stats.hibernate_drain_timeout++;
39236c6e
A
5903
5904 if (q == &vm_pageout_queue_external)
5905 return (0);
5906
0b4c1975
A
5907 return (1);
5908 }
5909 vm_page_lock_queues();
5910
5911 hibernate_stats.hibernate_drained++;
5912 }
5913 vm_page_unlock_queues();
5914
5915 return (0);
5916}
5917
0b4c1975 5918
39236c6e
A
5919boolean_t hibernate_skip_external = FALSE;
5920
0b4c1975 5921static int
39037602 5922hibernate_flush_queue(vm_page_queue_head_t *q, int qcount)
0b4c1975
A
5923{
5924 vm_page_t m;
5925 vm_object_t l_object = NULL;
5926 vm_object_t m_object = NULL;
5927 int refmod_state = 0;
5928 int try_failed_count = 0;
5929 int retval = 0;
5930 int current_run = 0;
5931 struct vm_pageout_queue *iq;
5932 struct vm_pageout_queue *eq;
5933 struct vm_pageout_queue *tq;
5934
5935
5936 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 4) | DBG_FUNC_START, q, qcount, 0, 0, 0);
5937
5938 iq = &vm_pageout_queue_internal;
5939 eq = &vm_pageout_queue_external;
5940
5941 vm_page_lock_queues();
5942
39037602 5943 while (qcount && !vm_page_queue_empty(q)) {
0b4c1975
A
5944
5945 if (current_run++ == 1000) {
5946 if (hibernate_should_abort()) {
5947 retval = 1;
5948 break;
5949 }
5950 current_run = 0;
5951 }
5952
39037602
A
5953 m = (vm_page_t) vm_page_queue_first(q);
5954 m_object = VM_PAGE_OBJECT(m);
0b4c1975
A
5955
5956 /*
5957 * check to see if we currently are working
5958 * with the same object... if so, we've
5959 * already got the lock
5960 */
5961 if (m_object != l_object) {
5962 /*
5963 * the object associated with candidate page is
5964 * different from the one we were just working
5965 * with... dump the lock if we still own it
5966 */
5967 if (l_object != NULL) {
5968 vm_object_unlock(l_object);
5969 l_object = NULL;
5970 }
5971 /*
5972 * Try to lock object; since we've alread got the
5973 * page queues lock, we can only 'try' for this one.
5974 * if the 'try' fails, we need to do a mutex_pause
5975 * to allow the owner of the object lock a chance to
5976 * run...
5977 */
5978 if ( !vm_object_lock_try_scan(m_object)) {
5979
5980 if (try_failed_count > 20) {
5981 hibernate_stats.hibernate_queue_nolock++;
5982
5983 goto reenter_pg_on_q;
5984 }
0b4c1975
A
5985
5986 vm_page_unlock_queues();
5987 mutex_pause(try_failed_count++);
5988 vm_page_lock_queues();
5989
5990 hibernate_stats.hibernate_queue_paused++;
5991 continue;
5992 } else {
5993 l_object = m_object;
0b4c1975
A
5994 }
5995 }
316670eb 5996 if ( !m_object->alive || m->encrypted_cleaning || m->cleaning || m->laundry || m->busy || m->absent || m->error) {
0b4c1975
A
5997 /*
5998 * page is not to be cleaned
5999 * put it back on the head of its queue
6000 */
6001 if (m->cleaning)
6002 hibernate_stats.hibernate_skipped_cleaning++;
6003 else
6004 hibernate_stats.hibernate_skipped_transient++;
6005
6006 goto reenter_pg_on_q;
6007 }
0b4c1975
A
6008 if (m_object->copy == VM_OBJECT_NULL) {
6009 if (m_object->purgable == VM_PURGABLE_VOLATILE || m_object->purgable == VM_PURGABLE_EMPTY) {
6010 /*
6011 * let the normal hibernate image path
6012 * deal with these
6013 */
6014 goto reenter_pg_on_q;
6015 }
6016 }
6017 if ( !m->dirty && m->pmapped) {
39037602 6018 refmod_state = pmap_get_refmod(VM_PAGE_GET_PHYS_PAGE(m));
0b4c1975 6019
316670eb
A
6020 if ((refmod_state & VM_MEM_MODIFIED)) {
6021 SET_PAGE_DIRTY(m, FALSE);
6022 }
0b4c1975
A
6023 } else
6024 refmod_state = 0;
6025
6026 if ( !m->dirty) {
6027 /*
6028 * page is not to be cleaned
6029 * put it back on the head of its queue
6030 */
6031 if (m->precious)
6032 hibernate_stats.hibernate_skipped_precious++;
6033
6034 goto reenter_pg_on_q;
6035 }
39236c6e
A
6036
6037 if (hibernate_skip_external == TRUE && !m_object->internal) {
6038
6039 hibernate_stats.hibernate_skipped_external++;
6040
6041 goto reenter_pg_on_q;
6042 }
0b4c1975
A
6043 tq = NULL;
6044
6045 if (m_object->internal) {
6046 if (VM_PAGE_Q_THROTTLED(iq))
6047 tq = iq;
6048 } else if (VM_PAGE_Q_THROTTLED(eq))
6049 tq = eq;
6050
6051 if (tq != NULL) {
6052 wait_result_t wait_result;
6053 int wait_count = 5;
6054
6055 if (l_object != NULL) {
6056 vm_object_unlock(l_object);
6057 l_object = NULL;
6058 }
0b4c1975 6059
0b4c1975
A
6060 while (retval == 0) {
6061
39236c6e
A
6062 tq->pgo_throttled = TRUE;
6063
0b4c1975
A
6064 assert_wait_timeout((event_t) &tq->pgo_laundry, THREAD_INTERRUPTIBLE, 1000, 1000*NSEC_PER_USEC);
6065
316670eb 6066 vm_page_unlock_queues();
0b4c1975 6067
316670eb 6068 wait_result = thread_block(THREAD_CONTINUE_NULL);
0b4c1975
A
6069
6070 vm_page_lock_queues();
6071
39236c6e
A
6072 if (wait_result != THREAD_TIMED_OUT)
6073 break;
6074 if (!VM_PAGE_Q_THROTTLED(tq))
6075 break;
6076
0b4c1975
A
6077 if (hibernate_should_abort())
6078 retval = 1;
6079
0b4c1975 6080 if (--wait_count == 0) {
39236c6e 6081
316670eb 6082 hibernate_stats.hibernate_throttle_timeout++;
39236c6e
A
6083
6084 if (tq == eq) {
6085 hibernate_skip_external = TRUE;
6086 break;
6087 }
316670eb
A
6088 retval = 1;
6089 }
0b4c1975
A
6090 }
6091 if (retval)
6092 break;
6093
6094 hibernate_stats.hibernate_throttled++;
6095
6096 continue;
6097 }
316670eb
A
6098 /*
6099 * we've already factored out pages in the laundry which
6100 * means this page can't be on the pageout queue so it's
3e170ce0 6101 * safe to do the vm_page_queues_remove
316670eb 6102 */
39037602 6103 vm_page_queues_remove(m, TRUE);
0b4c1975 6104
39037602
A
6105 if (m_object->internal == TRUE)
6106 pmap_disconnect_options(VM_PAGE_GET_PHYS_PAGE(m), PMAP_OPTIONS_COMPRESSOR, NULL);
39236c6e 6107
39037602 6108 (void)vm_pageout_cluster(m, FALSE, FALSE);
0b4c1975
A
6109
6110 hibernate_stats.hibernate_found_dirty++;
6111
6112 goto next_pg;
6113
6114reenter_pg_on_q:
39037602
A
6115 vm_page_queue_remove(q, m, vm_page_t, pageq);
6116 vm_page_queue_enter(q, m, vm_page_t, pageq);
0b4c1975
A
6117
6118 hibernate_stats.hibernate_reentered_on_q++;
6119next_pg:
6120 hibernate_stats.hibernate_considered++;
6121
6122 qcount--;
6123 try_failed_count = 0;
6124 }
6125 if (l_object != NULL) {
6126 vm_object_unlock(l_object);
6127 l_object = NULL;
6128 }
0b4c1975
A
6129
6130 vm_page_unlock_queues();
6131
6132 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 4) | DBG_FUNC_END, hibernate_stats.hibernate_found_dirty, retval, 0, 0, 0);
6133
6134 return (retval);
6135}
6136
6137
6138static int
39236c6e 6139hibernate_flush_dirty_pages(int pass)
0b4c1975
A
6140{
6141 struct vm_speculative_age_q *aq;
6142 uint32_t i;
6143
0b4c1975
A
6144 if (vm_page_local_q) {
6145 for (i = 0; i < vm_page_local_q_count; i++)
6146 vm_page_reactivate_local(i, TRUE, FALSE);
6147 }
6148
6149 for (i = 0; i <= VM_PAGE_MAX_SPECULATIVE_AGE_Q; i++) {
6150 int qcount;
6151 vm_page_t m;
6152
6153 aq = &vm_page_queue_speculative[i];
6154
39037602 6155 if (vm_page_queue_empty(&aq->age_q))
0b4c1975
A
6156 continue;
6157 qcount = 0;
6158
6159 vm_page_lockspin_queues();
6160
39037602 6161 vm_page_queue_iterate(&aq->age_q,
0b4c1975
A
6162 m,
6163 vm_page_t,
6164 pageq)
6165 {
6166 qcount++;
6167 }
6168 vm_page_unlock_queues();
6169
6170 if (qcount) {
6171 if (hibernate_flush_queue(&aq->age_q, qcount))
6172 return (1);
6173 }
6174 }
316670eb 6175 if (hibernate_flush_queue(&vm_page_queue_inactive, vm_page_inactive_count - vm_page_anonymous_count - vm_page_cleaned_count))
0b4c1975 6176 return (1);
39037602 6177 /* XXX FBDP TODO: flush secluded queue */
316670eb
A
6178 if (hibernate_flush_queue(&vm_page_queue_anonymous, vm_page_anonymous_count))
6179 return (1);
6180 if (hibernate_flush_queue(&vm_page_queue_cleaned, vm_page_cleaned_count))
0b4c1975 6181 return (1);
0b4c1975
A
6182 if (hibernate_drain_pageout_queue(&vm_pageout_queue_internal))
6183 return (1);
0b4c1975 6184
39037602 6185 if (pass == 1)
39236c6e
A
6186 vm_compressor_record_warmup_start();
6187
6188 if (hibernate_flush_queue(&vm_page_queue_active, vm_page_active_count)) {
39037602 6189 if (pass == 1)
39236c6e
A
6190 vm_compressor_record_warmup_end();
6191 return (1);
6192 }
6193 if (hibernate_drain_pageout_queue(&vm_pageout_queue_internal)) {
39037602 6194 if (pass == 1)
39236c6e
A
6195 vm_compressor_record_warmup_end();
6196 return (1);
6197 }
39037602 6198 if (pass == 1)
39236c6e
A
6199 vm_compressor_record_warmup_end();
6200
6201 if (hibernate_skip_external == FALSE && hibernate_drain_pageout_queue(&vm_pageout_queue_external))
6202 return (1);
6203
6204 return (0);
6205}
0b4c1975 6206
0b4c1975 6207
fe8ab488
A
6208void
6209hibernate_reset_stats()
6210{
6211 bzero(&hibernate_stats, sizeof(struct hibernate_statistics));
6212}
6213
6214
0b4c1975
A
6215int
6216hibernate_flush_memory()
6217{
6218 int retval;
6219
39037602
A
6220 assert(VM_CONFIG_COMPRESSOR_IS_PRESENT);
6221
0b4c1975
A
6222 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 3) | DBG_FUNC_START, vm_page_free_count, 0, 0, 0, 0);
6223
39236c6e
A
6224 hibernate_cleaning_in_progress = TRUE;
6225 hibernate_skip_external = FALSE;
6226
6227 if ((retval = hibernate_flush_dirty_pages(1)) == 0) {
6228
39037602 6229 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 10) | DBG_FUNC_START, VM_PAGE_COMPRESSOR_COUNT, 0, 0, 0, 0);
0b4c1975 6230
39037602 6231 vm_compressor_flush();
0b4c1975 6232
39037602 6233 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 10) | DBG_FUNC_END, VM_PAGE_COMPRESSOR_COUNT, 0, 0, 0, 0);
39236c6e 6234
fe8ab488 6235 if (consider_buffer_cache_collect != NULL) {
39236c6e
A
6236 unsigned int orig_wire_count;
6237
6238 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 7) | DBG_FUNC_START, 0, 0, 0, 0, 0);
6239 orig_wire_count = vm_page_wire_count;
0b4c1975 6240
0b4c1975 6241 (void)(*consider_buffer_cache_collect)(1);
39037602 6242 consider_zone_gc();
0b4c1975 6243
39236c6e
A
6244 HIBLOG("hibernate_flush_memory: buffer_cache_gc freed up %d wired pages\n", orig_wire_count - vm_page_wire_count);
6245
6246 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 7) | DBG_FUNC_END, orig_wire_count - vm_page_wire_count, 0, 0, 0, 0);
0b4c1975
A
6247 }
6248 }
39236c6e
A
6249 hibernate_cleaning_in_progress = FALSE;
6250
0b4c1975
A
6251 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 3) | DBG_FUNC_END, vm_page_free_count, hibernate_stats.hibernate_found_dirty, retval, 0, 0);
6252
39037602 6253 if (retval)
39236c6e
A
6254 HIBLOG("hibernate_flush_memory() failed to finish - vm_page_compressor_count(%d)\n", VM_PAGE_COMPRESSOR_COUNT);
6255
6256
0b4c1975
A
6257 HIBPRINT("hibernate_flush_memory() considered(%d) reentered_on_q(%d) found_dirty(%d)\n",
6258 hibernate_stats.hibernate_considered,
6259 hibernate_stats.hibernate_reentered_on_q,
6260 hibernate_stats.hibernate_found_dirty);
39236c6e 6261 HIBPRINT(" skipped_cleaning(%d) skipped_transient(%d) skipped_precious(%d) skipped_external(%d) queue_nolock(%d)\n",
0b4c1975
A
6262 hibernate_stats.hibernate_skipped_cleaning,
6263 hibernate_stats.hibernate_skipped_transient,
6264 hibernate_stats.hibernate_skipped_precious,
39236c6e 6265 hibernate_stats.hibernate_skipped_external,
0b4c1975
A
6266 hibernate_stats.hibernate_queue_nolock);
6267 HIBPRINT(" queue_paused(%d) throttled(%d) throttle_timeout(%d) drained(%d) drain_timeout(%d)\n",
6268 hibernate_stats.hibernate_queue_paused,
6269 hibernate_stats.hibernate_throttled,
6270 hibernate_stats.hibernate_throttle_timeout,
6271 hibernate_stats.hibernate_drained,
6272 hibernate_stats.hibernate_drain_timeout);
6273
6274 return (retval);
6275}
6276
6d2010ae 6277
b0d623f7
A
6278static void
6279hibernate_page_list_zero(hibernate_page_list_t *list)
6280{
6281 uint32_t bank;
6282 hibernate_bitmap_t * bitmap;
6283
6284 bitmap = &list->bank_bitmap[0];
6285 for (bank = 0; bank < list->bank_count; bank++)
6286 {
6287 uint32_t last_bit;
6288
6289 bzero((void *) &bitmap->bitmap[0], bitmap->bitmapwords << 2);
6290 // set out-of-bound bits at end of bitmap.
6291 last_bit = ((bitmap->last_page - bitmap->first_page + 1) & 31);
6292 if (last_bit)
6293 bitmap->bitmap[bitmap->bitmapwords - 1] = (0xFFFFFFFF >> last_bit);
6294
6295 bitmap = (hibernate_bitmap_t *) &bitmap->bitmap[bitmap->bitmapwords];
6296 }
6297}
6298
b0d623f7
A
6299void
6300hibernate_free_gobble_pages(void)
6301{
6302 vm_page_t m, next;
6303 uint32_t count = 0;
6304
6305 m = (vm_page_t) hibernate_gobble_queue;
6306 while(m)
6307 {
39037602 6308 next = m->snext;
b0d623f7
A
6309 vm_page_free(m);
6310 count++;
6311 m = next;
6312 }
6313 hibernate_gobble_queue = VM_PAGE_NULL;
6314
6315 if (count)
6316 HIBLOG("Freed %d pages\n", count);
6317}
6318
6319static boolean_t
db609669 6320hibernate_consider_discard(vm_page_t m, boolean_t preflight)
b0d623f7
A
6321{
6322 vm_object_t object = NULL;
6323 int refmod_state;
6324 boolean_t discard = FALSE;
6325
6326 do
6327 {
0b4c1975 6328 if (m->private)
b0d623f7
A
6329 panic("hibernate_consider_discard: private");
6330
39037602
A
6331 object = VM_PAGE_OBJECT(m);
6332
6333 if (!vm_object_lock_try(object)) {
6334 object = NULL;
db609669 6335 if (!preflight) hibernate_stats.cd_lock_failed++;
b0d623f7 6336 break;
0b4c1975 6337 }
0b4c1975 6338 if (VM_PAGE_WIRED(m)) {
db609669 6339 if (!preflight) hibernate_stats.cd_found_wired++;
b0d623f7 6340 break;
0b4c1975
A
6341 }
6342 if (m->precious) {
db609669 6343 if (!preflight) hibernate_stats.cd_found_precious++;
b0d623f7 6344 break;
0b4c1975
A
6345 }
6346 if (m->busy || !object->alive) {
b0d623f7
A
6347 /*
6348 * Somebody is playing with this page.
6349 */
db609669 6350 if (!preflight) hibernate_stats.cd_found_busy++;
6d2010ae 6351 break;
0b4c1975
A
6352 }
6353 if (m->absent || m->unusual || m->error) {
b0d623f7
A
6354 /*
6355 * If it's unusual in anyway, ignore it
6356 */
db609669 6357 if (!preflight) hibernate_stats.cd_found_unusual++;
b0d623f7 6358 break;
0b4c1975
A
6359 }
6360 if (m->cleaning) {
db609669 6361 if (!preflight) hibernate_stats.cd_found_cleaning++;
b0d623f7 6362 break;
0b4c1975 6363 }
316670eb 6364 if (m->laundry) {
db609669 6365 if (!preflight) hibernate_stats.cd_found_laundry++;
b0d623f7 6366 break;
0b4c1975 6367 }
b0d623f7
A
6368 if (!m->dirty)
6369 {
39037602 6370 refmod_state = pmap_get_refmod(VM_PAGE_GET_PHYS_PAGE(m));
b0d623f7
A
6371
6372 if (refmod_state & VM_MEM_REFERENCED)
6373 m->reference = TRUE;
316670eb
A
6374 if (refmod_state & VM_MEM_MODIFIED) {
6375 SET_PAGE_DIRTY(m, FALSE);
6376 }
b0d623f7
A
6377 }
6378
6379 /*
6380 * If it's clean or purgeable we can discard the page on wakeup.
6381 */
6382 discard = (!m->dirty)
6383 || (VM_PURGABLE_VOLATILE == object->purgable)
0b4c1975
A
6384 || (VM_PURGABLE_EMPTY == object->purgable);
6385
39236c6e
A
6386
6387 if (discard == FALSE) {
6388 if (!preflight)
6389 hibernate_stats.cd_found_dirty++;
8a3053a0
A
6390 } else if (m->xpmapped && m->reference && !object->internal) {
6391 if (hibernate_stats.cd_found_xpmapped < HIBERNATE_XPMAPPED_LIMIT) {
6392 if (!preflight)
6393 hibernate_stats.cd_found_xpmapped++;
6394 discard = FALSE;
6395 } else {
6396 if (!preflight)
6397 hibernate_stats.cd_skipped_xpmapped++;
6398 }
39236c6e 6399 }
b0d623f7
A
6400 }
6401 while (FALSE);
6402
6403 if (object)
6404 vm_object_unlock(object);
6405
6406 return (discard);
6407}
6408
6409
6410static void
6411hibernate_discard_page(vm_page_t m)
6412{
39037602
A
6413 vm_object_t m_object;
6414
b0d623f7
A
6415 if (m->absent || m->unusual || m->error)
6416 /*
6417 * If it's unusual in anyway, ignore
6418 */
6419 return;
6420
39037602
A
6421 m_object = VM_PAGE_OBJECT(m);
6422
fe8ab488 6423#if MACH_ASSERT || DEBUG
39037602 6424 if (!vm_object_lock_try(m_object))
316670eb
A
6425 panic("hibernate_discard_page(%p) !vm_object_lock_try", m);
6426#else
6427 /* No need to lock page queue for token delete, hibernate_vm_unlock()
6428 makes sure these locks are uncontended before sleep */
fe8ab488 6429#endif /* MACH_ASSERT || DEBUG */
316670eb 6430
b0d623f7
A
6431 if (m->pmapped == TRUE)
6432 {
39037602 6433 __unused int refmod_state = pmap_disconnect(VM_PAGE_GET_PHYS_PAGE(m));
b0d623f7
A
6434 }
6435
6436 if (m->laundry)
6437 panic("hibernate_discard_page(%p) laundry", m);
6438 if (m->private)
6439 panic("hibernate_discard_page(%p) private", m);
6440 if (m->fictitious)
6441 panic("hibernate_discard_page(%p) fictitious", m);
6442
39037602 6443 if (VM_PURGABLE_VOLATILE == m_object->purgable)
b0d623f7
A
6444 {
6445 /* object should be on a queue */
39037602
A
6446 assert((m_object->objq.next != NULL) && (m_object->objq.prev != NULL));
6447 purgeable_q_t old_queue = vm_purgeable_object_remove(m_object);
b0d623f7 6448 assert(old_queue);
39037602 6449 if (m_object->purgeable_when_ripe) {
39236c6e
A
6450 vm_purgeable_token_delete_first(old_queue);
6451 }
39037602
A
6452 vm_object_lock_assert_exclusive(m_object);
6453 m_object->purgable = VM_PURGABLE_EMPTY;
fe8ab488
A
6454
6455 /*
6456 * Purgeable ledgers: pages of VOLATILE and EMPTY objects are
6457 * accounted in the "volatile" ledger, so no change here.
6458 * We have to update vm_page_purgeable_count, though, since we're
6459 * effectively purging this object.
6460 */
6461 unsigned int delta;
39037602
A
6462 assert(m_object->resident_page_count >= m_object->wired_page_count);
6463 delta = (m_object->resident_page_count - m_object->wired_page_count);
fe8ab488
A
6464 assert(vm_page_purgeable_count >= delta);
6465 assert(delta > 0);
6466 OSAddAtomic(-delta, (SInt32 *)&vm_page_purgeable_count);
b0d623f7
A
6467 }
6468
6469 vm_page_free(m);
316670eb 6470
fe8ab488 6471#if MACH_ASSERT || DEBUG
39037602 6472 vm_object_unlock(m_object);
fe8ab488 6473#endif /* MACH_ASSERT || DEBUG */
b0d623f7
A
6474}
6475
db609669
A
6476/*
6477 Grab locks for hibernate_page_list_setall()
6478*/
6479void
6480hibernate_vm_lock_queues(void)
6481{
39236c6e 6482 vm_object_lock(compressor_object);
db609669
A
6483 vm_page_lock_queues();
6484 lck_mtx_lock(&vm_page_queue_free_lock);
6485
6486 if (vm_page_local_q) {
6487 uint32_t i;
6488 for (i = 0; i < vm_page_local_q_count; i++) {
6489 struct vpl *lq;
6490 lq = &vm_page_local_q[i].vpl_un.vpl;
6491 VPL_LOCK(&lq->vpl_lock);
6492 }
6493 }
6494}
6495
6496void
6497hibernate_vm_unlock_queues(void)
6498{
6499 if (vm_page_local_q) {
6500 uint32_t i;
6501 for (i = 0; i < vm_page_local_q_count; i++) {
6502 struct vpl *lq;
6503 lq = &vm_page_local_q[i].vpl_un.vpl;
6504 VPL_UNLOCK(&lq->vpl_lock);
6505 }
6506 }
6507 lck_mtx_unlock(&vm_page_queue_free_lock);
6508 vm_page_unlock_queues();
39236c6e 6509 vm_object_unlock(compressor_object);
db609669
A
6510}
6511
b0d623f7
A
6512/*
6513 Bits zero in the bitmaps => page needs to be saved. All pages default to be saved,
6514 pages known to VM to not need saving are subtracted.
6515 Wired pages to be saved are present in page_list_wired, pageable in page_list.
6516*/
6517
6518void
6519hibernate_page_list_setall(hibernate_page_list_t * page_list,
6520 hibernate_page_list_t * page_list_wired,
6d2010ae 6521 hibernate_page_list_t * page_list_pal,
39236c6e
A
6522 boolean_t preflight,
6523 boolean_t will_discard,
b0d623f7
A
6524 uint32_t * pagesOut)
6525{
6526 uint64_t start, end, nsec;
6527 vm_page_t m;
39236c6e 6528 vm_page_t next;
b0d623f7 6529 uint32_t pages = page_list->page_count;
39236c6e 6530 uint32_t count_anonymous = 0, count_throttled = 0, count_compressor = 0;
316670eb 6531 uint32_t count_inactive = 0, count_active = 0, count_speculative = 0, count_cleaned = 0;
b0d623f7
A
6532 uint32_t count_wire = pages;
6533 uint32_t count_discard_active = 0;
6534 uint32_t count_discard_inactive = 0;
316670eb 6535 uint32_t count_discard_cleaned = 0;
b0d623f7
A
6536 uint32_t count_discard_purgeable = 0;
6537 uint32_t count_discard_speculative = 0;
39236c6e 6538 uint32_t count_discard_vm_struct_pages = 0;
b0d623f7
A
6539 uint32_t i;
6540 uint32_t bank;
6541 hibernate_bitmap_t * bitmap;
6542 hibernate_bitmap_t * bitmap_wired;
39236c6e
A
6543 boolean_t discard_all;
6544 boolean_t discard;
b0d623f7 6545
3e170ce0 6546 HIBLOG("hibernate_page_list_setall(preflight %d) start\n", preflight);
b0d623f7 6547
db609669
A
6548 if (preflight) {
6549 page_list = NULL;
6550 page_list_wired = NULL;
6551 page_list_pal = NULL;
39236c6e
A
6552 discard_all = FALSE;
6553 } else {
6554 discard_all = will_discard;
db609669 6555 }
0b4c1975 6556
fe8ab488 6557#if MACH_ASSERT || DEBUG
39236c6e
A
6558 if (!preflight)
6559 {
316670eb
A
6560 vm_page_lock_queues();
6561 if (vm_page_local_q) {
6562 for (i = 0; i < vm_page_local_q_count; i++) {
6563 struct vpl *lq;
6564 lq = &vm_page_local_q[i].vpl_un.vpl;
6565 VPL_LOCK(&lq->vpl_lock);
6566 }
6567 }
39236c6e 6568 }
fe8ab488 6569#endif /* MACH_ASSERT || DEBUG */
316670eb
A
6570
6571
0b4c1975 6572 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 8) | DBG_FUNC_START, count_wire, 0, 0, 0, 0);
b0d623f7
A
6573
6574 clock_get_uptime(&start);
6575
db609669
A
6576 if (!preflight) {
6577 hibernate_page_list_zero(page_list);
6578 hibernate_page_list_zero(page_list_wired);
6579 hibernate_page_list_zero(page_list_pal);
6580
6581 hibernate_stats.cd_vm_page_wire_count = vm_page_wire_count;
6582 hibernate_stats.cd_pages = pages;
6583 }
0b4c1975 6584
b0d623f7
A
6585 if (vm_page_local_q) {
6586 for (i = 0; i < vm_page_local_q_count; i++)
db609669
A
6587 vm_page_reactivate_local(i, TRUE, !preflight);
6588 }
6589
6590 if (preflight) {
39236c6e 6591 vm_object_lock(compressor_object);
db609669
A
6592 vm_page_lock_queues();
6593 lck_mtx_lock(&vm_page_queue_free_lock);
b0d623f7
A
6594 }
6595
6596 m = (vm_page_t) hibernate_gobble_queue;
39236c6e 6597 while (m)
b0d623f7
A
6598 {
6599 pages--;
6600 count_wire--;
db609669 6601 if (!preflight) {
39037602
A
6602 hibernate_page_bitset(page_list, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
6603 hibernate_page_bitset(page_list_wired, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
db609669 6604 }
39037602 6605 m = m->snext;
b0d623f7 6606 }
6d2010ae 6607
db609669 6608 if (!preflight) for( i = 0; i < real_ncpus; i++ )
0b4c1975
A
6609 {
6610 if (cpu_data_ptr[i] && cpu_data_ptr[i]->cpu_processor)
6611 {
39037602 6612 for (m = PROCESSOR_DATA(cpu_data_ptr[i]->cpu_processor, free_pages); m; m = m->snext)
0b4c1975 6613 {
39037602
A
6614 assert(m->vm_page_q_state == VM_PAGE_ON_FREE_LOCAL_Q);
6615
0b4c1975
A
6616 pages--;
6617 count_wire--;
39037602
A
6618 hibernate_page_bitset(page_list, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
6619 hibernate_page_bitset(page_list_wired, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
0b4c1975
A
6620
6621 hibernate_stats.cd_local_free++;
6622 hibernate_stats.cd_total_free++;
6623 }
6624 }
6625 }
6d2010ae 6626
b0d623f7
A
6627 for( i = 0; i < vm_colors; i++ )
6628 {
39037602
A
6629 vm_page_queue_iterate(&vm_page_queue_free[i].qhead,
6630 m,
6631 vm_page_t,
6632 pageq)
b0d623f7 6633 {
39037602
A
6634 assert(m->vm_page_q_state == VM_PAGE_ON_FREE_Q);
6635
b0d623f7
A
6636 pages--;
6637 count_wire--;
db609669 6638 if (!preflight) {
39037602
A
6639 hibernate_page_bitset(page_list, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
6640 hibernate_page_bitset(page_list_wired, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
db609669
A
6641
6642 hibernate_stats.cd_total_free++;
6643 }
b0d623f7
A
6644 }
6645 }
6646
39037602
A
6647 vm_page_queue_iterate(&vm_lopage_queue_free,
6648 m,
6649 vm_page_t,
6650 pageq)
b0d623f7 6651 {
39037602
A
6652 assert(m->vm_page_q_state == VM_PAGE_ON_FREE_LOPAGE_Q);
6653
b0d623f7
A
6654 pages--;
6655 count_wire--;
db609669 6656 if (!preflight) {
39037602
A
6657 hibernate_page_bitset(page_list, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
6658 hibernate_page_bitset(page_list_wired, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
db609669
A
6659
6660 hibernate_stats.cd_total_free++;
6661 }
b0d623f7
A
6662 }
6663
39037602
A
6664 m = (vm_page_t) vm_page_queue_first(&vm_page_queue_throttled);
6665 while (m && !vm_page_queue_end(&vm_page_queue_throttled, (vm_page_queue_entry_t)m))
b0d623f7 6666 {
39037602
A
6667 assert(m->vm_page_q_state == VM_PAGE_ON_THROTTLED_Q);
6668
6669 next = (vm_page_t)VM_PAGE_UNPACK_PTR(m->pageq.next);
39236c6e 6670 discard = FALSE;
b0d623f7 6671 if ((kIOHibernateModeDiscardCleanInactive & gIOHibernateMode)
db609669 6672 && hibernate_consider_discard(m, preflight))
b0d623f7 6673 {
39037602 6674 if (!preflight) hibernate_page_bitset(page_list, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
b0d623f7 6675 count_discard_inactive++;
39236c6e 6676 discard = discard_all;
b0d623f7
A
6677 }
6678 else
6679 count_throttled++;
6680 count_wire--;
39037602 6681 if (!preflight) hibernate_page_bitset(page_list_wired, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
39236c6e
A
6682
6683 if (discard) hibernate_discard_page(m);
6684 m = next;
b0d623f7
A
6685 }
6686
39037602
A
6687 m = (vm_page_t) vm_page_queue_first(&vm_page_queue_anonymous);
6688 while (m && !vm_page_queue_end(&vm_page_queue_anonymous, (vm_page_queue_entry_t)m))
b0d623f7 6689 {
39037602
A
6690 assert(m->vm_page_q_state == VM_PAGE_ON_INACTIVE_INTERNAL_Q);
6691
6692 next = (vm_page_t)VM_PAGE_UNPACK_PTR(m->pageq.next);
39236c6e 6693 discard = FALSE;
b0d623f7 6694 if ((kIOHibernateModeDiscardCleanInactive & gIOHibernateMode)
db609669 6695 && hibernate_consider_discard(m, preflight))
b0d623f7 6696 {
39037602 6697 if (!preflight) hibernate_page_bitset(page_list, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
b0d623f7
A
6698 if (m->dirty)
6699 count_discard_purgeable++;
6700 else
6701 count_discard_inactive++;
39236c6e 6702 discard = discard_all;
b0d623f7
A
6703 }
6704 else
39236c6e 6705 count_anonymous++;
b0d623f7 6706 count_wire--;
39037602 6707 if (!preflight) hibernate_page_bitset(page_list_wired, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
39236c6e
A
6708 if (discard) hibernate_discard_page(m);
6709 m = next;
b0d623f7
A
6710 }
6711
39037602
A
6712 m = (vm_page_t) vm_page_queue_first(&vm_page_queue_cleaned);
6713 while (m && !vm_page_queue_end(&vm_page_queue_cleaned, (vm_page_queue_entry_t)m))
b0d623f7 6714 {
39037602
A
6715 assert(m->vm_page_q_state == VM_PAGE_ON_INACTIVE_CLEANED_Q);
6716
6717 next = (vm_page_t)VM_PAGE_UNPACK_PTR(m->pageq.next);
39236c6e 6718 discard = FALSE;
b0d623f7 6719 if ((kIOHibernateModeDiscardCleanInactive & gIOHibernateMode)
db609669 6720 && hibernate_consider_discard(m, preflight))
b0d623f7 6721 {
39037602 6722 if (!preflight) hibernate_page_bitset(page_list, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
b0d623f7
A
6723 if (m->dirty)
6724 count_discard_purgeable++;
6725 else
8a3053a0 6726 count_discard_cleaned++;
39236c6e 6727 discard = discard_all;
b0d623f7
A
6728 }
6729 else
8a3053a0 6730 count_cleaned++;
b0d623f7 6731 count_wire--;
39037602 6732 if (!preflight) hibernate_page_bitset(page_list_wired, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
39236c6e
A
6733 if (discard) hibernate_discard_page(m);
6734 m = next;
b0d623f7
A
6735 }
6736
39037602
A
6737 m = (vm_page_t) vm_page_queue_first(&vm_page_queue_active);
6738 while (m && !vm_page_queue_end(&vm_page_queue_active, (vm_page_queue_entry_t)m))
8a3053a0 6739 {
39037602
A
6740 assert(m->vm_page_q_state == VM_PAGE_ON_ACTIVE_Q);
6741
6742 next = (vm_page_t)VM_PAGE_UNPACK_PTR(m->pageq.next);
8a3053a0
A
6743 discard = FALSE;
6744 if ((kIOHibernateModeDiscardCleanActive & gIOHibernateMode)
6745 && hibernate_consider_discard(m, preflight))
6746 {
39037602 6747 if (!preflight) hibernate_page_bitset(page_list, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
8a3053a0
A
6748 if (m->dirty)
6749 count_discard_purgeable++;
6750 else
6751 count_discard_active++;
6752 discard = discard_all;
6753 }
6754 else
6755 count_active++;
6756 count_wire--;
39037602 6757 if (!preflight) hibernate_page_bitset(page_list_wired, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
8a3053a0
A
6758 if (discard) hibernate_discard_page(m);
6759 m = next;
6760 }
6761
39037602
A
6762 m = (vm_page_t) vm_page_queue_first(&vm_page_queue_inactive);
6763 while (m && !vm_page_queue_end(&vm_page_queue_inactive, (vm_page_queue_entry_t)m))
316670eb 6764 {
39037602
A
6765 assert(m->vm_page_q_state == VM_PAGE_ON_INACTIVE_EXTERNAL_Q);
6766
6767 next = (vm_page_t)VM_PAGE_UNPACK_PTR(m->pageq.next);
39236c6e 6768 discard = FALSE;
316670eb 6769 if ((kIOHibernateModeDiscardCleanInactive & gIOHibernateMode)
db609669 6770 && hibernate_consider_discard(m, preflight))
316670eb 6771 {
39037602 6772 if (!preflight) hibernate_page_bitset(page_list, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
316670eb
A
6773 if (m->dirty)
6774 count_discard_purgeable++;
6775 else
8a3053a0 6776 count_discard_inactive++;
39236c6e 6777 discard = discard_all;
316670eb
A
6778 }
6779 else
8a3053a0 6780 count_inactive++;
316670eb 6781 count_wire--;
39037602 6782 if (!preflight) hibernate_page_bitset(page_list_wired, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
39236c6e
A
6783 if (discard) hibernate_discard_page(m);
6784 m = next;
316670eb 6785 }
39037602 6786 /* XXX FBDP TODO: secluded queue */
316670eb 6787
b0d623f7
A
6788 for( i = 0; i <= VM_PAGE_MAX_SPECULATIVE_AGE_Q; i++ )
6789 {
39037602
A
6790 m = (vm_page_t) vm_page_queue_first(&vm_page_queue_speculative[i].age_q);
6791 while (m && !vm_page_queue_end(&vm_page_queue_speculative[i].age_q, (vm_page_queue_entry_t)m))
39236c6e 6792 {
39037602
A
6793 assert(m->vm_page_q_state == VM_PAGE_ON_SPECULATIVE_Q);
6794
6795 next = (vm_page_t)VM_PAGE_UNPACK_PTR(m->pageq.next);
39236c6e
A
6796 discard = FALSE;
6797 if ((kIOHibernateModeDiscardCleanInactive & gIOHibernateMode)
6798 && hibernate_consider_discard(m, preflight))
6799 {
39037602 6800 if (!preflight) hibernate_page_bitset(page_list, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
39236c6e
A
6801 count_discard_speculative++;
6802 discard = discard_all;
6803 }
6804 else
6805 count_speculative++;
6806 count_wire--;
39037602 6807 if (!preflight) hibernate_page_bitset(page_list_wired, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
39236c6e
A
6808 if (discard) hibernate_discard_page(m);
6809 m = next;
6810 }
b0d623f7
A
6811 }
6812
39037602 6813 vm_page_queue_iterate(&compressor_object->memq, m, vm_page_t, listq)
39236c6e 6814 {
39037602
A
6815 assert(m->vm_page_q_state == VM_PAGE_USED_BY_COMPRESSOR);
6816
39236c6e
A
6817 count_compressor++;
6818 count_wire--;
39037602 6819 if (!preflight) hibernate_page_bitset(page_list_wired, TRUE, VM_PAGE_GET_PHYS_PAGE(m));
39236c6e
A
6820 }
6821
6822 if (preflight == FALSE && discard_all == TRUE) {
6823 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 12) | DBG_FUNC_START, 0, 0, 0, 0, 0);
6824
6825 HIBLOG("hibernate_teardown started\n");
6826 count_discard_vm_struct_pages = hibernate_teardown_vm_structs(page_list, page_list_wired);
6827 HIBLOG("hibernate_teardown completed - discarded %d\n", count_discard_vm_struct_pages);
6828
6829 pages -= count_discard_vm_struct_pages;
6830 count_wire -= count_discard_vm_struct_pages;
6831
6832 hibernate_stats.cd_vm_struct_pages_unneeded = count_discard_vm_struct_pages;
6833
6834 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 13) | DBG_FUNC_END, 0, 0, 0, 0, 0);
b0d623f7
A
6835 }
6836
db609669
A
6837 if (!preflight) {
6838 // pull wired from hibernate_bitmap
6839 bitmap = &page_list->bank_bitmap[0];
6840 bitmap_wired = &page_list_wired->bank_bitmap[0];
6841 for (bank = 0; bank < page_list->bank_count; bank++)
6842 {
6843 for (i = 0; i < bitmap->bitmapwords; i++)
6844 bitmap->bitmap[i] = bitmap->bitmap[i] | ~bitmap_wired->bitmap[i];
6845 bitmap = (hibernate_bitmap_t *) &bitmap->bitmap [bitmap->bitmapwords];
6846 bitmap_wired = (hibernate_bitmap_t *) &bitmap_wired->bitmap[bitmap_wired->bitmapwords];
6847 }
b0d623f7
A
6848 }
6849
6850 // machine dependent adjustments
db609669 6851 hibernate_page_list_setall_machine(page_list, page_list_wired, preflight, &pages);
b0d623f7 6852
db609669
A
6853 if (!preflight) {
6854 hibernate_stats.cd_count_wire = count_wire;
39236c6e
A
6855 hibernate_stats.cd_discarded = count_discard_active + count_discard_inactive + count_discard_purgeable +
6856 count_discard_speculative + count_discard_cleaned + count_discard_vm_struct_pages;
db609669 6857 }
0b4c1975 6858
b0d623f7
A
6859 clock_get_uptime(&end);
6860 absolutetime_to_nanoseconds(end - start, &nsec);
6861 HIBLOG("hibernate_page_list_setall time: %qd ms\n", nsec / 1000000ULL);
6862
39236c6e
A
6863 HIBLOG("pages %d, wire %d, act %d, inact %d, cleaned %d spec %d, zf %d, throt %d, compr %d, xpmapped %d\n %s discard act %d inact %d purgeable %d spec %d cleaned %d\n",
6864 pages, count_wire, count_active, count_inactive, count_cleaned, count_speculative, count_anonymous, count_throttled, count_compressor, hibernate_stats.cd_found_xpmapped,
6865 discard_all ? "did" : "could",
316670eb 6866 count_discard_active, count_discard_inactive, count_discard_purgeable, count_discard_speculative, count_discard_cleaned);
b0d623f7 6867
8a3053a0
A
6868 if (hibernate_stats.cd_skipped_xpmapped)
6869 HIBLOG("WARNING: hibernate_page_list_setall skipped %d xpmapped pages\n", hibernate_stats.cd_skipped_xpmapped);
6870
316670eb
A
6871 *pagesOut = pages - count_discard_active - count_discard_inactive - count_discard_purgeable - count_discard_speculative - count_discard_cleaned;
6872
39236c6e
A
6873 if (preflight && will_discard) *pagesOut -= count_compressor + count_throttled + count_anonymous + count_inactive + count_cleaned + count_speculative + count_active;
6874
fe8ab488 6875#if MACH_ASSERT || DEBUG
39236c6e
A
6876 if (!preflight)
6877 {
316670eb
A
6878 if (vm_page_local_q) {
6879 for (i = 0; i < vm_page_local_q_count; i++) {
6880 struct vpl *lq;
6881 lq = &vm_page_local_q[i].vpl_un.vpl;
6882 VPL_UNLOCK(&lq->vpl_lock);
6883 }
6884 }
6885 vm_page_unlock_queues();
39236c6e 6886 }
fe8ab488 6887#endif /* MACH_ASSERT || DEBUG */
0b4c1975 6888
db609669
A
6889 if (preflight) {
6890 lck_mtx_unlock(&vm_page_queue_free_lock);
6891 vm_page_unlock_queues();
39236c6e 6892 vm_object_unlock(compressor_object);
db609669
A
6893 }
6894
0b4c1975 6895 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 8) | DBG_FUNC_END, count_wire, *pagesOut, 0, 0, 0);
b0d623f7
A
6896}
6897
6898void
6899hibernate_page_list_discard(hibernate_page_list_t * page_list)
6900{
6901 uint64_t start, end, nsec;
6902 vm_page_t m;
6903 vm_page_t next;
6904 uint32_t i;
6905 uint32_t count_discard_active = 0;
6906 uint32_t count_discard_inactive = 0;
6907 uint32_t count_discard_purgeable = 0;
316670eb 6908 uint32_t count_discard_cleaned = 0;
b0d623f7
A
6909 uint32_t count_discard_speculative = 0;
6910
39236c6e 6911
fe8ab488 6912#if MACH_ASSERT || DEBUG
316670eb
A
6913 vm_page_lock_queues();
6914 if (vm_page_local_q) {
6915 for (i = 0; i < vm_page_local_q_count; i++) {
6916 struct vpl *lq;
6917 lq = &vm_page_local_q[i].vpl_un.vpl;
6918 VPL_LOCK(&lq->vpl_lock);
6919 }
6920 }
fe8ab488 6921#endif /* MACH_ASSERT || DEBUG */
316670eb 6922
b0d623f7
A
6923 clock_get_uptime(&start);
6924
39037602
A
6925 m = (vm_page_t) vm_page_queue_first(&vm_page_queue_anonymous);
6926 while (m && !vm_page_queue_end(&vm_page_queue_anonymous, (vm_page_queue_entry_t)m))
b0d623f7 6927 {
39037602
A
6928 assert(m->vm_page_q_state == VM_PAGE_ON_INACTIVE_INTERNAL_Q);
6929
6930 next = (vm_page_t) VM_PAGE_UNPACK_PTR(m->pageq.next);
6931 if (hibernate_page_bittst(page_list, VM_PAGE_GET_PHYS_PAGE(m)))
b0d623f7
A
6932 {
6933 if (m->dirty)
6934 count_discard_purgeable++;
6935 else
6936 count_discard_inactive++;
6937 hibernate_discard_page(m);
6938 }
6939 m = next;
6940 }
6941
6942 for( i = 0; i <= VM_PAGE_MAX_SPECULATIVE_AGE_Q; i++ )
6943 {
39037602
A
6944 m = (vm_page_t) vm_page_queue_first(&vm_page_queue_speculative[i].age_q);
6945 while (m && !vm_page_queue_end(&vm_page_queue_speculative[i].age_q, (vm_page_queue_entry_t)m))
b0d623f7 6946 {
39037602
A
6947 assert(m->vm_page_q_state == VM_PAGE_ON_SPECULATIVE_Q);
6948
6949 next = (vm_page_t) VM_PAGE_UNPACK_PTR(m->pageq.next);
6950 if (hibernate_page_bittst(page_list, VM_PAGE_GET_PHYS_PAGE(m)))
b0d623f7
A
6951 {
6952 count_discard_speculative++;
6953 hibernate_discard_page(m);
6954 }
6955 m = next;
6956 }
6957 }
6958
39037602
A
6959 m = (vm_page_t) vm_page_queue_first(&vm_page_queue_inactive);
6960 while (m && !vm_page_queue_end(&vm_page_queue_inactive, (vm_page_queue_entry_t)m))
b0d623f7 6961 {
39037602
A
6962 assert(m->vm_page_q_state == VM_PAGE_ON_INACTIVE_EXTERNAL_Q);
6963
6964 next = (vm_page_t) VM_PAGE_UNPACK_PTR(m->pageq.next);
6965 if (hibernate_page_bittst(page_list, VM_PAGE_GET_PHYS_PAGE(m)))
b0d623f7
A
6966 {
6967 if (m->dirty)
6968 count_discard_purgeable++;
6969 else
6970 count_discard_inactive++;
6971 hibernate_discard_page(m);
6972 }
6973 m = next;
6974 }
39037602 6975 /* XXX FBDP TODO: secluded queue */
b0d623f7 6976
39037602
A
6977 m = (vm_page_t) vm_page_queue_first(&vm_page_queue_active);
6978 while (m && !vm_page_queue_end(&vm_page_queue_active, (vm_page_queue_entry_t)m))
b0d623f7 6979 {
39037602
A
6980 assert(m->vm_page_q_state == VM_PAGE_ON_ACTIVE_Q);
6981
6982 next = (vm_page_t) VM_PAGE_UNPACK_PTR(m->pageq.next);
6983 if (hibernate_page_bittst(page_list, VM_PAGE_GET_PHYS_PAGE(m)))
b0d623f7
A
6984 {
6985 if (m->dirty)
6986 count_discard_purgeable++;
6987 else
6988 count_discard_active++;
6989 hibernate_discard_page(m);
6990 }
6991 m = next;
6992 }
6993
39037602
A
6994 m = (vm_page_t) vm_page_queue_first(&vm_page_queue_cleaned);
6995 while (m && !vm_page_queue_end(&vm_page_queue_cleaned, (vm_page_queue_entry_t)m))
316670eb 6996 {
39037602
A
6997 assert(m->vm_page_q_state == VM_PAGE_ON_INACTIVE_CLEANED_Q);
6998
6999 next = (vm_page_t) VM_PAGE_UNPACK_PTR(m->pageq.next);
7000 if (hibernate_page_bittst(page_list, VM_PAGE_GET_PHYS_PAGE(m)))
316670eb
A
7001 {
7002 if (m->dirty)
7003 count_discard_purgeable++;
7004 else
7005 count_discard_cleaned++;
7006 hibernate_discard_page(m);
7007 }
7008 m = next;
7009 }
7010
fe8ab488 7011#if MACH_ASSERT || DEBUG
316670eb
A
7012 if (vm_page_local_q) {
7013 for (i = 0; i < vm_page_local_q_count; i++) {
7014 struct vpl *lq;
7015 lq = &vm_page_local_q[i].vpl_un.vpl;
7016 VPL_UNLOCK(&lq->vpl_lock);
7017 }
7018 }
7019 vm_page_unlock_queues();
fe8ab488 7020#endif /* MACH_ASSERT || DEBUG */
316670eb 7021
b0d623f7
A
7022 clock_get_uptime(&end);
7023 absolutetime_to_nanoseconds(end - start, &nsec);
316670eb 7024 HIBLOG("hibernate_page_list_discard time: %qd ms, discarded act %d inact %d purgeable %d spec %d cleaned %d\n",
b0d623f7 7025 nsec / 1000000ULL,
316670eb 7026 count_discard_active, count_discard_inactive, count_discard_purgeable, count_discard_speculative, count_discard_cleaned);
b0d623f7
A
7027}
7028
39236c6e
A
7029boolean_t hibernate_paddr_map_inited = FALSE;
7030boolean_t hibernate_rebuild_needed = FALSE;
7031unsigned int hibernate_teardown_last_valid_compact_indx = -1;
7032vm_page_t hibernate_rebuild_hash_list = NULL;
7033
7034unsigned int hibernate_teardown_found_tabled_pages = 0;
7035unsigned int hibernate_teardown_found_created_pages = 0;
7036unsigned int hibernate_teardown_found_free_pages = 0;
7037unsigned int hibernate_teardown_vm_page_free_count;
7038
7039
7040struct ppnum_mapping {
7041 struct ppnum_mapping *ppnm_next;
7042 ppnum_t ppnm_base_paddr;
7043 unsigned int ppnm_sindx;
7044 unsigned int ppnm_eindx;
7045};
7046
7047struct ppnum_mapping *ppnm_head;
7048struct ppnum_mapping *ppnm_last_found = NULL;
7049
7050
7051void
7052hibernate_create_paddr_map()
7053{
7054 unsigned int i;
7055 ppnum_t next_ppnum_in_run = 0;
7056 struct ppnum_mapping *ppnm = NULL;
7057
7058 if (hibernate_paddr_map_inited == FALSE) {
7059
7060 for (i = 0; i < vm_pages_count; i++) {
7061
7062 if (ppnm)
7063 ppnm->ppnm_eindx = i;
7064
39037602 7065 if (ppnm == NULL || VM_PAGE_GET_PHYS_PAGE(&vm_pages[i]) != next_ppnum_in_run) {
39236c6e
A
7066
7067 ppnm = kalloc(sizeof(struct ppnum_mapping));
7068
7069 ppnm->ppnm_next = ppnm_head;
7070 ppnm_head = ppnm;
7071
7072 ppnm->ppnm_sindx = i;
39037602 7073 ppnm->ppnm_base_paddr = VM_PAGE_GET_PHYS_PAGE(&vm_pages[i]);
39236c6e 7074 }
39037602 7075 next_ppnum_in_run = VM_PAGE_GET_PHYS_PAGE(&vm_pages[i]) + 1;
39236c6e
A
7076 }
7077 ppnm->ppnm_eindx++;
7078
7079 hibernate_paddr_map_inited = TRUE;
7080 }
7081}
7082
7083ppnum_t
7084hibernate_lookup_paddr(unsigned int indx)
7085{
7086 struct ppnum_mapping *ppnm = NULL;
7087
7088 ppnm = ppnm_last_found;
7089
7090 if (ppnm) {
7091 if (indx >= ppnm->ppnm_sindx && indx < ppnm->ppnm_eindx)
7092 goto done;
7093 }
7094 for (ppnm = ppnm_head; ppnm; ppnm = ppnm->ppnm_next) {
7095
7096 if (indx >= ppnm->ppnm_sindx && indx < ppnm->ppnm_eindx) {
7097 ppnm_last_found = ppnm;
7098 break;
7099 }
7100 }
7101 if (ppnm == NULL)
7102 panic("hibernate_lookup_paddr of %d failed\n", indx);
7103done:
7104 return (ppnm->ppnm_base_paddr + (indx - ppnm->ppnm_sindx));
7105}
7106
7107
7108uint32_t
7109hibernate_mark_as_unneeded(addr64_t saddr, addr64_t eaddr, hibernate_page_list_t *page_list, hibernate_page_list_t *page_list_wired)
7110{
7111 addr64_t saddr_aligned;
7112 addr64_t eaddr_aligned;
7113 addr64_t addr;
7114 ppnum_t paddr;
7115 unsigned int mark_as_unneeded_pages = 0;
7116
7117 saddr_aligned = (saddr + PAGE_MASK_64) & ~PAGE_MASK_64;
7118 eaddr_aligned = eaddr & ~PAGE_MASK_64;
7119
7120 for (addr = saddr_aligned; addr < eaddr_aligned; addr += PAGE_SIZE_64) {
7121
7122 paddr = pmap_find_phys(kernel_pmap, addr);
7123
7124 assert(paddr);
7125
7126 hibernate_page_bitset(page_list, TRUE, paddr);
7127 hibernate_page_bitset(page_list_wired, TRUE, paddr);
7128
7129 mark_as_unneeded_pages++;
7130 }
7131 return (mark_as_unneeded_pages);
7132}
7133
7134
7135void
7136hibernate_hash_insert_page(vm_page_t mem)
7137{
7138 vm_page_bucket_t *bucket;
7139 int hash_id;
39037602
A
7140 vm_object_t m_object;
7141
7142 m_object = VM_PAGE_OBJECT(mem);
39236c6e 7143
15129b1c 7144 assert(mem->hashed);
39037602 7145 assert(m_object);
39236c6e
A
7146 assert(mem->offset != (vm_object_offset_t) -1);
7147
7148 /*
7149 * Insert it into the object_object/offset hash table
7150 */
39037602 7151 hash_id = vm_page_hash(m_object, mem->offset);
39236c6e
A
7152 bucket = &vm_page_buckets[hash_id];
7153
fe8ab488
A
7154 mem->next_m = bucket->page_list;
7155 bucket->page_list = VM_PAGE_PACK_PTR(mem);
39236c6e
A
7156}
7157
7158
7159void
7160hibernate_free_range(int sindx, int eindx)
7161{
7162 vm_page_t mem;
7163 unsigned int color;
7164
7165 while (sindx < eindx) {
7166 mem = &vm_pages[sindx];
7167
7168 vm_page_init(mem, hibernate_lookup_paddr(sindx), FALSE);
7169
7170 mem->lopage = FALSE;
39037602 7171 mem->vm_page_q_state = VM_PAGE_ON_FREE_Q;
39236c6e 7172
39037602
A
7173 color = VM_PAGE_GET_PHYS_PAGE(mem) & vm_color_mask;
7174 vm_page_queue_enter_first(&vm_page_queue_free[color].qhead,
7175 mem,
7176 vm_page_t,
7177 pageq);
39236c6e
A
7178 vm_page_free_count++;
7179
7180 sindx++;
7181 }
7182}
7183
7184
7185extern void hibernate_rebuild_pmap_structs(void);
7186
7187void
7188hibernate_rebuild_vm_structs(void)
7189{
7190 int cindx, sindx, eindx;
7191 vm_page_t mem, tmem, mem_next;
7192 AbsoluteTime startTime, endTime;
7193 uint64_t nsec;
7194
7195 if (hibernate_rebuild_needed == FALSE)
7196 return;
7197
7198 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 13) | DBG_FUNC_START, 0, 0, 0, 0, 0);
7199 HIBLOG("hibernate_rebuild started\n");
7200
7201 clock_get_uptime(&startTime);
7202
7203 hibernate_rebuild_pmap_structs();
7204
7205 bzero(&vm_page_buckets[0], vm_page_bucket_count * sizeof(vm_page_bucket_t));
7206 eindx = vm_pages_count;
7207
7208 for (cindx = hibernate_teardown_last_valid_compact_indx; cindx >= 0; cindx--) {
7209
7210 mem = &vm_pages[cindx];
7211 /*
7212 * hibernate_teardown_vm_structs leaves the location where
7213 * this vm_page_t must be located in "next".
7214 */
39037602 7215 tmem = (vm_page_t)(VM_PAGE_UNPACK_PTR(mem->next_m));
fe8ab488 7216 mem->next_m = VM_PAGE_PACK_PTR(NULL);
39236c6e
A
7217
7218 sindx = (int)(tmem - &vm_pages[0]);
7219
7220 if (mem != tmem) {
7221 /*
7222 * this vm_page_t was moved by hibernate_teardown_vm_structs,
7223 * so move it back to its real location
7224 */
7225 *tmem = *mem;
7226 mem = tmem;
7227 }
15129b1c 7228 if (mem->hashed)
39236c6e
A
7229 hibernate_hash_insert_page(mem);
7230 /*
7231 * the 'hole' between this vm_page_t and the previous
7232 * vm_page_t we moved needs to be initialized as
7233 * a range of free vm_page_t's
7234 */
7235 hibernate_free_range(sindx + 1, eindx);
7236
7237 eindx = sindx;
7238 }
7239 if (sindx)
7240 hibernate_free_range(0, sindx);
7241
7242 assert(vm_page_free_count == hibernate_teardown_vm_page_free_count);
7243
7244 /*
15129b1c 7245 * process the list of vm_page_t's that were entered in the hash,
39236c6e
A
7246 * but were not located in the vm_pages arrary... these are
7247 * vm_page_t's that were created on the fly (i.e. fictitious)
7248 */
7249 for (mem = hibernate_rebuild_hash_list; mem; mem = mem_next) {
39037602 7250 mem_next = (vm_page_t)(VM_PAGE_UNPACK_PTR(mem->next_m));
39236c6e 7251
39037602 7252 mem->next_m = 0;
39236c6e
A
7253 hibernate_hash_insert_page(mem);
7254 }
7255 hibernate_rebuild_hash_list = NULL;
7256
7257 clock_get_uptime(&endTime);
7258 SUB_ABSOLUTETIME(&endTime, &startTime);
7259 absolutetime_to_nanoseconds(endTime, &nsec);
7260
7261 HIBLOG("hibernate_rebuild completed - took %qd msecs\n", nsec / 1000000ULL);
7262
7263 hibernate_rebuild_needed = FALSE;
7264
7265 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 13) | DBG_FUNC_END, 0, 0, 0, 0, 0);
7266}
7267
7268
7269extern void hibernate_teardown_pmap_structs(addr64_t *, addr64_t *);
7270
7271uint32_t
7272hibernate_teardown_vm_structs(hibernate_page_list_t *page_list, hibernate_page_list_t *page_list_wired)
7273{
7274 unsigned int i;
7275 unsigned int compact_target_indx;
7276 vm_page_t mem, mem_next;
7277 vm_page_bucket_t *bucket;
7278 unsigned int mark_as_unneeded_pages = 0;
7279 unsigned int unneeded_vm_page_bucket_pages = 0;
7280 unsigned int unneeded_vm_pages_pages = 0;
7281 unsigned int unneeded_pmap_pages = 0;
7282 addr64_t start_of_unneeded = 0;
7283 addr64_t end_of_unneeded = 0;
7284
7285
7286 if (hibernate_should_abort())
7287 return (0);
7288
7289 HIBLOG("hibernate_teardown: wired_pages %d, free_pages %d, active_pages %d, inactive_pages %d, speculative_pages %d, cleaned_pages %d, compressor_pages %d\n",
7290 vm_page_wire_count, vm_page_free_count, vm_page_active_count, vm_page_inactive_count, vm_page_speculative_count,
7291 vm_page_cleaned_count, compressor_object->resident_page_count);
7292
7293 for (i = 0; i < vm_page_bucket_count; i++) {
7294
7295 bucket = &vm_page_buckets[i];
7296
39037602 7297 for (mem = (vm_page_t)(VM_PAGE_UNPACK_PTR(bucket->page_list)); mem != VM_PAGE_NULL; mem = mem_next) {
15129b1c 7298 assert(mem->hashed);
39236c6e 7299
39037602 7300 mem_next = (vm_page_t)(VM_PAGE_UNPACK_PTR(mem->next_m));
39236c6e
A
7301
7302 if (mem < &vm_pages[0] || mem >= &vm_pages[vm_pages_count]) {
fe8ab488 7303 mem->next_m = VM_PAGE_PACK_PTR(hibernate_rebuild_hash_list);
39236c6e
A
7304 hibernate_rebuild_hash_list = mem;
7305 }
7306 }
7307 }
7308 unneeded_vm_page_bucket_pages = hibernate_mark_as_unneeded((addr64_t)&vm_page_buckets[0], (addr64_t)&vm_page_buckets[vm_page_bucket_count], page_list, page_list_wired);
7309 mark_as_unneeded_pages += unneeded_vm_page_bucket_pages;
7310
7311 hibernate_teardown_vm_page_free_count = vm_page_free_count;
7312
7313 compact_target_indx = 0;
7314
7315 for (i = 0; i < vm_pages_count; i++) {
7316
7317 mem = &vm_pages[i];
7318
39037602 7319 if (mem->vm_page_q_state == VM_PAGE_ON_FREE_Q) {
39236c6e
A
7320 unsigned int color;
7321
7322 assert(mem->busy);
7323 assert(!mem->lopage);
7324
39037602
A
7325 color = VM_PAGE_GET_PHYS_PAGE(mem) & vm_color_mask;
7326
7327 vm_page_queue_remove(&vm_page_queue_free[color].qhead,
7328 mem,
7329 vm_page_t,
7330 pageq);
39236c6e 7331
39037602 7332 VM_PAGE_ZERO_PAGEQ_ENTRY(mem);
39236c6e
A
7333
7334 vm_page_free_count--;
7335
7336 hibernate_teardown_found_free_pages++;
7337
39037602 7338 if (vm_pages[compact_target_indx].vm_page_q_state != VM_PAGE_ON_FREE_Q)
39236c6e
A
7339 compact_target_indx = i;
7340 } else {
7341 /*
7342 * record this vm_page_t's original location
7343 * we need this even if it doesn't get moved
7344 * as an indicator to the rebuild function that
7345 * we don't have to move it
7346 */
fe8ab488 7347 mem->next_m = VM_PAGE_PACK_PTR(mem);
39236c6e 7348
39037602 7349 if (vm_pages[compact_target_indx].vm_page_q_state == VM_PAGE_ON_FREE_Q) {
39236c6e
A
7350 /*
7351 * we've got a hole to fill, so
7352 * move this vm_page_t to it's new home
7353 */
7354 vm_pages[compact_target_indx] = *mem;
39037602 7355 mem->vm_page_q_state = VM_PAGE_ON_FREE_Q;
39236c6e
A
7356
7357 hibernate_teardown_last_valid_compact_indx = compact_target_indx;
7358 compact_target_indx++;
7359 } else
7360 hibernate_teardown_last_valid_compact_indx = i;
7361 }
7362 }
7363 unneeded_vm_pages_pages = hibernate_mark_as_unneeded((addr64_t)&vm_pages[hibernate_teardown_last_valid_compact_indx+1],
7364 (addr64_t)&vm_pages[vm_pages_count-1], page_list, page_list_wired);
7365 mark_as_unneeded_pages += unneeded_vm_pages_pages;
7366
7367 hibernate_teardown_pmap_structs(&start_of_unneeded, &end_of_unneeded);
7368
7369 if (start_of_unneeded) {
7370 unneeded_pmap_pages = hibernate_mark_as_unneeded(start_of_unneeded, end_of_unneeded, page_list, page_list_wired);
7371 mark_as_unneeded_pages += unneeded_pmap_pages;
7372 }
7373 HIBLOG("hibernate_teardown: mark_as_unneeded_pages %d, %d, %d\n", unneeded_vm_page_bucket_pages, unneeded_vm_pages_pages, unneeded_pmap_pages);
7374
7375 hibernate_rebuild_needed = TRUE;
7376
7377 return (mark_as_unneeded_pages);
7378}
7379
7380
d1ecb069
A
7381#endif /* HIBERNATION */
7382
b0d623f7 7383/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1c79356b
A
7384
7385#include <mach_vm_debug.h>
7386#if MACH_VM_DEBUG
7387
7388#include <mach_debug/hash_info.h>
7389#include <vm/vm_debug.h>
7390
7391/*
7392 * Routine: vm_page_info
7393 * Purpose:
7394 * Return information about the global VP table.
7395 * Fills the buffer with as much information as possible
7396 * and returns the desired size of the buffer.
7397 * Conditions:
7398 * Nothing locked. The caller should provide
7399 * possibly-pageable memory.
7400 */
7401
7402unsigned int
7403vm_page_info(
7404 hash_info_bucket_t *info,
7405 unsigned int count)
7406{
91447636 7407 unsigned int i;
b0d623f7 7408 lck_spin_t *bucket_lock;
1c79356b
A
7409
7410 if (vm_page_bucket_count < count)
7411 count = vm_page_bucket_count;
7412
7413 for (i = 0; i < count; i++) {
7414 vm_page_bucket_t *bucket = &vm_page_buckets[i];
7415 unsigned int bucket_count = 0;
7416 vm_page_t m;
7417
b0d623f7
A
7418 bucket_lock = &vm_page_bucket_locks[i / BUCKETS_PER_LOCK];
7419 lck_spin_lock(bucket_lock);
7420
39037602
A
7421 for (m = (vm_page_t)(VM_PAGE_UNPACK_PTR(bucket->page_list));
7422 m != VM_PAGE_NULL;
7423 m = (vm_page_t)(VM_PAGE_UNPACK_PTR(m->next_m)))
1c79356b 7424 bucket_count++;
b0d623f7
A
7425
7426 lck_spin_unlock(bucket_lock);
1c79356b
A
7427
7428 /* don't touch pageable memory while holding locks */
7429 info[i].hib_count = bucket_count;
7430 }
7431
7432 return vm_page_bucket_count;
7433}
7434#endif /* MACH_VM_DEBUG */
15129b1c
A
7435
7436#if VM_PAGE_BUCKETS_CHECK
7437void
7438vm_page_buckets_check(void)
7439{
7440 unsigned int i;
7441 vm_page_t p;
7442 unsigned int p_hash;
7443 vm_page_bucket_t *bucket;
7444 lck_spin_t *bucket_lock;
7445
7446 if (!vm_page_buckets_check_ready) {
7447 return;
7448 }
7449
7450#if HIBERNATION
7451 if (hibernate_rebuild_needed ||
7452 hibernate_rebuild_hash_list) {
7453 panic("BUCKET_CHECK: hibernation in progress: "
7454 "rebuild_needed=%d rebuild_hash_list=%p\n",
7455 hibernate_rebuild_needed,
7456 hibernate_rebuild_hash_list);
7457 }
7458#endif /* HIBERNATION */
7459
7460#if VM_PAGE_FAKE_BUCKETS
7461 char *cp;
7462 for (cp = (char *) vm_page_fake_buckets_start;
7463 cp < (char *) vm_page_fake_buckets_end;
7464 cp++) {
7465 if (*cp != 0x5a) {
7466 panic("BUCKET_CHECK: corruption at %p in fake buckets "
7467 "[0x%llx:0x%llx]\n",
7468 cp,
fe8ab488
A
7469 (uint64_t) vm_page_fake_buckets_start,
7470 (uint64_t) vm_page_fake_buckets_end);
15129b1c
A
7471 }
7472 }
7473#endif /* VM_PAGE_FAKE_BUCKETS */
7474
7475 for (i = 0; i < vm_page_bucket_count; i++) {
39037602
A
7476 vm_object_t p_object;
7477
15129b1c 7478 bucket = &vm_page_buckets[i];
fe8ab488 7479 if (!bucket->page_list) {
15129b1c
A
7480 continue;
7481 }
7482
7483 bucket_lock = &vm_page_bucket_locks[i / BUCKETS_PER_LOCK];
7484 lck_spin_lock(bucket_lock);
39037602
A
7485 p = (vm_page_t)(VM_PAGE_UNPACK_PTR(bucket->page_list));
7486
15129b1c 7487 while (p != VM_PAGE_NULL) {
39037602
A
7488 p_object = VM_PAGE_OBJECT(p);
7489
15129b1c
A
7490 if (!p->hashed) {
7491 panic("BUCKET_CHECK: page %p (%p,0x%llx) "
7492 "hash %d in bucket %d at %p "
7493 "is not hashed\n",
39037602 7494 p, p_object, p->offset,
15129b1c
A
7495 p_hash, i, bucket);
7496 }
39037602 7497 p_hash = vm_page_hash(p_object, p->offset);
15129b1c
A
7498 if (p_hash != i) {
7499 panic("BUCKET_CHECK: corruption in bucket %d "
7500 "at %p: page %p object %p offset 0x%llx "
7501 "hash %d\n",
39037602 7502 i, bucket, p, p_object, p->offset,
15129b1c
A
7503 p_hash);
7504 }
39037602 7505 p = (vm_page_t)(VM_PAGE_UNPACK_PTR(p->next_m));
15129b1c
A
7506 }
7507 lck_spin_unlock(bucket_lock);
7508 }
7509
7510// printf("BUCKET_CHECK: checked buckets\n");
7511}
7512#endif /* VM_PAGE_BUCKETS_CHECK */
3e170ce0
A
7513
7514/*
7515 * 'vm_fault_enter' will place newly created pages (zero-fill and COW) onto the
7516 * local queues if they exist... its the only spot in the system where we add pages
7517 * to those queues... once on those queues, those pages can only move to one of the
7518 * global page queues or the free queues... they NEVER move from local q to local q.
7519 * the 'local' state is stable when vm_page_queues_remove is called since we're behind
7520 * the global vm_page_queue_lock at this point... we still need to take the local lock
7521 * in case this operation is being run on a different CPU then the local queue's identity,
7522 * but we don't have to worry about the page moving to a global queue or becoming wired
7523 * while we're grabbing the local lock since those operations would require the global
7524 * vm_page_queue_lock to be held, and we already own it.
7525 *
7526 * this is why its safe to utilze the wire_count field in the vm_page_t as the local_id...
7527 * 'wired' and local are ALWAYS mutually exclusive conditions.
7528 */
39037602
A
7529
7530#if CONFIG_BACKGROUND_QUEUE
7531void
7532vm_page_queues_remove(vm_page_t mem, boolean_t remove_from_backgroundq)
7533#else
3e170ce0 7534void
39037602
A
7535vm_page_queues_remove(vm_page_t mem, boolean_t __unused remove_from_backgroundq)
7536#endif
3e170ce0 7537{
39037602
A
7538 boolean_t was_pageable = TRUE;
7539 vm_object_t m_object;
3e170ce0 7540
39037602
A
7541 m_object = VM_PAGE_OBJECT(mem);
7542
7543 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
7544
7545 if (mem->vm_page_q_state == VM_PAGE_NOT_ON_Q)
7546 {
7547 assert(mem->pageq.next == 0 && mem->pageq.prev == 0);
7548#if CONFIG_BACKGROUND_QUEUE
743345f9
A
7549 if (remove_from_backgroundq == TRUE) {
7550 vm_page_remove_from_backgroundq(mem);
39037602 7551 }
743345f9
A
7552 if (mem->vm_page_on_backgroundq) {
7553 assert(mem->vm_page_backgroundq.next != 0);
7554 assert(mem->vm_page_backgroundq.prev != 0);
7555 } else {
7556 assert(mem->vm_page_backgroundq.next == 0);
7557 assert(mem->vm_page_backgroundq.prev == 0);
7558 }
7559#endif /* CONFIG_BACKGROUND_QUEUE */
39037602
A
7560 return;
7561 }
7562 if (mem->vm_page_q_state == VM_PAGE_USED_BY_COMPRESSOR)
7563 {
7564 assert(mem->pageq.next == 0 && mem->pageq.prev == 0);
7565#if CONFIG_BACKGROUND_QUEUE
7566 assert(mem->vm_page_backgroundq.next == 0 &&
7567 mem->vm_page_backgroundq.prev == 0 &&
7568 mem->vm_page_on_backgroundq == FALSE);
7569#endif
7570 return;
7571 }
7572 if (mem->vm_page_q_state == VM_PAGE_IS_WIRED) {
7573 /*
7574 * might put these guys on a list for debugging purposes
7575 * if we do, we'll need to remove this assert
7576 */
7577 assert(mem->pageq.next == 0 && mem->pageq.prev == 0);
7578#if CONFIG_BACKGROUND_QUEUE
7579 assert(mem->vm_page_backgroundq.next == 0 &&
7580 mem->vm_page_backgroundq.prev == 0 &&
7581 mem->vm_page_on_backgroundq == FALSE);
7582#endif
7583 return;
7584 }
7585
7586 assert(m_object != compressor_object);
7587 assert(m_object != kernel_object);
7588 assert(m_object != vm_submap_object);
7589 assert(!mem->fictitious);
7590
7591 switch(mem->vm_page_q_state) {
7592
7593 case VM_PAGE_ON_ACTIVE_LOCAL_Q:
7594 {
3e170ce0 7595 struct vpl *lq;
39037602 7596
3e170ce0
A
7597 lq = &vm_page_local_q[mem->local_id].vpl_un.vpl;
7598 VPL_LOCK(&lq->vpl_lock);
39037602
A
7599 vm_page_queue_remove(&lq->vpl_queue,
7600 mem, vm_page_t, pageq);
3e170ce0
A
7601 mem->local_id = 0;
7602 lq->vpl_count--;
39037602 7603 if (m_object->internal) {
3e170ce0
A
7604 lq->vpl_internal_count--;
7605 } else {
7606 lq->vpl_external_count--;
7607 }
7608 VPL_UNLOCK(&lq->vpl_lock);
7609 was_pageable = FALSE;
39037602 7610 break;
3e170ce0 7611 }
39037602
A
7612 case VM_PAGE_ON_ACTIVE_Q:
7613 {
7614 vm_page_queue_remove(&vm_page_queue_active,
7615 mem, vm_page_t, pageq);
3e170ce0 7616 vm_page_active_count--;
39037602 7617 break;
3e170ce0
A
7618 }
7619
39037602
A
7620 case VM_PAGE_ON_INACTIVE_INTERNAL_Q:
7621 {
7622 assert(m_object->internal == TRUE);
7623
3e170ce0 7624 vm_page_inactive_count--;
39037602
A
7625 vm_page_queue_remove(&vm_page_queue_anonymous,
7626 mem, vm_page_t, pageq);
7627 vm_page_anonymous_count--;
7628 vm_purgeable_q_advance_all();
7629 break;
7630 }
7631
7632 case VM_PAGE_ON_INACTIVE_EXTERNAL_Q:
7633 {
7634 assert(m_object->internal == FALSE);
7635
7636 vm_page_inactive_count--;
7637 vm_page_queue_remove(&vm_page_queue_inactive,
7638 mem, vm_page_t, pageq);
7639 vm_purgeable_q_advance_all();
7640 break;
7641 }
7642
7643 case VM_PAGE_ON_INACTIVE_CLEANED_Q:
7644 {
7645 assert(m_object->internal == FALSE);
7646
7647 vm_page_inactive_count--;
7648 vm_page_queue_remove(&vm_page_queue_cleaned,
7649 mem, vm_page_t, pageq);
7650 vm_page_cleaned_count--;
7651 break;
7652 }
7653
7654 case VM_PAGE_ON_THROTTLED_Q:
7655 {
7656 assert(m_object->internal == TRUE);
7657
7658 vm_page_queue_remove(&vm_page_queue_throttled,
7659 mem, vm_page_t, pageq);
3e170ce0
A
7660 vm_page_throttled_count--;
7661 was_pageable = FALSE;
39037602 7662 break;
3e170ce0
A
7663 }
7664
39037602
A
7665 case VM_PAGE_ON_SPECULATIVE_Q:
7666 {
7667 assert(m_object->internal == FALSE);
7668
7669 vm_page_remque(&mem->pageq);
3e170ce0 7670 vm_page_speculative_count--;
39037602
A
7671 break;
7672 }
7673
7674#if CONFIG_SECLUDED_MEMORY
7675 case VM_PAGE_ON_SECLUDED_Q:
7676 {
7677 vm_page_queue_remove(&vm_page_queue_secluded,
7678 mem, vm_page_t, pageq);
7679 vm_page_secluded_count--;
7680 if (m_object == VM_OBJECT_NULL) {
7681 vm_page_secluded_count_free--;
7682 was_pageable = FALSE;
7683 } else {
7684 assert(!m_object->internal);
7685 vm_page_secluded_count_inuse--;
7686 was_pageable = FALSE;
7687// was_pageable = TRUE;
7688 }
7689 break;
7690 }
7691#endif /* CONFIG_SECLUDED_MEMORY */
7692
7693 default:
7694 {
7695 /*
7696 * if (mem->vm_page_q_state == VM_PAGE_ON_PAGEOUT_Q)
7697 * NOTE: vm_page_queues_remove does not deal with removing pages from the pageout queue...
7698 * the caller is responsible for determing if the page is on that queue, and if so, must
7699 * either first remove it (it needs both the page queues lock and the object lock to do
7700 * this via vm_pageout_steal_laundry), or avoid the call to vm_page_queues_remove
7701 *
7702 * we also don't expect to encounter VM_PAGE_ON_FREE_Q, VM_PAGE_ON_FREE_LOCAL_Q, VM_PAGE_ON_FREE_LOPAGE_Q
7703 * or any of the undefined states
7704 */
7705 panic("vm_page_queues_remove - bad page q_state (%p, %d)\n", mem, mem->vm_page_q_state);
7706 break;
3e170ce0
A
7707 }
7708
3e170ce0 7709 }
39037602
A
7710 VM_PAGE_ZERO_PAGEQ_ENTRY(mem);
7711 mem->vm_page_q_state = VM_PAGE_NOT_ON_Q;
3e170ce0 7712
39037602
A
7713#if CONFIG_BACKGROUND_QUEUE
7714 if (remove_from_backgroundq == TRUE)
7715 vm_page_remove_from_backgroundq(mem);
7716#endif
3e170ce0 7717 if (was_pageable) {
39037602 7718 if (m_object->internal) {
3e170ce0
A
7719 vm_page_pageable_internal_count--;
7720 } else {
7721 vm_page_pageable_external_count--;
7722 }
7723 }
7724}
7725
7726void
7727vm_page_remove_internal(vm_page_t page)
7728{
39037602 7729 vm_object_t __object = VM_PAGE_OBJECT(page);
3e170ce0
A
7730 if (page == __object->memq_hint) {
7731 vm_page_t __new_hint;
39037602
A
7732 vm_page_queue_entry_t __qe;
7733 __qe = (vm_page_queue_entry_t)vm_page_queue_next(&page->listq);
7734 if (vm_page_queue_end(&__object->memq, __qe)) {
7735 __qe = (vm_page_queue_entry_t)vm_page_queue_prev(&page->listq);
7736 if (vm_page_queue_end(&__object->memq, __qe)) {
3e170ce0
A
7737 __qe = NULL;
7738 }
7739 }
39037602 7740 __new_hint = (vm_page_t)((uintptr_t) __qe);
3e170ce0
A
7741 __object->memq_hint = __new_hint;
7742 }
39037602
A
7743 vm_page_queue_remove(&__object->memq, page, vm_page_t, listq);
7744#if CONFIG_SECLUDED_MEMORY
7745 if (__object->eligible_for_secluded) {
7746 vm_page_secluded.eligible_for_secluded--;
7747 }
7748#endif /* CONFIG_SECLUDED_MEMORY */
3e170ce0
A
7749}
7750
7751void
7752vm_page_enqueue_inactive(vm_page_t mem, boolean_t first)
7753{
39037602
A
7754 vm_object_t m_object;
7755
7756 m_object = VM_PAGE_OBJECT(mem);
7757
7758 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
3e170ce0
A
7759 assert(!mem->fictitious);
7760 assert(!mem->laundry);
39037602 7761 assert(mem->vm_page_q_state == VM_PAGE_NOT_ON_Q);
3e170ce0 7762 vm_page_check_pageable_safe(mem);
39037602
A
7763
7764#if CONFIG_SECLUDED_MEMORY
7765 if (secluded_for_filecache &&
7766 vm_page_secluded_target != 0 &&
7767 num_tasks_can_use_secluded_mem == 0 &&
7768 m_object->eligible_for_secluded &&
7769 secluded_aging_policy == SECLUDED_AGING_FIFO) {
7770 mem->vm_page_q_state = VM_PAGE_ON_SECLUDED_Q;
7771 vm_page_queue_enter(&vm_page_queue_secluded, mem,
7772 vm_page_t, pageq);
7773 vm_page_secluded_count++;
7774 vm_page_secluded_count_inuse++;
7775 assert(!m_object->internal);
7776// vm_page_pageable_external_count++;
7777 return;
7778 }
7779#endif /* CONFIG_SECLUDED_MEMORY */
7780
7781 if (m_object->internal) {
7782 mem->vm_page_q_state = VM_PAGE_ON_INACTIVE_INTERNAL_Q;
7783
3e170ce0 7784 if (first == TRUE)
39037602 7785 vm_page_queue_enter_first(&vm_page_queue_anonymous, mem, vm_page_t, pageq);
3e170ce0 7786 else
39037602
A
7787 vm_page_queue_enter(&vm_page_queue_anonymous, mem, vm_page_t, pageq);
7788
3e170ce0
A
7789 vm_page_anonymous_count++;
7790 vm_page_pageable_internal_count++;
7791 } else {
39037602
A
7792 mem->vm_page_q_state = VM_PAGE_ON_INACTIVE_EXTERNAL_Q;
7793
3e170ce0 7794 if (first == TRUE)
39037602 7795 vm_page_queue_enter_first(&vm_page_queue_inactive, mem, vm_page_t, pageq);
3e170ce0 7796 else
39037602
A
7797 vm_page_queue_enter(&vm_page_queue_inactive, mem, vm_page_t, pageq);
7798
3e170ce0
A
7799 vm_page_pageable_external_count++;
7800 }
3e170ce0
A
7801 vm_page_inactive_count++;
7802 token_new_pagecount++;
39037602
A
7803
7804#if CONFIG_BACKGROUND_QUEUE
7805 if (mem->vm_page_in_background)
7806 vm_page_add_to_backgroundq(mem, FALSE);
7807#endif
7808}
7809
7810void
7811vm_page_enqueue_active(vm_page_t mem, boolean_t first)
7812{
7813 vm_object_t m_object;
7814
7815 m_object = VM_PAGE_OBJECT(mem);
7816
7817 LCK_MTX_ASSERT(&vm_page_queue_lock, LCK_MTX_ASSERT_OWNED);
7818 assert(!mem->fictitious);
7819 assert(!mem->laundry);
7820 assert(mem->vm_page_q_state == VM_PAGE_NOT_ON_Q);
7821 vm_page_check_pageable_safe(mem);
7822
7823 mem->vm_page_q_state = VM_PAGE_ON_ACTIVE_Q;
7824 if (first == TRUE)
7825 vm_page_queue_enter_first(&vm_page_queue_active, mem, vm_page_t, pageq);
7826 else
7827 vm_page_queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq);
7828 vm_page_active_count++;
7829
7830 if (m_object->internal) {
7831 vm_page_pageable_internal_count++;
7832 } else {
7833 vm_page_pageable_external_count++;
7834 }
7835
7836#if CONFIG_BACKGROUND_QUEUE
7837 if (mem->vm_page_in_background)
7838 vm_page_add_to_backgroundq(mem, FALSE);
7839#endif
3e170ce0
A
7840}
7841
7842/*
7843 * Pages from special kernel objects shouldn't
7844 * be placed on pageable queues.
7845 */
7846void
7847vm_page_check_pageable_safe(vm_page_t page)
7848{
39037602
A
7849 vm_object_t page_object;
7850
7851 page_object = VM_PAGE_OBJECT(page);
7852
7853 if (page_object == kernel_object) {
3e170ce0
A
7854 panic("vm_page_check_pageable_safe: trying to add page" \
7855 "from kernel object (%p) to pageable queue", kernel_object);
7856 }
7857
39037602 7858 if (page_object == compressor_object) {
3e170ce0
A
7859 panic("vm_page_check_pageable_safe: trying to add page" \
7860 "from compressor object (%p) to pageable queue", compressor_object);
7861 }
7862
39037602 7863 if (page_object == vm_submap_object) {
3e170ce0
A
7864 panic("vm_page_check_pageable_safe: trying to add page" \
7865 "from submap object (%p) to pageable queue", vm_submap_object);
7866 }
7867}
7868
7869/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7870 * wired page diagnose
7871 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7872
7873#include <libkern/OSKextLibPrivate.h>
7874
7875vm_allocation_site_t *
7876vm_allocation_sites[VM_KERN_MEMORY_COUNT];
7877
7878vm_tag_t
7879vm_tag_bt(void)
7880{
7881 uintptr_t* frameptr;
7882 uintptr_t* frameptr_next;
7883 uintptr_t retaddr;
7884 uintptr_t kstackb, kstackt;
7885 const vm_allocation_site_t * site;
7886 thread_t cthread;
7887
7888 cthread = current_thread();
7889 if (__improbable(cthread == NULL)) return VM_KERN_MEMORY_OSFMK;
7890
7891 kstackb = cthread->kernel_stack;
7892 kstackt = kstackb + kernel_stack_size;
7893
7894 /* Load stack frame pointer (EBP on x86) into frameptr */
7895 frameptr = __builtin_frame_address(0);
7896 site = NULL;
7897 while (frameptr != NULL)
7898 {
7899 /* Verify thread stack bounds */
7900 if (((uintptr_t)(frameptr + 2) > kstackt) || ((uintptr_t)frameptr < kstackb)) break;
7901
7902 /* Next frame pointer is pointed to by the previous one */
7903 frameptr_next = (uintptr_t*) *frameptr;
7904
7905 /* Pull return address from one spot above the frame pointer */
7906 retaddr = *(frameptr + 1);
7907
7908 if ((retaddr < vm_kernel_stext) || (retaddr > vm_kernel_top))
7909 {
7910 site = OSKextGetAllocationSiteForCaller(retaddr);
7911 break;
7912 }
7913
7914 frameptr = frameptr_next;
7915 }
7916 return (site ? site->tag : VM_KERN_MEMORY_NONE);
7917}
7918
7919static uint64_t free_tag_bits[256/64];
7920
7921void
7922vm_tag_alloc_locked(vm_allocation_site_t * site)
7923{
7924 vm_tag_t tag;
7925 uint64_t avail;
7926 uint64_t idx;
7927
7928 if (site->tag) return;
7929
7930 idx = 0;
7931 while (TRUE)
7932 {
7933 avail = free_tag_bits[idx];
7934 if (avail)
7935 {
7936 tag = __builtin_clzll(avail);
7937 avail &= ~(1ULL << (63 - tag));
7938 free_tag_bits[idx] = avail;
7939 tag += (idx << 6);
7940 break;
7941 }
7942 idx++;
7943 if (idx >= (sizeof(free_tag_bits) / sizeof(free_tag_bits[0])))
7944 {
7945 tag = VM_KERN_MEMORY_ANY;
7946 break;
7947 }
7948 }
7949 site->tag = tag;
7950 if (VM_KERN_MEMORY_ANY != tag)
7951 {
7952 assert(!vm_allocation_sites[tag]);
7953 vm_allocation_sites[tag] = site;
7954 }
7955}
7956
7957static void
7958vm_tag_free_locked(vm_tag_t tag)
7959{
7960 uint64_t avail;
7961 uint32_t idx;
7962 uint64_t bit;
7963
7964 if (VM_KERN_MEMORY_ANY == tag) return;
7965
7966 idx = (tag >> 6);
7967 avail = free_tag_bits[idx];
7968 tag &= 63;
7969 bit = (1ULL << (63 - tag));
7970 assert(!(avail & bit));
7971 free_tag_bits[idx] = (avail | bit);
7972}
7973
7974static void
7975vm_tag_init(void)
7976{
7977 vm_tag_t tag;
7978 for (tag = VM_KERN_MEMORY_FIRST_DYNAMIC; tag < VM_KERN_MEMORY_ANY; tag++)
7979 {
7980 vm_tag_free_locked(tag);
7981 }
7982}
7983
7984vm_tag_t
7985vm_tag_alloc(vm_allocation_site_t * site)
7986{
7987 vm_tag_t tag;
7988
7989 if (VM_TAG_BT & site->flags)
7990 {
7991 tag = vm_tag_bt();
7992 if (VM_KERN_MEMORY_NONE != tag) return (tag);
7993 }
7994
7995 if (!site->tag)
7996 {
7997 lck_spin_lock(&vm_allocation_sites_lock);
7998 vm_tag_alloc_locked(site);
7999 lck_spin_unlock(&vm_allocation_sites_lock);
8000 }
8001
8002 return (site->tag);
8003}
8004
8005static void
8006vm_page_count_object(mach_memory_info_t * sites, unsigned int __unused num_sites, vm_object_t object)
8007{
8008 if (!object->wired_page_count) return;
8009 if (object != kernel_object)
8010 {
8011 assert(object->wire_tag < num_sites);
8012 sites[object->wire_tag].size += ptoa_64(object->wired_page_count);
8013 }
8014}
8015
8016typedef void (*vm_page_iterate_proc)(mach_memory_info_t * sites,
8017 unsigned int num_sites, vm_object_t object);
8018
8019static void
8020vm_page_iterate_purgeable_objects(mach_memory_info_t * sites, unsigned int num_sites,
8021 vm_page_iterate_proc proc, purgeable_q_t queue,
8022 int group)
8023{
8024 vm_object_t object;
8025
8026 for (object = (vm_object_t) queue_first(&queue->objq[group]);
8027 !queue_end(&queue->objq[group], (queue_entry_t) object);
8028 object = (vm_object_t) queue_next(&object->objq))
8029 {
8030 proc(sites, num_sites, object);
8031 }
8032}
8033
8034static void
8035vm_page_iterate_objects(mach_memory_info_t * sites, unsigned int num_sites,
8036 vm_page_iterate_proc proc)
8037{
8038 purgeable_q_t volatile_q;
8039 queue_head_t * nonvolatile_q;
8040 vm_object_t object;
8041 int group;
8042
8043 lck_spin_lock(&vm_objects_wired_lock);
8044 queue_iterate(&vm_objects_wired,
8045 object,
8046 vm_object_t,
8047 objq)
8048 {
8049 proc(sites, num_sites, object);
8050 }
8051 lck_spin_unlock(&vm_objects_wired_lock);
8052
8053 lck_mtx_lock(&vm_purgeable_queue_lock);
8054 nonvolatile_q = &purgeable_nonvolatile_queue;
8055 for (object = (vm_object_t) queue_first(nonvolatile_q);
8056 !queue_end(nonvolatile_q, (queue_entry_t) object);
8057 object = (vm_object_t) queue_next(&object->objq))
8058 {
8059 proc(sites, num_sites, object);
8060 }
8061
8062 volatile_q = &purgeable_queues[PURGEABLE_Q_TYPE_OBSOLETE];
8063 vm_page_iterate_purgeable_objects(sites, num_sites, proc, volatile_q, 0);
8064
8065 volatile_q = &purgeable_queues[PURGEABLE_Q_TYPE_FIFO];
8066 for (group = 0; group < NUM_VOLATILE_GROUPS; group++)
8067 {
8068 vm_page_iterate_purgeable_objects(sites, num_sites, proc, volatile_q, group);
8069 }
8070
8071 volatile_q = &purgeable_queues[PURGEABLE_Q_TYPE_LIFO];
8072 for (group = 0; group < NUM_VOLATILE_GROUPS; group++)
8073 {
8074 vm_page_iterate_purgeable_objects(sites, num_sites, proc, volatile_q, group);
8075 }
8076 lck_mtx_unlock(&vm_purgeable_queue_lock);
8077}
8078
8079static uint64_t
39037602 8080process_account(mach_memory_info_t * sites, unsigned int __unused num_sites, uint64_t zones_collectable_bytes)
3e170ce0
A
8081{
8082 uint64_t found;
8083 unsigned int idx;
8084 vm_allocation_site_t * site;
8085
8086 assert(num_sites >= VM_KERN_MEMORY_COUNT);
8087 found = 0;
8088 for (idx = 0; idx < VM_KERN_MEMORY_COUNT; idx++)
8089 {
8090 found += sites[idx].size;
8091 if (idx < VM_KERN_MEMORY_FIRST_DYNAMIC)
8092 {
8093 sites[idx].site = idx;
8094 sites[idx].flags |= VM_KERN_SITE_TAG;
39037602
A
8095 if (VM_KERN_MEMORY_ZONE == idx)
8096 {
8097 sites[idx].flags |= VM_KERN_SITE_HIDE;
8098 sites[idx].collectable_bytes = zones_collectable_bytes;
8099 } else sites[idx].flags |= VM_KERN_SITE_WIRED;
8100 continue;
3e170ce0
A
8101 }
8102 lck_spin_lock(&vm_allocation_sites_lock);
8103 if ((site = vm_allocation_sites[idx]))
8104 {
8105 if (sites[idx].size)
8106 {
8107 sites[idx].flags |= VM_KERN_SITE_WIRED;
8108 if (VM_TAG_KMOD == (VM_KERN_SITE_TYPE & site->flags))
8109 {
39037602 8110 sites[idx].site = OSKextGetKmodIDForSite(site, NULL, 0);
3e170ce0
A
8111 sites[idx].flags |= VM_KERN_SITE_KMOD;
8112 }
8113 else
8114 {
8115 sites[idx].site = VM_KERNEL_UNSLIDE(site);
8116 sites[idx].flags |= VM_KERN_SITE_KERNEL;
8117 }
8118 site = NULL;
8119 }
8120 else
8121 {
490019cf
A
8122#if 1
8123 site = NULL;
8124#else
8125 /* this code would free a site with no allocations but can race a new
8126 * allocation being made */
3e170ce0
A
8127 vm_tag_free_locked(site->tag);
8128 site->tag = VM_KERN_MEMORY_NONE;
8129 vm_allocation_sites[idx] = NULL;
8130 if (!(VM_TAG_UNLOAD & site->flags)) site = NULL;
490019cf 8131#endif
3e170ce0
A
8132 }
8133 }
8134 lck_spin_unlock(&vm_allocation_sites_lock);
8135 if (site) OSKextFreeSite(site);
8136 }
39037602 8137
3e170ce0
A
8138 return (found);
8139}
8140
8141kern_return_t
39037602 8142vm_page_diagnose(mach_memory_info_t * sites, unsigned int num_sites, uint64_t zones_collectable_bytes)
3e170ce0
A
8143{
8144 enum { kMaxKernelDepth = 1 };
8145 vm_map_t maps [kMaxKernelDepth];
8146 vm_map_entry_t entries[kMaxKernelDepth];
8147 vm_map_t map;
8148 vm_map_entry_t entry;
8149 vm_object_offset_t offset;
8150 vm_page_t page;
8151 int stackIdx, count;
8152 uint64_t wired_size;
8153 uint64_t wired_managed_size;
8154 uint64_t wired_reserved_size;
8155 mach_memory_info_t * counts;
8156
8157 bzero(sites, num_sites * sizeof(mach_memory_info_t));
8158
39037602
A
8159 if (!vm_page_wire_count_initial) return (KERN_ABORTED);
8160
3e170ce0
A
8161 vm_page_iterate_objects(sites, num_sites, &vm_page_count_object);
8162
8163 wired_size = ptoa_64(vm_page_wire_count + vm_lopage_free_count + vm_page_throttled_count);
8164 wired_reserved_size = ptoa_64(vm_page_wire_count_initial - vm_page_stolen_count + vm_page_throttled_count);
8165 wired_managed_size = ptoa_64(vm_page_wire_count - vm_page_wire_count_initial);
8166
8167 assert(num_sites >= (VM_KERN_MEMORY_COUNT + VM_KERN_COUNTER_COUNT));
8168 counts = &sites[VM_KERN_MEMORY_COUNT];
8169
8170#define SET_COUNT(xcount, xsize, xflags) \
8171 counts[xcount].site = (xcount); \
8172 counts[xcount].size = (xsize); \
8173 counts[xcount].flags = VM_KERN_SITE_COUNTER | xflags;
8174
8175 SET_COUNT(VM_KERN_COUNT_MANAGED, ptoa_64(vm_page_pages), 0);
8176 SET_COUNT(VM_KERN_COUNT_WIRED, wired_size, 0);
8177 SET_COUNT(VM_KERN_COUNT_WIRED_MANAGED, wired_managed_size, 0);
8178 SET_COUNT(VM_KERN_COUNT_RESERVED, wired_reserved_size, VM_KERN_SITE_WIRED);
8179 SET_COUNT(VM_KERN_COUNT_STOLEN, ptoa_64(vm_page_stolen_count), VM_KERN_SITE_WIRED);
8180 SET_COUNT(VM_KERN_COUNT_LOPAGE, ptoa_64(vm_lopage_free_count), VM_KERN_SITE_WIRED);
8181
8182#define SET_MAP(xcount, xsize, xfree, xlargest) \
8183 counts[xcount].site = (xcount); \
8184 counts[xcount].size = (xsize); \
8185 counts[xcount].free = (xfree); \
8186 counts[xcount].largest = (xlargest); \
8187 counts[xcount].flags = VM_KERN_SITE_COUNTER;
8188
8189 vm_map_size_t map_size, map_free, map_largest;
8190
8191 vm_map_sizes(kernel_map, &map_size, &map_free, &map_largest);
8192 SET_MAP(VM_KERN_COUNT_MAP_KERNEL, map_size, map_free, map_largest);
8193
8194 vm_map_sizes(zone_map, &map_size, &map_free, &map_largest);
8195 SET_MAP(VM_KERN_COUNT_MAP_ZONE, map_size, map_free, map_largest);
8196
8197 vm_map_sizes(kalloc_map, &map_size, &map_free, &map_largest);
8198 SET_MAP(VM_KERN_COUNT_MAP_KALLOC, map_size, map_free, map_largest);
8199
8200 map = kernel_map;
8201 stackIdx = 0;
8202 while (map)
8203 {
8204 vm_map_lock(map);
8205 for (entry = map->hdr.links.next; map; entry = entry->links.next)
8206 {
8207 if (entry->is_sub_map)
8208 {
8209 assert(stackIdx < kMaxKernelDepth);
8210 maps[stackIdx] = map;
8211 entries[stackIdx] = entry;
8212 stackIdx++;
8213 map = VME_SUBMAP(entry);
8214 entry = NULL;
8215 break;
8216 }
8217 if (VME_OBJECT(entry) == kernel_object)
8218 {
8219 count = 0;
8220 vm_object_lock(VME_OBJECT(entry));
8221 for (offset = entry->links.start; offset < entry->links.end; offset += page_size)
8222 {
8223 page = vm_page_lookup(VME_OBJECT(entry), offset);
8224 if (page && VM_PAGE_WIRED(page)) count++;
8225 }
8226 vm_object_unlock(VME_OBJECT(entry));
8227
8228 if (count)
8229 {
8230 assert(VME_ALIAS(entry) < num_sites);
8231 sites[VME_ALIAS(entry)].size += ptoa_64(count);
8232 }
8233 }
39037602 8234 while (map && (entry == vm_map_last_entry(map)))
3e170ce0
A
8235 {
8236 vm_map_unlock(map);
8237 if (!stackIdx) map = NULL;
8238 else
8239 {
8240 --stackIdx;
8241 map = maps[stackIdx];
8242 entry = entries[stackIdx];
8243 }
8244 }
8245 }
8246 }
8247
39037602 8248 process_account(sites, num_sites, zones_collectable_bytes);
3e170ce0
A
8249
8250 return (KERN_SUCCESS);
8251}
39037602
A
8252
8253uint32_t
8254vm_tag_get_kext(vm_tag_t tag, char * name, vm_size_t namelen)
8255{
8256 vm_allocation_site_t * site;
8257 uint32_t kmodId;
8258
8259 kmodId = 0;
8260 lck_spin_lock(&vm_allocation_sites_lock);
8261 if ((site = vm_allocation_sites[tag]))
8262 {
8263 if (VM_TAG_KMOD == (VM_KERN_SITE_TYPE & site->flags))
8264 {
8265 kmodId = OSKextGetKmodIDForSite(site, name, namelen);
8266 }
8267 }
8268 lck_spin_unlock(&vm_allocation_sites_lock);
8269
8270 return (kmodId);
8271}
8272
8273#if DEBUG || DEVELOPMENT
8274
8275#define vm_tag_set_lock(set) lck_spin_lock(&set->lock)
8276#define vm_tag_set_unlock(set) lck_spin_unlock(&set->lock)
8277
8278void
8279vm_tag_set_init(vm_tag_set_t set, uint32_t count)
8280{
8281 lck_spin_init(&set->lock, &vm_page_lck_grp_bucket, &vm_page_lck_attr);
8282 bzero(&set->entries, count * sizeof(struct vm_tag_set_entry));
8283}
8284
8285kern_return_t
8286vm_tag_set_enter(vm_tag_set_t set, uint32_t count, vm_tag_t tag)
8287{
8288 kern_return_t kr;
8289 uint32_t idx, free;
8290
8291 vm_tag_set_lock(set);
8292
8293 assert(tag != VM_KERN_MEMORY_NONE);
8294
8295 kr = KERN_NO_SPACE;
8296 free = -1U;
8297 for (idx = 0; idx < count; idx++)
8298 {
8299 if (tag == set->entries[idx].tag)
8300 {
8301 set->entries[idx].count++;
8302 kr = KERN_SUCCESS;
8303 break;
8304 }
8305 if ((free == -1U) && !set->entries[idx].count) free = idx;
8306 }
8307
8308 if ((KERN_SUCCESS != kr) && (free != -1U))
8309 {
8310 set->entries[free].tag = tag;
8311 set->entries[free].count = 1;
8312 kr = KERN_SUCCESS;
8313 }
8314
8315 vm_tag_set_unlock(set);
8316
8317 return (kr);
8318}
8319
8320kern_return_t
8321vm_tag_set_remove(vm_tag_set_t set, uint32_t count, vm_tag_t tag, vm_tag_t * new_tagp)
8322{
8323 kern_return_t kr;
8324 uint32_t idx;
8325 vm_tag_t new_tag;
8326
8327 assert(tag != VM_KERN_MEMORY_NONE);
8328 new_tag = VM_KERN_MEMORY_NONE;
8329 vm_tag_set_lock(set);
8330
8331 kr = KERN_NOT_IN_SET;
8332 for (idx = 0; idx < count; idx++)
8333 {
8334 if ((tag != VM_KERN_MEMORY_NONE)
8335 && (tag == set->entries[idx].tag)
8336 && set->entries[idx].count)
8337 {
8338 set->entries[idx].count--;
8339 kr = KERN_SUCCESS;
8340 if (set->entries[idx].count)
8341 {
8342 new_tag = tag;
8343 break;
8344 }
8345 if (!new_tagp) break;
8346 tag = VM_KERN_MEMORY_NONE;
8347 }
8348
8349 if (set->entries[idx].count && (VM_KERN_MEMORY_NONE == new_tag))
8350 {
8351 new_tag = set->entries[idx].tag;
8352 if (VM_KERN_MEMORY_NONE == tag) break;
8353 }
8354 }
8355
8356 vm_tag_set_unlock(set);
8357 if (new_tagp) *new_tagp = new_tag;
8358
8359 return (kr);
8360}
8361
8362#endif /* DEBUG || DEVELOPMENT */