Home | History | Annotate | Line # | Download | only in uvm
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