|
|
1.1 root 1: /*
2: * Copyright (c) 1991 Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * The Mach Operating System project at Carnegie-Mellon University.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)vm_page.c 7.4 (Berkeley) 5/7/91
37: *
38: *
39: * Copyright (c) 1987, 1990 Carnegie-Mellon University.
40: * All rights reserved.
41: *
42: * Authors: Avadis Tevanian, Jr., Michael Wayne Young
43: *
44: * Permission to use, copy, modify and distribute this software and
45: * its documentation is hereby granted, provided that both the copyright
46: * notice and this permission notice appear in all copies of the
47: * software, derivative works or modified versions, and any portions
48: * thereof, and that both notices appear in supporting documentation.
49: *
50: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53: *
54: * Carnegie Mellon requests users of this software to return to
55: *
56: * Software Distribution Coordinator or [email protected]
57: * School of Computer Science
58: * Carnegie Mellon University
59: * Pittsburgh PA 15213-3890
60: *
61: * any improvements or extensions that they make and grant Carnegie the
62: * rights to redistribute these changes.
63: */
64:
65: /*
66: * Resident memory management module.
67: */
68:
69: #include "param.h"
70:
71: #include "vm.h"
72: #include "vm_map.h"
73: #include "vm_page.h"
74: #include "vm_pageout.h"
75:
76: /*
77: * Associated with page of user-allocatable memory is a
78: * page structure.
79: */
80:
81: queue_head_t *vm_page_buckets; /* Array of buckets */
82: int vm_page_bucket_count = 0; /* How big is array? */
83: int vm_page_hash_mask; /* Mask for hash function */
84: simple_lock_data_t bucket_lock; /* lock for all buckets XXX */
85:
86: vm_size_t page_size = 4096;
87: vm_size_t page_mask = 4095;
88: int page_shift = 12;
89:
90: queue_head_t vm_page_queue_free;
91: queue_head_t vm_page_queue_active;
92: queue_head_t vm_page_queue_inactive;
93: simple_lock_data_t vm_page_queue_lock;
94: simple_lock_data_t vm_page_queue_free_lock;
95:
96: vm_page_t vm_page_array;
97: long first_page;
98: long last_page;
99: vm_offset_t first_phys_addr;
100: vm_offset_t last_phys_addr;
101:
102: int vm_page_free_count;
103: int vm_page_active_count;
104: int vm_page_inactive_count;
105: int vm_page_wire_count;
106: int vm_page_laundry_count;
107:
108: int vm_page_free_target = 0;
109: int vm_page_free_min = 0;
110: int vm_page_inactive_target = 0;
111: int vm_page_free_reserved = 0;
112:
113: /*
114: * vm_set_page_size:
115: *
116: * Sets the page size, perhaps based upon the memory
117: * size. Must be called before any use of page-size
118: * dependent functions.
119: *
120: * Sets page_shift and page_mask from page_size.
121: */
122: void vm_set_page_size()
123: {
124: page_mask = page_size - 1;
125:
126: if ((page_mask & page_size) != 0)
127: panic("vm_set_page_size: page size not a power of two");
128:
129: for (page_shift = 0; ; page_shift++)
130: if ((1 << page_shift) == page_size)
131: break;
132: }
133:
134:
135: /*
136: * vm_page_startup:
137: *
138: * Initializes the resident memory module.
139: *
140: * Allocates memory for the page cells, and
141: * for the object/offset-to-page hash table headers.
142: * Each page cell is initialized and placed on the free list.
143: */
144: vm_offset_t vm_page_startup(start, end, vaddr)
145: register vm_offset_t start;
146: vm_offset_t end;
147: register vm_offset_t vaddr;
148: {
149: register vm_offset_t mapped;
150: register vm_page_t m;
151: register queue_t bucket;
152: vm_size_t npages;
153: register vm_offset_t new_start;
154: int i;
155: vm_offset_t pa;
156:
157: extern vm_offset_t kentry_data;
158: extern vm_size_t kentry_data_size;
159:
160:
161: /*
162: * Initialize the locks
163: */
164:
165: simple_lock_init(&vm_page_queue_free_lock);
166: simple_lock_init(&vm_page_queue_lock);
167:
168: /*
169: * Initialize the queue headers for the free queue,
170: * the active queue and the inactive queue.
171: */
172:
173: queue_init(&vm_page_queue_free);
174: queue_init(&vm_page_queue_active);
175: queue_init(&vm_page_queue_inactive);
176:
177: /*
178: * Allocate (and initialize) the hash table buckets.
179: *
180: * The number of buckets MUST BE a power of 2, and
181: * the actual value is the next power of 2 greater
182: * than the number of physical pages in the system.
183: *
184: * Note:
185: * This computation can be tweaked if desired.
186: */
187:
188: vm_page_buckets = (queue_t) vaddr;
189: bucket = vm_page_buckets;
190: if (vm_page_bucket_count == 0) {
191: vm_page_bucket_count = 1;
192: while (vm_page_bucket_count < atop(end - start))
193: vm_page_bucket_count <<= 1;
194: }
195:
196: vm_page_hash_mask = vm_page_bucket_count - 1;
197:
198: /*
199: * Validate these addresses.
200: */
201:
202: new_start = round_page(((queue_t)start) + vm_page_bucket_count);
203: mapped = vaddr;
204: vaddr = pmap_map(mapped, start, new_start,
205: VM_PROT_READ|VM_PROT_WRITE);
206: start = new_start;
207: blkclr((caddr_t) mapped, vaddr - mapped);
208: mapped = vaddr;
209:
210: for (i = vm_page_bucket_count; i--;) {
211: queue_init(bucket);
212: bucket++;
213: }
214:
215: simple_lock_init(&bucket_lock);
216:
217: /*
218: * round (or truncate) the addresses to our page size.
219: */
220:
221: end = trunc_page(end);
222:
223: /*
224: * Pre-allocate maps and map entries that cannot be dynamically
225: * allocated via malloc(). The maps include the kernel_map and
226: * kmem_map which must be initialized before malloc() will
227: * work (obviously). Also could include pager maps which would
228: * be allocated before kmeminit.
229: *
230: * Allow some kernel map entries... this should be plenty
231: * since people shouldn't be cluttering up the kernel
232: * map (they should use their own maps).
233: */
234:
235: kentry_data_size = MAX_KMAP * sizeof(struct vm_map) +
236: MAX_KMAPENT * sizeof(struct vm_map_entry);
237: kentry_data_size = round_page(kentry_data_size);
238: kentry_data = (vm_offset_t) vaddr;
239: vaddr += kentry_data_size;
240:
241: /*
242: * Validate these zone addresses.
243: */
244:
245: new_start = start + (vaddr - mapped);
246: pmap_map(mapped, start, new_start, VM_PROT_READ|VM_PROT_WRITE);
247: blkclr((caddr_t) mapped, (vaddr - mapped));
248: mapped = vaddr;
249: start = new_start;
250:
251: /*
252: * Compute the number of pages of memory that will be
253: * available for use (taking into account the overhead
254: * of a page structure per page).
255: */
256:
257: vm_page_free_count = npages =
258: (end - start)/(PAGE_SIZE + sizeof(struct vm_page));
259:
260: /*
261: * Initialize the mem entry structures now, and
262: * put them in the free queue.
263: */
264:
265: m = vm_page_array = (vm_page_t) vaddr;
266: first_page = start;
267: first_page += npages*sizeof(struct vm_page);
268: first_page = atop(round_page(first_page));
269: last_page = first_page + npages - 1;
270:
271: first_phys_addr = ptoa(first_page);
272: last_phys_addr = ptoa(last_page) + page_mask;
273:
274: /*
275: * Validate these addresses.
276: */
277:
278: new_start = start + (round_page(m + npages) - mapped);
279: mapped = pmap_map(mapped, start, new_start,
280: VM_PROT_READ|VM_PROT_WRITE);
281: start = new_start;
282:
283: /*
284: * Clear all of the page structures
285: */
286: blkclr((caddr_t)m, npages * sizeof(*m));
287:
288: pa = first_phys_addr;
289: while (npages--) {
290: m->copy_on_write = FALSE;
291: m->wanted = FALSE;
292: m->inactive = FALSE;
293: m->active = FALSE;
294: m->busy = FALSE;
295: m->object = NULL;
296: m->phys_addr = pa;
297: queue_enter(&vm_page_queue_free, m, vm_page_t, pageq);
298: m++;
299: pa += PAGE_SIZE;
300: }
301:
302: /*
303: * Initialize vm_pages_needed lock here - don't wait for pageout
304: * daemon XXX
305: */
306: simple_lock_init(&vm_pages_needed_lock);
307:
308: return(mapped);
309: }
310:
311: /*
312: * vm_page_hash:
313: *
314: * Distributes the object/offset key pair among hash buckets.
315: *
316: * NOTE: This macro depends on vm_page_bucket_count being a power of 2.
317: */
318: #define vm_page_hash(object, offset) \
319: (((unsigned)object+(unsigned)atop(offset))&vm_page_hash_mask)
320:
321: /*
322: * vm_page_insert: [ internal use only ]
323: *
324: * Inserts the given mem entry into the object/object-page
325: * table and object list.
326: *
327: * The object and page must be locked.
328: */
329:
330: void vm_page_insert(mem, object, offset)
331: register vm_page_t mem;
332: register vm_object_t object;
333: register vm_offset_t offset;
334: {
335: register queue_t bucket;
336: int spl;
337:
338: VM_PAGE_CHECK(mem);
339:
340: if (mem->tabled)
341: panic("vm_page_insert: already inserted");
342:
343: /*
344: * Record the object/offset pair in this page
345: */
346:
347: mem->object = object;
348: mem->offset = offset;
349:
350: /*
351: * Insert it into the object_object/offset hash table
352: */
353:
354: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
355: spl = splimp();
356: simple_lock(&bucket_lock);
357: queue_enter(bucket, mem, vm_page_t, hashq);
358: simple_unlock(&bucket_lock);
359: (void) splx(spl);
360:
361: /*
362: * Now link into the object's list of backed pages.
363: */
364:
365: queue_enter(&object->memq, mem, vm_page_t, listq);
366: mem->tabled = TRUE;
367:
368: /*
369: * And show that the object has one more resident
370: * page.
371: */
372:
373: object->resident_page_count++;
374: }
375:
376: /*
377: * vm_page_remove: [ internal use only ]
378: *
379: * Removes the given mem entry from the object/offset-page
380: * table and the object page list.
381: *
382: * The object and page must be locked.
383: */
384:
385: void vm_page_remove(mem)
386: register vm_page_t mem;
387: {
388: register queue_t bucket;
389: int spl;
390:
391: VM_PAGE_CHECK(mem);
392:
393: if (!mem->tabled)
394: return;
395:
396: /*
397: * Remove from the object_object/offset hash table
398: */
399:
400: bucket = &vm_page_buckets[vm_page_hash(mem->object, mem->offset)];
401: spl = splimp();
402: simple_lock(&bucket_lock);
403: queue_remove(bucket, mem, vm_page_t, hashq);
404: simple_unlock(&bucket_lock);
405: (void) splx(spl);
406:
407: /*
408: * Now remove from the object's list of backed pages.
409: */
410:
411: queue_remove(&mem->object->memq, mem, vm_page_t, listq);
412:
413: /*
414: * And show that the object has one fewer resident
415: * page.
416: */
417:
418: mem->object->resident_page_count--;
419:
420: mem->tabled = FALSE;
421: }
422:
423: /*
424: * vm_page_lookup:
425: *
426: * Returns the page associated with the object/offset
427: * pair specified; if none is found, NULL is returned.
428: *
429: * The object must be locked. No side effects.
430: */
431:
432: vm_page_t vm_page_lookup(object, offset)
433: register vm_object_t object;
434: register vm_offset_t offset;
435: {
436: register vm_page_t mem;
437: register queue_t bucket;
438: int spl;
439:
440: /*
441: * Search the hash table for this object/offset pair
442: */
443:
444: bucket = &vm_page_buckets[vm_page_hash(object, offset)];
445:
446: spl = splimp();
447: simple_lock(&bucket_lock);
448: mem = (vm_page_t) queue_first(bucket);
449: while (!queue_end(bucket, (queue_entry_t) mem)) {
450: VM_PAGE_CHECK(mem);
451: if ((mem->object == object) && (mem->offset == offset)) {
452: simple_unlock(&bucket_lock);
453: splx(spl);
454: return(mem);
455: }
456: mem = (vm_page_t) queue_next(&mem->hashq);
457: }
458:
459: simple_unlock(&bucket_lock);
460: splx(spl);
461: return(NULL);
462: }
463:
464: /*
465: * vm_page_rename:
466: *
467: * Move the given memory entry from its
468: * current object to the specified target object/offset.
469: *
470: * The object must be locked.
471: */
472: void vm_page_rename(mem, new_object, new_offset)
473: register vm_page_t mem;
474: register vm_object_t new_object;
475: vm_offset_t new_offset;
476: {
477: if (mem->object == new_object)
478: return;
479:
480: vm_page_lock_queues(); /* keep page from moving out from
481: under pageout daemon */
482: vm_page_remove(mem);
483: vm_page_insert(mem, new_object, new_offset);
484: vm_page_unlock_queues();
485: }
486:
487: void vm_page_init(mem, object, offset)
488: vm_page_t mem;
489: vm_object_t object;
490: vm_offset_t offset;
491: {
492: #ifdef DEBUG
493: #define vm_page_init(mem, object, offset) {\
494: (mem)->busy = TRUE; \
495: (mem)->tabled = FALSE; \
496: vm_page_insert((mem), (object), (offset)); \
497: (mem)->absent = FALSE; \
498: (mem)->fictitious = FALSE; \
499: (mem)->page_lock = VM_PROT_NONE; \
500: (mem)->unlock_request = VM_PROT_NONE; \
501: (mem)->laundry = FALSE; \
502: (mem)->active = FALSE; \
503: (mem)->inactive = FALSE; \
504: (mem)->wire_count = 0; \
505: (mem)->clean = TRUE; \
506: (mem)->copy_on_write = FALSE; \
507: (mem)->fake = TRUE; \
508: (mem)->pagerowned = FALSE; \
509: (mem)->ptpage = FALSE; \
510: }
511: #else
512: #define vm_page_init(mem, object, offset) {\
513: (mem)->busy = TRUE; \
514: (mem)->tabled = FALSE; \
515: vm_page_insert((mem), (object), (offset)); \
516: (mem)->absent = FALSE; \
517: (mem)->fictitious = FALSE; \
518: (mem)->page_lock = VM_PROT_NONE; \
519: (mem)->unlock_request = VM_PROT_NONE; \
520: (mem)->laundry = FALSE; \
521: (mem)->active = FALSE; \
522: (mem)->inactive = FALSE; \
523: (mem)->wire_count = 0; \
524: (mem)->clean = TRUE; \
525: (mem)->copy_on_write = FALSE; \
526: (mem)->fake = TRUE; \
527: }
528: #endif
529:
530: vm_page_init(mem, object, offset);
531: }
532:
533: /*
534: * vm_page_alloc:
535: *
536: * Allocate and return a memory cell associated
537: * with this VM object/offset pair.
538: *
539: * Object must be locked.
540: */
541: vm_page_t vm_page_alloc(object, offset)
542: vm_object_t object;
543: vm_offset_t offset;
544: {
545: register vm_page_t mem;
546: int spl;
547:
548: spl = splimp(); /* XXX */
549: simple_lock(&vm_page_queue_free_lock);
550: if (queue_empty(&vm_page_queue_free)) {
551: simple_unlock(&vm_page_queue_free_lock);
552: splx(spl);
553: return(NULL);
554: }
555:
556: queue_remove_first(&vm_page_queue_free, mem, vm_page_t, pageq);
557:
558: vm_page_free_count--;
559: simple_unlock(&vm_page_queue_free_lock);
560: splx(spl);
561:
562: vm_page_init(mem, object, offset);
563:
564: /*
565: * Decide if we should poke the pageout daemon.
566: * We do this if the free count is less than the low
567: * water mark, or if the free count is less than the high
568: * water mark (but above the low water mark) and the inactive
569: * count is less than its target.
570: *
571: * We don't have the counts locked ... if they change a little,
572: * it doesn't really matter.
573: */
574:
575: if ((vm_page_free_count < vm_page_free_min) ||
576: ((vm_page_free_count < vm_page_free_target) &&
577: (vm_page_inactive_count < vm_page_inactive_target)))
578: thread_wakeup(&vm_pages_needed);
579: return(mem);
580: }
581:
582: /*
583: * vm_page_free:
584: *
585: * Returns the given page to the free list,
586: * disassociating it with any VM object.
587: *
588: * Object and page must be locked prior to entry.
589: */
590: void vm_page_free(mem)
591: register vm_page_t mem;
592: {
593: vm_page_remove(mem);
594: if (mem->active) {
595: queue_remove(&vm_page_queue_active, mem, vm_page_t, pageq);
596: mem->active = FALSE;
597: vm_page_active_count--;
598: }
599:
600: if (mem->inactive) {
601: queue_remove(&vm_page_queue_inactive, mem, vm_page_t, pageq);
602: mem->inactive = FALSE;
603: vm_page_inactive_count--;
604: }
605:
606: if (!mem->fictitious) {
607: int spl;
608:
609: spl = splimp();
610: simple_lock(&vm_page_queue_free_lock);
611: queue_enter(&vm_page_queue_free, mem, vm_page_t, pageq);
612:
613: vm_page_free_count++;
614: simple_unlock(&vm_page_queue_free_lock);
615: splx(spl);
616: }
617: }
618:
619: /*
620: * vm_page_wire:
621: *
622: * Mark this page as wired down by yet
623: * another map, removing it from paging queues
624: * as necessary.
625: *
626: * The page queues must be locked.
627: */
628: void vm_page_wire(mem)
629: register vm_page_t mem;
630: {
631: VM_PAGE_CHECK(mem);
632:
633: if (mem->wire_count == 0) {
634: if (mem->active) {
635: queue_remove(&vm_page_queue_active, mem, vm_page_t,
636: pageq);
637: vm_page_active_count--;
638: mem->active = FALSE;
639: }
640: if (mem->inactive) {
641: queue_remove(&vm_page_queue_inactive, mem, vm_page_t,
642: pageq);
643: vm_page_inactive_count--;
644: mem->inactive = FALSE;
645: }
646: vm_page_wire_count++;
647: }
648: mem->wire_count++;
649: }
650:
651: /*
652: * vm_page_unwire:
653: *
654: * Release one wiring of this page, potentially
655: * enabling it to be paged again.
656: *
657: * The page queues must be locked.
658: */
659: void vm_page_unwire(mem)
660: register vm_page_t mem;
661: {
662: VM_PAGE_CHECK(mem);
663:
664: mem->wire_count--;
665: if (mem->wire_count == 0) {
666: queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq);
667: vm_page_active_count++;
668: mem->active = TRUE;
669: vm_page_wire_count--;
670: }
671: }
672:
673: /*
674: * vm_page_deactivate:
675: *
676: * Returns the given page to the inactive list,
677: * indicating that no physical maps have access
678: * to this page. [Used by the physical mapping system.]
679: *
680: * The page queues must be locked.
681: */
682: void vm_page_deactivate(m)
683: register vm_page_t m;
684: {
685: VM_PAGE_CHECK(m);
686:
687: /*
688: * Only move active pages -- ignore locked or already
689: * inactive ones.
690: */
691:
692: if (m->active) {
693: pmap_clear_reference(VM_PAGE_TO_PHYS(m));
694: queue_remove(&vm_page_queue_active, m, vm_page_t, pageq);
695: queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq);
696: m->active = FALSE;
697: m->inactive = TRUE;
698: vm_page_active_count--;
699: vm_page_inactive_count++;
700: if (pmap_is_modified(VM_PAGE_TO_PHYS(m)))
701: m->clean = FALSE;
702: m->laundry = !m->clean;
703: }
704: }
705:
706: /*
707: * vm_page_activate:
708: *
709: * Put the specified page on the active list (if appropriate).
710: *
711: * The page queues must be locked.
712: */
713:
714: void vm_page_activate(m)
715: register vm_page_t m;
716: {
717: VM_PAGE_CHECK(m);
718:
719: if (m->inactive) {
720: queue_remove(&vm_page_queue_inactive, m, vm_page_t,
721: pageq);
722: vm_page_inactive_count--;
723: m->inactive = FALSE;
724: }
725: if (m->wire_count == 0) {
726: if (m->active)
727: panic("vm_page_activate: already active");
728:
729: queue_enter(&vm_page_queue_active, m, vm_page_t, pageq);
730: m->active = TRUE;
731: vm_page_active_count++;
732: }
733: }
734:
735: /*
736: * vm_page_zero_fill:
737: *
738: * Zero-fill the specified page.
739: * Written as a standard pagein routine, to
740: * be used by the zero-fill object.
741: */
742:
743: boolean_t vm_page_zero_fill(m)
744: vm_page_t m;
745: {
746: VM_PAGE_CHECK(m);
747:
748: pmap_zero_page(VM_PAGE_TO_PHYS(m));
749: return(TRUE);
750: }
751:
752: /*
753: * vm_page_copy:
754: *
755: * Copy one page to another
756: */
757:
758: void vm_page_copy(src_m, dest_m)
759: vm_page_t src_m;
760: vm_page_t dest_m;
761: {
762: VM_PAGE_CHECK(src_m);
763: VM_PAGE_CHECK(dest_m);
764:
765: pmap_copy_page(VM_PAGE_TO_PHYS(src_m), VM_PAGE_TO_PHYS(dest_m));
766: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.