BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / vm / vm_page.c
CommitLineData
175f072e 1/*
175f072e
KM
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 *
af359dea
C
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.
175f072e 23 *
af359dea
C
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 Software.Distribution@CS.CMU.EDU
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.
175f072e
KM
63 */
64
65/*
66 * Resident memory management module.
67 */
68
af359dea
C
69#include "param.h"
70
71#include "vm.h"
72#include "vm_map.h"
73#include "vm_page.h"
74#include "vm_pageout.h"
175f072e
KM
75
76/*
77 * Associated with page of user-allocatable memory is a
78 * page structure.
79 */
80
81queue_head_t *vm_page_buckets; /* Array of buckets */
82int vm_page_bucket_count = 0; /* How big is array? */
83int vm_page_hash_mask; /* Mask for hash function */
84simple_lock_data_t bucket_lock; /* lock for all buckets XXX */
85
86vm_size_t page_size = 4096;
87vm_size_t page_mask = 4095;
88int page_shift = 12;
89
90queue_head_t vm_page_queue_free;
91queue_head_t vm_page_queue_active;
92queue_head_t vm_page_queue_inactive;
93simple_lock_data_t vm_page_queue_lock;
94simple_lock_data_t vm_page_queue_free_lock;
95
96vm_page_t vm_page_array;
97long first_page;
98long last_page;
99vm_offset_t first_phys_addr;
100vm_offset_t last_phys_addr;
101
102int vm_page_free_count;
103int vm_page_active_count;
104int vm_page_inactive_count;
105int vm_page_wire_count;
106int vm_page_laundry_count;
107
108int vm_page_free_target = 0;
109int vm_page_free_min = 0;
110int vm_page_inactive_target = 0;
111int 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 */
122void 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 */
144vm_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);
af359dea 272 last_phys_addr = ptoa(last_page) + page_mask;
175f072e
KM
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;
af359dea 295 m->object = NULL;
175f072e
KM
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
330void 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
385void 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
af359dea 427 * pair specified; if none is found, NULL is returned.
175f072e
KM
428 *
429 * The object must be locked. No side effects.
430 */
431
432vm_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);
af359dea 461 return(NULL);
175f072e
KM
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 */
472void 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
487void vm_page_init(mem, object, offset)
488 vm_page_t mem;
489 vm_object_t object;
490 vm_offset_t offset;
491{
af359dea
C
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
175f072e
KM
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 }
af359dea 528#endif
175f072e
KM
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 */
541vm_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);
af359dea 553 return(NULL);
175f072e
KM
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 */
590void 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 */
628void 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 */
659void 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 */
682void 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
714void 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
743boolean_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
758void 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}