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