|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University.
4: * Copyright (c) 1993,1994 The University of Utah and
5: * the Computer Systems Laboratory (CSL).
6: * All rights reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
17: * THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or [email protected]
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: */
29: /*
30: * File: vm/vm_page.c
31: * Author: Avadis Tevanian, Jr., Michael Wayne Young
32: *
33: * Resident memory management module.
34: */
35: #include <cpus.h>
36:
37: #include <mach/vm_prot.h>
38: #include <kern/counters.h>
39: #include <kern/sched_prim.h>
40: #include <kern/task.h>
41: #include <kern/thread.h>
42: #include <mach/vm_statistics.h>
43: #include "vm_param.h"
44: #include <kern/xpr.h>
45: #include <kern/zalloc.h>
46: #include <vm/pmap.h>
47: #include <vm/vm_map.h>
48: #include <vm/vm_page.h>
49: #include <vm/vm_pageout.h>
50: #include <vm/vm_kern.h>
51:
52: #include <mach_vm_debug.h>
53: #if MACH_VM_DEBUG
54: #include <mach/kern_return.h>
55: #include <mach_debug/hash_info.h>
56: #include <vm/vm_user.h>
57: #endif
58:
59: /* in zalloc.c XXX */
60: extern vm_offset_t zdata;
61: extern vm_size_t zdata_size;
62:
63: /*
64: * Associated with eacn page of user-allocatable memory is a
65: * page structure.
66: */
67:
68: /*
69: * These variables record the values returned by vm_page_bootstrap,
70: * for debugging purposes. The implementation of pmap_steal_memory
71: * and pmap_startup here also uses them internally.
72: */
73:
74: vm_offset_t virtual_space_start;
75: vm_offset_t virtual_space_end;
76:
77: /*
78: * The vm_page_lookup() routine, which provides for fast
79: * (virtual memory object, offset) to page lookup, employs
80: * the following hash table. The vm_page_{insert,remove}
81: * routines install and remove associations in the table.
82: * [This table is often called the virtual-to-physical,
83: * or VP, table.]
84: */
85: typedef struct {
86: decl_simple_lock_data(,lock)
87: vm_page_t pages;
88: } vm_page_bucket_t;
89:
90: vm_page_bucket_t *vm_page_buckets; /* Array of buckets */
91: unsigned int vm_page_bucket_count = 0; /* How big is array? */
92: unsigned int vm_page_hash_mask; /* Mask for hash function */
93:
94: /*
95: * Resident page structures are initialized from
96: * a template (see vm_page_alloc).
97: *
98: * When adding a new field to the virtual memory
99: * object structure, be sure to add initialization
100: * (see vm_page_bootstrap).
101: */
102: struct vm_page vm_page_template;
103:
104: /*
105: * Resident pages that represent real memory
106: * are allocated from a free list.
107: */
108: vm_page_t vm_page_queue_free;
109: vm_page_t vm_page_queue_fictitious;
110: decl_simple_lock_data(,vm_page_queue_free_lock)
111: unsigned int vm_page_free_wanted;
112: int vm_page_free_count;
113: int vm_page_fictitious_count;
114:
115: unsigned int vm_page_free_count_minimum; /* debugging */
116:
117: /*
118: * Occasionally, the virtual memory system uses
119: * resident page structures that do not refer to
120: * real pages, for example to leave a page with
121: * important state information in the VP table.
122: *
123: * These page structures are allocated the way
124: * most other kernel structures are.
125: */
126: zone_t vm_page_zone;
127:
128: /*
129: * Fictitious pages don't have a physical address,
130: * but we must initialize phys_addr to something.
131: * For debugging, this should be a strange value
132: * that the pmap module can recognize in assertions.
133: */
134: vm_offset_t vm_page_fictitious_addr = (vm_offset_t) -1;
135:
136: /*
137: * Resident page structures are also chained on
138: * queues that are used by the page replacement
139: * system (pageout daemon). These queues are
140: * defined here, but are shared by the pageout
141: * module.
142: */
143: queue_head_t vm_page_queue_active;
144: queue_head_t vm_page_queue_inactive;
145: decl_simple_lock_data(,vm_page_queue_lock)
146: int vm_page_active_count;
147: int vm_page_inactive_count;
148: int vm_page_wire_count;
149:
150: /*
151: * Several page replacement parameters are also
152: * shared with this module, so that page allocation
153: * (done here in vm_page_alloc) can trigger the
154: * pageout daemon.
155: */
156: int vm_page_free_target = 0;
157: int vm_page_free_min = 0;
158: int vm_page_inactive_target = 0;
159: int vm_page_free_reserved = 0;
160: int vm_page_laundry_count = 0;
161:
162: /*
163: * The VM system has a couple of heuristics for deciding
164: * that pages are "uninteresting" and should be placed
165: * on the inactive queue as likely candidates for replacement.
166: * These variables let the heuristics be controlled at run-time
167: * to make experimentation easier.
168: */
169:
170: boolean_t vm_page_deactivate_behind = TRUE;
171: boolean_t vm_page_deactivate_hint = TRUE;
172:
173: /*
174: * vm_page_bootstrap:
175: *
176: * Initializes the resident memory module.
177: *
178: * Allocates memory for the page cells, and
179: * for the object/offset-to-page hash table headers.
180: * Each page cell is initialized and placed on the free list.
181: * Returns the range of available kernel virtual memory.
182: */
183:
184: void vm_page_bootstrap(
185: vm_offset_t *startp,
186: vm_offset_t *endp)
187: {
188: register vm_page_t m;
189: int i;
190:
191: /*
192: * Initialize the vm_page template.
193: */
194:
195: m = &vm_page_template;
196: m->object = VM_OBJECT_NULL; /* reset later */
197: m->offset = 0; /* reset later */
198: m->wire_count = 0;
199:
200: m->inactive = FALSE;
201: m->active = FALSE;
202: m->laundry = FALSE;
203: m->free = FALSE;
204:
205: m->busy = TRUE;
206: m->wanted = FALSE;
207: m->tabled = FALSE;
208: m->fictitious = FALSE;
209: m->private = FALSE;
210: m->absent = FALSE;
211: m->error = FALSE;
212: m->dirty = FALSE;
213: m->precious = FALSE;
214: m->reference = FALSE;
215:
216: m->phys_addr = 0; /* reset later */
217:
218: m->page_lock = VM_PROT_NONE;
219: m->unlock_request = VM_PROT_NONE;
220:
221: /*
222: * Initialize the page queues.
223: */
224:
225: simple_lock_init(&vm_page_queue_free_lock);
226: simple_lock_init(&vm_page_queue_lock);
227:
228: vm_page_queue_free = VM_PAGE_NULL;
229: vm_page_queue_fictitious = VM_PAGE_NULL;
230: queue_init(&vm_page_queue_active);
231: queue_init(&vm_page_queue_inactive);
232:
233: vm_page_free_wanted = 0;
234:
235: /*
236: * Steal memory for the zone system.
237: */
238:
239: kentry_data_size = kentry_count * sizeof(struct vm_map_entry);
240: kentry_data = pmap_steal_memory(kentry_data_size);
241:
242: zdata = pmap_steal_memory(zdata_size);
243:
244: /*
245: * Allocate (and initialize) the virtual-to-physical
246: * table hash buckets.
247: *
248: * The number of buckets should be a power of two to
249: * get a good hash function. The following computation
250: * chooses the first power of two that is greater
251: * than the number of physical pages in the system.
252: */
253:
254: if (vm_page_bucket_count == 0) {
255: unsigned int npages = pmap_free_pages();
256:
257: vm_page_bucket_count = 1;
258: while (vm_page_bucket_count < npages)
259: vm_page_bucket_count <<= 1;
260: }
261:
262: vm_page_hash_mask = vm_page_bucket_count - 1;
263:
264: if (vm_page_hash_mask & vm_page_bucket_count)
265: printf("vm_page_bootstrap: WARNING -- strange page hash\n");
266:
267: vm_page_buckets = (vm_page_bucket_t *)
268: pmap_steal_memory(vm_page_bucket_count *
269: sizeof(vm_page_bucket_t));
270:
271: for (i = 0; i < vm_page_bucket_count; i++) {
272: register vm_page_bucket_t *bucket = &vm_page_buckets[i];
273:
274: bucket->pages = VM_PAGE_NULL;
275: simple_lock_init(&bucket->lock);
276: }
277:
278: /*
279: * Machine-dependent code allocates the resident page table.
280: * It uses vm_page_init to initialize the page frames.
281: * The code also returns to us the virtual space available
282: * to the kernel. We don't trust the pmap module
283: * to get the alignment right.
284: */
285:
286: pmap_startup(&virtual_space_start, &virtual_space_end);
287: virtual_space_start = round_page(virtual_space_start);
288: virtual_space_end = trunc_page(virtual_space_end);
289:
290: *startp = virtual_space_start;
291: *endp = virtual_space_end;
292:
293: /* printf("vm_page_bootstrap: %d free pages\n", vm_page_free_count);*/
294: vm_page_free_count_minimum = vm_page_free_count;
295: }
296:
297: #ifndef MACHINE_PAGES
298: /*
299: * We implement pmap_steal_memory and pmap_startup with the help
300: * of two simpler functions, pmap_virtual_space and pmap_next_page.
301: */
302:
303: vm_offset_t pmap_steal_memory(
304: vm_size_t size)
305: {
306: vm_offset_t addr, vaddr, paddr;
307:
308: /*
309: * We round the size to an integer multiple.
310: */
311:
312: size = (size + 3) &~ 3;
313:
314: /*
315: * If this is the first call to pmap_steal_memory,
316: * we have to initialize ourself.
317: */
318:
319: if (virtual_space_start == virtual_space_end) {
320: pmap_virtual_space(&virtual_space_start, &virtual_space_end);
321:
322: /*
323: * The initial values must be aligned properly, and
324: * we don't trust the pmap module to do it right.
325: */
326:
327: virtual_space_start = round_page(virtual_space_start);
328: virtual_space_end = trunc_page(virtual_space_end);
329: }
330:
331: /*
332: * Allocate virtual memory for this request.
333: */
334:
335: addr = virtual_space_start;
336: virtual_space_start += size;
337:
338: /*
339: * Allocate and map physical pages to back new virtual pages.
340: */
341:
342: for (vaddr = round_page(addr);
343: vaddr < addr + size;
344: vaddr += PAGE_SIZE) {
345: if (!pmap_next_page(&paddr))
346: panic("pmap_steal_memory");
347:
348: /*
349: * XXX Logically, these mappings should be wired,
350: * but some pmap modules barf if they are.
351: */
352:
353: pmap_enter(kernel_pmap, vaddr, paddr,
354: VM_PROT_READ|VM_PROT_WRITE, FALSE);
355: }
356:
357: return addr;
358: }
359:
360: void pmap_startup(
361: vm_offset_t *startp,
362: vm_offset_t *endp)
363: {
364: unsigned int i, npages, pages_initialized;
365: vm_page_t pages;
366: vm_offset_t paddr;
367:
368: /*
369: * We calculate how many page frames we will have
370: * and then allocate the page structures in one chunk.
371: */
372:
373: npages = ((PAGE_SIZE * pmap_free_pages() +
374: (round_page(virtual_space_start) - virtual_space_start)) /
375: (PAGE_SIZE + sizeof *pages));
376:
377: pages = (vm_page_t) pmap_steal_memory(npages * sizeof *pages);
378:
379: /*
380: * Initialize the page frames.
381: */
382:
383: for (i = 0, pages_initialized = 0; i < npages; i++) {
384: if (!pmap_next_page(&paddr))
385: break;
386:
387: vm_page_init(&pages[i], paddr);
388: pages_initialized++;
389: }
390:
391: /*
392: * Release pages in reverse order so that physical pages
393: * initially get allocated in ascending addresses. This keeps
394: * the devices (which must address physical memory) happy if
395: * they require several consecutive pages.
396: */
397:
398: for (i = pages_initialized; i > 0; i--) {
399: vm_page_release(&pages[i - 1]);
400: }
401:
402: /*
403: * We have to re-align virtual_space_start,
404: * because pmap_steal_memory has been using it.
405: */
406:
407: virtual_space_start = round_page(virtual_space_start);
408:
409: *startp = virtual_space_start;
410: *endp = virtual_space_end;
411: }
412: #endif /* MACHINE_PAGES */
413:
414: /*
415: * Routine: vm_page_module_init
416: * Purpose:
417: * Second initialization pass, to be done after
418: * the basic VM system is ready.
419: */
420: void vm_page_module_init(void)
421: {
422: vm_page_zone = zinit((vm_size_t) sizeof(struct vm_page),
423: VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS,
424: PAGE_SIZE,
425: 0, "vm pages");
426: }
427:
428: /*
429: * Routine: vm_page_create
430: * Purpose:
431: * After the VM system is up, machine-dependent code
432: * may stumble across more physical memory. For example,
433: * memory that it was reserving for a frame buffer.
434: * vm_page_create turns this memory into available pages.
435: */
436:
437: void vm_page_create(
438: vm_offset_t start,
439: vm_offset_t end)
440: {
441: vm_offset_t paddr;
442: vm_page_t m;
443:
444: for (paddr = round_page(start);
445: paddr < trunc_page(end);
446: paddr += PAGE_SIZE) {
447: m = (vm_page_t) zalloc(vm_page_zone);
448: if (m == VM_PAGE_NULL)
449: panic("vm_page_create");
450:
451: vm_page_init(m, paddr);
452: vm_page_release(m);
453: }
454: }
455:
456: /*
457: * vm_page_hash:
458: *
459: * Distributes the object/offset key pair among hash buckets.
460: *
461: * NOTE: To get a good hash function, the bucket count should
462: * be a power of two.
463: */
464: #define vm_page_hash(object, offset) \
465: (((unsigned int)(vm_offset_t)object + (unsigned int)atop(offset)) \
466: & vm_page_hash_mask)
467:
468: /*
469: * vm_page_insert: [ internal use only ]
470: *
471: * Inserts the given mem entry into the object/object-page
472: * table and object list.
473: *
474: * The object and page must be locked.
475: */
476:
477: void vm_page_insert(
478: register vm_page_t mem,
479: register vm_object_t object,
480: register vm_offset_t offset)
481: {
482: register vm_page_bucket_t *bucket;
483:
484: VM_PAGE_CHECK(mem);
485:
486: if (mem->tabled)
487: panic("vm_page_insert");
488:
489: /*
490: * Record the object/offset pair in this page
491: */
492:
493: mem->object = object;
494: mem->offset = offset;
495:
496: /*
497: * Insert it into the object_object/offset hash table
498: */
499:
500: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
501: simple_lock(&bucket->lock);
502: mem->next = bucket->pages;
503: bucket->pages = mem;
504: simple_unlock(&bucket->lock);
505:
506: /*
507: * Now link into the object's list of backed pages.
508: */
509:
510: queue_enter(&object->memq, mem, vm_page_t, listq);
511: mem->tabled = TRUE;
512:
513: /*
514: * Show that the object has one more resident page.
515: */
516:
517: object->resident_page_count++;
518:
519: /*
520: * Detect sequential access and inactivate previous page.
521: * We ignore busy pages.
522: */
523:
524: if (vm_page_deactivate_behind &&
525: (offset == object->last_alloc + PAGE_SIZE)) {
526: vm_page_t last_mem;
527:
528: last_mem = vm_page_lookup(object, object->last_alloc);
529: if ((last_mem != VM_PAGE_NULL) && !last_mem->busy)
530: vm_page_deactivate(last_mem);
531: }
532: object->last_alloc = offset;
533: }
534:
535: /*
536: * vm_page_replace:
537: *
538: * Exactly like vm_page_insert, except that we first
539: * remove any existing page at the given offset in object
540: * and we don't do deactivate-behind.
541: *
542: * The object and page must be locked.
543: */
544:
545: void vm_page_replace(
546: register vm_page_t mem,
547: register vm_object_t object,
548: register vm_offset_t offset)
549: {
550: register vm_page_bucket_t *bucket;
551:
552: VM_PAGE_CHECK(mem);
553:
554: if (mem->tabled)
555: panic("vm_page_replace");
556:
557: /*
558: * Record the object/offset pair in this page
559: */
560:
561: mem->object = object;
562: mem->offset = offset;
563:
564: /*
565: * Insert it into the object_object/offset hash table,
566: * replacing any page that might have been there.
567: */
568:
569: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
570: simple_lock(&bucket->lock);
571: if (bucket->pages) {
572: vm_page_t *mp = &bucket->pages;
573: register vm_page_t m = *mp;
574: do {
575: if (m->object == object && m->offset == offset) {
576: /*
577: * Remove page from bucket and from object,
578: * and return it to the free list.
579: */
580: *mp = m->next;
581: queue_remove(&object->memq, m, vm_page_t,
582: listq);
583: m->tabled = FALSE;
584: object->resident_page_count--;
585:
586: /*
587: * Return page to the free list.
588: * Note the page is not tabled now, so this
589: * won't self-deadlock on the bucket lock.
590: */
591:
592: vm_page_free(m);
593: break;
594: }
595: mp = &m->next;
596: } while ((m = *mp) != 0);
597: mem->next = bucket->pages;
598: } else {
599: mem->next = VM_PAGE_NULL;
600: }
601: bucket->pages = mem;
602: simple_unlock(&bucket->lock);
603:
604: /*
605: * Now link into the object's list of backed pages.
606: */
607:
608: queue_enter(&object->memq, mem, vm_page_t, listq);
609: mem->tabled = TRUE;
610:
611: /*
612: * And show that the object has one more resident
613: * page.
614: */
615:
616: object->resident_page_count++;
617: }
618:
619: /*
620: * vm_page_remove: [ internal use only ]
621: *
622: * Removes the given mem entry from the object/offset-page
623: * table and the object page list.
624: *
625: * The object and page must be locked.
626: */
627:
628: void vm_page_remove(
629: register vm_page_t mem)
630: {
631: register vm_page_bucket_t *bucket;
632: register vm_page_t this;
633:
634: assert(mem->tabled);
635: VM_PAGE_CHECK(mem);
636:
637: /*
638: * Remove from the object_object/offset hash table
639: */
640:
641: bucket = &vm_page_buckets[vm_page_hash(mem->object, mem->offset)];
642: simple_lock(&bucket->lock);
643: if ((this = bucket->pages) == mem) {
644: /* optimize for common case */
645:
646: bucket->pages = mem->next;
647: } else {
648: register vm_page_t *prev;
649:
650: for (prev = &this->next;
651: (this = *prev) != mem;
652: prev = &this->next)
653: continue;
654: *prev = this->next;
655: }
656: simple_unlock(&bucket->lock);
657:
658: /*
659: * Now remove from the object's list of backed pages.
660: */
661:
662: queue_remove(&mem->object->memq, mem, vm_page_t, listq);
663:
664: /*
665: * And show that the object has one fewer resident
666: * page.
667: */
668:
669: mem->object->resident_page_count--;
670:
671: mem->tabled = FALSE;
672: }
673:
674: /*
675: * vm_page_lookup:
676: *
677: * Returns the page associated with the object/offset
678: * pair specified; if none is found, VM_PAGE_NULL is returned.
679: *
680: * The object must be locked. No side effects.
681: */
682:
683: vm_page_t vm_page_lookup(
684: register vm_object_t object,
685: register vm_offset_t offset)
686: {
687: register vm_page_t mem;
688: register vm_page_bucket_t *bucket;
689:
690: /*
691: * Search the hash table for this object/offset pair
692: */
693:
694: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
695:
696: simple_lock(&bucket->lock);
697: for (mem = bucket->pages; mem != VM_PAGE_NULL; mem = mem->next) {
698: VM_PAGE_CHECK(mem);
699: if ((mem->object == object) && (mem->offset == offset))
700: break;
701: }
702: simple_unlock(&bucket->lock);
703: return mem;
704: }
705:
706: /*
707: * vm_page_rename:
708: *
709: * Move the given memory entry from its
710: * current object to the specified target object/offset.
711: *
712: * The object must be locked.
713: */
714: void vm_page_rename(
715: register vm_page_t mem,
716: register vm_object_t new_object,
717: vm_offset_t new_offset)
718: {
719: /*
720: * Changes to mem->object require the page lock because
721: * the pageout daemon uses that lock to get the object.
722: */
723:
724: vm_page_lock_queues();
725: vm_page_remove(mem);
726: vm_page_insert(mem, new_object, new_offset);
727: vm_page_unlock_queues();
728: }
729:
730: /*
731: * vm_page_init:
732: *
733: * Initialize the fields in a new page.
734: * This takes a structure with random values and initializes it
735: * so that it can be given to vm_page_release or vm_page_insert.
736: */
737: void vm_page_init(
738: vm_page_t mem,
739: vm_offset_t phys_addr)
740: {
741: *mem = vm_page_template;
742: mem->phys_addr = phys_addr;
743: }
744:
745: /*
746: * vm_page_grab_fictitious:
747: *
748: * Remove a fictitious page from the free list.
749: * Returns VM_PAGE_NULL if there are no free pages.
750: */
751:
752: vm_page_t vm_page_grab_fictitious(void)
753: {
754: register vm_page_t m;
755:
756: simple_lock(&vm_page_queue_free_lock);
757: m = vm_page_queue_fictitious;
758: if (m != VM_PAGE_NULL) {
759: vm_page_fictitious_count--;
760: vm_page_queue_fictitious = (vm_page_t) m->pageq.next;
761: m->free = FALSE;
762: }
763: simple_unlock(&vm_page_queue_free_lock);
764:
765: return m;
766: }
767:
768: /*
769: * vm_page_release_fictitious:
770: *
771: * Release a fictitious page to the free list.
772: */
773:
774: void vm_page_release_fictitious(
775: register vm_page_t m)
776: {
777: simple_lock(&vm_page_queue_free_lock);
778: if (m->free)
779: panic("vm_page_release_fictitious");
780: m->free = TRUE;
781: m->pageq.next = (queue_entry_t) vm_page_queue_fictitious;
782: vm_page_queue_fictitious = m;
783: vm_page_fictitious_count++;
784: simple_unlock(&vm_page_queue_free_lock);
785: }
786:
787: /*
788: * vm_page_more_fictitious:
789: *
790: * Add more fictitious pages to the free list.
791: * Allowed to block.
792: */
793:
794: int vm_page_fictitious_quantum = 5;
795:
796: void vm_page_more_fictitious(void)
797: {
798: register vm_page_t m;
799: int i;
800:
801: for (i = 0; i < vm_page_fictitious_quantum; i++) {
802: m = (vm_page_t) zalloc(vm_page_zone);
803: if (m == VM_PAGE_NULL)
804: panic("vm_page_more_fictitious");
805:
806: vm_page_init(m, vm_page_fictitious_addr);
807: m->fictitious = TRUE;
808: vm_page_release_fictitious(m);
809: }
810: }
811:
812: /*
813: * vm_page_convert:
814: *
815: * Attempt to convert a fictitious page into a real page.
816: */
817:
818: boolean_t vm_page_convert(
819: register vm_page_t m)
820: {
821: register vm_page_t real_m;
822:
823: real_m = vm_page_grab();
824: if (real_m == VM_PAGE_NULL)
825: return FALSE;
826:
827: m->phys_addr = real_m->phys_addr;
828: m->fictitious = FALSE;
829:
830: real_m->phys_addr = vm_page_fictitious_addr;
831: real_m->fictitious = TRUE;
832:
833: vm_page_release_fictitious(real_m);
834: return TRUE;
835: }
836:
837: /*
838: * vm_page_grab:
839: *
840: * Remove a page from the free list.
841: * Returns VM_PAGE_NULL if the free list is too small.
842: */
843:
844: vm_page_t vm_page_grab(void)
845: {
846: register vm_page_t mem;
847:
848: simple_lock(&vm_page_queue_free_lock);
849:
850: /*
851: * Only let privileged threads (involved in pageout)
852: * dip into the reserved pool.
853: */
854:
855: if ((vm_page_free_count < vm_page_free_reserved) &&
856: !current_thread()->vm_privilege) {
857: simple_unlock(&vm_page_queue_free_lock);
858: return VM_PAGE_NULL;
859: }
860:
861: if (vm_page_queue_free == VM_PAGE_NULL)
862: panic("vm_page_grab");
863:
864: if (--vm_page_free_count < vm_page_free_count_minimum)
865: vm_page_free_count_minimum = vm_page_free_count;
866: mem = vm_page_queue_free;
867: vm_page_queue_free = (vm_page_t) mem->pageq.next;
868: mem->free = FALSE;
869: simple_unlock(&vm_page_queue_free_lock);
870:
871: /*
872: * Decide if we should poke the pageout daemon.
873: * We do this if the free count is less than the low
874: * water mark, or if the free count is less than the high
875: * water mark (but above the low water mark) and the inactive
876: * count is less than its target.
877: *
878: * We don't have the counts locked ... if they change a little,
879: * it doesn't really matter.
880: */
881:
882: if ((vm_page_free_count < vm_page_free_min) ||
883: ((vm_page_free_count < vm_page_free_target) &&
884: (vm_page_inactive_count < vm_page_inactive_target)))
885: thread_wakeup((event_t) &vm_page_free_wanted);
886:
887: return mem;
888: }
889:
890: vm_offset_t vm_page_grab_phys_addr(void)
891: {
892: vm_page_t p = vm_page_grab();
893: if (p == VM_PAGE_NULL)
894: return -1;
895: else
896: return p->phys_addr;
897: }
898:
899: /*
900: * vm_page_grab_contiguous_pages:
901: *
902: * Take N pages off the free list, the pages should
903: * cover a contiguous range of physical addresses.
904: * [Used by device drivers to cope with DMA limitations]
905: *
906: * Returns the page descriptors in ascending order, or
907: * Returns KERN_RESOURCE_SHORTAGE if it could not.
908: */
909:
910: /* Biggest phys page number for the pages we handle in VM */
911:
912: vm_size_t vm_page_big_pagenum = 0; /* Set this before call! */
913:
914: kern_return_t
915: vm_page_grab_contiguous_pages(
916: int npages,
917: vm_page_t pages[],
918: natural_t *bits)
919: {
920: register int first_set;
921: int size, alloc_size;
922: kern_return_t ret;
923: vm_page_t mem, prevmem;
924:
925: #ifndef NBBY
926: #define NBBY 8 /* size in bits of sizeof()`s unity */
927: #endif
928:
929: #define NBPEL (sizeof(natural_t)*NBBY)
930:
931: size = (vm_page_big_pagenum + NBPEL - 1)
932: & ~(NBPEL - 1); /* in bits */
933:
934: size = size / NBBY; /* in bytes */
935:
936: /*
937: * If we are called before the VM system is fully functional
938: * the invoker must provide us with the work space. [one bit
939: * per page starting at phys 0 and up to vm_page_big_pagenum]
940: */
941: if (bits == 0) {
942: alloc_size = round_page(size);
943: if (kmem_alloc_wired(kernel_map,
944: (vm_offset_t *)&bits,
945: alloc_size)
946: != KERN_SUCCESS)
947: return KERN_RESOURCE_SHORTAGE;
948: } else
949: alloc_size = 0;
950:
951: bzero(bits, size);
952:
953: /*
954: * A very large granularity call, its rare so that is ok
955: */
956: simple_lock(&vm_page_queue_free_lock);
957:
958: /*
959: * Do not dip into the reserved pool.
960: */
961:
962: if (vm_page_free_count < vm_page_free_reserved) {
963: simple_unlock(&vm_page_queue_free_lock);
964: return KERN_RESOURCE_SHORTAGE;
965: }
966:
967: /*
968: * First pass through, build a big bit-array of
969: * the pages that are free. It is not going to
970: * be too large anyways, in 4k we can fit info
971: * for 32k pages.
972: */
973: mem = vm_page_queue_free;
974: while (mem) {
975: register int word_index, bit_index;
976:
977: bit_index = (mem->phys_addr >> PAGE_SHIFT);
978: word_index = bit_index / NBPEL;
979: bit_index = bit_index - (word_index * NBPEL);
980: bits[word_index] |= 1 << bit_index;
981:
982: mem = (vm_page_t) mem->pageq.next;
983: }
984:
985: /*
986: * Second loop. Scan the bit array for NPAGES
987: * contiguous bits. That gives us, if any,
988: * the range of pages we will be grabbing off
989: * the free list.
990: */
991: {
992: register int bits_so_far = 0, i;
993:
994: first_set = 0;
995:
996: for (i = 0; i < size; i += sizeof(natural_t)) {
997:
998: register natural_t v = bits[i / sizeof(natural_t)];
999: register int bitpos;
1000:
1001: /*
1002: * Bitscan this one word
1003: */
1004: if (v) {
1005: /*
1006: * keep counting them beans ?
1007: */
1008: bitpos = 0;
1009:
1010: if (bits_so_far) {
1011: count_ones:
1012: while (v & 1) {
1013: bitpos++;
1014: /*
1015: * got enough beans ?
1016: */
1017: if (++bits_so_far == npages)
1018: goto found_em;
1019: v >>= 1;
1020: }
1021: /* if we are being lucky, roll again */
1022: if (bitpos == NBPEL)
1023: continue;
1024: }
1025:
1026: /*
1027: * search for beans here
1028: */
1029: bits_so_far = 0;
1030: count_zeroes:
1031: while ((bitpos < NBPEL) && ((v & 1) == 0)) {
1032: bitpos++;
1033: v >>= 1;
1034: }
1035: if (v & 1) {
1036: first_set = (i * NBBY) + bitpos;
1037: goto count_ones;
1038: }
1039: }
1040: /*
1041: * No luck
1042: */
1043: bits_so_far = 0;
1044: }
1045: }
1046:
1047: /*
1048: * We could not find enough contiguous pages.
1049: */
1050: not_found_em:
1051: simple_unlock(&vm_page_queue_free_lock);
1052:
1053: ret = KERN_RESOURCE_SHORTAGE;
1054: goto out;
1055:
1056: /*
1057: * Final pass. Now we know which pages we want.
1058: * Scan the list until we find them all, grab
1059: * pages as we go. FIRST_SET tells us where
1060: * in the bit-array our pages start.
1061: */
1062: found_em:
1063: vm_page_free_count -= npages;
1064: if (vm_page_free_count < vm_page_free_count_minimum)
1065: vm_page_free_count_minimum = vm_page_free_count;
1066:
1067: {
1068: register vm_offset_t first_phys, last_phys;
1069:
1070: /* cache values for compare */
1071: first_phys = first_set << PAGE_SHIFT;
1072: last_phys = first_phys + (npages << PAGE_SHIFT);/* not included */
1073:
1074: /* running pointers */
1075: mem = vm_page_queue_free;
1076: prevmem = VM_PAGE_NULL;
1077:
1078: while (mem) {
1079:
1080: register vm_offset_t addr;
1081:
1082: addr = mem->phys_addr;
1083:
1084: if ((addr >= first_phys) &&
1085: (addr < last_phys)) {
1086: if (prevmem)
1087: prevmem->pageq.next = mem->pageq.next;
1088: pages[(addr - first_phys) >> PAGE_SHIFT] = mem;
1089: mem->free = FALSE;
1090: /*
1091: * Got them all ?
1092: */
1093: if (--npages == 0) break;
1094: } else
1095: prevmem = mem;
1096:
1097: mem = (vm_page_t) mem->pageq.next;
1098: }
1099: }
1100:
1101: simple_unlock(&vm_page_queue_free_lock);
1102:
1103: /*
1104: * Decide if we should poke the pageout daemon.
1105: * We do this if the free count is less than the low
1106: * water mark, or if the free count is less than the high
1107: * water mark (but above the low water mark) and the inactive
1108: * count is less than its target.
1109: *
1110: * We don't have the counts locked ... if they change a little,
1111: * it doesn't really matter.
1112: */
1113:
1114: if ((vm_page_free_count < vm_page_free_min) ||
1115: ((vm_page_free_count < vm_page_free_target) &&
1116: (vm_page_inactive_count < vm_page_inactive_target)))
1117: thread_wakeup(&vm_page_free_wanted);
1118:
1119: ret = KERN_SUCCESS;
1120: out:
1121: if (alloc_size)
1122: kmem_free(kernel_map, (vm_offset_t) bits, alloc_size);
1123:
1124: return ret;
1125: }
1126:
1127: /*
1128: * vm_page_release:
1129: *
1130: * Return a page to the free list.
1131: */
1132:
1133: void vm_page_release(
1134: register vm_page_t mem)
1135: {
1136: simple_lock(&vm_page_queue_free_lock);
1137: if (mem->free)
1138: panic("vm_page_release");
1139: mem->free = TRUE;
1140: mem->pageq.next = (queue_entry_t) vm_page_queue_free;
1141: vm_page_queue_free = mem;
1142: vm_page_free_count++;
1143:
1144: /*
1145: * Check if we should wake up someone waiting for page.
1146: * But don't bother waking them unless they can allocate.
1147: *
1148: * We wakeup only one thread, to prevent starvation.
1149: * Because the scheduling system handles wait queues FIFO,
1150: * if we wakeup all waiting threads, one greedy thread
1151: * can starve multiple niceguy threads. When the threads
1152: * all wakeup, the greedy threads runs first, grabs the page,
1153: * and waits for another page. It will be the first to run
1154: * when the next page is freed.
1155: *
1156: * However, there is a slight danger here.
1157: * The thread we wake might not use the free page.
1158: * Then the other threads could wait indefinitely
1159: * while the page goes unused. To forestall this,
1160: * the pageout daemon will keep making free pages
1161: * as long as vm_page_free_wanted is non-zero.
1162: */
1163:
1164: if ((vm_page_free_wanted > 0) &&
1165: (vm_page_free_count >= vm_page_free_reserved)) {
1166: vm_page_free_wanted--;
1167: thread_wakeup_one((event_t) &vm_page_free_count);
1168: }
1169:
1170: simple_unlock(&vm_page_queue_free_lock);
1171: }
1172:
1173: /*
1174: * vm_page_wait:
1175: *
1176: * Wait for a page to become available.
1177: * If there are plenty of free pages, then we don't sleep.
1178: */
1179:
1180: void vm_page_wait(
1181: void (*continuation)(void))
1182: {
1183:
1184: #ifndef CONTINUATIONS
1185: assert (continuation == 0);
1186: #endif
1187:
1188: /*
1189: * We can't use vm_page_free_reserved to make this
1190: * determination. Consider: some thread might
1191: * need to allocate two pages. The first allocation
1192: * succeeds, the second fails. After the first page is freed,
1193: * a call to vm_page_wait must really block.
1194: */
1195:
1196: simple_lock(&vm_page_queue_free_lock);
1197: if (vm_page_free_count < vm_page_free_target) {
1198: if (vm_page_free_wanted++ == 0)
1199: thread_wakeup((event_t)&vm_page_free_wanted);
1200: assert_wait((event_t)&vm_page_free_count, FALSE);
1201: simple_unlock(&vm_page_queue_free_lock);
1202: if (continuation != 0) {
1203: counter(c_vm_page_wait_block_user++);
1204: thread_block(continuation);
1205: } else {
1206: counter(c_vm_page_wait_block_kernel++);
1207: thread_block((void (*)(void)) 0);
1208: }
1209: } else
1210: simple_unlock(&vm_page_queue_free_lock);
1211: }
1212:
1213: /*
1214: * vm_page_alloc:
1215: *
1216: * Allocate and return a memory cell associated
1217: * with this VM object/offset pair.
1218: *
1219: * Object must be locked.
1220: */
1221:
1222: vm_page_t vm_page_alloc(
1223: vm_object_t object,
1224: vm_offset_t offset)
1225: {
1226: register vm_page_t mem;
1227:
1228: mem = vm_page_grab();
1229: if (mem == VM_PAGE_NULL)
1230: return VM_PAGE_NULL;
1231:
1232: vm_page_lock_queues();
1233: vm_page_insert(mem, object, offset);
1234: vm_page_unlock_queues();
1235:
1236: return mem;
1237: }
1238:
1239: /*
1240: * vm_page_free:
1241: *
1242: * Returns the given page to the free list,
1243: * disassociating it with any VM object.
1244: *
1245: * Object and page queues must be locked prior to entry.
1246: */
1247: void vm_page_free(
1248: register vm_page_t mem)
1249: {
1250: if (mem->free)
1251: panic("vm_page_free");
1252:
1253: if (mem->tabled)
1254: vm_page_remove(mem);
1255: VM_PAGE_QUEUES_REMOVE(mem);
1256:
1257: if (mem->wire_count != 0) {
1258: if (!mem->private && !mem->fictitious)
1259: vm_page_wire_count--;
1260: mem->wire_count = 0;
1261: }
1262:
1263: if (mem->laundry) {
1264: vm_page_laundry_count--;
1265: mem->laundry = FALSE;
1266: }
1267:
1268: PAGE_WAKEUP_DONE(mem);
1269:
1270: if (mem->absent)
1271: vm_object_absent_release(mem->object);
1272:
1273: /*
1274: * XXX The calls to vm_page_init here are
1275: * really overkill.
1276: */
1277:
1278: if (mem->private || mem->fictitious) {
1279: vm_page_init(mem, vm_page_fictitious_addr);
1280: mem->fictitious = TRUE;
1281: vm_page_release_fictitious(mem);
1282: } else {
1283: vm_page_init(mem, mem->phys_addr);
1284: vm_page_release(mem);
1285: }
1286: }
1287:
1288: /*
1289: * vm_page_wire:
1290: *
1291: * Mark this page as wired down by yet
1292: * another map, removing it from paging queues
1293: * as necessary.
1294: *
1295: * The page's object and the page queues must be locked.
1296: */
1297: void vm_page_wire(
1298: register vm_page_t mem)
1299: {
1300: VM_PAGE_CHECK(mem);
1301:
1302: if (mem->wire_count == 0) {
1303: VM_PAGE_QUEUES_REMOVE(mem);
1304: if (!mem->private && !mem->fictitious)
1305: vm_page_wire_count++;
1306: }
1307: mem->wire_count++;
1308: }
1309:
1310: /*
1311: * vm_page_unwire:
1312: *
1313: * Release one wiring of this page, potentially
1314: * enabling it to be paged again.
1315: *
1316: * The page's object and the page queues must be locked.
1317: */
1318: void vm_page_unwire(
1319: register vm_page_t mem)
1320: {
1321: VM_PAGE_CHECK(mem);
1322:
1323: if (--mem->wire_count == 0) {
1324: queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq);
1325: vm_page_active_count++;
1326: mem->active = TRUE;
1327: if (!mem->private && !mem->fictitious)
1328: vm_page_wire_count--;
1329: }
1330: }
1331:
1332: /*
1333: * vm_page_deactivate:
1334: *
1335: * Returns the given page to the inactive list,
1336: * indicating that no physical maps have access
1337: * to this page. [Used by the physical mapping system.]
1338: *
1339: * The page queues must be locked.
1340: */
1341: void vm_page_deactivate(
1342: register vm_page_t m)
1343: {
1344: VM_PAGE_CHECK(m);
1345:
1346: /*
1347: * This page is no longer very interesting. If it was
1348: * interesting (active or inactive/referenced), then we
1349: * clear the reference bit and (re)enter it in the
1350: * inactive queue. Note wired pages should not have
1351: * their reference bit cleared.
1352: */
1353:
1354: if (m->active || (m->inactive && m->reference)) {
1355: if (!m->fictitious && !m->absent)
1356: pmap_clear_reference(m->phys_addr);
1357: m->reference = FALSE;
1358: VM_PAGE_QUEUES_REMOVE(m);
1359: }
1360: if (m->wire_count == 0 && !m->inactive) {
1361: queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
1362: m->inactive = TRUE;
1363: vm_page_inactive_count++;
1364: }
1365: }
1366:
1367: /*
1368: * vm_page_activate:
1369: *
1370: * Put the specified page on the active list (if appropriate).
1371: *
1372: * The page queues must be locked.
1373: */
1374:
1375: void vm_page_activate(
1376: register vm_page_t m)
1377: {
1378: VM_PAGE_CHECK(m);
1379:
1380: if (m->inactive) {
1381: queue_remove(&vm_page_queue_inactive, m, vm_page_t,
1382: pageq);
1383: vm_page_inactive_count--;
1384: m->inactive = FALSE;
1385: }
1386: if (m->wire_count == 0) {
1387: if (m->active)
1388: panic("vm_page_activate: already active");
1389:
1390: queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
1391: m->active = TRUE;
1392: vm_page_active_count++;
1393: }
1394: }
1395:
1396: /*
1397: * vm_page_zero_fill:
1398: *
1399: * Zero-fill the specified page.
1400: */
1401: void vm_page_zero_fill(
1402: vm_page_t m)
1403: {
1404: VM_PAGE_CHECK(m);
1405:
1406: pmap_zero_page(m->phys_addr);
1407: }
1408:
1409: /*
1410: * vm_page_copy:
1411: *
1412: * Copy one page to another
1413: */
1414:
1415: void vm_page_copy(
1416: vm_page_t src_m,
1417: vm_page_t dest_m)
1418: {
1419: VM_PAGE_CHECK(src_m);
1420: VM_PAGE_CHECK(dest_m);
1421:
1422: pmap_copy_page(src_m->phys_addr, dest_m->phys_addr);
1423: }
1424:
1425: #if MACH_VM_DEBUG
1426: /*
1427: * Routine: vm_page_info
1428: * Purpose:
1429: * Return information about the global VP table.
1430: * Fills the buffer with as much information as possible
1431: * and returns the desired size of the buffer.
1432: * Conditions:
1433: * Nothing locked. The caller should provide
1434: * possibly-pageable memory.
1435: */
1436:
1437: unsigned int
1438: vm_page_info(
1439: hash_info_bucket_t *info,
1440: unsigned int count)
1441: {
1442: int i;
1443:
1444: if (vm_page_bucket_count < count)
1445: count = vm_page_bucket_count;
1446:
1447: for (i = 0; i < count; i++) {
1448: vm_page_bucket_t *bucket = &vm_page_buckets[i];
1449: unsigned int bucket_count = 0;
1450: vm_page_t m;
1451:
1452: simple_lock(&bucket->lock);
1453: for (m = bucket->pages; m != VM_PAGE_NULL; m = m->next)
1454: bucket_count++;
1455: simple_unlock(&bucket->lock);
1456:
1457: /* don't touch pageable memory while holding locks */
1458: info[i].hib_count = bucket_count;
1459: }
1460:
1461: return vm_page_bucket_count;
1462: }
1463: #endif /* MACH_VM_DEBUG */
1464:
1465: #include <mach_kdb.h>
1466: #if MACH_KDB
1467: #define printf kdbprintf
1468:
1469: /*
1470: * Routine: vm_page_print [exported]
1471: */
1472: void vm_page_print(p)
1473: vm_page_t p;
1474: {
1475: iprintf("Page 0x%X: object 0x%X,", (vm_offset_t) p, (vm_offset_t) p->object);
1476: printf(" offset 0x%X", (vm_offset_t) p->offset);
1477: printf("wire_count %d,", p->wire_count);
1478: printf(" %s",
1479: (p->active ? "active" : (p->inactive ? "inactive" : "loose")));
1480: printf("%s",
1481: (p->free ? " free" : ""));
1482: printf("%s ",
1483: (p->laundry ? " laundry" : ""));
1484: printf("%s",
1485: (p->dirty ? "dirty" : "clean"));
1486: printf("%s",
1487: (p->busy ? " busy" : ""));
1488: printf("%s",
1489: (p->absent ? " absent" : ""));
1490: printf("%s",
1491: (p->error ? " error" : ""));
1492: printf("%s",
1493: (p->fictitious ? " fictitious" : ""));
1494: printf("%s",
1495: (p->private ? " private" : ""));
1496: printf("%s",
1497: (p->wanted ? " wanted" : ""));
1498: printf("%s,",
1499: (p->tabled ? "" : "not_tabled"));
1500: printf("phys_addr = 0x%X, lock = 0x%X, unlock_request = 0x%X\n",
1501: (vm_offset_t) p->phys_addr,
1502: (vm_offset_t) p->page_lock,
1503: (vm_offset_t) p->unlock_request);
1504: }
1505: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.