|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52: /*
53: * File: vm/vm_page.c
54: * Author: Avadis Tevanian, Jr., Michael Wayne Young
55: *
56: * Resident memory management module.
57: */
58:
59: #include <mach/vm_prot.h>
60: #include <mach/vm_statistics.h>
61: #include <kern/counters.h>
62: #include <kern/sched_prim.h>
63: #include <kern/task.h>
64: #include <kern/thread.h>
65: #include <kern/zalloc.h>
66: #include <kern/xpr.h>
67: #include <vm/pmap.h>
68: #include <vm/vm_init.h>
69: #include <vm/vm_map.h>
70: #include <vm/vm_page.h>
71: #include <vm/vm_pageout.h>
72: #include <vm/vm_kern.h> /* kernel_memory_allocate() */
73: #include <kern/misc_protos.h>
74: #include <zone_debug.h>
75: #include <vm/cpm.h>
76:
77: /*
78: * Associated with page of user-allocatable memory is a
79: * page structure.
80: */
81:
82: /*
83: * These variables record the values returned by vm_page_bootstrap,
84: * for debugging purposes. The implementation of pmap_steal_memory
85: * and pmap_startup here also uses them internally.
86: */
87:
88: vm_offset_t virtual_space_start;
89: vm_offset_t virtual_space_end;
90: int vm_page_pages;
91:
92: /*
93: * The vm_page_lookup() routine, which provides for fast
94: * (virtual memory object, offset) to page lookup, employs
95: * the following hash table. The vm_page_{insert,remove}
96: * routines install and remove associations in the table.
97: * [This table is often called the virtual-to-physical,
98: * or VP, table.]
99: */
100: typedef struct {
101: vm_page_t pages;
102: #if MACH_PAGE_HASH_STATS
103: int cur_count; /* current count */
104: int hi_count; /* high water mark */
105: #endif /* MACH_PAGE_HASH_STATS */
106: } vm_page_bucket_t;
107:
108: vm_page_bucket_t *vm_page_buckets; /* Array of buckets */
109: unsigned int vm_page_bucket_count = 0; /* How big is array? */
110: unsigned int vm_page_hash_mask; /* Mask for hash function */
111: unsigned int vm_page_hash_shift; /* Shift for hash function */
112: decl_simple_lock_data(,vm_page_bucket_lock)
113:
114: #if MACH_PAGE_HASH_STATS
115: /* This routine is only for debug. It is intended to be called by
116: * hand by a developer using a kernel debugger. This routine prints
117: * out vm_page_hash table statistics to the kernel debug console.
118: */
119: void
120: hash_debug(void)
121: {
122: int i;
123: int numbuckets = 0;
124: int highsum = 0;
125: int maxdepth = 0;
126:
127: for (i = 0; i < vm_page_bucket_count; i++) {
128: if (vm_page_buckets[i].hi_count) {
129: numbuckets++;
130: highsum += vm_page_buckets[i].hi_count;
131: if (vm_page_buckets[i].hi_count > maxdepth)
132: maxdepth = vm_page_buckets[i].hi_count;
133: }
134: }
135: printf("Total number of buckets: %d\n", vm_page_bucket_count);
136: printf("Number used buckets: %d = %d%%\n",
137: numbuckets, 100*numbuckets/vm_page_bucket_count);
138: printf("Number unused buckets: %d = %d%%\n",
139: vm_page_bucket_count - numbuckets,
140: 100*(vm_page_bucket_count-numbuckets)/vm_page_bucket_count);
141: printf("Sum of bucket max depth: %d\n", highsum);
142: printf("Average bucket depth: %d.%2d\n",
143: highsum/vm_page_bucket_count,
144: highsum%vm_page_bucket_count);
145: printf("Maximum bucket depth: %d\n", maxdepth);
146: }
147: #endif /* MACH_PAGE_HASH_STATS */
148:
149: /*
150: * The virtual page size is currently implemented as a runtime
151: * variable, but is constant once initialized using vm_set_page_size.
152: * This initialization must be done in the machine-dependent
153: * bootstrap sequence, before calling other machine-independent
154: * initializations.
155: *
156: * All references to the virtual page size outside this
157: * module must use the PAGE_SIZE, PAGE_MASK and PAGE_SHIFT
158: * constants.
159: */
160: #ifndef PAGE_SIZE_FIXED
161: vm_size_t page_size = 4096;
162: vm_size_t page_mask = 4095;
163: int page_shift = 12;
164: #endif /* PAGE_SIZE_FIXED */
165:
166: /*
167: * Resident page structures are initialized from
168: * a template (see vm_page_alloc).
169: *
170: * When adding a new field to the virtual memory
171: * object structure, be sure to add initialization
172: * (see vm_page_bootstrap).
173: */
174: struct vm_page vm_page_template;
175:
176: /*
177: * Resident pages that represent real memory
178: * are allocated from a free list.
179: */
180: vm_page_t vm_page_queue_free;
181: vm_page_t vm_page_queue_fictitious;
182: decl_mutex_data(,vm_page_queue_free_lock)
183: unsigned int vm_page_free_wanted;
184: int vm_page_free_count;
185: int vm_page_fictitious_count;
186:
187: unsigned int vm_page_free_count_minimum; /* debugging */
188:
189: /*
190: * Occasionally, the virtual memory system uses
191: * resident page structures that do not refer to
192: * real pages, for example to leave a page with
193: * important state information in the VP table.
194: *
195: * These page structures are allocated the way
196: * most other kernel structures are.
197: */
198: zone_t vm_page_zone;
199: decl_mutex_data(,vm_page_alloc_lock)
200:
201: /*
202: * Fictitious pages don't have a physical address,
203: * but we must initialize phys_addr to something.
204: * For debugging, this should be a strange value
205: * that the pmap module can recognize in assertions.
206: */
207: vm_offset_t vm_page_fictitious_addr = (vm_offset_t) -1;
208:
209: /*
210: * Resident page structures are also chained on
211: * queues that are used by the page replacement
212: * system (pageout daemon). These queues are
213: * defined here, but are shared by the pageout
214: * module.
215: */
216: queue_head_t vm_page_queue_active;
217: queue_head_t vm_page_queue_inactive;
218: decl_mutex_data(,vm_page_queue_lock)
219: int vm_page_active_count;
220: int vm_page_inactive_count;
221: int vm_page_wire_count;
222: int vm_page_gobble_count = 0;
223: int vm_page_wire_count_warning = 0;
224: int vm_page_gobble_count_warning = 0;
225:
226: /* the following fields are protected by the vm_page_queue_lock */
227: queue_head_t vm_page_queue_limbo;
228: int vm_page_limbo_count = 0; /* total pages in limbo */
229: int vm_page_limbo_real_count = 0; /* real pages in limbo */
230: int vm_page_pin_count = 0; /* number of pinned pages */
231:
232: decl_simple_lock_data(,vm_page_preppin_lock)
233:
234: /*
235: * Several page replacement parameters are also
236: * shared with this module, so that page allocation
237: * (done here in vm_page_alloc) can trigger the
238: * pageout daemon.
239: */
240: int vm_page_free_target = 0;
241: int vm_page_free_min = 0;
242: int vm_page_inactive_target = 0;
243: int vm_page_free_reserved = 0;
244: int vm_page_laundry_count = 0;
245:
246: /*
247: * The VM system has a couple of heuristics for deciding
248: * that pages are "uninteresting" and should be placed
249: * on the inactive queue as likely candidates for replacement.
250: * These variables let the heuristics be controlled at run-time
251: * to make experimentation easier.
252: */
253:
254: boolean_t vm_page_deactivate_hint = TRUE;
255:
256: /*
257: * Definition for automatic physical memory reservation. Declared in
258: * vm_page.h, defined here. See vm_page.h for details. There's an
259: * extra zero entry to allow the code to compile if there are no requests
260: * for physical memory allocation; pmem_reserve_ctl_size is decremented
261: * by one to compensate.
262: */
263: #include <flipc.h>
264: #if FLIPC
265: #include <flipc/flipc_usermsg.h>
266: #endif
267:
268: struct pmem_reserve pmem_reserve_ctl_array[] = {
269: #if FLIPC
270: { &flipc_cb_length, (vm_offset_t *) &flipc_cb_base },
271: #endif
272: { 0, (vm_offset_t *) 0 }
273: };
274:
275: struct pmem_reserve *pmem_reserve_ctl = &pmem_reserve_ctl_array[0];
276:
277: int pmem_reserve_ctl_size =
278: (sizeof(pmem_reserve_ctl_array) / sizeof(struct pmem_reserve)) - 1;
279:
280: /*
281: * vm_set_page_size:
282: *
283: * Sets the page size, perhaps based upon the memory
284: * size. Must be called before any use of page-size
285: * dependent functions.
286: *
287: * Sets page_shift and page_mask from page_size.
288: */
289: void
290: vm_set_page_size(void)
291: {
292: #ifndef PAGE_SIZE_FIXED
293: page_mask = page_size - 1;
294:
295: if ((page_mask & page_size) != 0)
296: panic("vm_set_page_size: page size not a power of two");
297:
298: for (page_shift = 0; ; page_shift++)
299: if ((1 << page_shift) == page_size)
300: break;
301: #endif /* PAGE_SIZE_FIXED */
302: }
303:
304: /*
305: * vm_page_bootstrap:
306: *
307: * Initializes the resident memory module.
308: *
309: * Allocates memory for the page cells, and
310: * for the object/offset-to-page hash table headers.
311: * Each page cell is initialized and placed on the free list.
312: * Returns the range of available kernel virtual memory.
313: */
314:
315: void
316: vm_page_bootstrap(
317: vm_offset_t *startp,
318: vm_offset_t *endp)
319: {
320: register vm_page_t m;
321: int i;
322: unsigned int log1;
323: unsigned int log2;
324: unsigned int size;
325:
326: /*
327: * Initialize the vm_page template.
328: */
329:
330: m = &vm_page_template;
331: m->object = VM_OBJECT_NULL; /* reset later */
332: m->offset = 0; /* reset later */
333: m->wire_count = 0;
334:
335: m->inactive = FALSE;
336: m->active = FALSE;
337: m->laundry = FALSE;
338: m->free = FALSE;
339: m->reference = FALSE;
340: m->pageout = FALSE;
341: m->list_req_pending = FALSE;
342:
343: m->busy = TRUE;
344: m->wanted = FALSE;
345: m->tabled = FALSE;
346: m->fictitious = FALSE;
347: m->private = FALSE;
348: m->absent = FALSE;
349: m->error = FALSE;
350: m->dirty = FALSE;
351: m->cleaning = FALSE;
352: m->precious = FALSE;
353: m->clustered = FALSE;
354: m->lock_supplied = FALSE;
355: m->unusual = FALSE;
356: m->restart = FALSE;
357: m->limbo = FALSE;
358:
359: m->phys_addr = 0; /* reset later */
360:
361: m->page_lock = VM_PROT_NONE;
362: m->unlock_request = VM_PROT_NONE;
363: m->page_error = KERN_SUCCESS;
364:
365: /*
366: * Initialize the page queues.
367: */
368:
369: mutex_init(&vm_page_queue_free_lock, ETAP_VM_PAGEQ_FREE);
370: mutex_init(&vm_page_queue_lock, ETAP_VM_PAGEQ);
371: simple_lock_init(&vm_page_preppin_lock, ETAP_VM_PREPPIN);
372:
373: vm_page_queue_free = VM_PAGE_NULL;
374: vm_page_queue_fictitious = VM_PAGE_NULL;
375: queue_init(&vm_page_queue_active);
376: queue_init(&vm_page_queue_inactive);
377: queue_init(&vm_page_queue_limbo);
378:
379: vm_page_free_wanted = 0;
380:
381: /*
382: * Steal memory for the map and zone subsystems.
383: */
384:
385: vm_map_steal_memory();
386: zone_steal_memory();
387:
388: /*
389: * Allocate (and initialize) the virtual-to-physical
390: * table hash buckets.
391: *
392: * The number of buckets should be a power of two to
393: * get a good hash function. The following computation
394: * chooses the first power of two that is greater
395: * than the number of physical pages in the system.
396: */
397:
398: simple_lock_init(&vm_page_bucket_lock, ETAP_VM_BUCKET);
399:
400: if (vm_page_bucket_count == 0) {
401: unsigned int npages = pmap_free_pages();
402:
403: vm_page_bucket_count = 1;
404: while (vm_page_bucket_count < npages)
405: vm_page_bucket_count <<= 1;
406: }
407:
408: vm_page_hash_mask = vm_page_bucket_count - 1;
409:
410: /*
411: * Calculate object shift value for hashing algorithm:
412: * O = log2(sizeof(struct vm_object))
413: * B = log2(vm_page_bucket_count)
414: * hash shifts the object left by
415: * B/2 - O
416: */
417: size = vm_page_bucket_count;
418: for (log1 = 0; size > 1; log1++)
419: size /= 2;
420: size = sizeof(struct vm_object);
421: for (log2 = 0; size > 1; log2++)
422: size /= 2;
423: vm_page_hash_shift = log1/2 - log2 + 1;
424:
425: if (vm_page_hash_mask & vm_page_bucket_count)
426: printf("vm_page_bootstrap: WARNING -- strange page hash\n");
427:
428: vm_page_buckets = (vm_page_bucket_t *)
429: pmap_steal_memory(vm_page_bucket_count *
430: sizeof(vm_page_bucket_t));
431:
432: for (i = 0; i < vm_page_bucket_count; i++) {
433: register vm_page_bucket_t *bucket = &vm_page_buckets[i];
434:
435: bucket->pages = VM_PAGE_NULL;
436: #if MACH_PAGE_HASH_STATS
437: bucket->cur_count = 0;
438: bucket->hi_count = 0;
439: #endif /* MACH_PAGE_HASH_STATS */
440: }
441:
442: /*
443: * Machine-dependent code allocates the resident page table.
444: * It uses vm_page_init to initialize the page frames.
445: * The code also returns to us the virtual space available
446: * to the kernel. We don't trust the pmap module
447: * to get the alignment right.
448: */
449:
450: pmap_startup(&virtual_space_start, &virtual_space_end);
451: virtual_space_start = round_page(virtual_space_start);
452: virtual_space_end = trunc_page(virtual_space_end);
453:
454: *startp = virtual_space_start;
455: *endp = virtual_space_end;
456:
457: /*
458: * Compute the initial "wire" count.
459: * Up until now, the pages which have been set aside are not under
460: * the VM system's control, so although they aren't explicitly
461: * wired, they nonetheless can't be moved. At this moment,
462: * all VM managed pages are "free", courtesy of pmap_startup.
463: */
464: vm_page_wire_count = atop(mem_size) - vm_page_free_count; /* initial value */
465:
466: printf("vm_page_bootstrap: %d free pages\n", vm_page_free_count);
467: vm_page_free_count_minimum = vm_page_free_count;
468: }
469:
470: #ifndef MACHINE_PAGES
471: /*
472: * We implement pmap_steal_memory and pmap_startup with the help
473: * of two simpler functions, pmap_virtual_space and pmap_next_page.
474: */
475:
476: vm_offset_t
477: pmap_steal_memory(
478: vm_size_t size)
479: {
480: vm_offset_t addr, vaddr, paddr;
481:
482: /*
483: * We round the size to a round multiple.
484: */
485:
486: size = (size + sizeof (void *) - 1) &~ (sizeof (void *) - 1);
487:
488: /*
489: * If this is the first call to pmap_steal_memory,
490: * we have to initialize ourself.
491: */
492:
493: if (virtual_space_start == virtual_space_end) {
494: pmap_virtual_space(&virtual_space_start, &virtual_space_end);
495:
496: /*
497: * The initial values must be aligned properly, and
498: * we don't trust the pmap module to do it right.
499: */
500:
501: virtual_space_start = round_page(virtual_space_start);
502: virtual_space_end = trunc_page(virtual_space_end);
503: }
504:
505: /*
506: * Allocate virtual memory for this request.
507: */
508:
509: addr = virtual_space_start;
510: virtual_space_start += size;
511:
512: kprintf("pmap_steal_memory: %08X - %08X; size=%08X\n", addr, virtual_space_start, size); /* (TEST/DEBUG) */
513:
514: /*
515: * Allocate and map physical pages to back new virtual pages.
516: */
517:
518: for (vaddr = round_page(addr);
519: vaddr < addr + size;
520: vaddr += PAGE_SIZE) {
521: if (!pmap_next_page(&paddr))
522: panic("pmap_steal_memory");
523:
524: /*
525: * XXX Logically, these mappings should be wired,
526: * but some pmap modules barf if they are.
527: */
528:
529: pmap_enter(kernel_pmap, vaddr, paddr,
530: VM_PROT_READ|VM_PROT_WRITE, FALSE);
531: /*
532: * Account for newly stolen memory
533: */
534: vm_page_wire_count++;
535:
536: }
537:
538: return addr;
539: }
540:
541: void
542: pmap_startup(
543: vm_offset_t *startp,
544: vm_offset_t *endp)
545: {
546: unsigned int i, npages, pages_initialized;
547: vm_page_t pages;
548: vm_offset_t paddr;
549:
550: /*
551: * We calculate how many page frames we will have
552: * and then allocate the page structures in one chunk.
553: */
554:
555: npages = ((PAGE_SIZE * pmap_free_pages() +
556: (round_page(virtual_space_start) - virtual_space_start)) /
557: (PAGE_SIZE + sizeof *pages));
558:
559: pages = (vm_page_t) pmap_steal_memory(npages * sizeof *pages);
560:
561: /*
562: * Initialize the page frames.
563: */
564:
565: for (i = 0, pages_initialized = 0; i < npages; i++) {
566: if (!pmap_next_page(&paddr))
567: break;
568:
569: vm_page_init(&pages[i], paddr);
570: vm_page_pages++;
571: pages_initialized++;
572: }
573:
574: /*
575: * Release pages in reverse order so that physical pages
576: * initially get allocated in ascending addresses. This keeps
577: * the devices (which must address physical memory) happy if
578: * they require several consecutive pages.
579: */
580:
581: for (i = pages_initialized; i > 0; i--) {
582: vm_page_release(&pages[i - 1]);
583: }
584:
585: /*
586: * We have to re-align virtual_space_start,
587: * because pmap_steal_memory has been using it.
588: */
589:
590: virtual_space_start = round_page(virtual_space_start);
591:
592: *startp = virtual_space_start;
593: *endp = virtual_space_end;
594: }
595: #endif /* MACHINE_PAGES */
596:
597: /*
598: * Routine: vm_page_module_init
599: * Purpose:
600: * Second initialization pass, to be done after
601: * the basic VM system is ready.
602: */
603: void
604: vm_page_module_init(void)
605: {
606: vm_page_zone = zinit((vm_size_t) sizeof(struct vm_page),
607: 0, PAGE_SIZE, "vm pages");
608:
609: #if ZONE_DEBUG
610: zone_debug_disable(vm_page_zone);
611: #endif /* ZONE_DEBUG */
612:
613: zone_change(vm_page_zone, Z_EXPAND, FALSE);
614: zone_change(vm_page_zone, Z_EXHAUST, TRUE);
615: zone_change(vm_page_zone, Z_FOREIGN, TRUE);
616:
617: /*
618: * Adjust zone statistics to account for the real pages allocated
619: * in vm_page_create(). [Q: is this really what we want?]
620: */
621: vm_page_zone->count += vm_page_pages;
622: vm_page_zone->cur_size += vm_page_pages * vm_page_zone->elem_size;
623:
624: mutex_init(&vm_page_alloc_lock, ETAP_VM_PAGE_ALLOC);
625: }
626:
627: /*
628: * Routine: vm_page_create
629: * Purpose:
630: * After the VM system is up, machine-dependent code
631: * may stumble across more physical memory. For example,
632: * memory that it was reserving for a frame buffer.
633: * vm_page_create turns this memory into available pages.
634: */
635:
636: void
637: vm_page_create(
638: vm_offset_t start,
639: vm_offset_t end)
640: {
641: vm_offset_t paddr;
642: vm_page_t m;
643:
644: for (paddr = round_page(start);
645: paddr < trunc_page(end);
646: paddr += PAGE_SIZE) {
647: while ((m = (vm_page_t) vm_page_grab_fictitious())
648: == VM_PAGE_NULL)
649: vm_page_more_fictitious();
650:
651: vm_page_init(m, paddr);
652: vm_page_pages++;
653: vm_page_release(m);
654: }
655: }
656:
657: /*
658: * vm_page_hash:
659: *
660: * Distributes the object/offset key pair among hash buckets.
661: *
662: * NOTE: To get a good hash function, the bucket count should
663: * be a power of two.
664: */
665: #define vm_page_hash(object, offset) (\
666: ( ((natural_t)(vm_offset_t)object<<vm_page_hash_shift) + (natural_t)atop(offset))\
667: & vm_page_hash_mask)
668:
669: /*
670: * vm_page_insert: [ internal use only ]
671: *
672: * Inserts the given mem entry into the object/object-page
673: * table and object list.
674: *
675: * The object must be locked.
676: */
677:
678: void
679: vm_page_insert(
680: register vm_page_t mem,
681: register vm_object_t object,
682: register vm_offset_t offset)
683: {
684: register vm_page_bucket_t *bucket;
685:
686: XPR(XPR_VM_PAGE,
687: "vm_page_insert, object 0x%X offset 0x%X page 0x%X\n",
688: (integer_t)object, (integer_t)offset, (integer_t)mem, 0,0);
689:
690: VM_PAGE_CHECK(mem);
691:
692: if (mem->tabled)
693: panic("vm_page_insert");
694:
695: assert(!object->internal || offset < object->size);
696:
697: /* only insert "pageout" pages into "pageout" objects,
698: * and normal pages into normal objects */
699: assert(object->pageout == mem->pageout);
700:
701: /*
702: * Record the object/offset pair in this page
703: */
704:
705: mem->object = object;
706: mem->offset = offset;
707:
708: /*
709: * Insert it into the object_object/offset hash table
710: */
711:
712: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
713: simple_lock(&vm_page_bucket_lock);
714: mem->next = bucket->pages;
715: bucket->pages = mem;
716: #if MACH_PAGE_HASH_STATS
717: if (++bucket->cur_count > bucket->hi_count)
718: bucket->hi_count = bucket->cur_count;
719: #endif /* MACH_PAGE_HASH_STATS */
720: simple_unlock(&vm_page_bucket_lock);
721:
722: /*
723: * Now link into the object's list of backed pages.
724: */
725:
726: queue_enter(&object->memq, mem, vm_page_t, listq);
727: mem->tabled = TRUE;
728:
729: /*
730: * Show that the object has one more resident page.
731: */
732:
733: object->resident_page_count++;
734: }
735:
736: /*
737: * vm_page_replace:
738: *
739: * Exactly like vm_page_insert, except that we first
740: * remove any existing page at the given offset in object.
741: *
742: * The object and page queues must be locked.
743: */
744:
745: void
746: vm_page_replace(
747: register vm_page_t mem,
748: register vm_object_t object,
749: register vm_offset_t offset)
750: {
751: register vm_page_bucket_t *bucket;
752:
753: VM_PAGE_CHECK(mem);
754:
755: if (mem->tabled)
756: panic("vm_page_replace");
757:
758: /*
759: * Record the object/offset pair in this page
760: */
761:
762: mem->object = object;
763: mem->offset = offset;
764:
765: /*
766: * Insert it into the object_object/offset hash table,
767: * replacing any page that might have been there.
768: */
769:
770: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
771: simple_lock(&vm_page_bucket_lock);
772: if (bucket->pages) {
773: vm_page_t *mp = &bucket->pages;
774: register vm_page_t m = *mp;
775: do {
776: if (m->object == object && m->offset == offset) {
777: /*
778: * Remove page from bucket and from object,
779: * and return it to the free list.
780: */
781: *mp = m->next;
782: queue_remove(&object->memq, m, vm_page_t,
783: listq);
784: m->tabled = FALSE;
785: object->resident_page_count--;
786:
787: /*
788: * Return page to the free list.
789: * Note the page is not tabled now, so this
790: * won't self-deadlock on the bucket lock.
791: */
792:
793: vm_page_free(m);
794: break;
795: }
796: mp = &m->next;
797: } while (m = *mp);
798: mem->next = bucket->pages;
799: } else {
800: mem->next = VM_PAGE_NULL;
801: }
802: bucket->pages = mem;
803: simple_unlock(&vm_page_bucket_lock);
804:
805: /*
806: * Now link into the object's list of backed pages.
807: */
808:
809: queue_enter(&object->memq, mem, vm_page_t, listq);
810: mem->tabled = TRUE;
811:
812: /*
813: * And show that the object has one more resident
814: * page.
815: */
816:
817: object->resident_page_count++;
818: }
819:
820: /*
821: * vm_page_remove: [ internal use only ]
822: *
823: * Removes the given mem entry from the object/offset-page
824: * table and the object page list.
825: *
826: * The object and page must be locked.
827: */
828:
829: void
830: vm_page_remove(
831: register vm_page_t mem)
832: {
833: register vm_page_bucket_t *bucket;
834: register vm_page_t this;
835:
836: XPR(XPR_VM_PAGE,
837: "vm_page_remove, object 0x%X offset 0x%X page 0x%X\n",
838: (integer_t)mem->object, (integer_t)mem->offset,
839: (integer_t)mem, 0,0);
840:
841: assert(mem->tabled);
842: assert(!mem->cleaning);
843: VM_PAGE_CHECK(mem);
844:
845: /*
846: * Remove from the object_object/offset hash table
847: */
848:
849: bucket = &vm_page_buckets[vm_page_hash(mem->object, mem->offset)];
850: simple_lock(&vm_page_bucket_lock);
851: if ((this = bucket->pages) == mem) {
852: /* optimize for common case */
853:
854: bucket->pages = mem->next;
855: } else {
856: register vm_page_t *prev;
857:
858: for (prev = &this->next;
859: (this = *prev) != mem;
860: prev = &this->next)
861: continue;
862: *prev = this->next;
863: }
864: #if MACH_PAGE_HASH_STATS
865: bucket->cur_count--;
866: #endif /* MACH_PAGE_HASH_STATS */
867: simple_unlock(&vm_page_bucket_lock);
868:
869: /*
870: * Now remove from the object's list of backed pages.
871: */
872:
873: queue_remove(&mem->object->memq, mem, vm_page_t, listq);
874:
875: /*
876: * And show that the object has one fewer resident
877: * page.
878: */
879:
880: mem->object->resident_page_count--;
881:
882: mem->tabled = FALSE;
883: mem->object = VM_OBJECT_NULL;
884: mem->offset = 0;
885: }
886:
887: /*
888: * vm_page_lookup:
889: *
890: * Returns the page associated with the object/offset
891: * pair specified; if none is found, VM_PAGE_NULL is returned.
892: *
893: * The object must be locked. No side effects.
894: */
895:
896: vm_page_t
897: vm_page_lookup(
898: register vm_object_t object,
899: register vm_offset_t offset)
900: {
901: register vm_page_t mem;
902: register vm_page_bucket_t *bucket;
903:
904: /*
905: * Search the hash table for this object/offset pair
906: */
907:
908: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
909:
910: simple_lock(&vm_page_bucket_lock);
911: for (mem = bucket->pages; mem != VM_PAGE_NULL; mem = mem->next) {
912: VM_PAGE_CHECK(mem);
913: if ((mem->object == object) && (mem->offset == offset))
914: break;
915: }
916: simple_unlock(&vm_page_bucket_lock);
917: return(mem);
918: }
919:
920: /*
921: * vm_page_rename:
922: *
923: * Move the given memory entry from its
924: * current object to the specified target object/offset.
925: *
926: * The object must be locked.
927: */
928: void
929: vm_page_rename(
930: register vm_page_t mem,
931: register vm_object_t new_object,
932: vm_offset_t new_offset)
933: {
934: assert(mem->object != new_object);
935: /*
936: * Changes to mem->object require the page lock because
937: * the pageout daemon uses that lock to get the object.
938: */
939:
940: XPR(XPR_VM_PAGE,
941: "vm_page_rename, new object 0x%X, offset 0x%X page 0x%X\n",
942: (integer_t)new_object, (integer_t)new_offset,
943: (integer_t)mem, 0,0);
944:
945: vm_page_lock_queues();
946: vm_page_remove(mem);
947: vm_page_insert(mem, new_object, new_offset);
948: vm_page_unlock_queues();
949: }
950:
951: /*
952: * vm_page_init:
953: *
954: * Initialize the fields in a new page.
955: * This takes a structure with random values and initializes it
956: * so that it can be given to vm_page_release or vm_page_insert.
957: */
958: void
959: vm_page_init(
960: vm_page_t mem,
961: vm_offset_t phys_addr)
962: {
963: *mem = vm_page_template;
964: mem->phys_addr = phys_addr;
965: }
966:
967: /*
968: * vm_page_grab_fictitious:
969: *
970: * Remove a fictitious page from the free list.
971: * Returns VM_PAGE_NULL if there are no free pages.
972: */
973: int c_vm_page_grab_fictitious = 0;
974: int c_vm_page_release_fictitious = 0;
975: int c_vm_page_more_fictitious = 0;
976:
977: vm_page_t
978: vm_page_grab_fictitious(void)
979: {
980: register vm_page_t m;
981:
982: m = (vm_page_t)zget(vm_page_zone);
983: if (m) {
984: m->free = FALSE;
985: #if MACH_ASSERT || ZONE_DEBUG
986: vm_page_init(m, vm_page_fictitious_addr);
987: m->fictitious = TRUE;
988: #endif /* MACH_ASSERT || ZONE_DEBUG */
989: }
990:
991: c_vm_page_grab_fictitious++;
992: return m;
993: }
994:
995: /*
996: * vm_page_release_fictitious:
997: *
998: * Release a fictitious page to the free list.
999: */
1000:
1001: void
1002: vm_page_release_fictitious(
1003: register vm_page_t m)
1004: {
1005: assert(!m->free);
1006: assert(m->busy);
1007: assert(m->fictitious);
1008: assert(m->phys_addr == vm_page_fictitious_addr);
1009:
1010: c_vm_page_release_fictitious++;
1011:
1012: if (m->free)
1013: panic("vm_page_release_fictitious");
1014: m->free = TRUE;
1015: zfree(vm_page_zone, (vm_offset_t)m);
1016: }
1017:
1018: /*
1019: * vm_page_more_fictitious:
1020: *
1021: * Add more fictitious pages to the free list.
1022: * Allowed to block. This routine is way intimate
1023: * with the zones code, for several reasons:
1024: * 1. we need to carve some page structures out of physical
1025: * memory before zones work, so they _cannot_ come from
1026: * the zone_map.
1027: * 2. the zone needs to be collectable in order to prevent
1028: * growth without bound. These structures are used by
1029: * the device pager (by the hundreds and thousands), as
1030: * private pages for pageout, and as blocking pages for
1031: * pagein. Temporary bursts in demand should not result in
1032: * permanent allocation of a resource.
1033: * 3. To smooth allocation humps, we allocate single pages
1034: * with kernel_memory_allocate(), and cram them into the
1035: * zone. This also allows us to initialize the vm_page_t's
1036: * on the way into the zone, so that zget() always returns
1037: * an initialized structure. The zone free element pointer
1038: * and the free page pointer are both the first item in the
1039: * vm_page_t.
1040: * 4. By having the pages in the zone pre-initialized, we need
1041: * not keep 2 levels of lists. The garbage collector simply
1042: * scans our list, and reduces physical memory usage as it
1043: * sees fit.
1044: */
1045:
1046: void vm_page_more_fictitious(void)
1047: {
1048: extern vm_map_t zone_map;
1049: register vm_page_t m;
1050: vm_offset_t addr;
1051: kern_return_t retval;
1052: int i;
1053:
1054: c_vm_page_more_fictitious++;
1055:
1056: /* this may free up some fictitious pages */
1057: cleanup_limbo_queue();
1058:
1059: /*
1060: * Allocate a single page from the zone_map. Do not wait if no physical
1061: * pages are immediately available, and do not zero the space. We need
1062: * our own blocking lock here to prevent having multiple,
1063: * simultaneous requests from piling up on the zone_map lock. Exactly
1064: * one (of our) threads should be potentially waiting on the map lock.
1065: * If winner is not vm-privileged, then the page allocation will fail,
1066: * and it will temporarily block here in the vm_page_wait().
1067: */
1068: mutex_lock(&vm_page_alloc_lock);
1069: /*
1070: * If another thread allocated space, just bail out now.
1071: */
1072: if (zone_free_count(vm_page_zone) > 5) {
1073: /*
1074: * The number "5" is a small number that is larger than the
1075: * number of fictitious pages that any single caller will
1076: * attempt to allocate. Otherwise, a thread will attempt to
1077: * acquire a fictitious page (vm_page_grab_fictitious), fail,
1078: * release all of the resources and locks already acquired,
1079: * and then call this routine. This routine finds the pages
1080: * that the caller released, so fails to allocate new space.
1081: * The process repeats infinitely. The largest known number
1082: * of fictitious pages required in this manner is 2. 5 is
1083: * simply a somewhat larger number.
1084: */
1085: mutex_unlock(&vm_page_alloc_lock);
1086: return;
1087: }
1088:
1089: if ((retval = kernel_memory_allocate(zone_map,
1090: &addr, PAGE_SIZE, VM_PROT_ALL,
1091: KMA_KOBJECT|KMA_NOPAGEWAIT)) != KERN_SUCCESS) {
1092: /*
1093: * No page was available. Tell the pageout daemon, drop the
1094: * lock to give another thread a chance at it, and
1095: * wait for the pageout daemon to make progress.
1096: */
1097: mutex_unlock(&vm_page_alloc_lock);
1098: vm_page_wait();
1099: return;
1100: }
1101: /*
1102: * Initialize as many vm_page_t's as will fit on this page. This
1103: * depends on the zone code disturbing ONLY the first item of
1104: * each zone element.
1105: */
1106: m = (vm_page_t)addr;
1107: for (i = PAGE_SIZE/sizeof(struct vm_page); i > 0; i--) {
1108: vm_page_init(m, vm_page_fictitious_addr);
1109: m->fictitious = TRUE;
1110: m++;
1111: }
1112: zcram(vm_page_zone, addr, PAGE_SIZE);
1113: mutex_unlock(&vm_page_alloc_lock);
1114: }
1115:
1116: /*
1117: * vm_page_convert:
1118: *
1119: * Attempt to convert a fictitious page into a real page.
1120: */
1121:
1122: boolean_t
1123: vm_page_convert(
1124: register vm_page_t m)
1125: {
1126: register vm_page_t real_m;
1127:
1128: assert(m->busy);
1129: assert(m->fictitious);
1130: assert(!m->dirty);
1131:
1132: real_m = vm_page_grab();
1133: if (real_m == VM_PAGE_NULL)
1134: return FALSE;
1135:
1136: m->phys_addr = real_m->phys_addr;
1137: m->fictitious = FALSE;
1138:
1139: vm_page_lock_queues();
1140: if (m->active)
1141: vm_page_active_count++;
1142: else if (m->inactive)
1143: vm_page_inactive_count++;
1144: vm_page_unlock_queues();
1145:
1146: real_m->phys_addr = vm_page_fictitious_addr;
1147: real_m->fictitious = TRUE;
1148:
1149: vm_page_release_fictitious(real_m);
1150: return TRUE;
1151: }
1152:
1153: /*
1154: * vm_pool_low():
1155: *
1156: * Return true if it is not likely that a non-vm_privileged thread
1157: * can get memory without blocking. Advisory only, since the
1158: * situation may change under us.
1159: */
1160: int
1161: vm_pool_low(void)
1162: {
1163: /* No locking, at worst we will fib. */
1164: return( vm_page_free_count < vm_page_free_reserved );
1165: }
1166:
1167: /*
1168: * vm_page_grab:
1169: *
1170: * Remove a page from the free list.
1171: * Returns VM_PAGE_NULL if the free list is too small.
1172: */
1173:
1174: unsigned long vm_page_grab_count = 0; /* measure demand */
1175:
1176: vm_page_t
1177: vm_page_grab(void)
1178: {
1179: register vm_page_t mem;
1180:
1181: mutex_lock(&vm_page_queue_free_lock);
1182: vm_page_grab_count++;
1183:
1184: /*
1185: * Optionally produce warnings if the wire or gobble
1186: * counts exceed some threshold.
1187: */
1188: if (vm_page_wire_count_warning > 0
1189: && vm_page_wire_count >= vm_page_wire_count_warning) {
1190: printf("mk: vm_page_grab(): high wired page count of %d\n",
1191: vm_page_wire_count);
1192: assert(vm_page_wire_count < vm_page_wire_count_warning);
1193: }
1194: if (vm_page_gobble_count_warning > 0
1195: && vm_page_gobble_count >= vm_page_gobble_count_warning) {
1196: printf("mk: vm_page_grab(): high gobbled page count of %d\n",
1197: vm_page_gobble_count);
1198: assert(vm_page_gobble_count < vm_page_gobble_count_warning);
1199: }
1200:
1201: /*
1202: * Only let privileged threads (involved in pageout)
1203: * dip into the reserved pool.
1204: */
1205:
1206: if ((vm_page_free_count < vm_page_free_reserved) &&
1207: !current_thread()->vm_privilege) {
1208: mutex_unlock(&vm_page_queue_free_lock);
1209: mem = VM_PAGE_NULL;
1210: goto wakeup_pageout;
1211: }
1212:
1213: while (vm_page_queue_free == VM_PAGE_NULL) {
1214: printf("vm_page_grab: no free pages, trouble expected...\n");
1215: mutex_unlock(&vm_page_queue_free_lock);
1216: VM_PAGE_WAIT();
1217: mutex_lock(&vm_page_queue_free_lock);
1218: }
1219:
1220: if (--vm_page_free_count < vm_page_free_count_minimum)
1221: vm_page_free_count_minimum = vm_page_free_count;
1222: mem = vm_page_queue_free;
1223: vm_page_queue_free = (vm_page_t) mem->pageq.next;
1224: mem->free = FALSE;
1225: mutex_unlock(&vm_page_queue_free_lock);
1226:
1227: /*
1228: * Decide if we should poke the pageout daemon.
1229: * We do this if the free count is less than the low
1230: * water mark, or if the free count is less than the high
1231: * water mark (but above the low water mark) and the inactive
1232: * count is less than its target.
1233: *
1234: * We don't have the counts locked ... if they change a little,
1235: * it doesn't really matter.
1236: */
1237:
1238: wakeup_pageout:
1239: if ((vm_page_free_count < vm_page_free_min) ||
1240: ((vm_page_free_count < vm_page_free_target) &&
1241: (vm_page_inactive_count < vm_page_inactive_target)))
1242: thread_wakeup((event_t) &vm_page_free_wanted);
1243:
1244: // dbgLog(mem->phys_addr, vm_page_free_count, vm_page_wire_count, 4); /* (TEST/DEBUG) */
1245:
1246: return mem;
1247: }
1248:
1249: /*
1250: * vm_page_release:
1251: *
1252: * Return a page to the free list.
1253: */
1254:
1255: void
1256: vm_page_release(
1257: register vm_page_t mem)
1258: {
1259: assert(!mem->private && !mem->fictitious);
1260:
1261: // dbgLog(mem->phys_addr, vm_page_free_count, vm_page_wire_count, 5); /* (TEST/DEBUG) */
1262:
1263: mutex_lock(&vm_page_queue_free_lock);
1264: if (mem->free)
1265: panic("vm_page_release");
1266: mem->free = TRUE;
1267: mem->pageq.next = (queue_entry_t) vm_page_queue_free;
1268: vm_page_queue_free = mem;
1269: vm_page_free_count++;
1270:
1271: /*
1272: * Check if we should wake up someone waiting for page.
1273: * But don't bother waking them unless they can allocate.
1274: *
1275: * We wakeup only one thread, to prevent starvation.
1276: * Because the scheduling system handles wait queues FIFO,
1277: * if we wakeup all waiting threads, one greedy thread
1278: * can starve multiple niceguy threads. When the threads
1279: * all wakeup, the greedy threads runs first, grabs the page,
1280: * and waits for another page. It will be the first to run
1281: * when the next page is freed.
1282: *
1283: * However, there is a slight danger here.
1284: * The thread we wake might not use the free page.
1285: * Then the other threads could wait indefinitely
1286: * while the page goes unused. To forestall this,
1287: * the pageout daemon will keep making free pages
1288: * as long as vm_page_free_wanted is non-zero.
1289: */
1290:
1291: if ((vm_page_free_wanted > 0) &&
1292: (vm_page_free_count >= vm_page_free_reserved)) {
1293: vm_page_free_wanted--;
1294: thread_wakeup_one((event_t) &vm_page_free_count);
1295: }
1296:
1297: mutex_unlock(&vm_page_queue_free_lock);
1298: }
1299:
1300: /*
1301: * Release a page to the limbo list.
1302: * Put real pages at the head of the queue, fictitious at the tail.
1303: * Page queues must be locked.
1304: */
1305: void
1306: vm_page_release_limbo(
1307: register vm_page_t m)
1308: {
1309: assert(m->limbo);
1310: vm_page_limbo_count++;
1311: if (m->fictitious) {
1312: queue_enter(&vm_page_queue_limbo, m, vm_page_t, pageq);
1313: } else {
1314: vm_page_limbo_real_count++;
1315: queue_enter_first(&vm_page_queue_limbo, m, vm_page_t, pageq);
1316: }
1317: }
1318:
1319: /*
1320: * Exchange a real page in limbo (limbo_m) with a fictitious page (new_m).
1321: * The end result is that limbo_m is fictitious and still in limbo, and new_m
1322: * is the real page. The prep and pin counts remain with the page in limbo
1323: * although they will be briefly cleared by vm_page_init. This is OK since
1324: * there will be no interrupt-level interactions (the page is in limbo) and
1325: * vm_page_unprep must lock the page queues before changing the prep count.
1326: *
1327: * Page queues must be locked, and limbo_m must have been removed from its
1328: * object.
1329: */
1330: void
1331: vm_page_limbo_exchange(
1332: register vm_page_t limbo_m,
1333: register vm_page_t new_m)
1334: {
1335: assert(limbo_m->limbo && !limbo_m->fictitious);
1336: assert(!limbo_m->tabled);
1337: assert(new_m->fictitious);
1338:
1339: *new_m = *limbo_m;
1340: vm_page_init(limbo_m, vm_page_fictitious_addr);
1341:
1342: limbo_m->fictitious = TRUE;
1343: limbo_m->limbo = TRUE;
1344: new_m->limbo = FALSE;
1345:
1346: limbo_m->prep_pin_count = new_m->prep_pin_count;
1347: new_m->prep_pin_count = 0;
1348: }
1349:
1350: /*
1351: * vm_page_wait:
1352: *
1353: * Wait for a page to become available.
1354: * If there are plenty of free pages, then we don't sleep.
1355: */
1356:
1357: void
1358: vm_page_wait( void )
1359: {
1360: /*
1361: * We can't use vm_page_free_reserved to make this
1362: * determination. Consider: some thread might
1363: * need to allocate two pages. The first allocation
1364: * succeeds, the second fails. After the first page is freed,
1365: * a call to vm_page_wait must really block.
1366: */
1367:
1368: mutex_lock(&vm_page_queue_free_lock);
1369: if (vm_page_free_count < vm_page_free_target) {
1370: if (vm_page_free_wanted++ == 0)
1371: thread_wakeup((event_t)&vm_page_free_wanted);
1372: assert_wait((event_t)&vm_page_free_count, THREAD_UNINT);
1373: mutex_unlock(&vm_page_queue_free_lock);
1374: counter(c_vm_page_wait_block++);
1375: thread_block((void (*)(void))0);
1376: } else
1377: mutex_unlock(&vm_page_queue_free_lock);
1378: }
1379:
1380: /*
1381: * vm_page_alloc:
1382: *
1383: * Allocate and return a memory cell associated
1384: * with this VM object/offset pair.
1385: *
1386: * Object must be locked.
1387: */
1388:
1389: vm_page_t
1390: vm_page_alloc(
1391: vm_object_t object,
1392: vm_offset_t offset)
1393: {
1394: register vm_page_t mem;
1395:
1396: mem = vm_page_grab();
1397: if (mem == VM_PAGE_NULL)
1398: return VM_PAGE_NULL;
1399:
1400: vm_page_insert(mem, object, offset);
1401:
1402: return(mem);
1403: }
1404:
1405: int c_limbo_page_free = 0; /* debugging */
1406: int c_limbo_convert = 0; /* debugging */
1407: counter(unsigned int c_laundry_pages_freed = 0;)
1408:
1409: int vm_pagein_cluster_unused = 0;
1410: boolean_t vm_page_free_verify = FALSE;
1411: /*
1412: * vm_page_free:
1413: *
1414: * Returns the given page to the free list,
1415: * disassociating it with any VM object.
1416: *
1417: * Object and page queues must be locked prior to entry.
1418: */
1419: void
1420: vm_page_free(
1421: register vm_page_t mem)
1422: {
1423: vm_object_t object = mem->object;
1424:
1425: assert(!mem->free);
1426: assert(!mem->cleaning);
1427: assert(!mem->pageout);
1428: assert(!vm_page_free_verify || pmap_verify_free(mem->phys_addr));
1429:
1430: if (mem->tabled)
1431: vm_page_remove(mem); /* clears tabled, object, offset */
1432: VM_PAGE_QUEUES_REMOVE(mem); /* clears active or inactive */
1433:
1434: if (mem->clustered) {
1435: mem->clustered = FALSE;
1436: vm_pagein_cluster_unused++;
1437: }
1438:
1439: if (mem->wire_count) {
1440: if (!mem->private && !mem->fictitious)
1441: vm_page_wire_count--;
1442: mem->wire_count = 0;
1443: assert(!mem->gobbled);
1444: } else if (mem->gobbled) {
1445: if (!mem->private && !mem->fictitious)
1446: vm_page_wire_count--;
1447: vm_page_gobble_count--;
1448: }
1449: mem->gobbled = FALSE;
1450:
1451: if (mem->laundry) {
1452: extern int vm_page_laundry_min;
1453: vm_page_laundry_count--;
1454: mem->laundry = FALSE; /* laundry is now clear */
1455: counter(++c_laundry_pages_freed);
1456: if (vm_page_laundry_count < vm_page_laundry_min) {
1457: vm_page_laundry_min = 0;
1458: thread_wakeup((event_t) &vm_page_laundry_count);
1459: }
1460: }
1461:
1462: mem->discard_request = FALSE;
1463:
1464: PAGE_WAKEUP(mem); /* clears wanted */
1465:
1466: if (mem->absent)
1467: vm_object_absent_release(object);
1468:
1469: if (mem->limbo) {
1470: /*
1471: * The pageout daemon put this page into limbo and then freed
1472: * it. The page has already been removed from the object and
1473: * queues, so any attempt to look it up will fail. Put it
1474: * on the limbo queue; the pageout daemon will convert it to a
1475: * fictitious page and/or free the real one later.
1476: */
1477: /* assert that it came from pageout daemon (how?) */
1478: assert(!mem->fictitious && !mem->absent);
1479: c_limbo_page_free++;
1480: vm_page_release_limbo(mem);
1481: return;
1482: }
1483: assert(mem->prep_pin_count == 0);
1484:
1485: /* Some of these may be unnecessary */
1486: mem->page_lock = 0;
1487: mem->unlock_request = 0;
1488: mem->busy = TRUE;
1489: mem->absent = FALSE;
1490: mem->error = FALSE;
1491: mem->dirty = FALSE;
1492: mem->precious = FALSE;
1493: mem->reference = FALSE;
1494:
1495: mem->page_error = KERN_SUCCESS;
1496:
1497: if (mem->private) {
1498: mem->private = FALSE;
1499: mem->fictitious = TRUE;
1500: mem->phys_addr = vm_page_fictitious_addr;
1501: }
1502: if (mem->fictitious) {
1503: vm_page_release_fictitious(mem);
1504: } else {
1505: vm_page_init(mem, mem->phys_addr);
1506: vm_page_release(mem);
1507: }
1508: }
1509:
1510: /*
1511: * vm_page_wire:
1512: *
1513: * Mark this page as wired down by yet
1514: * another map, removing it from paging queues
1515: * as necessary.
1516: *
1517: * The page's object and the page queues must be locked.
1518: */
1519: void
1520: vm_page_wire(
1521: register vm_page_t mem)
1522: {
1523:
1524: // dbgLog(current_act(), mem->offset, mem->object, 1); /* (TEST/DEBUG) */
1525:
1526: VM_PAGE_CHECK(mem);
1527:
1528: if (mem->wire_count == 0) {
1529: VM_PAGE_QUEUES_REMOVE(mem);
1530: if (!mem->private && !mem->fictitious && !mem->gobbled)
1531: vm_page_wire_count++;
1532: if (mem->gobbled)
1533: vm_page_gobble_count--;
1534: mem->gobbled = FALSE;
1535: }
1536: assert(!mem->gobbled);
1537: mem->wire_count++;
1538: }
1539:
1540: /*
1541: * vm_page_gobble:
1542: *
1543: * Mark this page as consumed by the vm/ipc/xmm subsystems.
1544: *
1545: * Called only for freshly vm_page_grab()ed pages - w/ nothing locked.
1546: */
1547: void
1548: vm_page_gobble(
1549: register vm_page_t mem)
1550: {
1551: vm_page_lock_queues();
1552: VM_PAGE_CHECK(mem);
1553:
1554: assert(!mem->gobbled);
1555: assert(mem->wire_count == 0);
1556:
1557: if (!mem->gobbled && mem->wire_count == 0) {
1558: if (!mem->private && !mem->fictitious)
1559: vm_page_wire_count++;
1560: }
1561: vm_page_gobble_count++;
1562: mem->gobbled = TRUE;
1563: vm_page_unlock_queues();
1564: }
1565:
1566: /*
1567: * vm_page_unwire:
1568: *
1569: * Release one wiring of this page, potentially
1570: * enabling it to be paged again.
1571: *
1572: * The page's object and the page queues must be locked.
1573: */
1574: void
1575: vm_page_unwire(
1576: register vm_page_t mem)
1577: {
1578:
1579: // dbgLog(current_act(), mem->offset, mem->object, 0); /* (TEST/DEBUG) */
1580:
1581: VM_PAGE_CHECK(mem);
1582: assert(mem->wire_count > 0);
1583:
1584: if (--mem->wire_count == 0) {
1585: assert(!mem->private && !mem->fictitious);
1586: vm_page_wire_count--;
1587: queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq);
1588: vm_page_active_count++;
1589: mem->active = TRUE;
1590: mem->reference = TRUE;
1591: }
1592: }
1593:
1594: /*
1595: * vm_page_deactivate:
1596: *
1597: * Returns the given page to the inactive list,
1598: * indicating that no physical maps have access
1599: * to this page. [Used by the physical mapping system.]
1600: *
1601: * The page queues must be locked.
1602: */
1603: void
1604: vm_page_deactivate(
1605: register vm_page_t m)
1606: {
1607: VM_PAGE_CHECK(m);
1608:
1609: // dbgLog(m->phys_addr, vm_page_free_count, vm_page_wire_count, 6); /* (TEST/DEBUG) */
1610:
1611: /*
1612: * This page is no longer very interesting. If it was
1613: * interesting (active or inactive/referenced), then we
1614: * clear the reference bit and (re)enter it in the
1615: * inactive queue. Note wired pages should not have
1616: * their reference bit cleared.
1617: */
1618: if (m->gobbled) { /* can this happen? */
1619: assert(m->wire_count == 0);
1620: if (!m->private && !m->fictitious)
1621: vm_page_wire_count--;
1622: vm_page_gobble_count--;
1623: m->gobbled = FALSE;
1624: }
1625: if (m->private || (m->wire_count != 0))
1626: return;
1627: if (m->active || (m->inactive && m->reference)) {
1628: if (!m->fictitious && !m->absent)
1629: pmap_clear_reference(m->phys_addr);
1630: m->reference = FALSE;
1631: VM_PAGE_QUEUES_REMOVE(m);
1632: }
1633: if (m->wire_count == 0 && !m->inactive) {
1634: queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
1635: m->inactive = TRUE;
1636: if (!m->fictitious)
1637: vm_page_inactive_count++;
1638: }
1639: }
1640:
1641: /*
1642: * vm_page_activate:
1643: *
1644: * Put the specified page on the active list (if appropriate).
1645: *
1646: * The page queues must be locked.
1647: */
1648:
1649: void
1650: vm_page_activate(
1651: register vm_page_t m)
1652: {
1653: VM_PAGE_CHECK(m);
1654:
1655: if (m->gobbled) {
1656: assert(m->wire_count == 0);
1657: if (!m->private && !m->fictitious)
1658: vm_page_wire_count--;
1659: vm_page_gobble_count--;
1660: m->gobbled = FALSE;
1661: }
1662: if (m->private)
1663: return;
1664:
1665: if (m->inactive) {
1666: queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq);
1667: if (!m->fictitious)
1668: vm_page_inactive_count--;
1669: m->inactive = FALSE;
1670: }
1671: if (m->wire_count == 0) {
1672: if (m->active)
1673: panic("vm_page_activate: already active");
1674:
1675: queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
1676: m->active = TRUE;
1677: m->reference = TRUE;
1678: if (!m->fictitious)
1679: vm_page_active_count++;
1680: }
1681: }
1682:
1683: /*
1684: * vm_page_part_zero_fill:
1685: *
1686: * Zero-fill a part of the page.
1687: */
1688: void
1689: vm_page_part_zero_fill(
1690: vm_page_t m,
1691: vm_offset_t m_pa,
1692: vm_size_t len)
1693: {
1694: VM_PAGE_CHECK(m);
1695:
1696: pmap_zero_part_page(m->phys_addr, m_pa, len);
1697: }
1698:
1699: /*
1700: * vm_page_zero_fill:
1701: *
1702: * Zero-fill the specified page.
1703: */
1704: void
1705: vm_page_zero_fill(
1706: vm_page_t m)
1707: {
1708: XPR(XPR_VM_PAGE,
1709: "vm_page_zero_fill, object 0x%X offset 0x%X page 0x%X\n",
1710: (integer_t)m->object, (integer_t)m->offset, (integer_t)m, 0,0);
1711:
1712: VM_PAGE_CHECK(m);
1713:
1714: pmap_zero_page(m->phys_addr);
1715: }
1716:
1717: /*
1718: * vm_page_part_copy:
1719: *
1720: * copy part of one page to another
1721: */
1722:
1723: void
1724: vm_page_part_copy(
1725: vm_page_t src_m,
1726: vm_offset_t src_pa,
1727: vm_page_t dst_m,
1728: vm_offset_t dst_pa,
1729: vm_size_t len)
1730: {
1731: VM_PAGE_CHECK(src_m);
1732: VM_PAGE_CHECK(dst_m);
1733:
1734: pmap_copy_part_page(src_m->phys_addr, src_pa,
1735: dst_m->phys_addr, dst_pa, len);
1736: }
1737:
1738: /*
1739: * vm_page_copy:
1740: *
1741: * Copy one page to another
1742: */
1743:
1744: void
1745: vm_page_copy(
1746: vm_page_t src_m,
1747: vm_page_t dest_m)
1748: {
1749: XPR(XPR_VM_PAGE,
1750: "vm_page_copy, object 0x%X offset 0x%X to object 0x%X offset 0x%X\n",
1751: (integer_t)src_m->object, src_m->offset,
1752: (integer_t)dest_m->object, dest_m->offset,
1753: 0);
1754:
1755: VM_PAGE_CHECK(src_m);
1756: VM_PAGE_CHECK(dest_m);
1757:
1758: pmap_copy_page(src_m->phys_addr, dest_m->phys_addr);
1759: }
1760:
1761: /*
1762: * Limbo pages are placed on the limbo queue to await their prep count
1763: * going to zero. A page is put into limbo by the pageout daemon. If the
1764: * page is real, then the pageout daemon did not need to page out the page,
1765: * it just freed it. When the prep_pin_count is zero the page can be freed.
1766: * Real pages with a non-zero prep count are converted to fictitious pages
1767: * so that the memory can be reclaimed; the fictitious page will remain on
1768: * the limbo queue until its prep count reaches zero.
1769: *
1770: * cleanup_limbo_queue is called by vm_page_more_fictitious and the pageout
1771: * daemon since it can free both real and fictitious pages.
1772: * It returns the number of fictitious pages freed.
1773: */
1774: void
1775: cleanup_limbo_queue(void)
1776: {
1777: register vm_page_t free_m, m;
1778: vm_offset_t phys_addr;
1779:
1780: vm_page_lock_queues();
1781: assert(vm_page_limbo_count >= vm_page_limbo_real_count);
1782:
1783: /*
1784: * first free up all pages with prep/pin counts of zero. This
1785: * may free both real and fictitious pages, which may be needed
1786: * later to convert real ones.
1787: */
1788: m = (vm_page_t)queue_first(&vm_page_queue_limbo);
1789: while (!queue_end(&vm_page_queue_limbo, (queue_entry_t)m)) {
1790: if (m->prep_pin_count == 0) {
1791: free_m = m;
1792: m = (vm_page_t)queue_next(&m->pageq);
1793: queue_remove(&vm_page_queue_limbo, free_m, vm_page_t,
1794: pageq);
1795: vm_page_limbo_count--;
1796: if (!free_m->fictitious)
1797: vm_page_limbo_real_count--;
1798: free_m->limbo = FALSE;
1799: vm_page_free(free_m);
1800: assert(vm_page_limbo_count >= 0);
1801: assert(vm_page_limbo_real_count >= 0);
1802: } else {
1803: m = (vm_page_t)queue_next(&m->pageq);
1804: }
1805: }
1806:
1807: /*
1808: * now convert any remaining real pages to fictitious and free the
1809: * real ones.
1810: */
1811: while (vm_page_limbo_real_count > 0) {
1812: queue_remove_first(&vm_page_queue_limbo, m, vm_page_t, pageq);
1813: assert(!m->fictitious);
1814: assert(m->limbo);
1815:
1816: /*
1817: * Try to get a fictitious page. If impossible,
1818: * requeue the real one and give up.
1819: */
1820: free_m = vm_page_grab_fictitious();
1821: if (free_m == VM_PAGE_NULL) {
1822: queue_enter_first(&vm_page_queue_limbo, m, vm_page_t,
1823: pageq);
1824: break;
1825: }
1826: c_limbo_convert++;
1827: vm_page_limbo_exchange(m, free_m);
1828: assert(m->limbo && m->fictitious);
1829: assert(!free_m->limbo && !free_m->fictitious);
1830: queue_enter(&vm_page_queue_limbo, m, vm_page_t, pageq);
1831: vm_page_free(free_m);
1832: vm_page_limbo_real_count--;
1833: }
1834:
1835: vm_page_unlock_queues();
1836: }
1837:
1838: /*
1839: * Increment prep_count on a page.
1840: * Must be called in thread context. Page must not disappear: object
1841: * must be locked.
1842: */
1843: kern_return_t
1844: vm_page_prep(
1845: register vm_page_t m)
1846: {
1847: kern_return_t retval = KERN_SUCCESS;
1848:
1849: assert(m != VM_PAGE_NULL);
1850: vm_page_lock_queues();
1851: if (!m->busy && !m->error && !m->fictitious && !m->absent) {
1852: if (m->prep_pin_count != 0) {
1853: vm_page_pin_lock();
1854: m->prep_count++;
1855: vm_page_pin_unlock();
1856: } else {
1857: m->prep_count++;
1858: }
1859: assert(m->prep_count != 0); /* check for wraparound */
1860: } else {
1861: retval = KERN_FAILURE;
1862: }
1863: vm_page_unlock_queues();
1864: return retval;
1865: }
1866:
1867:
1868: /*
1869: * Pin a page (increment pin count).
1870: * Must have been previously prepped.
1871: *
1872: * MUST BE CALLED AT SPLVM.
1873: *
1874: * May be called from thread or interrupt context.
1875: * If page is in "limbo" it cannot be pinned.
1876: */
1877: kern_return_t
1878: vm_page_pin(
1879: register vm_page_t m)
1880: {
1881: kern_return_t retval = KERN_SUCCESS;
1882:
1883: assert(m != VM_PAGE_NULL);
1884: vm_page_pin_lock();
1885: if (m->limbo || m->prep_count == 0) {
1886: retval = KERN_FAILURE;
1887: } else {
1888: assert(!m->fictitious);
1889: if (m->pin_count == 0)
1890: vm_page_pin_count++;
1891: m->pin_count++;
1892: }
1893: vm_page_pin_unlock();
1894: return retval;
1895: }
1896:
1897:
1898: /*
1899: * Unprep a page (decrement prep count).
1900: * Must have been previously prepped.
1901: * Called to decrement prep count after an attempt to pin failed.
1902: * Must be called from thread context.
1903: */
1904: kern_return_t
1905: vm_page_unprep(
1906: register vm_page_t m)
1907: {
1908: kern_return_t retval = KERN_SUCCESS;
1909:
1910: assert(m != VM_PAGE_NULL);
1911: vm_page_lock_queues();
1912: vm_page_pin_lock();
1913: assert(m->prep_count != 0);
1914: if (m->prep_count == 0)
1915: retval = KERN_FAILURE; /* shouldn't happen */
1916: else
1917: m->prep_count--;
1918: vm_page_pin_unlock();
1919: vm_page_unlock_queues();
1920: return retval;
1921: }
1922:
1923:
1924: /*
1925: * Unpin a page: decrement pin AND prep counts.
1926: * Must have been previously prepped AND pinned.
1927: *
1928: * MUST BE CALLED AT SPLVM.
1929: *
1930: * May be called from thread or interrupt context.
1931: */
1932: kern_return_t
1933: vm_page_unpin(
1934: register vm_page_t m)
1935: {
1936: kern_return_t retval = KERN_SUCCESS;
1937:
1938: assert(m != VM_PAGE_NULL);
1939: vm_page_pin_lock();
1940: assert(m->prep_count != 0 && m->pin_count != 0);
1941: assert(m->prep_count >= m->pin_count);
1942: assert(!m->limbo && !m->fictitious);
1943: if (m->prep_count != 0 && m->pin_count != 0) {
1944: m->prep_count--;
1945: m->pin_count--;
1946: if (m->pin_count == 0)
1947: vm_page_pin_count--;
1948: } else {
1949: retval = KERN_FAILURE; /* shouldn't happen */
1950: }
1951: vm_page_pin_unlock();
1952: return retval;
1953: }
1954:
1955: /*
1956: * Currently, this is a primitive allocator that grabs
1957: * free pages from the system, sorts them by physical
1958: * address, then searches for a region large enough to
1959: * satisfy the user's request.
1960: *
1961: * Additional levels of effort:
1962: * + steal clean active/inactive pages
1963: * + force pageouts of dirty pages
1964: * + maintain a map of available physical
1965: * memory
1966: */
1967:
1968: #define SET_NEXT_PAGE(m,n) ((m)->pageq.next = (struct queue_entry *) (n))
1969:
1970: #if MACH_ASSERT
1971: int vm_page_verify_contiguous(
1972: vm_page_t pages,
1973: unsigned int npages);
1974: #endif /* MACH_ASSERT */
1975:
1976: cpm_counter(unsigned int vpfls_pages_handled = 0;)
1977: cpm_counter(unsigned int vpfls_head_insertions = 0;)
1978: cpm_counter(unsigned int vpfls_tail_insertions = 0;)
1979: cpm_counter(unsigned int vpfls_general_insertions = 0;)
1980: cpm_counter(unsigned int vpfc_failed = 0;)
1981: cpm_counter(unsigned int vpfc_satisfied = 0;)
1982:
1983: /*
1984: * Sort free list by ascending physical address,
1985: * using a not-particularly-bright sort algorithm.
1986: * Caller holds vm_page_queue_free_lock.
1987: */
1988: static void
1989: vm_page_free_list_sort(void)
1990: {
1991: vm_page_t sort_list;
1992: vm_page_t sort_list_end;
1993: vm_page_t m, m1, *prev, next_m;
1994: vm_offset_t addr;
1995: #if MACH_ASSERT
1996: unsigned int npages;
1997: int old_free_count;
1998: #endif /* MACH_ASSERT */
1999:
2000: #if MACH_ASSERT
2001: /*
2002: * Verify pages in the free list..
2003: */
2004: npages = 0;
2005: for (m = vm_page_queue_free; m != VM_PAGE_NULL; m = NEXT_PAGE(m))
2006: ++npages;
2007: if (npages != vm_page_free_count)
2008: panic("vm_sort_free_list: prelim: npages %d free_count %d",
2009: npages, vm_page_free_count);
2010: old_free_count = vm_page_free_count;
2011: #endif /* MACH_ASSERT */
2012:
2013: sort_list = sort_list_end = vm_page_queue_free;
2014: m = NEXT_PAGE(vm_page_queue_free);
2015: SET_NEXT_PAGE(vm_page_queue_free, VM_PAGE_NULL);
2016: cpm_counter(vpfls_pages_handled = 0);
2017: while (m != VM_PAGE_NULL) {
2018: cpm_counter(++vpfls_pages_handled);
2019: next_m = NEXT_PAGE(m);
2020: if (m->phys_addr < sort_list->phys_addr) {
2021: cpm_counter(++vpfls_head_insertions);
2022: SET_NEXT_PAGE(m, sort_list);
2023: sort_list = m;
2024: } else if (m->phys_addr > sort_list_end->phys_addr) {
2025: cpm_counter(++vpfls_tail_insertions);
2026: SET_NEXT_PAGE(sort_list_end, m);
2027: SET_NEXT_PAGE(m, VM_PAGE_NULL);
2028: sort_list_end = m;
2029: } else {
2030: cpm_counter(++vpfls_general_insertions);
2031: /* general sorted list insertion */
2032: prev = &sort_list;
2033: for (m1=sort_list; m1!=VM_PAGE_NULL; m1=NEXT_PAGE(m1)) {
2034: if (m1->phys_addr > m->phys_addr) {
2035: if (*prev != m1)
2036: panic("vm_sort_free_list: ugh");
2037: SET_NEXT_PAGE(m, *prev);
2038: *prev = m;
2039: break;
2040: }
2041: prev = (vm_page_t *) &m1->pageq.next;
2042: }
2043: }
2044: m = next_m;
2045: }
2046:
2047: #if MACH_ASSERT
2048: /*
2049: * Verify that pages are sorted into ascending order.
2050: */
2051: for (m = sort_list, npages = 0; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) {
2052: if (m != sort_list &&
2053: m->phys_addr <= addr) {
2054: printf("m 0x%x addr 0x%x\n", m, addr);
2055: panic("vm_sort_free_list");
2056: }
2057: addr = m->phys_addr;
2058: ++npages;
2059: }
2060: if (old_free_count != vm_page_free_count)
2061: panic("vm_sort_free_list: old_free %d free_count %d",
2062: old_free_count, vm_page_free_count);
2063: if (npages != vm_page_free_count)
2064: panic("vm_sort_free_list: npages %d free_count %d",
2065: npages, vm_page_free_count);
2066: #endif /* MACH_ASSERT */
2067:
2068: vm_page_queue_free = sort_list;
2069: }
2070:
2071:
2072: #if MACH_ASSERT
2073: /*
2074: * Check that the list of pages is ordered by
2075: * ascending physical address and has no holes.
2076: */
2077: int
2078: vm_page_verify_contiguous(
2079: vm_page_t pages,
2080: unsigned int npages)
2081: {
2082: register vm_page_t m;
2083: unsigned int page_count;
2084: vm_offset_t prev_addr;
2085:
2086: prev_addr = pages->phys_addr;
2087: page_count = 1;
2088: for (m = NEXT_PAGE(pages); m != VM_PAGE_NULL; m = NEXT_PAGE(m)) {
2089: if (m->phys_addr != prev_addr + page_size) {
2090: printf("m 0x%x prev_addr 0x%x, current addr 0x%x\n",
2091: m, prev_addr, m->phys_addr);
2092: printf("pages 0x%x page_count %d\n", pages, page_count);
2093: panic("vm_page_verify_contiguous: not contiguous!");
2094: }
2095: prev_addr = m->phys_addr;
2096: ++page_count;
2097: }
2098: if (page_count != npages) {
2099: printf("pages 0x%x actual count 0x%x but requested 0x%x\n",
2100: pages, page_count, npages);
2101: panic("vm_page_verify_contiguous: count error");
2102: }
2103: return 1;
2104: }
2105: #endif /* MACH_ASSERT */
2106:
2107:
2108: /*
2109: * Find a region large enough to contain at least npages
2110: * of contiguous physical memory.
2111: *
2112: * Requirements:
2113: * - Called while holding vm_page_queue_free_lock.
2114: * - Doesn't respect vm_page_free_reserved; caller
2115: * must not ask for more pages than are legal to grab.
2116: *
2117: * Returns a pointer to a list of gobbled pages or VM_PAGE_NULL.
2118: *
2119: */
2120: static vm_page_t
2121: vm_page_find_contiguous(
2122: int npages)
2123: {
2124: vm_page_t m, *contig_prev, *prev_ptr;
2125: vm_offset_t prev_addr;
2126: unsigned int contig_npages;
2127: vm_page_t list;
2128:
2129: if (npages < 1)
2130: return VM_PAGE_NULL;
2131:
2132: prev_addr = vm_page_queue_free->phys_addr - (page_size + 1);
2133: prev_ptr = &vm_page_queue_free;
2134: for (m = vm_page_queue_free; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) {
2135:
2136: if (m->phys_addr != prev_addr + page_size) {
2137: /*
2138: * Whoops! Pages aren't contiguous. Start over.
2139: */
2140: contig_npages = 0;
2141: contig_prev = prev_ptr;
2142: }
2143:
2144: if (++contig_npages == npages) {
2145: /*
2146: * Chop these pages out of the free list.
2147: * Mark them all as gobbled.
2148: */
2149: list = *contig_prev;
2150: *contig_prev = NEXT_PAGE(m);
2151: SET_NEXT_PAGE(m, VM_PAGE_NULL);
2152: for (m = list; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) {
2153: assert(m->free);
2154: assert(!m->wanted);
2155: m->free = FALSE;
2156: m->gobbled = TRUE;
2157: }
2158: vm_page_free_count -= npages;
2159: if (vm_page_free_count < vm_page_free_count_minimum)
2160: vm_page_free_count_minimum = vm_page_free_count;
2161: vm_page_gobble_count += npages;
2162: cpm_counter(++vpfc_satisfied);
2163: assert(vm_page_verify_contiguous(list, contig_npages));
2164: return list;
2165: }
2166:
2167: assert(contig_npages < npages);
2168: prev_ptr = (vm_page_t *) &m->pageq.next;
2169: prev_addr = m->phys_addr;
2170: }
2171: cpm_counter(++vpfc_failed);
2172: return VM_PAGE_NULL;
2173: }
2174:
2175: /*
2176: * Allocate a list of contiguous, wired pages.
2177: */
2178: kern_return_t
2179: cpm_allocate(
2180: vm_size_t size,
2181: vm_page_t *list,
2182: boolean_t wire)
2183: {
2184: register vm_page_t m;
2185: vm_page_t *first_contig;
2186: vm_page_t free_list, pages;
2187: unsigned int npages, n1pages;
2188: int vm_pages_available;
2189:
2190: if (size % page_size != 0)
2191: return KERN_INVALID_ARGUMENT;
2192:
2193: vm_page_lock_queues();
2194: mutex_lock(&vm_page_queue_free_lock);
2195:
2196: /*
2197: * Should also take active and inactive pages
2198: * into account... One day...
2199: */
2200: vm_pages_available = vm_page_free_count - vm_page_free_reserved;
2201:
2202: if (size > vm_pages_available * page_size) {
2203: mutex_unlock(&vm_page_queue_free_lock);
2204: return KERN_RESOURCE_SHORTAGE;
2205: }
2206:
2207: vm_page_free_list_sort();
2208:
2209: npages = size / page_size;
2210:
2211: /*
2212: * Obtain a pointer to a subset of the free
2213: * list large enough to satisfy the request;
2214: * the region will be physically contiguous.
2215: */
2216: pages = vm_page_find_contiguous(npages);
2217: if (pages == VM_PAGE_NULL) {
2218: mutex_unlock(&vm_page_queue_free_lock);
2219: return KERN_NO_SPACE;
2220: }
2221:
2222: mutex_unlock(&vm_page_queue_free_lock);
2223:
2224: /*
2225: * Walk the returned list, wiring the pages.
2226: */
2227: if (wire == TRUE)
2228: for (m = pages; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) {
2229: /*
2230: * Essentially inlined vm_page_wire.
2231: */
2232: assert(!m->active);
2233: assert(!m->inactive);
2234: assert(!m->private);
2235: assert(!m->fictitious);
2236: assert(m->wire_count == 0);
2237: assert(m->gobbled);
2238: m->gobbled = FALSE;
2239: m->wire_count++;
2240: ++vm_page_wire_count;
2241: --vm_page_gobble_count;
2242: }
2243: vm_page_unlock_queues();
2244:
2245: /*
2246: * The CPM pages should now be available and
2247: * ordered by ascending physical address.
2248: */
2249: assert(vm_page_verify_contiguous(pages, npages));
2250:
2251: *list = pages;
2252: return KERN_SUCCESS;
2253: }
2254:
2255:
2256: #include <mach_vm_debug.h>
2257: #if MACH_VM_DEBUG
2258:
2259: #include <mach_debug/hash_info.h>
2260: #include <vm/vm_debug.h>
2261:
2262: /*
2263: * Routine: vm_page_info
2264: * Purpose:
2265: * Return information about the global VP table.
2266: * Fills the buffer with as much information as possible
2267: * and returns the desired size of the buffer.
2268: * Conditions:
2269: * Nothing locked. The caller should provide
2270: * possibly-pageable memory.
2271: */
2272:
2273: unsigned int
2274: vm_page_info(
2275: hash_info_bucket_t *info,
2276: unsigned int count)
2277: {
2278: int i;
2279:
2280: if (vm_page_bucket_count < count)
2281: count = vm_page_bucket_count;
2282:
2283: for (i = 0; i < count; i++) {
2284: vm_page_bucket_t *bucket = &vm_page_buckets[i];
2285: unsigned int bucket_count = 0;
2286: vm_page_t m;
2287:
2288: simple_lock(&vm_page_bucket_lock);
2289: for (m = bucket->pages; m != VM_PAGE_NULL; m = m->next)
2290: bucket_count++;
2291: simple_unlock(&vm_page_bucket_lock);
2292:
2293: /* don't touch pageable memory while holding locks */
2294: info[i].hib_count = bucket_count;
2295: }
2296:
2297: return vm_page_bucket_count;
2298: }
2299: #endif /* MACH_VM_DEBUG */
2300:
2301: #include <mach_kdb.h>
2302: #if MACH_KDB
2303:
2304: #include <ddb/db_output.h>
2305: #include <vm/vm_print.h>
2306: #define printf kdbprintf
2307:
2308: /*
2309: * Routine: vm_page_print [exported]
2310: */
2311: void
2312: vm_page_print(
2313: vm_page_t p)
2314: {
2315: extern db_indent;
2316:
2317: iprintf("page 0x%x\n", p);
2318:
2319: db_indent += 2;
2320:
2321: iprintf("object=0x%x", p->object);
2322: printf(", offset=0x%x", p->offset);
2323: printf(", wire_count=%d", p->wire_count);
2324: printf(", prep_count=%d", p->prep_count);
2325: printf(", pin_count=%d\n", p->pin_count);
2326:
2327: iprintf("%sinactive, %sactive, %sgobbled, %slaundry, %sfree, %sref, %sdiscard\n",
2328: (p->inactive ? "" : "!"),
2329: (p->active ? "" : "!"),
2330: (p->gobbled ? "" : "!"),
2331: (p->laundry ? "" : "!"),
2332: (p->free ? "" : "!"),
2333: (p->reference ? "" : "!"),
2334: (p->discard_request ? "" : "!"));
2335: iprintf("%sbusy, %swanted, %stabled, %sfictitious, %sprivate, %sprecious\n",
2336: (p->busy ? "" : "!"),
2337: (p->wanted ? "" : "!"),
2338: (p->tabled ? "" : "!"),
2339: (p->fictitious ? "" : "!"),
2340: (p->private ? "" : "!"),
2341: (p->precious ? "" : "!"));
2342: iprintf("%sabsent, %serror, %sdirty, %scleaning, %spageout, %sclustered\n",
2343: (p->absent ? "" : "!"),
2344: (p->error ? "" : "!"),
2345: (p->dirty ? "" : "!"),
2346: (p->cleaning ? "" : "!"),
2347: (p->pageout ? "" : "!"),
2348: (p->clustered ? "" : "!"));
2349: iprintf("%slock_supplied, %soverwriting, %srestart, %sunusual, %slimbo\n",
2350: (p->lock_supplied ? "" : "!"),
2351: (p->overwriting ? "" : "!"),
2352: (p->restart ? "" : "!"),
2353: (p->unusual ? "" : "!"),
2354: (p->limbo ? "" : "!"));
2355:
2356: iprintf("phys_addr=0x%x", p->phys_addr);
2357: printf(", page_error=0x%x", p->page_error);
2358: printf(", page_lock=0x%x", p->page_lock);
2359: printf(", unlock_request=%d\n", p->unlock_request);
2360:
2361: db_indent -= 2;
2362: }
2363: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.