|
|
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: /*
1.1.1.4 root 30: * File: vm/vm_resident.c
1.1 root 31: * Author: Avadis Tevanian, Jr., Michael Wayne Young
32: *
33: * Resident memory management module.
34: */
1.1.1.3 root 35:
36: #include <kern/printf.h>
37: #include <string.h>
1.1 root 38:
39: #include <mach/vm_prot.h>
40: #include <kern/counters.h>
1.1.1.3 root 41: #include <kern/debug.h>
1.1.1.6 ! root 42: #include <kern/list.h>
1.1 root 43: #include <kern/sched_prim.h>
44: #include <kern/task.h>
45: #include <kern/thread.h>
46: #include <mach/vm_statistics.h>
1.1.1.3 root 47: #include <machine/vm_param.h>
1.1 root 48: #include <kern/xpr.h>
1.1.1.3 root 49: #include <kern/slab.h>
1.1 root 50: #include <vm/pmap.h>
51: #include <vm/vm_map.h>
52: #include <vm/vm_page.h>
53: #include <vm/vm_pageout.h>
54: #include <vm/vm_kern.h>
55:
56: #if MACH_VM_DEBUG
57: #include <mach/kern_return.h>
58: #include <mach_debug/hash_info.h>
59: #include <vm/vm_user.h>
60: #endif
61:
1.1.1.3 root 62: #if MACH_KDB
63: #include <ddb/db_output.h>
64: #include <vm/vm_print.h>
65: #endif /* MACH_KDB */
66:
1.1 root 67:
68: /*
1.1.1.4 root 69: * Associated with each page of user-allocatable memory is a
1.1 root 70: * page structure.
71: */
72:
73: /*
74: * These variables record the values returned by vm_page_bootstrap,
75: * for debugging purposes. The implementation of pmap_steal_memory
1.1.1.5 root 76: * here also uses them internally.
1.1 root 77: */
78:
79: vm_offset_t virtual_space_start;
80: vm_offset_t virtual_space_end;
81:
82: /*
83: * The vm_page_lookup() routine, which provides for fast
84: * (virtual memory object, offset) to page lookup, employs
85: * the following hash table. The vm_page_{insert,remove}
86: * routines install and remove associations in the table.
87: * [This table is often called the virtual-to-physical,
88: * or VP, table.]
89: */
90: typedef struct {
91: decl_simple_lock_data(,lock)
92: vm_page_t pages;
93: } vm_page_bucket_t;
94:
95: vm_page_bucket_t *vm_page_buckets; /* Array of buckets */
1.1.1.6 ! root 96: unsigned long vm_page_bucket_count = 0; /* How big is array? */
! 97: unsigned long vm_page_hash_mask; /* Mask for hash function */
1.1 root 98:
1.1.1.6 ! root 99: static struct list vm_page_queue_fictitious;
1.1 root 100: decl_simple_lock_data(,vm_page_queue_free_lock)
101: int vm_page_fictitious_count;
1.1.1.6 ! root 102: int vm_object_external_count;
! 103: int vm_object_external_pages;
1.1 root 104:
105: /*
106: * Occasionally, the virtual memory system uses
107: * resident page structures that do not refer to
108: * real pages, for example to leave a page with
109: * important state information in the VP table.
110: *
111: * These page structures are allocated the way
112: * most other kernel structures are.
113: */
1.1.1.3 root 114: struct kmem_cache vm_page_cache;
1.1 root 115:
116: /*
117: * Fictitious pages don't have a physical address,
118: * but we must initialize phys_addr to something.
119: * For debugging, this should be a strange value
120: * that the pmap module can recognize in assertions.
121: */
1.1.1.6 ! root 122: phys_addr_t vm_page_fictitious_addr = (phys_addr_t) -1;
1.1 root 123:
124: /*
125: * Resident page structures are also chained on
126: * queues that are used by the page replacement
127: * system (pageout daemon). These queues are
128: * defined here, but are shared by the pageout
129: * module.
130: */
131: decl_simple_lock_data(,vm_page_queue_lock)
132: int vm_page_active_count;
133: int vm_page_inactive_count;
134: int vm_page_wire_count;
135:
136: /*
137: * Several page replacement parameters are also
138: * shared with this module, so that page allocation
139: * (done here in vm_page_alloc) can trigger the
140: * pageout daemon.
141: */
142: int vm_page_laundry_count = 0;
1.1.1.6 ! root 143: int vm_page_external_laundry_count = 0;
1.1.1.2 root 144:
1.1 root 145:
146: /*
147: * The VM system has a couple of heuristics for deciding
148: * that pages are "uninteresting" and should be placed
149: * on the inactive queue as likely candidates for replacement.
150: * These variables let the heuristics be controlled at run-time
151: * to make experimentation easier.
152: */
153:
154: boolean_t vm_page_deactivate_behind = TRUE;
155: boolean_t vm_page_deactivate_hint = TRUE;
156:
157: /*
158: * vm_page_bootstrap:
159: *
160: * Initializes the resident memory module.
161: *
162: * Allocates memory for the page cells, and
163: * for the object/offset-to-page hash table headers.
164: * Each page cell is initialized and placed on the free list.
165: * Returns the range of available kernel virtual memory.
166: */
167:
168: void vm_page_bootstrap(
169: vm_offset_t *startp,
170: vm_offset_t *endp)
171: {
172: int i;
173:
174: /*
175: * Initialize the page queues.
176: */
177:
178: simple_lock_init(&vm_page_queue_free_lock);
179: simple_lock_init(&vm_page_queue_lock);
180:
1.1.1.6 ! root 181: list_init(&vm_page_queue_fictitious);
1.1 root 182:
183: /*
184: * Allocate (and initialize) the virtual-to-physical
185: * table hash buckets.
186: *
187: * The number of buckets should be a power of two to
188: * get a good hash function. The following computation
189: * chooses the first power of two that is greater
190: * than the number of physical pages in the system.
191: */
192:
193: if (vm_page_bucket_count == 0) {
1.1.1.6 ! root 194: unsigned long npages = vm_page_table_size();
1.1 root 195:
196: vm_page_bucket_count = 1;
197: while (vm_page_bucket_count < npages)
198: vm_page_bucket_count <<= 1;
199: }
200:
201: vm_page_hash_mask = vm_page_bucket_count - 1;
202:
203: if (vm_page_hash_mask & vm_page_bucket_count)
204: printf("vm_page_bootstrap: WARNING -- strange page hash\n");
205:
206: vm_page_buckets = (vm_page_bucket_t *)
207: pmap_steal_memory(vm_page_bucket_count *
208: sizeof(vm_page_bucket_t));
209:
210: for (i = 0; i < vm_page_bucket_count; i++) {
1.1.1.4 root 211: vm_page_bucket_t *bucket = &vm_page_buckets[i];
1.1 root 212:
213: bucket->pages = VM_PAGE_NULL;
214: simple_lock_init(&bucket->lock);
215: }
216:
1.1.1.5 root 217: vm_page_setup();
1.1 root 218:
219: virtual_space_start = round_page(virtual_space_start);
220: virtual_space_end = trunc_page(virtual_space_end);
221:
222: *startp = virtual_space_start;
223: *endp = virtual_space_end;
224: }
225:
226: #ifndef MACHINE_PAGES
227: /*
1.1.1.5 root 228: * We implement pmap_steal_memory with the help
229: * of two simpler functions, pmap_virtual_space and vm_page_bootalloc.
1.1 root 230: */
231:
232: vm_offset_t pmap_steal_memory(
233: vm_size_t size)
234: {
235: vm_offset_t addr, vaddr, paddr;
236:
1.1.1.5 root 237: size = round_page(size);
1.1 root 238:
239: /*
240: * If this is the first call to pmap_steal_memory,
241: * we have to initialize ourself.
242: */
243:
244: if (virtual_space_start == virtual_space_end) {
245: pmap_virtual_space(&virtual_space_start, &virtual_space_end);
246:
247: /*
248: * The initial values must be aligned properly, and
249: * we don't trust the pmap module to do it right.
250: */
251:
252: virtual_space_start = round_page(virtual_space_start);
253: virtual_space_end = trunc_page(virtual_space_end);
254: }
255:
256: /*
257: * Allocate virtual memory for this request.
258: */
259:
260: addr = virtual_space_start;
261: virtual_space_start += size;
262:
263: /*
264: * Allocate and map physical pages to back new virtual pages.
265: */
266:
267: for (vaddr = round_page(addr);
268: vaddr < addr + size;
269: vaddr += PAGE_SIZE) {
1.1.1.5 root 270: paddr = vm_page_bootalloc(PAGE_SIZE);
1.1 root 271:
272: /*
273: * XXX Logically, these mappings should be wired,
274: * but some pmap modules barf if they are.
275: */
276:
277: pmap_enter(kernel_pmap, vaddr, paddr,
278: VM_PROT_READ|VM_PROT_WRITE, FALSE);
279: }
280:
281: return addr;
282: }
283: #endif /* MACHINE_PAGES */
284:
285: /*
286: * Routine: vm_page_module_init
287: * Purpose:
288: * Second initialization pass, to be done after
289: * the basic VM system is ready.
290: */
291: void vm_page_module_init(void)
292: {
1.1.1.3 root 293: kmem_cache_init(&vm_page_cache, "vm_page", sizeof(struct vm_page), 0,
1.1.1.5 root 294: NULL, 0);
1.1 root 295: }
296:
297: /*
298: * vm_page_hash:
299: *
300: * Distributes the object/offset key pair among hash buckets.
301: *
302: * NOTE: To get a good hash function, the bucket count should
303: * be a power of two.
304: */
305: #define vm_page_hash(object, offset) \
306: (((unsigned int)(vm_offset_t)object + (unsigned int)atop(offset)) \
307: & vm_page_hash_mask)
308:
309: /*
310: * vm_page_insert: [ internal use only ]
311: *
312: * Inserts the given mem entry into the object/object-page
313: * table and object list.
314: *
315: * The object and page must be locked.
1.1.1.6 ! root 316: * The free page queue must not be locked.
1.1 root 317: */
318:
319: void vm_page_insert(
1.1.1.4 root 320: vm_page_t mem,
321: vm_object_t object,
322: vm_offset_t offset)
1.1 root 323: {
1.1.1.4 root 324: vm_page_bucket_t *bucket;
1.1 root 325:
326: VM_PAGE_CHECK(mem);
327:
1.1.1.6 ! root 328: assert(!mem->active && !mem->inactive);
! 329: assert(!mem->external);
! 330:
! 331: if (!object->internal) {
! 332: mem->external = TRUE;
! 333: vm_object_external_pages++;
! 334: }
! 335:
1.1 root 336: if (mem->tabled)
337: panic("vm_page_insert");
338:
339: /*
340: * Record the object/offset pair in this page
341: */
342:
343: mem->object = object;
344: mem->offset = offset;
345:
346: /*
347: * Insert it into the object_object/offset hash table
348: */
349:
350: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
351: simple_lock(&bucket->lock);
352: mem->next = bucket->pages;
353: bucket->pages = mem;
354: simple_unlock(&bucket->lock);
355:
356: /*
357: * Now link into the object's list of backed pages.
358: */
359:
360: queue_enter(&object->memq, mem, vm_page_t, listq);
361: mem->tabled = TRUE;
362:
363: /*
364: * Show that the object has one more resident page.
365: */
366:
367: object->resident_page_count++;
1.1.1.5 root 368: assert(object->resident_page_count != 0);
1.1.1.3 root 369:
1.1 root 370: /*
371: * Detect sequential access and inactivate previous page.
372: * We ignore busy pages.
373: */
374:
375: if (vm_page_deactivate_behind &&
376: (offset == object->last_alloc + PAGE_SIZE)) {
377: vm_page_t last_mem;
378:
379: last_mem = vm_page_lookup(object, object->last_alloc);
380: if ((last_mem != VM_PAGE_NULL) && !last_mem->busy)
381: vm_page_deactivate(last_mem);
382: }
383: object->last_alloc = offset;
384: }
385:
386: /*
387: * vm_page_replace:
388: *
389: * Exactly like vm_page_insert, except that we first
390: * remove any existing page at the given offset in object
391: * and we don't do deactivate-behind.
392: *
393: * The object and page must be locked.
1.1.1.6 ! root 394: * The free page queue must not be locked.
1.1 root 395: */
396:
397: void vm_page_replace(
1.1.1.4 root 398: vm_page_t mem,
399: vm_object_t object,
400: vm_offset_t offset)
1.1 root 401: {
1.1.1.4 root 402: vm_page_bucket_t *bucket;
1.1 root 403:
404: VM_PAGE_CHECK(mem);
405:
1.1.1.6 ! root 406: assert(!mem->active && !mem->inactive);
! 407: assert(!mem->external);
! 408:
! 409: if (!object->internal) {
! 410: mem->external = TRUE;
! 411: vm_object_external_pages++;
! 412: }
! 413:
1.1 root 414: if (mem->tabled)
415: panic("vm_page_replace");
416:
417: /*
418: * Record the object/offset pair in this page
419: */
420:
421: mem->object = object;
422: mem->offset = offset;
423:
424: /*
425: * Insert it into the object_object/offset hash table,
426: * replacing any page that might have been there.
427: */
428:
429: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
430: simple_lock(&bucket->lock);
431: if (bucket->pages) {
432: vm_page_t *mp = &bucket->pages;
1.1.1.4 root 433: vm_page_t m = *mp;
1.1 root 434: do {
435: if (m->object == object && m->offset == offset) {
436: /*
437: * Remove page from bucket and from object,
438: * and return it to the free list.
439: */
440: *mp = m->next;
441: queue_remove(&object->memq, m, vm_page_t,
442: listq);
443: m->tabled = FALSE;
444: object->resident_page_count--;
1.1.1.6 ! root 445: VM_PAGE_QUEUES_REMOVE(m);
1.1 root 446:
1.1.1.6 ! root 447: if (m->external) {
! 448: m->external = FALSE;
! 449: vm_object_external_pages--;
! 450: }
1.1.1.3 root 451:
1.1 root 452: /*
453: * Return page to the free list.
454: * Note the page is not tabled now, so this
455: * won't self-deadlock on the bucket lock.
456: */
457:
458: vm_page_free(m);
459: break;
460: }
461: mp = &m->next;
462: } while ((m = *mp) != 0);
463: mem->next = bucket->pages;
464: } else {
465: mem->next = VM_PAGE_NULL;
466: }
467: bucket->pages = mem;
468: simple_unlock(&bucket->lock);
469:
470: /*
471: * Now link into the object's list of backed pages.
472: */
473:
474: queue_enter(&object->memq, mem, vm_page_t, listq);
475: mem->tabled = TRUE;
476:
477: /*
478: * And show that the object has one more resident
479: * page.
480: */
481:
482: object->resident_page_count++;
1.1.1.5 root 483: assert(object->resident_page_count != 0);
1.1 root 484: }
485:
486: /*
487: * vm_page_remove: [ internal use only ]
488: *
489: * Removes the given mem entry from the object/offset-page
1.1.1.6 ! root 490: * table, the object page list, and the page queues.
1.1 root 491: *
492: * The object and page must be locked.
1.1.1.6 ! root 493: * The free page queue must not be locked.
1.1 root 494: */
495:
496: void vm_page_remove(
1.1.1.4 root 497: vm_page_t mem)
1.1 root 498: {
1.1.1.4 root 499: vm_page_bucket_t *bucket;
500: vm_page_t this;
1.1 root 501:
502: assert(mem->tabled);
503: VM_PAGE_CHECK(mem);
504:
505: /*
506: * Remove from the object_object/offset hash table
507: */
508:
509: bucket = &vm_page_buckets[vm_page_hash(mem->object, mem->offset)];
510: simple_lock(&bucket->lock);
511: if ((this = bucket->pages) == mem) {
512: /* optimize for common case */
513:
514: bucket->pages = mem->next;
515: } else {
1.1.1.4 root 516: vm_page_t *prev;
1.1 root 517:
518: for (prev = &this->next;
519: (this = *prev) != mem;
520: prev = &this->next)
521: continue;
522: *prev = this->next;
523: }
524: simple_unlock(&bucket->lock);
525:
526: /*
527: * Now remove from the object's list of backed pages.
528: */
529:
530: queue_remove(&mem->object->memq, mem, vm_page_t, listq);
531:
532: /*
533: * And show that the object has one fewer resident
534: * page.
535: */
536:
537: mem->object->resident_page_count--;
538:
539: mem->tabled = FALSE;
1.1.1.3 root 540:
1.1.1.6 ! root 541: VM_PAGE_QUEUES_REMOVE(mem);
! 542:
! 543: if (mem->external) {
! 544: mem->external = FALSE;
! 545: vm_object_external_pages--;
! 546: }
1.1 root 547: }
548:
549: /*
550: * vm_page_lookup:
551: *
552: * Returns the page associated with the object/offset
553: * pair specified; if none is found, VM_PAGE_NULL is returned.
554: *
555: * The object must be locked. No side effects.
556: */
557:
558: vm_page_t vm_page_lookup(
1.1.1.4 root 559: vm_object_t object,
560: vm_offset_t offset)
1.1 root 561: {
1.1.1.4 root 562: vm_page_t mem;
563: vm_page_bucket_t *bucket;
1.1 root 564:
565: /*
566: * Search the hash table for this object/offset pair
567: */
568:
569: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
570:
571: simple_lock(&bucket->lock);
572: for (mem = bucket->pages; mem != VM_PAGE_NULL; mem = mem->next) {
573: VM_PAGE_CHECK(mem);
574: if ((mem->object == object) && (mem->offset == offset))
575: break;
576: }
577: simple_unlock(&bucket->lock);
578: return mem;
579: }
580:
581: /*
582: * vm_page_rename:
583: *
584: * Move the given memory entry from its
585: * current object to the specified target object/offset.
586: *
587: * The object must be locked.
588: */
589: void vm_page_rename(
1.1.1.4 root 590: vm_page_t mem,
591: vm_object_t new_object,
592: vm_offset_t new_offset)
1.1 root 593: {
594: /*
595: * Changes to mem->object require the page lock because
596: * the pageout daemon uses that lock to get the object.
597: */
598:
599: vm_page_lock_queues();
600: vm_page_remove(mem);
601: vm_page_insert(mem, new_object, new_offset);
602: vm_page_unlock_queues();
603: }
604:
1.1.1.5 root 605: static void vm_page_init_template(vm_page_t m)
606: {
607: m->object = VM_OBJECT_NULL; /* reset later */
608: m->offset = 0; /* reset later */
609: m->wire_count = 0;
610:
611: m->inactive = FALSE;
612: m->active = FALSE;
613: m->laundry = FALSE;
1.1.1.6 ! root 614: m->external_laundry = FALSE;
1.1.1.5 root 615: m->free = FALSE;
616: m->external = FALSE;
617:
618: m->busy = TRUE;
619: m->wanted = FALSE;
620: m->tabled = FALSE;
621: m->fictitious = FALSE;
622: m->private = FALSE;
623: m->absent = FALSE;
624: m->error = FALSE;
625: m->dirty = FALSE;
626: m->precious = FALSE;
627: m->reference = FALSE;
628:
629: m->page_lock = VM_PROT_NONE;
630: m->unlock_request = VM_PROT_NONE;
631: }
632:
1.1 root 633: /*
634: * vm_page_init:
635: *
636: * Initialize the fields in a new page.
637: * This takes a structure with random values and initializes it
638: * so that it can be given to vm_page_release or vm_page_insert.
639: */
640: void vm_page_init(
1.1.1.5 root 641: vm_page_t mem)
1.1 root 642: {
1.1.1.5 root 643: vm_page_init_template(mem);
1.1 root 644: }
645:
646: /*
647: * vm_page_grab_fictitious:
648: *
649: * Remove a fictitious page from the free list.
650: * Returns VM_PAGE_NULL if there are no free pages.
651: */
652:
653: vm_page_t vm_page_grab_fictitious(void)
654: {
1.1.1.4 root 655: vm_page_t m;
1.1 root 656:
657: simple_lock(&vm_page_queue_free_lock);
1.1.1.6 ! root 658: if (list_empty(&vm_page_queue_fictitious)) {
! 659: m = VM_PAGE_NULL;
! 660: } else {
! 661: m = list_first_entry(&vm_page_queue_fictitious,
! 662: struct vm_page, node);
! 663: assert(m->fictitious);
! 664: list_remove(&m->node);
1.1 root 665: m->free = FALSE;
1.1.1.6 ! root 666: vm_page_fictitious_count--;
1.1 root 667: }
668: simple_unlock(&vm_page_queue_free_lock);
669:
670: return m;
671: }
672:
673: /*
674: * vm_page_release_fictitious:
675: *
676: * Release a fictitious page to the free list.
677: */
678:
1.1.1.5 root 679: static void vm_page_release_fictitious(
1.1.1.4 root 680: vm_page_t m)
1.1 root 681: {
682: simple_lock(&vm_page_queue_free_lock);
683: if (m->free)
684: panic("vm_page_release_fictitious");
685: m->free = TRUE;
1.1.1.6 ! root 686: list_insert_head(&vm_page_queue_fictitious, &m->node);
1.1 root 687: vm_page_fictitious_count++;
688: simple_unlock(&vm_page_queue_free_lock);
689: }
690:
691: /*
692: * vm_page_more_fictitious:
693: *
694: * Add more fictitious pages to the free list.
695: * Allowed to block.
696: */
697:
698: int vm_page_fictitious_quantum = 5;
699:
700: void vm_page_more_fictitious(void)
701: {
1.1.1.4 root 702: vm_page_t m;
1.1 root 703: int i;
704:
705: for (i = 0; i < vm_page_fictitious_quantum; i++) {
1.1.1.3 root 706: m = (vm_page_t) kmem_cache_alloc(&vm_page_cache);
1.1 root 707: if (m == VM_PAGE_NULL)
708: panic("vm_page_more_fictitious");
709:
1.1.1.5 root 710: vm_page_init(m);
711: m->phys_addr = vm_page_fictitious_addr;
1.1 root 712: m->fictitious = TRUE;
713: vm_page_release_fictitious(m);
714: }
715: }
716:
717: /*
718: * vm_page_convert:
719: *
720: * Attempt to convert a fictitious page into a real page.
1.1.1.5 root 721: *
722: * The object referenced by *MP must be locked.
1.1 root 723: */
724:
1.1.1.6 ! root 725: boolean_t vm_page_convert(struct vm_page **mp)
1.1 root 726: {
1.1.1.5 root 727: struct vm_page *real_m, *fict_m;
728: vm_object_t object;
729: vm_offset_t offset;
730:
731: fict_m = *mp;
732:
733: assert(fict_m->fictitious);
734: assert(fict_m->phys_addr == vm_page_fictitious_addr);
735: assert(!fict_m->active);
736: assert(!fict_m->inactive);
1.1 root 737:
1.1.1.6 ! root 738: real_m = vm_page_grab();
1.1 root 739: if (real_m == VM_PAGE_NULL)
740: return FALSE;
741:
1.1.1.5 root 742: object = fict_m->object;
743: offset = fict_m->offset;
744: vm_page_remove(fict_m);
745:
746: memcpy(&real_m->vm_page_header,
747: &fict_m->vm_page_header,
748: sizeof(*fict_m) - VM_PAGE_HEADER_SIZE);
749: real_m->fictitious = FALSE;
750:
751: vm_page_insert(real_m, object, offset);
752:
753: assert(real_m->phys_addr != vm_page_fictitious_addr);
754: assert(fict_m->fictitious);
755: assert(fict_m->phys_addr == vm_page_fictitious_addr);
1.1 root 756:
1.1.1.5 root 757: vm_page_release_fictitious(fict_m);
758: *mp = real_m;
1.1 root 759: return TRUE;
760: }
761:
762: /*
763: * vm_page_grab:
764: *
765: * Remove a page from the free list.
766: * Returns VM_PAGE_NULL if the free list is too small.
767: */
768:
1.1.1.6 ! root 769: vm_page_t vm_page_grab(void)
1.1 root 770: {
1.1.1.4 root 771: vm_page_t mem;
1.1 root 772:
773: simple_lock(&vm_page_queue_free_lock);
774:
775: /*
1.1.1.6 ! root 776: * XXX Mach has many modules that merely assume memory is
! 777: * directly mapped in kernel space. Instead of updating all
! 778: * users, we assume those which need specific physical memory
! 779: * properties will wire down their pages, either because
! 780: * they can't be paged (not part of an object), or with
! 781: * explicit VM calls. The strategy is then to let memory
! 782: * pressure balance the physical segments with pageable pages.
1.1 root 783: */
1.1.1.5 root 784: mem = vm_page_alloc_pa(0, VM_PAGE_SEL_DIRECTMAP, VM_PT_KERNEL);
785:
786: if (mem == NULL) {
787: simple_unlock(&vm_page_queue_free_lock);
788: return NULL;
789: }
1.1 root 790:
791: mem->free = FALSE;
792: simple_unlock(&vm_page_queue_free_lock);
793:
794: return mem;
795: }
796:
1.1.1.6 ! root 797: phys_addr_t vm_page_grab_phys_addr(void)
1.1 root 798: {
1.1.1.6 ! root 799: vm_page_t p = vm_page_grab();
1.1 root 800: if (p == VM_PAGE_NULL)
801: return -1;
802: else
803: return p->phys_addr;
804: }
805:
806: /*
1.1.1.5 root 807: * vm_page_release:
1.1 root 808: *
1.1.1.5 root 809: * Return a page to the free list.
1.1 root 810: */
811:
1.1.1.6 ! root 812: void vm_page_release(
1.1.1.5 root 813: vm_page_t mem,
1.1.1.6 ! root 814: boolean_t laundry,
! 815: boolean_t external_laundry)
1.1 root 816: {
1.1.1.5 root 817: simple_lock(&vm_page_queue_free_lock);
818: if (mem->free)
819: panic("vm_page_release");
820: mem->free = TRUE;
821: vm_page_free_pa(mem, 0);
1.1.1.6 ! root 822: if (laundry) {
! 823: vm_page_laundry_count--;
1.1 root 824:
1.1.1.6 ! root 825: if (vm_page_laundry_count == 0) {
! 826: vm_pageout_resume();
! 827: }
! 828: }
! 829: if (external_laundry) {
! 830:
! 831: /*
! 832: * If vm_page_external_laundry_count is negative,
! 833: * the pageout daemon isn't expecting to be
! 834: * notified.
! 835: */
1.1 root 836:
1.1.1.6 ! root 837: if (vm_page_external_laundry_count > 0) {
! 838: vm_page_external_laundry_count--;
! 839:
! 840: if (vm_page_external_laundry_count == 0) {
! 841: vm_pageout_resume();
! 842: }
! 843: }
1.1.1.5 root 844: }
1.1 root 845:
1.1.1.5 root 846: simple_unlock(&vm_page_queue_free_lock);
847: }
1.1 root 848:
1.1.1.5 root 849: /*
850: * vm_page_grab_contig:
851: *
852: * Remove a block of contiguous pages from the free list.
853: * Returns VM_PAGE_NULL if the request fails.
854: */
1.1 root 855:
1.1.1.5 root 856: vm_page_t vm_page_grab_contig(
857: vm_size_t size,
858: unsigned int selector)
859: {
860: unsigned int i, order, nr_pages;
861: vm_page_t mem;
1.1 root 862:
1.1.1.5 root 863: order = vm_page_order(size);
864: nr_pages = 1 << order;
1.1 root 865:
866: simple_lock(&vm_page_queue_free_lock);
867:
1.1.1.5 root 868: /* TODO Allow caller to pass type */
869: mem = vm_page_alloc_pa(order, selector, VM_PT_KERNEL);
1.1 root 870:
1.1.1.5 root 871: if (mem == NULL) {
872: simple_unlock(&vm_page_queue_free_lock);
873: return NULL;
1.1 root 874: }
875:
1.1.1.5 root 876: for (i = 0; i < nr_pages; i++) {
877: mem[i].free = FALSE;
1.1 root 878: }
879:
880: simple_unlock(&vm_page_queue_free_lock);
881:
1.1.1.5 root 882: return mem;
1.1 root 883: }
884:
885: /*
1.1.1.5 root 886: * vm_page_free_contig:
1.1 root 887: *
1.1.1.5 root 888: * Return a block of contiguous pages to the free list.
1.1 root 889: */
890:
1.1.1.5 root 891: void vm_page_free_contig(vm_page_t mem, vm_size_t size)
1.1 root 892: {
1.1.1.5 root 893: unsigned int i, order, nr_pages;
894:
895: order = vm_page_order(size);
896: nr_pages = 1 << order;
897:
1.1 root 898: simple_lock(&vm_page_queue_free_lock);
899:
1.1.1.5 root 900: for (i = 0; i < nr_pages; i++) {
901: if (mem[i].free)
902: panic("vm_page_free_contig");
903:
904: mem[i].free = TRUE;
905: }
906:
907: vm_page_free_pa(mem, order);
1.1 root 908:
909: simple_unlock(&vm_page_queue_free_lock);
910: }
911:
912: /*
913: * vm_page_alloc:
914: *
915: * Allocate and return a memory cell associated
916: * with this VM object/offset pair.
917: *
918: * Object must be locked.
919: */
920:
921: vm_page_t vm_page_alloc(
922: vm_object_t object,
923: vm_offset_t offset)
924: {
1.1.1.4 root 925: vm_page_t mem;
1.1 root 926:
1.1.1.6 ! root 927: mem = vm_page_grab();
1.1 root 928: if (mem == VM_PAGE_NULL)
929: return VM_PAGE_NULL;
930:
931: vm_page_lock_queues();
932: vm_page_insert(mem, object, offset);
933: vm_page_unlock_queues();
934:
935: return mem;
936: }
937:
938: /*
939: * vm_page_free:
940: *
941: * Returns the given page to the free list,
942: * disassociating it with any VM object.
943: *
944: * Object and page queues must be locked prior to entry.
945: */
946: void vm_page_free(
1.1.1.4 root 947: vm_page_t mem)
1.1 root 948: {
949: if (mem->free)
950: panic("vm_page_free");
951:
1.1.1.6 ! root 952: if (mem->tabled) {
1.1 root 953: vm_page_remove(mem);
1.1.1.6 ! root 954: }
! 955:
! 956: assert(!mem->active && !mem->inactive);
1.1 root 957:
958: if (mem->wire_count != 0) {
959: if (!mem->private && !mem->fictitious)
960: vm_page_wire_count--;
961: mem->wire_count = 0;
962: }
963:
964: PAGE_WAKEUP_DONE(mem);
965:
966: if (mem->absent)
967: vm_object_absent_release(mem->object);
968:
969: /*
970: * XXX The calls to vm_page_init here are
971: * really overkill.
972: */
973:
974: if (mem->private || mem->fictitious) {
1.1.1.5 root 975: vm_page_init(mem);
976: mem->phys_addr = vm_page_fictitious_addr;
1.1 root 977: mem->fictitious = TRUE;
978: vm_page_release_fictitious(mem);
979: } else {
1.1.1.6 ! root 980: boolean_t laundry = mem->laundry;
! 981: boolean_t external_laundry = mem->external_laundry;
1.1.1.5 root 982: vm_page_init(mem);
1.1.1.6 ! root 983: vm_page_release(mem, laundry, external_laundry);
1.1 root 984: }
985: }
986:
987: /*
988: * vm_page_zero_fill:
989: *
990: * Zero-fill the specified page.
991: */
992: void vm_page_zero_fill(
993: vm_page_t m)
994: {
995: VM_PAGE_CHECK(m);
996:
997: pmap_zero_page(m->phys_addr);
998: }
999:
1000: /*
1001: * vm_page_copy:
1002: *
1003: * Copy one page to another
1004: */
1005:
1006: void vm_page_copy(
1007: vm_page_t src_m,
1008: vm_page_t dest_m)
1009: {
1010: VM_PAGE_CHECK(src_m);
1011: VM_PAGE_CHECK(dest_m);
1012:
1013: pmap_copy_page(src_m->phys_addr, dest_m->phys_addr);
1014: }
1015:
1016: #if MACH_VM_DEBUG
1017: /*
1018: * Routine: vm_page_info
1019: * Purpose:
1020: * Return information about the global VP table.
1021: * Fills the buffer with as much information as possible
1022: * and returns the desired size of the buffer.
1023: * Conditions:
1024: * Nothing locked. The caller should provide
1025: * possibly-pageable memory.
1026: */
1027:
1028: unsigned int
1029: vm_page_info(
1030: hash_info_bucket_t *info,
1031: unsigned int count)
1032: {
1033: int i;
1034:
1035: if (vm_page_bucket_count < count)
1036: count = vm_page_bucket_count;
1037:
1038: for (i = 0; i < count; i++) {
1039: vm_page_bucket_t *bucket = &vm_page_buckets[i];
1040: unsigned int bucket_count = 0;
1041: vm_page_t m;
1042:
1043: simple_lock(&bucket->lock);
1044: for (m = bucket->pages; m != VM_PAGE_NULL; m = m->next)
1045: bucket_count++;
1046: simple_unlock(&bucket->lock);
1047:
1048: /* don't touch pageable memory while holding locks */
1049: info[i].hib_count = bucket_count;
1050: }
1051:
1052: return vm_page_bucket_count;
1053: }
1054: #endif /* MACH_VM_DEBUG */
1055:
1.1.1.3 root 1056:
1.1 root 1057: #if MACH_KDB
1058: #define printf kdbprintf
1059:
1060: /*
1061: * Routine: vm_page_print [exported]
1062: */
1063: void vm_page_print(p)
1.1.1.4 root 1064: const vm_page_t p;
1.1 root 1065: {
1066: iprintf("Page 0x%X: object 0x%X,", (vm_offset_t) p, (vm_offset_t) p->object);
1.1.1.4 root 1067: printf(" offset 0x%X", p->offset);
1.1 root 1068: printf("wire_count %d,", p->wire_count);
1069: printf(" %s",
1070: (p->active ? "active" : (p->inactive ? "inactive" : "loose")));
1071: printf("%s",
1072: (p->free ? " free" : ""));
1073: printf("%s ",
1074: (p->laundry ? " laundry" : ""));
1075: printf("%s",
1076: (p->dirty ? "dirty" : "clean"));
1077: printf("%s",
1078: (p->busy ? " busy" : ""));
1079: printf("%s",
1080: (p->absent ? " absent" : ""));
1081: printf("%s",
1082: (p->error ? " error" : ""));
1083: printf("%s",
1084: (p->fictitious ? " fictitious" : ""));
1085: printf("%s",
1086: (p->private ? " private" : ""));
1087: printf("%s",
1088: (p->wanted ? " wanted" : ""));
1089: printf("%s,",
1090: (p->tabled ? "" : "not_tabled"));
1091: printf("phys_addr = 0x%X, lock = 0x%X, unlock_request = 0x%X\n",
1.1.1.4 root 1092: p->phys_addr,
1.1 root 1093: (vm_offset_t) p->page_lock,
1094: (vm_offset_t) p->unlock_request);
1095: }
1096: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.