uvm_page.c revision 1.4 1 /* $NetBSD: uvm_page.c,v 1.4 1998/02/07 11:09:19 mrg Exp $ */
2
3 /*
4 * XXXCDC: "ROUGH DRAFT" QUALITY UVM PRE-RELEASE FILE!
5 * >>>USE AT YOUR OWN RISK, WORK IS NOT FINISHED<<<
6 */
7 /*
8 * Copyright (c) 1997 Charles D. Cranor and Washington University.
9 * Copyright (c) 1991, 1993, The Regents of the University of California.
10 *
11 * All rights reserved.
12 *
13 * This code is derived from software contributed to Berkeley by
14 * The Mach Operating System project at Carnegie-Mellon University.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by Charles D. Cranor,
27 * Washington University, the University of California, Berkeley and
28 * its contributors.
29 * 4. Neither the name of the University nor the names of its contributors
30 * may be used to endorse or promote products derived from this software
31 * without specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 * SUCH DAMAGE.
44 *
45 * @(#)vm_page.c 8.3 (Berkeley) 3/21/94
46 * from: Id: uvm_page.c,v 1.1.2.18 1998/02/06 05:24:42 chs Exp
47 *
48 *
49 * Copyright (c) 1987, 1990 Carnegie-Mellon University.
50 * All rights reserved.
51 *
52 * Permission to use, copy, modify and distribute this software and
53 * its documentation is hereby granted, provided that both the copyright
54 * notice and this permission notice appear in all copies of the
55 * software, derivative works or modified versions, and any portions
56 * thereof, and that both notices appear in supporting documentation.
57 *
58 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
59 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
60 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
61 *
62 * Carnegie Mellon requests users of this software to return to
63 *
64 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
65 * School of Computer Science
66 * Carnegie Mellon University
67 * Pittsburgh PA 15213-3890
68 *
69 * any improvements or extensions that they make and grant Carnegie the
70 * rights to redistribute these changes.
71 */
72
73 /*
74 * uvm_page.c: page ops.
75 */
76
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/malloc.h>
80 #include <sys/mount.h>
81 #include <sys/proc.h>
82
83 #include <vm/vm.h>
84 #include <vm/vm_page.h>
85 #include <vm/vm_kern.h>
86
87 #include <sys/syscallargs.h>
88
89 #define UVM_PAGE /* pull in uvm_page.h functions */
90 #include <uvm/uvm.h>
91
92 /*
93 * global vars... XXXCDC: move to uvm. structure.
94 */
95
96 /*
97 * physical memory config is stored in vm_physmem.
98 */
99
100 struct vm_physseg vm_physmem[VM_PHYSSEG_MAX]; /* XXXCDC: uvm.physmem */
101 int vm_nphysseg = 0; /* XXXCDC: uvm.nphysseg */
102
103 /*
104 * local variables
105 */
106
107 /*
108 * these variables record the values returned by vm_page_bootstrap,
109 * for debugging purposes. The implementation of uvm_pageboot_alloc
110 * and pmap_startup here also uses them internally.
111 */
112
113 static vm_offset_t virtual_space_start;
114 static vm_offset_t virtual_space_end;
115
116 /*
117 * we use a hash table with only one bucket during bootup. we will
118 * later rehash (resize) the hash table once malloc() is ready.
119 * we static allocate the bootstrap bucket below...
120 */
121
122 static struct pglist uvm_bootbucket;
123
124 /*
125 * local prototypes
126 */
127
128 static void uvm_pageinsert __P((struct vm_page *));
129 #if !defined(PMAP_STEAL_MEMORY)
130 static boolean_t uvm_page_physget __P((vm_offset_t *));
131 #endif
132
133
134 /*
135 * inline functions
136 */
137
138 /*
139 * uvm_pageinsert: insert a page in the object and the hash table
140 *
141 * => caller must lock object
142 * => caller must lock page queues
143 * => call should have already set pg's object and offset pointers
144 * and bumped the version counter
145 */
146
147 __inline static void uvm_pageinsert(pg)
148
149 struct vm_page *pg;
150
151 {
152 struct pglist *buck;
153 int s;
154
155 #ifdef DIAGNOSTIC
156 if (pg->flags & PG_TABLED)
157 panic("uvm_pageinsert: already inserted");
158 #endif
159
160 buck = &uvm.page_hash[uvm_pagehash(pg->uobject,pg->offset)];
161 s = splimp();
162 simple_lock(&uvm.hashlock);
163 TAILQ_INSERT_TAIL(buck, pg, hashq); /* put in hash */
164 simple_unlock(&uvm.hashlock);
165 splx(s);
166
167 TAILQ_INSERT_TAIL(&pg->uobject->memq, pg, listq); /* put in object */
168 pg->flags |= PG_TABLED;
169 pg->uobject->uo_npages++;
170
171 }
172
173 /*
174 * uvm_page_remove: remove page from object and hash
175 *
176 * => caller must lock object
177 * => caller must lock page queues
178 */
179
180 void __inline uvm_pageremove(pg)
181
182 struct vm_page *pg;
183
184 {
185 struct pglist *buck;
186 int s;
187
188 #ifdef DIAGNOSTIC
189 if ((pg->flags & (PG_FAULTING)) != 0)
190 panic("uvm_pageremove: page is faulting");
191 #endif
192
193 if ((pg->flags & PG_TABLED) == 0)
194 return; /* XXX: log */
195
196 buck = &uvm.page_hash[uvm_pagehash(pg->uobject,pg->offset)];
197 s = splimp();
198 simple_lock(&uvm.hashlock);
199 TAILQ_REMOVE(buck, pg, hashq);
200 simple_unlock(&uvm.hashlock);
201 splx(s);
202
203 TAILQ_REMOVE(&pg->uobject->memq, pg, listq);/* object should be locked */
204
205 pg->flags &= ~PG_TABLED;
206 pg->uobject->uo_npages--;
207 pg->uobject = NULL;
208 pg->version++;
209
210 }
211
212 /*
213 * uvm_page_init: init the page system. called from uvm_init().
214 *
215 * => we return the range of kernel virtual memory in kvm_startp/kvm_endp
216 */
217
218 void uvm_page_init(kvm_startp, kvm_endp)
219
220 vm_offset_t *kvm_startp, *kvm_endp;
221
222 {
223 int freepages, pagecount;
224 vm_page_t pagearray;
225 int lcv, n, i;
226 vm_offset_t paddr;
227
228
229 /*
230 * step 1: init the page queues and page queue locks
231 */
232
233 TAILQ_INIT(&uvm.page_free);
234 TAILQ_INIT(&uvm.page_active);
235 TAILQ_INIT(&uvm.page_inactive_swp);
236 TAILQ_INIT(&uvm.page_inactive_obj);
237 simple_lock_init(&uvm.pageqlock);
238 simple_lock_init(&uvm.fpageqlock);
239
240 /*
241 * step 2: init the <obj,offset> => <page> hash table. for now
242 * we just have one bucket (the bootstrap bucket). later on we
243 * will malloc() new buckets as we dynamically resize the hash table.
244 */
245
246 uvm.page_nhash = 1; /* 1 bucket */
247 uvm.page_hashmask = 0; /* mask for hash function */
248 uvm.page_hash = &uvm_bootbucket; /* install bootstrap bucket */
249 TAILQ_INIT(uvm.page_hash); /* init hash table */
250 simple_lock_init(&uvm.hashlock); /* init hash table lock */
251
252 /*
253 * step 3: allocate vm_page structures.
254 */
255
256 /*
257 * sanity check:
258 * before calling this function the MD code is expected to register
259 * some free RAM with the uvm_page_physload() function. our job
260 * now is to allocate vm_page structures for this memory.
261 */
262
263 if (vm_nphysseg == 0)
264 panic("vm_page_bootstrap: no memory pre-allocated");
265
266 /*
267 * first calculate the number of free pages...
268 *
269 * note that we use start/end rather than avail_start/avail_end.
270 * this allows us to allocate extra vm_page structures in case we
271 * want to return some memory to the pool after booting.
272 */
273
274 freepages = 0;
275 for (lcv = 0 ; lcv < vm_nphysseg ; lcv++) {
276 freepages = freepages + (vm_physmem[lcv].end - vm_physmem[lcv].start);
277 }
278
279 /*
280 * we now know we have (PAGE_SIZE * freepages) bytes of memory we can
281 * use. for each page of memory we use we need a vm_page structure.
282 * thus, the total number of pages we can use is the total size of
283 * the memory divided by the PAGE_SIZE plus the size of the vm_page
284 * structure. we add one to freepages as a fudge factor to avoid
285 * truncation errors (since we can only allocate in terms of whole
286 * pages).
287 */
288
289 pagecount = (PAGE_SIZE * (freepages + 1)) /
290 (PAGE_SIZE + sizeof(struct vm_page));
291 pagearray = (vm_page_t)uvm_pageboot_alloc(pagecount * sizeof(struct vm_page));
292 bzero(pagearray, pagecount * sizeof(struct vm_page));
293
294 /*
295 * step 4: init the vm_page structures and put them in the correct
296 * place...
297 */
298
299 for (lcv = 0 ; lcv < vm_nphysseg ; lcv++) {
300
301 n = vm_physmem[lcv].end - vm_physmem[lcv].start;
302 if (n > pagecount) {
303 printf("uvm_page_init: lost %d page(s) in init\n", n - pagecount);
304 panic("uvm_page_init"); /* XXXCDC: shouldn't happen? */
305 /* n = pagecount; */
306 }
307 /* set up page array pointers */
308 vm_physmem[lcv].pgs = pagearray;
309 pagearray += n;
310 pagecount -= n;
311 vm_physmem[lcv].lastpg = vm_physmem[lcv].pgs + (n - 1);
312
313 /* init and free vm_pages (we've already bzero'd them) */
314 paddr = ptoa(vm_physmem[lcv].start);
315 for (i = 0 ; i < n ; i++, paddr += PAGE_SIZE) {
316 vm_physmem[lcv].pgs[i].phys_addr = paddr;
317 if (atop(paddr) >= vm_physmem[lcv].avail_start &&
318 atop(paddr) <= vm_physmem[lcv].avail_end) {
319 uvmexp.npages++;
320 uvm_pagefree(&vm_physmem[lcv].pgs[i]); /* add page to free pool */
321 }
322 }
323 }
324 /*
325 * step 5: pass up the values of virtual_space_start and
326 * virtual_space_end (obtained by uvm_pageboot_alloc) to the upper
327 * layers of the VM.
328 */
329
330 *kvm_startp = round_page(virtual_space_start);
331 *kvm_endp = trunc_page(virtual_space_end);
332
333 /*
334 * step 6: init pagedaemon lock
335 */
336
337 simple_lock_init(&uvm.pagedaemon_lock);
338
339 /*
340 * step 7: init reserve thresholds
341 * XXXCDC - values may need adjusting
342 */
343 uvmexp.reserve_pagedaemon = 1;
344 uvmexp.reserve_kernel = 5;
345
346 /*
347 * done!
348 */
349
350 }
351
352 /*
353 * uvm_setpagesize: set the page size
354 *
355 * => sets page_shift and page_mask from uvmexp.pagesize.
356 * => XXXCDC: move global vars.
357 */
358
359 void uvm_setpagesize()
360 {
361 if (uvmexp.pagesize == 0)
362 uvmexp.pagesize = DEFAULT_PAGE_SIZE;
363 uvmexp.pagemask = uvmexp.pagesize - 1;
364 if ((uvmexp.pagemask & uvmexp.pagesize) != 0)
365 panic("uvm_setpagesize: page size not a power of two");
366 for (uvmexp.pageshift = 0; ; uvmexp.pageshift++)
367 if ((1 << uvmexp.pageshift) == uvmexp.pagesize)
368 break;
369 }
370
371 /*
372 * uvm_pageboot_alloc: steal memory from physmem for bootstrapping
373 */
374
375 vm_offset_t uvm_pageboot_alloc(size)
376
377 vm_size_t size;
378
379 {
380 #if defined(PMAP_STEAL_MEMORY)
381 vm_offset_t addr;
382
383 /*
384 * defer bootstrap allocation to MD code (it may want to allocate
385 * from a direct-mapped segment). pmap_steal_memory should round
386 * off virtual_space_start/virtual_space_end.
387 */
388
389 addr = pmap_steal_memory(size, &virtual_space_start, &virtual_space_end);
390
391 return(addr);
392
393 #else /* !PMAP_STEAL_MEMORY */
394
395 vm_offset_t addr, vaddr, paddr;
396
397 /* round the size to an integer multiple */
398 size = (size + 3) &~ 3; /* XXX */
399
400 /*
401 * on first call to this function init ourselves. we detect this
402 * by checking virtual_space_start/end which are in the zero'd BSS area.
403 */
404
405 if (virtual_space_start == virtual_space_end) {
406 pmap_virtual_space(&virtual_space_start, &virtual_space_end);
407
408 /* round it the way we like it */
409 virtual_space_start = round_page(virtual_space_start);
410 virtual_space_end = trunc_page(virtual_space_end);
411 }
412
413 /*
414 * allocate virtual memory for this request
415 */
416
417 addr = virtual_space_start;
418 virtual_space_start += size;
419
420 /*
421 * allocate and mapin physical pages to back new virtual pages
422 */
423
424 for (vaddr = round_page(addr) ; vaddr < addr + size ; vaddr += PAGE_SIZE) {
425
426 if (!uvm_page_physget(&paddr))
427 panic("uvm_pageboot_alloc: out of memory");
428
429 /* XXX: should be wired, but some pmaps don't like that ... */
430 #if defined(PMAP_NEW)
431 pmap_kenter_pa(vaddr, paddr, VM_PROT_READ|VM_PROT_WRITE);
432 #else
433 pmap_enter(pmap_kernel(), vaddr, paddr,
434 VM_PROT_READ|VM_PROT_WRITE, FALSE);
435 #endif
436
437 }
438
439 return(addr);
440 #endif /* PMAP_STEAL_MEMORY */
441 }
442
443 #if !defined(PMAP_STEAL_MEMORY)
444 /*
445 * uvm_page_physget: "steal" one page from the vm_physmem structure.
446 *
447 * => attempt to allocate it off the end of a segment in which the "avail"
448 * values match the start/end values. if we can't do that, then we
449 * will advance both values (making them equal, and removing some
450 * vm_page structures from the non-avail area).
451 * => return false if out of memory.
452 */
453
454 static boolean_t uvm_page_physget(paddrp)
455
456 vm_offset_t *paddrp;
457
458 {
459 int lcv, x;
460
461 /* pass 1: try allocating from a matching end */
462 #if (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST)
463 for (lcv = vm_nphysseg - 1 ; lcv >= 0 ; lcv--)
464 #else
465 for (lcv = 0 ; lcv < vm_nphysseg ; lcv++)
466 #endif
467 {
468
469 if (vm_physmem[lcv].pgs)
470 panic("vm_page_physget: called _after_ bootstrap");
471
472 /* try from front */
473 if (vm_physmem[lcv].avail_start == vm_physmem[lcv].start &&
474 vm_physmem[lcv].avail_start < vm_physmem[lcv].avail_end) {
475 *paddrp = ptoa(vm_physmem[lcv].avail_start);
476 vm_physmem[lcv].avail_start++;
477 vm_physmem[lcv].start++;
478 /* nothing left? nuke it */
479 if (vm_physmem[lcv].avail_start == vm_physmem[lcv].end) {
480 if (vm_nphysseg == 1)
481 panic("vm_page_physget: out of memory!");
482 vm_nphysseg--;
483 for (x = lcv ; x < vm_nphysseg ; x++)
484 vm_physmem[x] = vm_physmem[x+1]; /* structure copy */
485 }
486 return(TRUE);
487 }
488
489 /* try from rear */
490 if (vm_physmem[lcv].avail_end == vm_physmem[lcv].end &&
491 vm_physmem[lcv].avail_start < vm_physmem[lcv].avail_end) {
492 *paddrp = ptoa(vm_physmem[lcv].avail_end - 1);
493 vm_physmem[lcv].avail_end--;
494 vm_physmem[lcv].end--;
495 /* nothing left? nuke it */
496 if (vm_physmem[lcv].avail_end == vm_physmem[lcv].start) {
497 if (vm_nphysseg == 1)
498 panic("vm_page_physget: out of memory!");
499 vm_nphysseg--;
500 for (x = lcv ; x < vm_nphysseg ; x++)
501 vm_physmem[x] = vm_physmem[x+1]; /* structure copy */
502 }
503 return(TRUE);
504 }
505 }
506
507 /* pass2: forget about matching ends, just allocate something */
508 #if (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST)
509 for (lcv = vm_nphysseg - 1 ; lcv >= 0 ; lcv--)
510 #else
511 for (lcv = 0 ; lcv < vm_nphysseg ; lcv++)
512 #endif
513 {
514
515 /* any room in this bank? */
516 if (vm_physmem[lcv].avail_start >= vm_physmem[lcv].avail_end)
517 continue; /* nope */
518
519 *paddrp = ptoa(vm_physmem[lcv].avail_start);
520 vm_physmem[lcv].avail_start++;
521 vm_physmem[lcv].start = vm_physmem[lcv].avail_start; /* truncate! */
522 /* nothing left? nuke it */
523 if (vm_physmem[lcv].avail_start == vm_physmem[lcv].end) {
524 if (vm_nphysseg == 1)
525 panic("vm_page_physget: out of memory!");
526 vm_nphysseg--;
527 for (x = lcv ; x < vm_nphysseg ; x++)
528 vm_physmem[x] = vm_physmem[x+1]; /* structure copy */
529 }
530 return(TRUE);
531 }
532
533 return(FALSE); /* whoops! */
534 }
535 #endif /* PMAP_STEAL_MEMORY */
536
537 /*
538 * uvm_page_physload: load physical memory into VM system
539 *
540 * => all args are PFs
541 * => all pages in start/end get vm_page structures
542 * => areas marked by avail_start/avail_end get added to the free page pool
543 * => we are limited to VM_PHYSSEG_MAX physical memory segments
544 */
545
546 void uvm_page_physload(start, end, avail_start, avail_end)
547
548 vm_offset_t start, end, avail_start, avail_end;
549
550 {
551 int preload, lcv, npages;
552 struct vm_page *pgs;
553 struct vm_physseg *ps;
554
555 if (uvmexp.pagesize == 0)
556 panic("vm_page_physload: page size not set!");
557
558 /*
559 * do we have room?
560 */
561 if (vm_nphysseg == VM_PHYSSEG_MAX) {
562 printf("vm_page_physload: unable to load physical memory segment\n");
563 printf("\t%d segments allocated, ignoring 0x%lx -> 0x%lx\n",
564 VM_PHYSSEG_MAX, start, end);
565 return;
566 }
567
568 /*
569 * check to see if this is a "preload" (i.e. uvm_mem_init hasn't been
570 * called yet, so malloc is not available).
571 */
572 for (lcv = 0 ; lcv < vm_nphysseg ; lcv++) {
573 if (vm_physmem[lcv].pgs)
574 break;
575 }
576 preload = (lcv == vm_nphysseg);
577
578 /*
579 * if VM is already running, attempt to malloc() vm_page structures
580 */
581 if (!preload) {
582 #if defined(VM_PHYSSEG_NOADD)
583 panic("vm_page_physload: tried to add RAM after vm_mem_init");
584 #else
585 /* XXXCDC: need some sort of lockout for this case */
586 vm_offset_t paddr;
587 npages = end - start; /* # of pages */
588 MALLOC(pgs, struct vm_page *, sizeof(struct vm_page) * npages,
589 M_VMPAGE, M_NOWAIT);
590 if (pgs == NULL) {
591 printf("vm_page_physload: can not malloc vm_page structs for segment\n");
592 printf("\tignoring 0x%lx -> 0x%lx\n", start, end);
593 return;
594 }
595 /* zero data, init phys_addr, and free pages */
596 bzero(pgs, sizeof(struct vm_page) * npages);
597 for (lcv = 0, paddr = ptoa(start) ;
598 lcv < npages ; lcv++, paddr += PAGE_SIZE) {
599 pgs[lcv].phys_addr = paddr;
600 if (atop(paddr) >= avail_start && atop(paddr) <= avail_end)
601 vm_page_free(&pgs[i]);
602 }
603 /* XXXCDC: incomplete: need to update uvmexp.free, what else? */
604 /* XXXCDC: need hook to tell pmap to rebuild pv_list, etc... */
605 #endif
606 } else {
607
608 /* gcc complains if these don't get init'd */
609 pgs = NULL;
610 npages = 0;
611
612 }
613
614 /*
615 * now insert us in the proper place in vm_physmem[]
616 */
617
618 #if (VM_PHYSSEG_STRAT == VM_PSTRAT_RANDOM)
619
620 /* random: put it at the end (easy!) */
621 ps = &vm_physmem[vm_nphysseg];
622
623 #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
624
625 {
626 int x;
627 /* sort by address for binary search */
628 for (lcv = 0 ; lcv < vm_nphysseg ; lcv++)
629 if (start < vm_physmem[lcv].start)
630 break;
631 ps = &vm_physmem[lcv];
632 /* move back other entries, if necessary ... */
633 for (x = vm_nphysseg ; x > lcv ; x--)
634 vm_physmem[x] = vm_physmem[x - 1]; /* structure copy */
635 }
636
637 #elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST)
638
639 {
640 int x;
641 /* sort by largest segment first */
642 for (lcv = 0 ; lcv < vm_nphysseg ; lcv++)
643 if ((end - start) > (vm_physmem[lcv].end - vm_physmem[lcv].start))
644 break;
645 ps = &vm_physmem[lcv];
646 /* move back other entries, if necessary ... */
647 for (x = vm_nphysseg ; x > lcv ; x--)
648 vm_physmem[x] = vm_physmem[x - 1]; /* structure copy */
649 }
650
651 #else
652
653 panic("vm_page_physload: unknown physseg strategy selected!");
654
655 #endif
656
657 ps->start = start;
658 ps->end = end;
659 ps->avail_start = avail_start;
660 ps->avail_end = avail_end;
661 if (preload) {
662 ps->pgs = NULL;
663 } else {
664 ps->pgs = pgs;
665 ps->lastpg = pgs + npages - 1;
666 }
667 vm_nphysseg++;
668
669 /*
670 * done!
671 */
672
673 if (!preload)
674 uvm_page_rehash();
675
676 return;
677 }
678
679 /*
680 * uvm_page_rehash: reallocate hash table based on number of free pages.
681 */
682
683 void uvm_page_rehash()
684
685 {
686 int freepages, lcv, bucketcount, s, oldcount;
687 struct pglist *newbuckets, *oldbuckets;
688 struct vm_page *pg;
689
690 /*
691 * compute number of pages that can go in the free pool
692 */
693
694 freepages = 0;
695 for (lcv = 0 ; lcv < vm_nphysseg ; lcv++)
696 freepages = freepages +
697 (vm_physmem[lcv].avail_end - vm_physmem[lcv].avail_start);
698
699 /*
700 * compute number of buckets needed for this number of pages
701 */
702
703 bucketcount = 1;
704 while (bucketcount < freepages)
705 bucketcount = bucketcount * 2;
706
707 /*
708 * malloc new buckets
709 */
710
711 MALLOC(newbuckets, struct pglist *, sizeof(struct pglist) * bucketcount,
712 M_VMPBUCKET, M_NOWAIT);
713 if (newbuckets == NULL) {
714 printf("vm_page_physrehash: WARNING: could not grow page hash table\n");
715 return;
716 }
717 for (lcv = 0 ; lcv < bucketcount ; lcv++)
718 TAILQ_INIT(&newbuckets[lcv]);
719
720 /*
721 * now replace the old buckets with the new ones and rehash everything
722 */
723
724 s = splimp();
725 simple_lock(&uvm.hashlock);
726 /* swap old for new ... */
727 oldbuckets = uvm.page_hash;
728 oldcount = uvm.page_nhash;
729 uvm.page_hash = newbuckets;
730 uvm.page_nhash = bucketcount;
731 uvm.page_hashmask = bucketcount - 1; /* power of 2 */
732
733 /* ... and rehash */
734 for (lcv = 0 ; lcv < oldcount ; lcv++) {
735 while ((pg = oldbuckets[lcv].tqh_first) != NULL) {
736 TAILQ_REMOVE(&oldbuckets[lcv], pg, hashq);
737 TAILQ_INSERT_TAIL(
738 &uvm.page_hash[uvm_pagehash(pg->uobject, pg->offset)], pg, hashq);
739 }
740 }
741 simple_unlock(&uvm.hashlock);
742 splx(s);
743
744 /*
745 * free old bucket array if we malloc'd it previously
746 */
747
748 if (oldbuckets != &uvm_bootbucket)
749 FREE(oldbuckets, M_VMPBUCKET);
750
751 /*
752 * done
753 */
754 return;
755 }
756
757
758 #if 1 /* XXXCDC: TMP TMP TMP DEBUG DEBUG DEBUG */
759
760 void uvm_page_physdump __P((void)); /* SHUT UP GCC */
761
762 /* call from DDB */
763 void uvm_page_physdump() {
764 int lcv;
765 printf("rehash: physical memory config [segs=%d of %d]:\n",
766 vm_nphysseg, VM_PHYSSEG_MAX);
767 for (lcv = 0 ; lcv < vm_nphysseg ; lcv++)
768 printf("0x%lx->0x%lx [0x%lx->0x%lx]\n", vm_physmem[lcv].start,
769 vm_physmem[lcv].end, vm_physmem[lcv].avail_start,
770 vm_physmem[lcv].avail_end);
771 printf("STRATEGY = ");
772 switch (VM_PHYSSEG_STRAT) {
773 case VM_PSTRAT_RANDOM: printf("RANDOM\n"); break;
774 case VM_PSTRAT_BSEARCH: printf("BSEARCH\n"); break;
775 case VM_PSTRAT_BIGFIRST: printf("BIGFIRST\n"); break;
776 default: printf("<<UNKNOWN>>!!!!\n");
777 }
778 printf("number of buckets = %d\n", uvm.page_nhash);
779 }
780 #endif
781
782 /*
783 * uvm_pagealloc: allocate vm_page.
784 *
785 * => return null if no pages free
786 * => wake up pagedaemon if number of free pages drops below low water mark
787 * => if obj != NULL, obj must be locked (to put in hash)
788 * => if anon != NULL, anon must be locked (to put in anon)
789 * => only one of obj or anon can be non-null
790 * => caller must activate/deactivate page if it is not wired.
791 */
792
793 struct vm_page *uvm_pagealloc(obj, off, anon)
794
795 struct uvm_object *obj;
796 vm_offset_t off;
797 struct vm_anon *anon;
798
799 {
800 int s;
801 struct vm_page *pg;
802
803 #ifdef DIAGNOSTIC
804 /* sanity check */
805 if (obj && anon)
806 panic("uvm_pagealloc: obj and anon != NULL");
807 #endif
808
809 s = splimp();
810
811 uvm_lock_fpageq(); /* lock free page queue */
812
813 /*
814 * check to see if we need to generate some free pages waking
815 * the pagedaemon.
816 */
817
818 if (uvmexp.free < uvmexp.freemin ||
819 (uvmexp.free < uvmexp.freetarg && uvmexp.inactive < uvmexp.inactarg)) {
820
821 thread_wakeup(&uvm.pagedaemon);
822 }
823
824 /*
825 * fail if any of these conditions is true:
826 * [1] there really are no free pages, or
827 * [2] only kernel "reserved" pages remain and
828 * the page isn't being allocated to a kernel object.
829 * [3] only pagedaemon "reserved" pages remain and
830 * the requestor isn't the pagedaemon.
831 */
832
833 pg = uvm.page_free.tqh_first;
834 if (pg == NULL ||
835 (uvmexp.free <= uvmexp.reserve_kernel &&
836 !(obj && obj->uo_refs == UVM_OBJ_KERN)) ||
837 (uvmexp.free <= uvmexp.reserve_pagedaemon &&
838 !(obj == uvmexp.kmem_object && curproc == uvm.pagedaemon_proc))) {
839 uvm_unlock_fpageq();
840 splx(s);
841 return(NULL);
842 }
843
844 TAILQ_REMOVE(&uvm.page_free, pg, pageq);
845 uvmexp.free--;
846
847 uvm_unlock_fpageq(); /* unlock free page queue */
848 splx(s);
849
850 pg->offset = off;
851 pg->uobject = obj;
852 pg->uanon = anon;
853 pg->flags = PG_BUSY|PG_CLEAN|PG_FAKE;
854 pg->version++;
855 pg->wire_count = 0;
856 pg->loan_count = 0;
857 if (anon) {
858 anon->u.an_page = pg;
859 pg->pqflags = PQ_ANON;
860 } else {
861 if (obj)
862 uvm_pageinsert(pg);
863 pg->pqflags = 0;
864 }
865 #if defined(UVM_PAGE_TRKOWN)
866 pg->owner_tag = NULL;
867 #endif
868 UVM_PAGE_OWN(pg, "new alloc");
869
870 return(pg);
871 }
872
873 /*
874 * uvm_pagerealloc: reallocate a page from one object to another
875 *
876 * => both objects must be locked
877 */
878
879 void uvm_pagerealloc(pg, newobj, newoff)
880
881 struct vm_page *pg;
882 struct uvm_object *newobj;
883 vm_offset_t newoff;
884
885 {
886 /*
887 * remove it from the old object
888 */
889
890 if (pg->uobject) {
891 uvm_pageremove(pg);
892 }
893
894 /*
895 * put it in the new object
896 */
897
898 if (newobj) {
899 pg->uobject = newobj;
900 pg->offset = newoff;
901 pg->version++;
902 uvm_pageinsert(pg);
903 }
904
905 return;
906 }
907
908
909 /*
910 * uvm_pagefree: free page
911 *
912 * => erase page's identity (i.e. remove from hash/object)
913 * => put page on free list
914 * => caller must lock owning object (either anon or uvm_object)
915 * => caller must lock page queues
916 * => assumes all valid mappings of pg are gone
917 */
918
919 void uvm_pagefree(pg)
920
921 struct vm_page *pg;
922
923 {
924 int s;
925 int saved_loan_count = pg->loan_count;
926
927 /*
928 * if the page was an object page (and thus "TABLED"), remove it
929 * from the object.
930 */
931
932 if (pg->flags & PG_TABLED) {
933
934 /*
935 * if the object page is on loan we are going to drop ownership.
936 * it is possible that an anon will take over as owner for this
937 * page later on. the anon will want a !PG_CLEAN page so that
938 * it knows it needs to allocate swap if it wants to page the
939 * page out.
940 */
941
942 if (saved_loan_count)
943 pg->flags &= ~PG_CLEAN; /* in case an anon takes over */
944
945 uvm_pageremove(pg);
946
947 /*
948 * if our page was on loan, then we just lost control over it
949 * (in fact, if it was loaned to an anon, the anon may have
950 * already taken over ownership of the page by now and thus
951 * changed the loan_count [e.g. in uvmfault_anonget()]) we just
952 * return (when the last loan is dropped, then the page can be
953 * freed by whatever was holding the last loan).
954 */
955 if (saved_loan_count)
956 return;
957
958 } else if (saved_loan_count && (pg->pqflags & PQ_ANON)) {
959
960 /*
961 * if our page is owned by an anon and is loaned out to the kernel
962 * then we just want to drop ownership and return. the kernel
963 * must free the page when all its loans clear ... note that the
964 * kernel can't change the loan status of our page as long as we
965 * are holding PQ lock.
966 */
967 pg->pqflags &= ~PQ_ANON;
968 pg->uanon = NULL;
969 return;
970
971 }
972
973 #ifdef DIAGNOSTIC
974 if (saved_loan_count) {
975 printf("uvm_pagefree: warning: freeing page with a loan count of %d\n",
976 saved_loan_count);
977 panic("uvm_pagefree: loan count");
978 }
979 #endif
980
981
982 /*
983 * now remove the page from the queues
984 */
985
986 if (pg->pqflags & PQ_ACTIVE) {
987 TAILQ_REMOVE(&uvm.page_active, pg, pageq);
988 pg->pqflags &= ~PQ_ACTIVE;
989 uvmexp.active--;
990 }
991 if (pg->pqflags & PQ_INACTIVE) {
992 if (pg->pqflags & PQ_SWAPBACKED)
993 TAILQ_REMOVE(&uvm.page_inactive_swp, pg, pageq);
994 else
995 TAILQ_REMOVE(&uvm.page_inactive_obj, pg, pageq);
996 pg->pqflags &= ~PQ_INACTIVE;
997 uvmexp.inactive--;
998 }
999
1000 /*
1001 * if the page was wired, unwire it now.
1002 */
1003 if (pg->wire_count)
1004 {
1005 pg->wire_count = 0;
1006 uvmexp.wired--;
1007 }
1008
1009 /*
1010 * and put on free queue
1011 */
1012
1013 s = splimp();
1014 uvm_lock_fpageq();
1015 TAILQ_INSERT_TAIL(&uvm.page_free, pg, pageq);
1016 pg->pqflags = PQ_FREE;
1017 #ifdef DEBUG
1018 pg->uobject = (void *)0xdeadbeef;
1019 pg->offset = 0xdeadbeef;
1020 pg->uanon = (void *)0xdeadbeef;
1021 #endif
1022 uvmexp.free++;
1023 uvm_unlock_fpageq();
1024 splx(s);
1025 }
1026
1027 #if defined(UVM_PAGE_TRKOWN)
1028 /*
1029 * uvm_page_own: set or release page ownership
1030 *
1031 * => this is a debugging function that keeps track of who sets PG_BUSY
1032 * and where they do it. it can be used to track down problems
1033 * such a process setting "PG_BUSY" and never releasing it.
1034 * => page's object [if any] must be locked
1035 * => if "tag" is NULL then we are releasing page ownership
1036 */
1037 void uvm_page_own(pg, tag)
1038
1039 struct vm_page *pg;
1040 char *tag;
1041
1042 {
1043 /* gain ownership? */
1044 if (tag) {
1045 if (pg->owner_tag) {
1046 printf("uvm_page_own: page %p already owned by proc %d [%s]\n", pg,
1047 pg->owner, pg->owner_tag);
1048 panic("uvm_page_own");
1049 }
1050 pg->owner = (curproc) ? curproc->p_pid : (pid_t) -1;
1051 pg->owner_tag = tag;
1052 return;
1053 }
1054
1055 /* drop ownership */
1056 if (pg->owner_tag == NULL) {
1057 printf("uvm_page_own: dropping ownership of an non-owned page (%p)\n", pg);
1058 panic("uvm_page_own");
1059 }
1060 pg->owner_tag = NULL;
1061 return;
1062 }
1063 #endif
1064