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