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