head    1.9;
access;
symbols;
locks
       cherry:1.9; strict;
comment @# @;


1.9
date    2016.12.13.12.56.39;    author cherry;  state Exp;
branches;
next    1.8;

1.8
date    2016.11.20.11.11.46;    author cherry;  state Exp;
branches;
next    1.7;

1.7
date    2016.11.20.11.08.57;    author cherry;  state Exp;
branches;
next    1.6;

1.6
date    2016.11.17.15.45.02;    author cherry;  state Exp;
branches;
next    1.5;

1.5
date    2016.11.13.11.23.05;    author cherry;  state Exp;
branches;
next    1.4;

1.4
date    2016.10.30.17.28.09;    author cherry;  state Exp;
branches;
next    1.3;

1.3
date    2016.10.28.08.32.31;    author cherry;  state Exp;
branches;
next    1.2;

1.2
date    2016.10.28.08.27.28;    author cherry;  state Exp;
branches;
next    1.1;

1.1
date    2016.10.20.14.29.09;    author cherry;  state Exp;
branches;
next    ;


desc
@Initial version for fox review
@


1.9
log
@s/physmem/physseg//
remove rump testing and dependency for tests
@
text
@Index: sys/uvm/Makefile
===================================================================
RCS file: /cvsroot/src/sys/uvm/Makefile,v
retrieving revision 1.9
diff -p -u -r1.9 Makefile
--- sys/uvm/Makefile    11 Feb 2006 12:45:07 -0000      1.9
+++ sys/uvm/Makefile    13 Dec 2016 12:44:34 -0000
@@@@ -5,7 +5,7 @@@@ INCSDIR= /usr/include/uvm
INCS=  uvm.h uvm_amap.h uvm_anon.h uvm_aobj.h uvm_device.h \
       uvm_extern.h uvm_fault.h uvm_fault_i.h uvm_glue.h \
       uvm_km.h uvm_loan.h \
-       uvm_map.h uvm_object.h uvm_page.h \
+       uvm_map.h uvm_object.h uvm_page.h uvm_physseg.h \
       uvm_pager.h uvm_param.h uvm_pdaemon.h uvm_pglist.h \
       uvm_pmap.h uvm_prot.h uvm_stat.h \
       uvm_swap.h
Index: sys/uvm/files.uvm
===================================================================
RCS file: /cvsroot/src/sys/uvm/files.uvm,v
retrieving revision 1.27
diff -p -u -r1.27 files.uvm
--- sys/uvm/files.uvm   1 Dec 2016 02:09:03 -0000       1.27
+++ sys/uvm/files.uvm   13 Dec 2016 12:44:34 -0000
@@@@ -15,6 +15,7 @@@@ defparam opt_pagermap.h           PAGER_MAP_SIZE
defflag                                PDPOLICY_CLOCKPRO
defparam                       USER_VA0_DISABLE_DEFAULT
defflag opt_uvm_page_trkown.h  UVM_PAGE_TRKOWN
+defflag opt_uvm_hotplug.h      UVM_HOTPLUG

define uvm
defflag        opt_uvm.h                       UVM
@@@@ -42,6 +43,7 @@@@ file      uvm/uvm_pdaemon.c               uvm
file   uvm/uvm_pdpolicy_clock.c        !pdpolicy_clockpro
file   uvm/uvm_pdpolicy_clockpro.c     pdpolicy_clockpro
file   uvm/uvm_pglist.c                uvm
+file   uvm/uvm_physseg.c               uvm
file   uvm/uvm_readahead.c             uvm
file   uvm/uvm_stat.c                  uvm
file   uvm/uvm_swap.c                  vmswap
Index: sys/uvm/uvm.h
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm.h,v
retrieving revision 1.66
diff -p -u -r1.66 uvm.h
--- sys/uvm/uvm.h       13 Apr 2015 22:04:44 -0000      1.66
+++ sys/uvm/uvm.h       13 Dec 2016 12:44:34 -0000
@@@@ -57,6 +57,7 @@@@
#include <uvm/uvm_object.h>
#include <uvm/uvm_page.h>
#include <uvm/uvm_pager.h>
+#include <uvm/uvm_physseg.h>
#include <uvm/uvm_pdaemon.h>
#include <uvm/uvm_swap.h>

Index: sys/uvm/uvm_extern.h
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_extern.h,v
retrieving revision 1.198
diff -p -u -r1.198 uvm_extern.h
--- sys/uvm/uvm_extern.h        20 Jul 2016 12:38:43 -0000      1.198
+++ sys/uvm/uvm_extern.h        13 Dec 2016 12:44:34 -0000
@@@@ -708,9 +708,6 @@@@ void                    uvm_pagereplace(struct vm_page *,
                           struct vm_page *);
void                   uvm_pagerealloc(struct vm_page *,
                           struct uvm_object *, voff_t);
-/* Actually, uvm_page_physload takes PF#s which need their own type */
-void                   uvm_page_physload(paddr_t, paddr_t, paddr_t,
-                           paddr_t, int);
void                   uvm_setpagesize(void);

/* uvm_pager.c */
Index: sys/uvm/uvm_page.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_page.c,v
retrieving revision 1.187
diff -p -u -r1.187 uvm_page.c
--- sys/uvm/uvm_page.c  11 Apr 2015 19:24:13 -0000      1.187
+++ sys/uvm/uvm_page.c  13 Dec 2016 12:44:35 -0000
@@@@ -81,24 +81,13 @@@@ __KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v
#include <sys/proc.h>
#include <sys/atomic.h>
#include <sys/cpu.h>
+#include <sys/extent.h>

#include <uvm/uvm.h>
#include <uvm/uvm_ddb.h>
#include <uvm/uvm_pdpolicy.h>

/*
- * global vars... XXXCDC: move to uvm. structure.
- */
-
-/*
- * physical memory config is stored in vm_physmem.
- */
-
-struct vm_physseg vm_physmem[VM_PHYSSEG_MAX];  /* XXXCDC: uvm.physmem */
-int vm_nphysseg = 0;                           /* XXXCDC: uvm.nphysseg */
-#define        vm_nphysmem     vm_nphysseg
-
-/*
 * Some supported CPUs in a given architecture don't support all
 * of the things necessary to do idle page zero'ing efficiently.
 * We therefore provide a way to enable it from machdep code here.
@@@@ -116,7 +105,7 @@@@ int vm_page_reserve_kernel = UVM_RESERVE
/*
 * physical memory size;
 */
-int physmem;
+psize_t physmem;

/*
 * local variables
@@@@ -146,6 +135,18 @@@@ vaddr_t uvm_zerocheckkva;
#endif /* DEBUG */

/*
+ * These functions are reserved for uvm(9) internal use and are not
+ * exported in the header file uvm_physseg.h
+ *
+ * Thus they are redefined here.
+ */
+void uvm_physseg_init_seg(uvm_physseg_t, struct vm_page *);
+void uvm_physseg_seg_chomp_slab(uvm_physseg_t, struct vm_page *, size_t);
+
+/* returns a pgs array */
+struct vm_page *uvm_physseg_seg_alloc_from_slab(uvm_physseg_t, size_t);
+
+/*
 * local prototypes
 */

@@@@ -337,11 +338,9 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
       static struct uvm_cpu boot_cpu;
       psize_t freepages, pagecount, bucketcount, n;
       struct pgflbucket *bucketarray, *cpuarray;
-       struct vm_physseg *seg;
       struct vm_page *pagearray;
+       uvm_physseg_t bank;
       int lcv;
-       u_int i;
-       paddr_t paddr;

       KASSERT(ncpu <= 1);
       CTASSERT(sizeof(pagearray->offset) >= sizeof(struct uvm_cpu *));
@@@@ -369,7 +368,7 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
        * now is to allocate vm_page structures for this memory.
        */

-       if (vm_nphysmem == 0)
+       if (uvm_physseg_get_last() == UVM_PHYSSEG_TYPE_INVALID)
               panic("uvm_page_bootstrap: no memory pre-allocated");

       /*
@@@@ -381,9 +380,11 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
        */

       freepages = 0;
-       for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) {
-               seg = VM_PHYSMEM_PTR(lcv);
-               freepages += (seg->end - seg->start);
+
+       for (bank = uvm_physseg_get_first();
+            uvm_physseg_valid(bank) ;
+            bank = uvm_physseg_get_next(bank)) {
+               freepages += (uvm_physseg_get_end(bank) - uvm_physseg_get_start(bank));
       }

       /*
@@@@ -428,31 +429,20 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
       /*
        * init the vm_page structures and put them in the correct place.
        */
+       /* First init the extent */

-       for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) {
-               seg = VM_PHYSMEM_PTR(lcv);
-               n = seg->end - seg->start;
+       for (bank = uvm_physseg_get_first(),
+                uvm_physseg_seg_chomp_slab(bank, pagearray, pagecount);
+            uvm_physseg_valid(bank);
+            bank = uvm_physseg_get_next(bank)) {
+
+               n = uvm_physseg_get_end(bank) - uvm_physseg_get_start(bank);
+               uvm_physseg_seg_alloc_from_slab(bank, n);
+               uvm_physseg_init_seg(bank, pagearray);

               /* set up page array pointers */
-               seg->pgs = pagearray;
               pagearray += n;
               pagecount -= n;
-               seg->lastpg = seg->pgs + n;
-
-               /* init and free vm_pages (we've already zeroed them) */
-               paddr = ctob(seg->start);
-               for (i = 0 ; i < n ; i++, paddr += PAGE_SIZE) {
-                       seg->pgs[i].phys_addr = paddr;
-#ifdef __HAVE_VM_PAGE_MD
-                       VM_MDPAGE_INIT(&seg->pgs[i]);
-#endif
-                       if (atop(paddr) >= seg->avail_start &&
-                           atop(paddr) < seg->avail_end) {
-                               uvmexp.npages++;
-                               /* add page to free pool */
-                               uvm_pagefree(&seg->pgs[i]);
-                       }
-               }
       }

       /*
@@@@ -625,92 +615,42 @@@@ static bool uvm_page_physget_freelist(pa
static bool
uvm_page_physget_freelist(paddr_t *paddrp, int freelist)
{
-       struct vm_physseg *seg;
-       int lcv, x;
+       uvm_physseg_t lcv;

       /* pass 1: try allocating from a matching end */
#if (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST)
-       for (lcv = vm_nphysmem - 1 ; lcv >= 0 ; lcv--)
+       for (lcv = uvm_physseg_get_last() ; uvm_physseg_valid(lcv) ; lcv = uvm_physseg_get_prev(lcv))
#else
-       for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
+               for (lcv = uvm_physseg_get_first() ; uvm_physseg_valid(lcv) ; lcv = uvm_physseg_get_next(lcv))
#endif
       {
-               seg = VM_PHYSMEM_PTR(lcv);
-
               if (uvm.page_init_done == true)
                       panic("uvm_page_physget: called _after_ bootstrap");

-               if (seg->free_list != freelist)
-                       continue;
+               /* Try to match at front or back on unused segment */
+               if (uvm_page_physunload(lcv, freelist, paddrp) == false) {
+                       if (paddrp == NULL) /* freelist fail, try next */
+                               continue;
+               } else
+                       return true;

-               /* try from front */
-               if (seg->avail_start == seg->start &&
-                   seg->avail_start < seg->avail_end) {
-                       *paddrp = ctob(seg->avail_start);
-                       seg->avail_start++;
-                       seg->start++;
-                       /* nothing left?   nuke it */
-                       if (seg->avail_start == seg->end) {
-                               if (vm_nphysmem == 1)
-                                   panic("uvm_page_physget: out of memory!");
-                               vm_nphysmem--;
-                               for (x = lcv ; x < vm_nphysmem ; x++)
-                                       /* structure copy */
-                                       VM_PHYSMEM_PTR_SWAP(x, x + 1);
-                       }
-                       return (true);
-               }
-
-               /* try from rear */
-               if (seg->avail_end == seg->end &&
-                   seg->avail_start < seg->avail_end) {
-                       *paddrp = ctob(seg->avail_end - 1);
-                       seg->avail_end--;
-                       seg->end--;
-                       /* nothing left?   nuke it */
-                       if (seg->avail_end == seg->start) {
-                               if (vm_nphysmem == 1)
-                                   panic("uvm_page_physget: out of memory!");
-                               vm_nphysmem--;
-                               for (x = lcv ; x < vm_nphysmem ; x++)
-                                       /* structure copy */
-                                       VM_PHYSMEM_PTR_SWAP(x, x + 1);
-                       }
-                       return (true);
-               }
-       }

       /* pass2: forget about matching ends, just allocate something */
#if (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST)
-       for (lcv = vm_nphysmem - 1 ; lcv >= 0 ; lcv--)
+               for (lcv = uvm_physseg_get_last() ; uvm_physseg_valid(lcv); lcv = uvm_physseg_get_prev(lcv))
#else
-       for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
+               for (lcv = uvm_physseg_get_first() ; uvm_physseg_valid(lcv) ; lcv = uvm_physseg_get_next(lcv))
#endif
       {
-               seg = VM_PHYSMEM_PTR(lcv);
-
-               /* any room in this bank? */
-               if (seg->avail_start >= seg->avail_end)
-                       continue;  /* nope */
-
-               *paddrp = ctob(seg->avail_start);
-               seg->avail_start++;
-               /* truncate! */
-               seg->start = seg->avail_start;
-
-               /* nothing left?   nuke it */
-               if (seg->avail_start == seg->end) {
-                       if (vm_nphysmem == 1)
-                               panic("uvm_page_physget: out of memory!");
-                       vm_nphysmem--;
-                       for (x = lcv ; x < vm_nphysmem ; x++)
-                               /* structure copy */
-                               VM_PHYSMEM_PTR_SWAP(x, x + 1);
-               }
-               return (true);
+               /* Try the front regardless. */
+               if (uvm_page_physunload_force(lcv, freelist, paddrp) == false) {
+                       if (paddrp == NULL) /* freelist fail, try next */
+                               continue;
+               } else
+                       return true;
       }
-
-       return (false);        /* whoops! */
+       }
+       return false;
}

bool
@@@@ -727,228 +667,6 @@@@ uvm_page_physget(paddr_t *paddrp)
#endif /* PMAP_STEAL_MEMORY */

/*
- * uvm_page_physload: load physical memory into VM system
- *
- * => all args are PFs
- * => all pages in start/end get vm_page structures
- * => areas marked by avail_start/avail_end get added to the free page pool
- * => we are limited to VM_PHYSSEG_MAX physical memory segments
- */
-
-void
-uvm_page_physload(paddr_t start, paddr_t end, paddr_t avail_start,
-    paddr_t avail_end, int free_list)
-{
-       int preload, lcv;
-       psize_t npages;
-       struct vm_page *pgs;
-       struct vm_physseg *ps;
-
-       if (uvmexp.pagesize == 0)
-               panic("uvm_page_physload: page size not set!");
-       if (free_list >= VM_NFREELIST || free_list < VM_FREELIST_DEFAULT)
-               panic("uvm_page_physload: bad free list %d", free_list);
-       if (start >= end)
-               panic("uvm_page_physload: start >= end");
-
-       /*
-        * do we have room?
-        */
-
-       if (vm_nphysmem == VM_PHYSSEG_MAX) {
-               printf("uvm_page_physload: unable to load physical memory "
-                   "segment\n");
-               printf("\t%d segments allocated, ignoring 0x%llx -> 0x%llx\n",
-                   VM_PHYSSEG_MAX, (long long)start, (long long)end);
-               printf("\tincrease VM_PHYSSEG_MAX\n");
-               return;
-       }
-
-       /*
-        * check to see if this is a "preload" (i.e. uvm_page_init hasn't been
-        * called yet, so kmem is not available).
-        */
-
-       for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) {
-               if (VM_PHYSMEM_PTR(lcv)->pgs)
-                       break;
-       }
-       preload = (lcv == vm_nphysmem);
-
-       /*
-        * if VM is already running, attempt to kmem_alloc vm_page structures
-        */
-
-       if (!preload) {
-               panic("uvm_page_physload: tried to add RAM after vm_mem_init");
-       } else {
-               pgs = NULL;
-               npages = 0;
-       }
-
-       /*
-        * now insert us in the proper place in vm_physmem[]
-        */
-
-#if (VM_PHYSSEG_STRAT == VM_PSTRAT_RANDOM)
-       /* random: put it at the end (easy!) */
-       ps = VM_PHYSMEM_PTR(vm_nphysmem);
-#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
-       {
-               int x;
-               /* sort by address for binary search */
-               for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
-                       if (start < VM_PHYSMEM_PTR(lcv)->start)
-                               break;
-               ps = VM_PHYSMEM_PTR(lcv);
-               /* move back other entries, if necessary ... */
-               for (x = vm_nphysmem ; x > lcv ; x--)
-                       /* structure copy */
-                       VM_PHYSMEM_PTR_SWAP(x, x - 1);
-       }
-#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST)
-       {
-               int x;
-               /* sort by largest segment first */
-               for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
-                       if ((end - start) >
-                           (VM_PHYSMEM_PTR(lcv)->end - VM_PHYSMEM_PTR(lcv)->start))
-                               break;
-               ps = VM_PHYSMEM_PTR(lcv);
-               /* move back other entries, if necessary ... */
-               for (x = vm_nphysmem ; x > lcv ; x--)
-                       /* structure copy */
-                       VM_PHYSMEM_PTR_SWAP(x, x - 1);
-       }
-#else
-       panic("uvm_page_physload: unknown physseg strategy selected!");
-#endif
-
-       ps->start = start;
-       ps->end = end;
-       ps->avail_start = avail_start;
-       ps->avail_end = avail_end;
-       if (preload) {
-               ps->pgs = NULL;
-       } else {
-               ps->pgs = pgs;
-               ps->lastpg = pgs + npages;
-       }
-       ps->free_list = free_list;
-       vm_nphysmem++;
-
-       if (!preload) {
-               uvmpdpol_reinit();
-       }
-}
-
-/*
- * when VM_PHYSSEG_MAX is 1, we can simplify these functions
- */
-
-#if VM_PHYSSEG_MAX == 1
-static inline int vm_physseg_find_contig(struct vm_physseg *, int, paddr_t, int *);
-#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
-static inline int vm_physseg_find_bsearch(struct vm_physseg *, int, paddr_t, int *);
-#else
-static inline int vm_physseg_find_linear(struct vm_physseg *, int, paddr_t, int *);
-#endif
-
-/*
- * vm_physseg_find: find vm_physseg structure that belongs to a PA
- */
-int
-vm_physseg_find(paddr_t pframe, int *offp)
-{
-
-#if VM_PHYSSEG_MAX == 1
-       return vm_physseg_find_contig(vm_physmem, vm_nphysseg, pframe, offp);
-#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
-       return vm_physseg_find_bsearch(vm_physmem, vm_nphysseg, pframe, offp);
-#else
-       return vm_physseg_find_linear(vm_physmem, vm_nphysseg, pframe, offp);
-#endif
-}
-
-#if VM_PHYSSEG_MAX == 1
-static inline int
-vm_physseg_find_contig(struct vm_physseg *segs, int nsegs, paddr_t pframe, int *offp)
-{
-
-       /* 'contig' case */
-       if (pframe >= segs[0].start && pframe < segs[0].end) {
-               if (offp)
-                       *offp = pframe - segs[0].start;
-               return(0);
-       }
-       return(-1);
-}
-
-#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
-
-static inline int
-vm_physseg_find_bsearch(struct vm_physseg *segs, int nsegs, paddr_t pframe, int *offp)
-{
-       /* binary search for it */
-       u_int   start, len, guess;
-
-       /*
-        * if try is too large (thus target is less than try) we reduce
-        * the length to trunc(len/2) [i.e. everything smaller than "try"]
-        *
-        * if the try is too small (thus target is greater than try) then
-        * we set the new start to be (try + 1).   this means we need to
-        * reduce the length to (round(len/2) - 1).
-        *
-        * note "adjust" below which takes advantage of the fact that
-        *  (round(len/2) - 1) == trunc((len - 1) / 2)
-        * for any value of len we may have
-        */
-
-       for (start = 0, len = nsegs ; len != 0 ; len = len / 2) {
-               guess = start + (len / 2);      /* try in the middle */
-
-               /* start past our try? */
-               if (pframe >= segs[guess].start) {
-                       /* was try correct? */
-                       if (pframe < segs[guess].end) {
-                               if (offp)
-                                       *offp = pframe - segs[guess].start;
-                               return guess;            /* got it */
-                       }
-                       start = guess + 1;      /* next time, start here */
-                       len--;                  /* "adjust" */
-               } else {
-                       /*
-                        * pframe before try, just reduce length of
-                        * region, done in "for" loop
-                        */
-               }
-       }
-       return(-1);
-}
-
-#else
-
-static inline int
-vm_physseg_find_linear(struct vm_physseg *segs, int nsegs, paddr_t pframe, int *offp)
-{
-       /* linear search for it */
-       int     lcv;
-
-       for (lcv = 0; lcv < nsegs; lcv++) {
-               if (pframe >= segs[lcv].start &&
-                   pframe < segs[lcv].end) {
-                       if (offp)
-                               *offp = pframe - segs[lcv].start;
-                       return(lcv);               /* got it */
-               }
-       }
-       return(-1);
-}
-#endif
-
-/*
 * PHYS_TO_VM_PAGE: find vm_page for a PA.   used by MI code to get vm_pages
 * back from an I/O mapping (ugh!).   used in some MD code as well.
 */
@@@@ -956,12 +674,12 @@@@ struct vm_page *
uvm_phys_to_vm_page(paddr_t pa)
{
       paddr_t pf = atop(pa);
-       int     off;
-       int     psi;
+       paddr_t off;
+       uvm_physseg_t   upm;

-       psi = vm_physseg_find(pf, &off);
-       if (psi != -1)
-               return(&VM_PHYSMEM_PTR(psi)->pgs[off]);
+       upm = uvm_physseg_find(pf, &off);
+       if (upm != UVM_PHYSSEG_TYPE_INVALID)
+               return uvm_physseg_get_pg(upm, off);
       return(NULL);
}

@@@@ -985,7 +703,8 @@@@ uvm_page_recolor(int newncolors)
       struct vm_page *pg;
       vsize_t bucketcount;
       size_t bucketmemsize, oldbucketmemsize;
-       int lcv, color, i, ocolors;
+       int color, i, ocolors;
+       int lcv;
       struct uvm_cpu *ucpu;

       KASSERT(((newncolors - 1) & newncolors) == 0);
@@@@ -1094,6 +813,7 @@@@ uvm_cpu_attach(struct cpu_info *ci)
       uvm.cpus[cpu_index(ci)] = ucpu;
       ci->ci_data.cpu_uvm = ucpu;
       for (lcv = 0; lcv < VM_NFREELIST; lcv++) {
+
               pgfl.pgfl_buckets = (bucketarray + (lcv * uvmexp.ncolors));
               uvm_page_init_buckets(&pgfl);
               ucpu->page_free[lcv].pgfl_buckets = pgfl.pgfl_buckets;
@@@@ -1219,7 +939,8 @@@@ struct vm_page *
uvm_pagealloc_strat(struct uvm_object *obj, voff_t off, struct vm_anon *anon,
    int flags, int strat, int free_list)
{
-       int lcv, try1, try2, zeroit = 0, color;
+       int try1, try2, zeroit = 0, color;
+       int lcv;
       struct uvm_cpu *ucpu;
       struct vm_page *pg;
       lwp_t *l;
@@@@ -2005,7 +1726,7 @@@@ bool
uvm_pageismanaged(paddr_t pa)
{

-       return (vm_physseg_find(atop(pa), NULL) != -1);
+       return (uvm_physseg_find(atop(pa), NULL) != UVM_PHYSSEG_TYPE_INVALID);
}

/*
@@@@ -2015,11 +1736,11 @@@@ uvm_pageismanaged(paddr_t pa)
int
uvm_page_lookup_freelist(struct vm_page *pg)
{
-       int lcv;
+       uvm_physseg_t upm;

-       lcv = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), NULL);
-       KASSERT(lcv != -1);
-       return (VM_PHYSMEM_PTR(lcv)->free_list);
+       upm = uvm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), NULL);
+       KASSERT(upm != UVM_PHYSSEG_TYPE_INVALID);
+       return uvm_physseg_get_free_list(upm);
}

/*
@@@@ -2135,7 +1856,8 @@@@ uvm_page_printit(struct vm_page *pg, boo
void
uvm_page_printall(void (*pr)(const char *, ...))
{
-       unsigned i;
+       uvm_physseg_t i;
+       paddr_t pfn;
       struct vm_page *pg;

       (*pr)("%18s %4s %4s %18s %18s"
@@@@ -2143,8 +1865,14 @@@@ uvm_page_printall(void (*pr)(const char
           " OWNER"
#endif
           "\n", "PAGE", "FLAG", "PQ", "UOBJECT", "UANON");
-       for (i = 0; i < vm_nphysmem; i++) {
-               for (pg = VM_PHYSMEM_PTR(i)->pgs; pg < VM_PHYSMEM_PTR(i)->lastpg; pg++) {
+       for (i = uvm_physseg_get_first();
+            uvm_physseg_valid(i);
+            i = uvm_physseg_get_next(i)) {
+               for (pfn = uvm_physseg_get_start(i);
+                    pfn <= uvm_physseg_get_end(i);
+                    pfn++) {
+                       pg = PHYS_TO_VM_PAGE(ptoa(pfn));
+
                       (*pr)("%18p %04x %04x %18p %18p",
                           pg, pg->flags, pg->pqflags, pg->uobject,
                           pg->uanon);
Index: sys/uvm/uvm_page.h
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_page.h,v
retrieving revision 1.80
diff -p -u -r1.80 uvm_page.h
--- sys/uvm/uvm_page.h  23 Mar 2015 07:59:12 -0000      1.80
+++ sys/uvm/uvm_page.h  13 Dec 2016 12:44:35 -0000
@@@@ -294,24 +294,6 @@@@ struct vm_page {
#define VM_PSTRAT_BSEARCH      2
#define VM_PSTRAT_BIGFIRST     3

-/*
- * vm_physseg: describes one segment of physical memory
- */
-struct vm_physseg {
-       paddr_t start;                  /* PF# of first page in segment */
-       paddr_t end;                    /* (PF# of last page in segment) + 1 */
-       paddr_t avail_start;            /* PF# of first free page in segment */
-       paddr_t avail_end;              /* (PF# of last free page in segment) +1  */
-       struct  vm_page *pgs;           /* vm_page structures (from start) */
-       struct  vm_page *lastpg;        /* vm_page structure for end */
-       int     free_list;              /* which free list they belong on */
-       u_int   start_hint;             /* start looking for free pages here */
-                                       /* protected by uvm_fpageqlock */
-#ifdef __HAVE_PMAP_PHYSSEG
-       struct  pmap_physseg pmseg;     /* pmap specific (MD) data */
-#endif
-};
-
#ifdef _KERNEL

/*
@@@@ -321,21 +303,6 @@@@ struct vm_physseg {
extern bool vm_page_zero_enable;

/*
- * physical memory config is stored in vm_physmem.
- */
-
-#define        VM_PHYSMEM_PTR(i)       (&vm_physmem[i])
-#if VM_PHYSSEG_MAX == 1
-#define VM_PHYSMEM_PTR_SWAP(i, j) /* impossible */
-#else
-#define VM_PHYSMEM_PTR_SWAP(i, j) \
-       do { vm_physmem[(i)] = vm_physmem[(j)]; } while (0)
-#endif
-
-extern struct vm_physseg vm_physmem[VM_PHYSSEG_MAX];
-extern int vm_nphysseg;
-
-/*
 * prototypes: the following prototypes define the interface to pages
 */

@@@@ -366,10 +333,13 @@@@ bool uvm_page_locked_p(struct vm_page *)

int uvm_page_lookup_freelist(struct vm_page *);

-int vm_physseg_find(paddr_t, int *);
struct vm_page *uvm_phys_to_vm_page(paddr_t);
paddr_t uvm_vm_page_to_phys(const struct vm_page *);

+#if !defined(PMAP_STEAL_MEMORY)
+bool uvm_page_physget(paddr_t *);
+#endif
+
/*
 * macros
 */
Index: sys/uvm/uvm_pglist.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_pglist.c,v
retrieving revision 1.67
diff -p -u -r1.67 uvm_pglist.c
--- sys/uvm/uvm_pglist.c        26 Oct 2014 01:42:07 -0000      1.67
+++ sys/uvm/uvm_pglist.c        13 Dec 2016 12:44:35 -0000
@@@@ -116,16 +116,15 @@@@ uvm_pglist_add(struct vm_page *pg, struc
}

static int
-uvm_pglistalloc_c_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high,
+uvm_pglistalloc_c_ps(uvm_physseg_t psi, int num, paddr_t low, paddr_t high,
    paddr_t alignment, paddr_t boundary, struct pglist *rlist)
{
       signed int candidate, limit, candidateidx, end, idx, skip;
-       struct vm_page *pgs;
       int pagemask;
       bool second_pass;
#ifdef DEBUG
       paddr_t idxpa, lastidxpa;
-       int cidx = 0;   /* XXX: GCC */
+       paddr_t cidx = 0;       /* XXX: GCC */
#endif
#ifdef PGALLOC_VERBOSE
       printf("pgalloc: contig %d pgs from psi %zd\n", num, ps - vm_physmem);
@@@@ -140,26 +139,26 @@@@ uvm_pglistalloc_c_ps(struct vm_physseg *
       /*
        * Make sure that physseg falls within with range to be allocated from.
        */
-       if (high <= ps->avail_start || low >= ps->avail_end)
+       if (high <= uvm_physseg_get_avail_start(psi) || low >= uvm_physseg_get_avail_end(psi))
               return 0;

       /*
        * We start our search at the just after where the last allocation
        * succeeded.
        */
-       candidate = roundup2(max(low, ps->avail_start + ps->start_hint), alignment);
-       limit = min(high, ps->avail_end);
+       candidate = roundup2(max(low, uvm_physseg_get_avail_start(psi) +
+               uvm_physseg_get_start_hint(psi)), alignment);
+       limit = min(high, uvm_physseg_get_avail_end(psi));
       pagemask = ~((boundary >> PAGE_SHIFT) - 1);
       skip = 0;
       second_pass = false;
-       pgs = ps->pgs;

       for (;;) {
               bool ok = true;
               signed int cnt;

               if (candidate + num > limit) {
-                       if (ps->start_hint == 0 || second_pass) {
+                       if (uvm_physseg_get_start_hint(psi) == 0 || second_pass) {
                               /*
                                * We've run past the allowable range.
                                */
@@@@ -171,8 +170,9 @@@@ uvm_pglistalloc_c_ps(struct vm_physseg *
                        * is were we started.
                        */
                       second_pass = true;
-                       candidate = roundup2(max(low, ps->avail_start), alignment);
-                       limit = min(limit, ps->avail_start + ps->start_hint);
+                       candidate = roundup2(max(low, uvm_physseg_get_avail_start(psi)), alignment);
+                       limit = min(limit, uvm_physseg_get_avail_start(psi) +
+                           uvm_physseg_get_start_hint(psi));
                       skip = 0;
                       continue;
               }
@@@@ -192,16 +192,16 @@@@ uvm_pglistalloc_c_ps(struct vm_physseg *
                * Make sure this is a managed physical page.
                */

-               if (vm_physseg_find(candidate, &cidx) != ps - vm_physmem)
+               if (uvm_physseg_find(candidate, &cidx) != psi)
                       panic("pgalloc contig: botch1");
-               if (cidx != candidate - ps->start)
+               if (cidx != candidate - uvm_physseg_get_start(psi))
                       panic("pgalloc contig: botch2");
-               if (vm_physseg_find(candidate + num - 1, &cidx) != ps - vm_physmem)
+               if (uvm_physseg_find(candidate + num - 1, &cidx) != psi)
                       panic("pgalloc contig: botch3");
-               if (cidx != candidate - ps->start + num - 1)
+               if (cidx != candidate - uvm_physseg_get_start(psi) + num - 1)
                       panic("pgalloc contig: botch4");
#endif
-               candidateidx = candidate - ps->start;
+               candidateidx = candidate - uvm_physseg_get_start(psi);
               end = candidateidx + num;

               /*
@@@@ -220,15 +220,15 @@@@ uvm_pglistalloc_c_ps(struct vm_physseg *
                * testing most of those pages again in the next pass.
                */
               for (idx = end - 1; idx >= candidateidx + skip; idx--) {
-                       if (VM_PAGE_IS_FREE(&pgs[idx]) == 0) {
+                       if (VM_PAGE_IS_FREE(uvm_physseg_get_pg(psi, idx)) == 0) {
                               ok = false;
                               break;
                       }

#ifdef DEBUG
                       if (idx > candidateidx) {
-                               idxpa = VM_PAGE_TO_PHYS(&pgs[idx]);
-                               lastidxpa = VM_PAGE_TO_PHYS(&pgs[idx - 1]);
+                               idxpa = VM_PAGE_TO_PHYS(uvm_physseg_get_pg(psi, idx));
+                               lastidxpa = VM_PAGE_TO_PHYS(uvm_physseg_get_pg(psi, idx));
                               if ((lastidxpa + PAGE_SIZE) != idxpa) {
                                       /*
                                        * Region not contiguous.
@@@@ -249,7 +249,7 @@@@ uvm_pglistalloc_c_ps(struct vm_physseg *

               if (ok) {
                       while (skip-- > 0) {
-                               KDASSERT(VM_PAGE_IS_FREE(&pgs[candidateidx + skip]));
+                               KDASSERT(VM_PAGE_IS_FREE(uvm_physseg_get_pg(psi, candidateidx + skip)));
                       }
#ifdef PGALLOC_VERBOSE
                       printf(": ok\n");
@@@@ -280,19 +280,22 @@@@ uvm_pglistalloc_c_ps(struct vm_physseg *
       /*
        * we have a chunk of memory that conforms to the requested constraints.
        */
-       for (idx = candidateidx, pgs += idx; idx < end; idx++, pgs++)
-               uvm_pglist_add(pgs, rlist);
+       for (idx = candidateidx; idx < end; idx++)
+               uvm_pglist_add(uvm_physseg_get_pg(psi, idx), rlist);

       /*
        * the next time we need to search this segment, start after this
        * chunk of pages we just allocated.
        */
-       ps->start_hint = candidate + num - ps->avail_start;
-       KASSERTMSG(ps->start_hint <= ps->avail_end - ps->avail_start,
+       uvm_physseg_set_start_hint(psi, candidate + num -
+           uvm_physseg_get_avail_start(psi));
+       KASSERTMSG(uvm_physseg_get_start_hint(psi) <=
+           uvm_physseg_get_avail_end(psi) - uvm_physseg_get_avail_start(psi),
           "%x %u (%#x) <= %#"PRIxPADDR" - %#"PRIxPADDR" (%#"PRIxPADDR")",
           candidate + num,
-           ps->start_hint, ps->start_hint, ps->avail_end, ps->avail_start,
-           ps->avail_end - ps->avail_start);
+           uvm_physseg_get_start_hint(psi), uvm_physseg_get_start_hint(psi),
+           uvm_physseg_get_avail_end(psi), uvm_physseg_get_avail_start(psi),
+           uvm_physseg_get_avail_end(psi) - uvm_physseg_get_avail_start(psi));

#ifdef PGALLOC_VERBOSE
       printf("got %d pgs\n", num);
@@@@ -304,10 +307,10 @@@@ static int
uvm_pglistalloc_contig(int num, paddr_t low, paddr_t high, paddr_t alignment,
    paddr_t boundary, struct pglist *rlist)
{
-       int fl, psi;
-       struct vm_physseg *ps;
+       int fl;
       int error;

+       uvm_physseg_t psi;
       /* Default to "lose". */
       error = ENOMEM;

@@@@ -322,17 +325,16 @@@@ uvm_pglistalloc_contig(int num, paddr_t

       for (fl = 0; fl < VM_NFREELIST; fl++) {
#if (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST)
-               for (psi = vm_nphysseg - 1 ; psi >= 0 ; psi--)
+               for (psi = uvm_physseg_get_last(); uvm_physseg_valid(psi); psi = uvm_physseg_get_prev(psi))
+
#else
-               for (psi = 0 ; psi < vm_nphysseg ; psi++)
+               for (psi = uvm_physseg_get_first(); uvm_physseg_valid(psi); psi = uvm_physseg_get_next(psi))
#endif
               {
-                       ps = &vm_physmem[psi];
-
-                       if (ps->free_list != fl)
+                       if (uvm_physseg_get_free_list(psi) != fl)
                               continue;

-                       num -= uvm_pglistalloc_c_ps(ps, num, low, high,
+                       num -= uvm_pglistalloc_c_ps(psi, num, low, high,
                                                   alignment, boundary, rlist);
                       if (num == 0) {
#ifdef PGALLOC_VERBOSE
@@@@ -358,59 +360,62 @@@@ out:
}

static int
-uvm_pglistalloc_s_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high,
+uvm_pglistalloc_s_ps(uvm_physseg_t psi, int num, paddr_t low, paddr_t high,
    struct pglist *rlist)
{
       int todo, limit, candidate;
       struct vm_page *pg;
       bool second_pass;
#ifdef PGALLOC_VERBOSE
-       printf("pgalloc: simple %d pgs from psi %zd\n", num, ps - vm_physmem);
+       printf("pgalloc: simple %d pgs from psi %zd\n", num, psi);
#endif

       KASSERT(mutex_owned(&uvm_fpageqlock));
-       KASSERT(ps->start <= ps->avail_start);
-       KASSERT(ps->start <= ps->avail_end);
-       KASSERT(ps->avail_start <= ps->end);
-       KASSERT(ps->avail_end <= ps->end);
+       KASSERT(uvm_physseg_get_start(psi) <= uvm_physseg_get_avail_start(psi));
+       KASSERT(uvm_physseg_get_start(psi) <= uvm_physseg_get_avail_end(psi));
+       KASSERT(uvm_physseg_get_avail_start(psi) <= uvm_physseg_get_end(psi));
+       KASSERT(uvm_physseg_get_avail_end(psi) <= uvm_physseg_get_end(psi));

       low = atop(low);
       high = atop(high);
       todo = num;
-       candidate = max(low, ps->avail_start + ps->start_hint);
-       limit = min(high, ps->avail_end);
-       pg = &ps->pgs[candidate - ps->start];
+       candidate = max(low, uvm_physseg_get_avail_start(psi) +
+           uvm_physseg_get_start_hint(psi));
+       limit = min(high, uvm_physseg_get_avail_end(psi));
+       pg = uvm_physseg_get_pg(psi, candidate - uvm_physseg_get_start(psi));
       second_pass = false;

       /*
        * Make sure that physseg falls within with range to be allocated from.
        */
-       if (high <= ps->avail_start || low >= ps->avail_end)
+       if (high <= uvm_physseg_get_avail_start(psi) ||
+           low >= uvm_physseg_get_avail_end(psi))
               return 0;

again:
       for (;; candidate++, pg++) {
               if (candidate >= limit) {
-                       if (ps->start_hint == 0 || second_pass) {
+                       if (uvm_physseg_get_start_hint(psi) == 0 || second_pass) {
                               candidate = limit - 1;
                               break;
                       }
                       second_pass = true;
-                       candidate = max(low, ps->avail_start);
-                       limit = min(limit, ps->avail_start + ps->start_hint);
-                       pg = &ps->pgs[candidate - ps->start];
+                       candidate = max(low, uvm_physseg_get_avail_start(psi));
+                       limit = min(limit, uvm_physseg_get_avail_start(psi) +
+                           uvm_physseg_get_start_hint(psi));
+                       pg = uvm_physseg_get_pg(psi, candidate - uvm_physseg_get_start(psi));
                       goto again;
               }
#if defined(DEBUG)
               {
-                       int cidx = 0;
-                       const int bank = vm_physseg_find(candidate, &cidx);
-                       KDASSERTMSG(bank == ps - vm_physmem,
-                           "vm_physseg_find(%#x) (%d) != ps %zd",
-                            candidate, bank, ps - vm_physmem);
-                       KDASSERTMSG(cidx == candidate - ps->start,
-                           "vm_physseg_find(%#x): %#x != off %"PRIxPADDR,
-                            candidate, cidx, candidate - ps->start);
+                       paddr_t cidx = 0;
+                       const uvm_physseg_t bank = uvm_physseg_find(candidate, &cidx);
+                       KDASSERTMSG(bank == psi,
+                           "uvm_physseg_find(%#x) (%"PRIxPHYSMEM ") != psi %"PRIxPHYSMEM,
+                            candidate, bank, psi);
+                       KDASSERTMSG(cidx == candidate - uvm_physseg_get_start(psi),
+                           "uvm_physseg_find(%#x): %#"PRIxPADDR" != off %"PRIxPADDR,
+                            candidate, cidx, candidate - uvm_physseg_get_start(psi));
               }
#endif
               if (VM_PAGE_IS_FREE(pg) == 0)
@@@@ -426,12 +431,16 @@@@ again:
        * The next time we need to search this segment,
        * start just after the pages we just allocated.
        */
-       ps->start_hint = candidate + 1 - ps->avail_start;
-       KASSERTMSG(ps->start_hint <= ps->avail_end - ps->avail_start,
+       uvm_physseg_set_start_hint(psi, candidate + 1 - uvm_physseg_get_avail_start(psi));
+       KASSERTMSG(uvm_physseg_get_start_hint(psi) <= uvm_physseg_get_avail_end(psi) -
+           uvm_physseg_get_avail_start(psi),
           "%#x %u (%#x) <= %#"PRIxPADDR" - %#"PRIxPADDR" (%#"PRIxPADDR")",
           candidate + 1,
-           ps->start_hint, ps->start_hint, ps->avail_end, ps->avail_start,
-           ps->avail_end - ps->avail_start);
+           uvm_physseg_get_start_hint(psi),
+           uvm_physseg_get_start_hint(psi),
+           uvm_physseg_get_avail_end(psi),
+           uvm_physseg_get_avail_start(psi),
+           uvm_physseg_get_avail_end(psi) - uvm_physseg_get_avail_start(psi));

#ifdef PGALLOC_VERBOSE
       printf("got %d pgs\n", num - todo);
@@@@ -443,9 +452,10 @@@@ static int
uvm_pglistalloc_simple(int num, paddr_t low, paddr_t high,
    struct pglist *rlist, int waitok)
{
-       int fl, psi, error;
-       struct vm_physseg *ps;
+       int fl, error;

+       uvm_physseg_t psi;
+
       /* Default to "lose". */
       error = ENOMEM;

@@@@ -461,17 +471,16 @@@@ again:

       for (fl = 0; fl < VM_NFREELIST; fl++) {
#if (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST)
-               for (psi = vm_nphysseg - 1 ; psi >= 0 ; psi--)
+               for (psi = uvm_physseg_get_last(); uvm_physseg_valid(psi); psi = uvm_physseg_get_prev(psi))
+
#else
-               for (psi = 0 ; psi < vm_nphysseg ; psi++)
+               for (psi = uvm_physseg_get_first(); uvm_physseg_valid(psi); psi = uvm_physseg_get_next(psi))
#endif
               {
-                       ps = &vm_physmem[psi];
-
-                       if (ps->free_list != fl)
+                       if (uvm_physseg_get_free_list(psi) != fl)
                               continue;

-                       num -= uvm_pglistalloc_s_ps(ps, num, low, high, rlist);
+                       num -= uvm_pglistalloc_s_ps(psi, num, low, high, rlist);
                       if (num == 0) {
                               error = 0;
                               goto out;
Index: sys/uvm/uvm_physseg.c
===================================================================
RCS file: sys/uvm/uvm_physseg.c
diff -N sys/uvm/uvm_physseg.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/uvm/uvm_physseg.c       13 Dec 2016 12:44:35 -0000
@@@@ -0,0 +1,1351 @@@@
+/* $NetBSD$ */
+
+/*
+ * Copyright (c) 1997 Charles D. Cranor and Washington University.
+ * Copyright (c) 1991, 1993, The Regents of the University of California.
+ *
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * The Mach Operating System project at Carnegie-Mellon University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @@(#)vm_page.h   7.3 (Berkeley) 4/21/91
+ * from: Id: uvm_page.h,v 1.1.2.6 1998/02/04 02:31:42 chuck Exp
+ *
+ *
+ * Copyright (c) 1987, 1990 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Consolidated API from uvm_page.c and others.
+ * Consolidated and designed by Cherry G. Mathew <cherry@@zyx.in>
+ * rbtree(3) backing implementation by:
+ * Santhosh N. Raju <santhosh.raju@@gmail.com>
+ */
+
+#ifdef _KERNEL_OPT
+#include "opt_uvm.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/extent.h>
+#include <sys/kmem.h>
+
+#include <uvm/uvm.h>
+#include <uvm/uvm_page.h>
+#include <uvm/uvm_param.h>
+#include <uvm/uvm_pdpolicy.h>
+#include <uvm/uvm_physseg.h>
+
+/*
+ * vm_physseg: describes one segment of physical memory
+ */
+struct uvm_physseg {
+       struct  rb_node rb_node;        /* tree information */
+       paddr_t start;                  /* PF# of first page in segment */
+       paddr_t end;                    /* (PF# of last page in segment) + 1 */
+       paddr_t avail_start;            /* PF# of first free page in segment */
+       paddr_t avail_end;              /* (PF# of last free page in segment) +1  */
+       struct  vm_page *pgs;           /* vm_page structures (from start) */
+       struct  extent *ext;            /* extent(9) structure to manage pgs[] */
+       int     free_list;              /* which free list they belong on */
+       u_int   start_hint;             /* start looking for free pages here */
+                                       /* protected by uvm_fpageqlock */
+#ifdef __HAVE_PMAP_PHYSSEG
+       struct  pmap_physseg pmseg;     /* pmap specific (MD) data */
+#endif
+};
+
+/*
+ * These functions are reserved for uvm(9) internal use and are not
+ * exported in the header file uvm_physseg.h
+ *
+ * Thus they are redefined here.
+ */
+void uvm_physseg_init_seg(uvm_physseg_t, struct vm_page *);
+void uvm_physseg_seg_chomp_slab(uvm_physseg_t, struct vm_page *, size_t);
+
+/* returns a pgs array */
+struct vm_page *uvm_physseg_seg_alloc_from_slab(uvm_physseg_t, size_t);
+
+#if defined(UVM_HOTPLUG) /* rbtree impementation */
+
+#define        HANDLE_TO_PHYSSEG_NODE(h)       ((struct uvm_physseg *)(h))
+#define                PHYSSEG_NODE_TO_HANDLE(u)       ((uvm_physseg_t)(u))
+
+
+struct uvm_physseg_graph {
+       struct rb_tree rb_tree;         /* Tree for entries */
+       int            nentries;        /* Number of entries */
+};
+
+static struct uvm_physseg_graph uvm_physseg_graph;
+
+/*
+ * Note on kmem(9) allocator usage:
+ * We take the conservative approach that plug/unplug are allowed to
+ * fail in high memory stress situations.
+ *
+ * We want to avoid re-entrant situations in which one plug/unplug
+ * operation is waiting on a previous one to complete, since this
+ * makes the design more complicated than necessary.
+ *
+ * We may review this and change its behaviour, once the use cases
+ * become more obvious.
+ */
+
+/*
+ * Special alloc()/free() functions for boot time support:
+ * We assume that alloc() at boot time is only for new 'vm_physseg's
+ * This allows us to use a static array for memory allocation at boot
+ * time. Thus we avoid using kmem(9) which is not ready at this point
+ * in boot.
+ *
+ * After kmem(9) is ready, we use it. We currently discard any free()s
+ * to this static array, since the size is small enough to be a
+ * trivial waste on all architectures we run on.
+ *
+ */
+
+static size_t nseg = 0;
+static struct uvm_physseg uvm_physseg[VM_PHYSSEG_MAX];
+
+static void *
+uvm_physseg_alloc(size_t sz)
+{
+       /*
+        * During boot time, we only support allocating vm_physseg
+        * entries from the static array.
+        * We need to assert for this.
+        */
+
+       if (__predict_false(uvm.page_init_done == false)) {
+               if (sz % sizeof(struct uvm_physseg))
+                       panic("%s: tried to alloc size other than multiple"
+                           "of struct uvm_physseg at boot\n", __func__);
+
+               size_t n = sz / sizeof(struct uvm_physseg);
+               nseg += n;
+
+               KASSERT(nseg > 0 && nseg <= VM_PHYSSEG_MAX);
+
+               return &uvm_physseg[nseg - n];
+       }
+
+       return kmem_zalloc(sz, KM_NOSLEEP);
+}
+
+static void
+uvm_physseg_free(void *p, size_t sz)
+{
+       /*
+        * This is a bit tricky. We do allow simulation of free()
+        * during boot (for eg: when MD code is "steal"ing memory,
+        * and the segment has been exhausted (and thus needs to be
+        * free() - ed.
+        * free() also complicates things because we leak the
+        * free(). Therefore calling code can't assume that free()-ed
+        * memory is available for alloc() again, at boot time.
+        *
+        * Thus we can't explicitly disallow free()s during
+        * boot time. However, the same restriction for alloc()
+        * applies to free(). We only allow vm_physseg related free()s
+        * via this function during boot time.
+        */
+
+       if (__predict_false(uvm.page_init_done == false)) {
+               if (sz % sizeof(struct uvm_physseg))
+                       panic("%s: tried to free size other than struct uvm_physseg"
+                           "at boot\n", __func__);
+
+       }
+
+       /*
+        * Could have been in a single if(){} block - split for
+        * clarity
+        */
+
+       if ((struct uvm_physseg *)p >= uvm_physseg &&
+           (struct uvm_physseg *)p < (uvm_physseg + VM_PHYSSEG_MAX)) {
+               if (sz % sizeof(struct uvm_physseg))
+                       panic("%s: tried to free() other than struct uvm_physseg"
+                           "from static array\n", __func__);
+
+               if ((sz / sizeof(struct uvm_physseg)) >= VM_PHYSSEG_MAX)
+                       panic("%s: tried to free() the entire static array!", __func__);
+               return; /* Nothing to free */
+       }
+
+       kmem_free(p, sz);
+}
+
+/* XXX: Multi page size */
+bool
+uvm_physseg_plug(paddr_t pfn, size_t pages, uvm_physseg_t *psp)
+{
+       int preload;
+       size_t slabpages;
+       struct uvm_physseg *ps, *current_ps = NULL;
+       struct vm_page *slab = NULL, *pgs = NULL;
+
+#ifdef DEBUG
+       paddr_t off;
+       uvm_physseg_t upm;
+       upm = uvm_physseg_find(pfn, &off);
+
+       ps = HANDLE_TO_PHYSSEG_NODE(upm);
+
+       if (ps != NULL) /* XXX; do we allow "update" plugs ? */
+               return false;
+#endif
+
+       /*
+        * do we have room?
+        */
+
+       ps = uvm_physseg_alloc(sizeof (struct uvm_physseg));
+       if (ps == NULL) {
+               printf("uvm_page_physload: unable to load physical memory "
+                   "segment\n");
+               printf("\t%d segments allocated, ignoring 0x%"PRIxPADDR" -> 0x%"PRIxPADDR"\n",
+                   VM_PHYSSEG_MAX, pfn, pfn + pages + 1);
+               printf("\tincrease VM_PHYSSEG_MAX\n");
+               return false;
+       }
+
+       /* span init */
+       ps->start = pfn;
+       ps->end = pfn + pages;
+
+       /*
+        * XXX: Ugly hack because uvmexp.npages accounts for only
+        * those pages in the segment included below as well - this
+        * should be legacy and removed.
+        */
+
+       ps->avail_start = ps->start;
+       ps->avail_end = ps->end;
+
+       /*
+        * check to see if this is a "preload" (i.e. uvm_page_init hasn't been
+        * called yet, so kmem is not available).
+        */
+
+       preload = 1; /* We are going to assume it is a preload */
+
+       RB_TREE_FOREACH(current_ps, &(uvm_physseg_graph.rb_tree)) {
+               /* If there are non NULL pages then we are not in a preload */
+               if (current_ps->pgs != NULL) {
+                       preload = 0;
+                       /* Try to scavenge from earlier unplug()s. */
+                       pgs = uvm_physseg_seg_alloc_from_slab(current_ps, pages);
+
+                       if (pgs != NULL) {
+                               break;
+                       }
+               }
+       }
+
+
+       /*
+        * if VM is already running, attempt to kmem_alloc vm_page structures
+        */
+
+       if (!preload) {
+               if (pgs == NULL) { /* Brand new */
+                       /* Iteratively try alloc down from uvmexp.npages */
+                       for (slabpages = (size_t) uvmexp.npages; slabpages >= pages; slabpages--) {
+                               slab = kmem_zalloc(sizeof *pgs * (long unsigned int)slabpages, KM_NOSLEEP);
+                               if (slab != NULL)
+                                       break;
+                       }
+
+                       if (slab == NULL) {
+                               uvm_physseg_free(ps, sizeof(struct uvm_physseg));
+                               return false;
+                       }
+
+                       uvm_physseg_seg_chomp_slab(ps, slab, (size_t) slabpages);
+                       /* We allocate enough for this plug */
+                       pgs = uvm_physseg_seg_alloc_from_slab(ps, pages);
+
+                       if (pgs == NULL) {
+                               printf("unable to uvm_physseg_seg_alloc_from_slab() from backend\n");
+                               return false;
+                       }
+               } else {
+                       /* Reuse scavenged extent */
+                       ps->ext = current_ps->ext;
+               }
+
+               physmem += pages;
+               uvmpdpol_reinit();
+       } else { /* Boot time - see uvm_page.c:uvm_page_init() */
+               pgs = NULL;
+               ps->pgs = pgs;
+       }
+
+       /*
+        * now insert us in the proper place in uvm_physseg_graph.rb_tree
+        */
+
+       current_ps = rb_tree_insert_node(&(uvm_physseg_graph.rb_tree), ps);
+       if (current_ps != ps) {
+               panic("uvm_page_physload: Duplicate address range detected!");
+       }
+       uvm_physseg_graph.nentries++;
+
+       /*
+        * uvm_pagefree() requires the PHYS_TO_VM_PAGE(pgs[i]) on the
+        * newly allocated pgs[] to return the correct value. This is
+        * a bit of a chicken and egg problem, since it needs
+        * uvm_physseg_find() to succeed. For this, the node needs to
+        * be inserted *before* uvm_physseg_init_seg() happens.
+        *
+        * During boot, this happens anyway, since
+        * uvm_physseg_init_seg() is called later on and separately
+        * from uvm_page.c:uvm_page_init().
+        * In the case of hotplug we need to ensure this.
+        */
+
+       if (__predict_true(!preload))
+               uvm_physseg_init_seg(ps, pgs);
+
+       if (psp != NULL)
+               *psp = ps;
+
+       return true;
+}
+
+static int
+uvm_physseg_compare_nodes(void *ctx, const void *nnode1, const void *nnode2)
+{
+       const struct uvm_physseg *enode1 = nnode1;
+       const struct uvm_physseg *enode2 = nnode2;
+
+       KASSERT(enode1->start < enode2->start || enode1->start >= enode2->end);
+       KASSERT(enode2->start < enode1->start || enode2->start >= enode1->end);
+
+       if (enode1->start < enode2->start)
+               return -1;
+       if (enode1->start >= enode2->end)
+               return 1;
+       return 0;
+}
+
+static int
+uvm_physseg_compare_key(void *ctx, const void *nnode, const void *pkey)
+{
+       const struct uvm_physseg *enode = nnode;
+       const paddr_t pa = *(const paddr_t *) pkey;
+
+       if(enode->start <= pa && pa < enode->end)
+               return 0;
+       if (enode->start < pa)
+               return -1;
+       if (enode->end > pa)
+               return 1;
+
+       return 0;
+}
+
+static const rb_tree_ops_t uvm_physseg_tree_ops = {
+       .rbto_compare_nodes = uvm_physseg_compare_nodes,
+       .rbto_compare_key = uvm_physseg_compare_key,
+       .rbto_node_offset = offsetof(struct uvm_physseg, rb_node),
+       .rbto_context = NULL
+};
+
+/*
+ * uvm_physseg_init: init the physmem
+ *
+ * => physmem unit should not be in use at this point
+ */
+
+void
+uvm_physseg_init(void) {
+       rb_tree_init(&(uvm_physseg_graph.rb_tree), &uvm_physseg_tree_ops);
+       uvm_physseg_graph.nentries = 0;
+}
+
+uvm_physseg_t
+uvm_physseg_get_next(uvm_physseg_t upm)
+{
+       return (uvm_physseg_t) rb_tree_iterate(&(uvm_physseg_graph.rb_tree), upm,
+           RB_DIR_RIGHT);
+}
+
+uvm_physseg_t
+uvm_physseg_get_prev(uvm_physseg_t upm)
+{
+       return (uvm_physseg_t) rb_tree_iterate(&(uvm_physseg_graph.rb_tree), upm,
+           RB_DIR_LEFT);
+}
+
+uvm_physseg_t
+uvm_physseg_get_last(void)
+{
+       return (uvm_physseg_t) RB_TREE_MAX(&(uvm_physseg_graph.rb_tree));
+}
+
+uvm_physseg_t
+uvm_physseg_get_first(void)
+{
+       return (uvm_physseg_t) RB_TREE_MIN(&(uvm_physseg_graph.rb_tree));
+}
+
+paddr_t
+uvm_physseg_get_highest_frame(void)
+{
+       struct uvm_physseg *ps =
+           (uvm_physseg_t) RB_TREE_MAX(&(uvm_physseg_graph.rb_tree));
+
+       return ps->end - 1;
+}
+
+/*
+ * uvm_page_physunload: unload physical memory and return it to
+ * caller.
+ */
+bool
+uvm_page_physunload(uvm_physseg_t upm, int freelist, paddr_t *paddrp)
+{
+       struct uvm_physseg *seg;
+
+       seg = HANDLE_TO_PHYSSEG_NODE(upm);
+
+       if (seg->free_list != freelist) {
+               paddrp = NULL;
+               return false;
+       }
+
+       /*
+        * During cold boot, what we're about to unplug hasn't been
+        * put on the uvm freelist, nor has uvmexp.npages been
+        * updated. (This happens in uvm_page.c:uvm_page_init())
+        *
+        * For hotplug, we assume here that the pages being unloaded
+        * here are completely out of sight of uvm (ie; not on any uvm
+        * lists), and that  uvmexp.npages has been suitably
+        * decremented before we're called.
+        *
+        * XXX: will avail_end == start if avail_start < avail_end?
+        */
+
+       /* try from front */
+       if (seg->avail_start == seg->start &&
+           seg->avail_start < seg->avail_end) {
+               *paddrp = ctob(seg->avail_start);
+               return uvm_physseg_unplug(seg->avail_start, 1);
+       }
+
+       /* try from rear */
+       if (seg->avail_end == seg->end &&
+           seg->avail_start < seg->avail_end) {
+               *paddrp = ctob(seg->avail_end - 1);
+               return uvm_physseg_unplug(seg->avail_end - 1, 1);
+       }
+
+       return false;
+}
+
+bool
+uvm_page_physunload_force(uvm_physseg_t upm, int freelist, paddr_t *paddrp)
+{
+       struct uvm_physseg *seg;
+
+       seg = HANDLE_TO_PHYSSEG_NODE(upm);
+
+       /* any room in this bank? */
+       if (seg->avail_start >= seg->avail_end) {
+               paddrp = NULL;
+               return false; /* nope */
+       }
+
+       *paddrp = ctob(seg->avail_start);
+
+       /* Always unplug from front */
+       return uvm_physseg_unplug(seg->avail_start, 1);
+}
+
+
+/*
+ * vm_physseg_find: find vm_physseg structure that belongs to a PA
+ */
+uvm_physseg_t
+uvm_physseg_find(paddr_t pframe, psize_t *offp)
+{
+       struct uvm_physseg * ps = NULL;
+
+       ps = rb_tree_find_node(&(uvm_physseg_graph.rb_tree), &pframe);
+
+       if(ps != NULL && offp != NULL)
+               *offp = pframe - ps->start;
+
+       return ps;
+}
+
+#if defined(PMAP_STEAL_MEMORY)
+void
+uvm_physseg_set_avail_start(uvm_physseg_t upm, paddr_t avail_start)
+{
+       struct uvm_physseg *ps = HANDLE_TO_PHYSSEG_NODE(upm);
+
+#if defined(DIAGNOSTIC)
+       paddr_t avail_end;
+       avail_end = uvm_physseg_get_avail_end(upm);
+#endif
+       KASSERT(avail_start < avail_end && avail_start >= ps->start);
+       ps->avail_start = avail_start;
+}
+void uvm_physseg_set_avail_end(uvm_physseg_t upm, paddr_t avail_end)
+{
+       struct uvm_physseg *ps = HANDLE_TO_PHYSSEG_NODE(upm);
+
+#if defined(DIAGNOSTIC)
+       paddr_t avail_start;
+       avail_start = uvm_physseg_get_avail_start(upm);
+#endif
+
+       KASSERT(avail_end > avail_start && avail_end <= ps->end);
+
+       ps->avail_end = avail_end;
+}
+
+#endif /* PMAP_STEAL_MEMORY */
+#else  /* UVM_HOTPLUG */
+
+/*
+ * physical memory config is stored in vm_physmem.
+ */
+
+#define        VM_PHYSMEM_PTR(i)       (&vm_physmem[i])
+#if VM_PHYSSEG_MAX == 1
+#define VM_PHYSMEM_PTR_SWAP(i, j) /* impossible */
+#else
+#define VM_PHYSMEM_PTR_SWAP(i, j) \
+       do { vm_physmem[(i)] = vm_physmem[(j)]; } while (0)
+#endif
+
+#define        HANDLE_TO_PHYSSEG_NODE(h)       (VM_PHYSMEM_PTR((int)h))
+#define                PHYSSEG_NODE_TO_HANDLE(u)       ((int)((vsize_t) (u - vm_physmem) / sizeof(struct uvm_physseg)))
+
+static struct uvm_physseg vm_physmem[VM_PHYSSEG_MAX];  /* XXXCDC: uvm.physmem */
+static int vm_nphysseg = 0;                            /* XXXCDC: uvm.nphysseg */
+#define        vm_nphysmem     vm_nphysseg
+
+void
+uvm_physseg_init(void) {
+       /* XXX: Provisioning for rb_tree related init(s) */
+       return;
+}
+
+int
+uvm_physseg_get_next(uvm_physseg_t lcv)
+{
+       return (lcv + 1);
+}
+
+int
+uvm_physseg_get_prev(uvm_physseg_t lcv)
+{
+       return (lcv - 1);
+}
+
+int
+uvm_physseg_get_last(void)
+{
+       return (vm_nphysseg - 1);
+}
+
+int
+uvm_physseg_get_first(void)
+{
+       return 0;
+}
+
+paddr_t
+uvm_physseg_get_highest_frame(void)
+{
+       int lcv;
+       paddr_t last = 0;
+       struct uvm_physseg *ps;
+
+       for (lcv = 0; lcv < vm_nphysseg; lcv++) {
+               ps = VM_PHYSMEM_PTR(lcv);
+               if (last < ps->end)
+                       last = ps->end;
+       }
+
+       return last;
+}
+
+/*
+ * uvm_page_physunload: unload physical memory and return it to
+ * caller.
+ */
+bool
+uvm_page_physunload(uvm_physseg_t psi, int freelist, paddr_t *paddrp)
+{
+       int x;
+       struct uvm_physseg *seg;
+
+       seg = VM_PHYSMEM_PTR(psi);
+
+       if (seg->free_list != freelist) {
+               paddrp = NULL;
+               return false;
+       }
+
+       /* try from front */
+       if (seg->avail_start == seg->start &&
+           seg->avail_start < seg->avail_end) {
+               *paddrp = ctob(seg->avail_start);
+               seg->avail_start++;
+               seg->start++;
+               /* nothing left?   nuke it */
+               if (seg->avail_start == seg->end) {
+                       if (vm_nphysmem == 1)
+                               panic("uvm_page_physget: out of memory!");
+                       vm_nphysmem--;
+                       for (x = psi ; x < vm_nphysmem ; x++)
+                               /* structure copy */
+                               VM_PHYSMEM_PTR_SWAP(x, x + 1);
+               }
+               return (true);
+       }
+
+       /* try from rear */
+       if (seg->avail_end == seg->end &&
+           seg->avail_start < seg->avail_end) {
+               *paddrp = ctob(seg->avail_end - 1);
+               seg->avail_end--;
+               seg->end--;
+               /* nothing left?   nuke it */
+               if (seg->avail_end == seg->start) {
+                       if (vm_nphysmem == 1)
+                               panic("uvm_page_physget: out of memory!");
+                       vm_nphysmem--;
+                       for (x = psi ; x < vm_nphysmem ; x++)
+                               /* structure copy */
+                               VM_PHYSMEM_PTR_SWAP(x, x + 1);
+               }
+               return (true);
+       }
+
+       return false;
+}
+
+bool
+uvm_page_physunload_force(uvm_physseg_t psi, int freelist, paddr_t *paddrp)
+{
+       int x;
+       struct uvm_physseg *seg;
+
+       seg = VM_PHYSMEM_PTR(psi);
+
+       /* any room in this bank? */
+       if (seg->avail_start >= seg->avail_end) {
+               paddrp = NULL;
+               return false; /* nope */
+       }
+
+       *paddrp = ctob(seg->avail_start);
+       seg->avail_start++;
+       /* truncate! */
+       seg->start = seg->avail_start;
+
+       /* nothing left?   nuke it */
+       if (seg->avail_start == seg->end) {
+               if (vm_nphysmem == 1)
+                       panic("uvm_page_physget: out of memory!");
+               vm_nphysmem--;
+               for (x = psi ; x < vm_nphysmem ; x++)
+                       /* structure copy */
+                       VM_PHYSMEM_PTR_SWAP(x, x + 1);
+       }
+       return (true);
+}
+
+bool
+uvm_physseg_plug(paddr_t pfn, size_t pages, uvm_physseg_t *psp)
+{
+       int preload, lcv;
+       struct vm_page *pgs;
+       struct uvm_physseg *ps;
+
+#ifdef DEBUG
+       paddr_t off;
+       uvm_physseg_t upm;
+       upm = uvm_physseg_find(pfn, &off);
+
+        if (uvm_physseg_valid(upm)) /* XXX; do we allow "update" plugs ? */
+               return false;
+#endif
+
+       paddr_t start = pfn;
+       paddr_t end = pfn + pages;
+       paddr_t avail_start = start;
+       paddr_t avail_end = end;
+
+       if (uvmexp.pagesize == 0)
+               panic("uvm_page_physload: page size not set!");
+
+       /*
+        * do we have room?
+        */
+
+       if (vm_nphysmem == VM_PHYSSEG_MAX) {
+               printf("uvm_page_physload: unable to load physical memory "
+                   "segment\n");
+               printf("\t%d segments allocated, ignoring 0x%llx -> 0x%llx\n",
+                   VM_PHYSSEG_MAX, (long long)start, (long long)end);
+               printf("\tincrease VM_PHYSSEG_MAX\n");
+               if (psp != NULL)
+                       *psp = UVM_PHYSSEG_TYPE_INVALID_OVERFLOW;
+               return false;
+       }
+
+       /*
+        * check to see if this is a "preload" (i.e. uvm_page_init hasn't been
+        * called yet, so kmem is not available).
+        */
+
+       for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) {
+               if (VM_PHYSMEM_PTR(lcv)->pgs)
+                       break;
+       }
+       preload = (lcv == vm_nphysmem);
+
+       /*
+        * if VM is already running, attempt to kmem_alloc vm_page structures
+        */
+
+       if (!preload) {
+               panic("uvm_page_physload: tried to add RAM after vm_mem_init");
+       } else {
+               pgs = NULL;
+       }
+
+       /*
+        * now insert us in the proper place in vm_physmem[]
+        */
+
+#if (VM_PHYSSEG_STRAT == VM_PSTRAT_RANDOM)
+       /* random: put it at the end (easy!) */
+       ps = VM_PHYSMEM_PTR(vm_nphysmem);
+#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
+       {
+               int x;
+               /* sort by address for binary search */
+               for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
+                       if (start < VM_PHYSMEM_PTR(lcv)->start)
+                               break;
+               ps = VM_PHYSMEM_PTR(lcv);
+               /* move back other entries, if necessary ... */
+               for (x = vm_nphysmem ; x > lcv ; x--)
+                       /* structure copy */
+                       VM_PHYSMEM_PTR_SWAP(x, x - 1);
+       }
+#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST)
+       {
+               int x;
+               /* sort by largest segment first */
+               for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
+                       if ((end - start) >
+                           (VM_PHYSMEM_PTR(lcv)->end - VM_PHYSMEM_PTR(lcv)->start))
+                               break;
+               ps = VM_PHYSMEM_PTR(lcv);
+               /* move back other entries, if necessary ... */
+               for (x = vm_nphysmem ; x > lcv ; x--)
+                       /* structure copy */
+                       VM_PHYSMEM_PTR_SWAP(x, x - 1);
+       }
+#else
+       panic("uvm_page_physload: unknown physseg strategy selected!");
+#endif
+
+       ps->start = start;
+       ps->end = end;
+       ps->avail_start = avail_start;
+       ps->avail_end = avail_end;
+
+       ps->pgs = pgs;
+
+       vm_nphysmem++;
+
+       if (psp != NULL)
+               *psp = lcv;
+
+       return true;
+}
+
+/*
+ * when VM_PHYSSEG_MAX is 1, we can simplify these functions
+ */
+
+#if VM_PHYSSEG_MAX == 1
+static inline int vm_physseg_find_contig(struct uvm_physseg *, int, paddr_t, psize_t *);
+#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
+static inline int vm_physseg_find_bsearch(struct uvm_physseg *, int, paddr_t, psize_t *);
+#else
+static inline int vm_physseg_find_linear(struct uvm_physseg *, int, paddr_t, psize_t *);
+#endif
+
+/*
+ * vm_physseg_find: find vm_physseg structure that belongs to a PA
+ */
+int
+uvm_physseg_find(paddr_t pframe, psize_t *offp)
+{
+
+#if VM_PHYSSEG_MAX == 1
+       return vm_physseg_find_contig(vm_physmem, vm_nphysseg, pframe, offp);
+#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
+       return vm_physseg_find_bsearch(vm_physmem, vm_nphysseg, pframe, offp);
+#else
+       return vm_physseg_find_linear(vm_physmem, vm_nphysseg, pframe, offp);
+#endif
+}
+
+#if VM_PHYSSEG_MAX == 1
+static inline int
+vm_physseg_find_contig(struct uvm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
+{
+
+       /* 'contig' case */
+       if (pframe >= segs[0].start && pframe < segs[0].end) {
+               if (offp)
+                       *offp = pframe - segs[0].start;
+               return(0);
+       }
+       return(-1);
+}
+
+#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
+
+static inline int
+vm_physseg_find_bsearch(struct uvm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
+{
+       /* binary search for it */
+       int     start, len, guess;
+
+       /*
+        * if try is too large (thus target is less than try) we reduce
+        * the length to trunc(len/2) [i.e. everything smaller than "try"]
+        *
+        * if the try is too small (thus target is greater than try) then
+        * we set the new start to be (try + 1).   this means we need to
+        * reduce the length to (round(len/2) - 1).
+        *
+        * note "adjust" below which takes advantage of the fact that
+        *  (round(len/2) - 1) == trunc((len - 1) / 2)
+        * for any value of len we may have
+        */
+
+       for (start = 0, len = nsegs ; len != 0 ; len = len / 2) {
+               guess = start + (len / 2);      /* try in the middle */
+
+               /* start past our try? */
+               if (pframe >= segs[guess].start) {
+                       /* was try correct? */
+                       if (pframe < segs[guess].end) {
+                               if (offp)
+                                       *offp = pframe - segs[guess].start;
+                               return guess;            /* got it */
+                       }
+                       start = guess + 1;      /* next time, start here */
+                       len--;                  /* "adjust" */
+               } else {
+                       /*
+                        * pframe before try, just reduce length of
+                        * region, done in "for" loop
+                        */
+               }
+       }
+       return(-1);
+}
+
+#else
+
+static inline int
+vm_physseg_find_linear(struct uvm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
+{
+       /* linear search for it */
+       int     lcv;
+
+       for (lcv = 0; lcv < nsegs; lcv++) {
+               if (pframe >= segs[lcv].start &&
+                   pframe < segs[lcv].end) {
+                       if (offp)
+                               *offp = pframe - segs[lcv].start;
+                       return(lcv);               /* got it */
+               }
+       }
+       return(-1);
+}
+#endif
+#endif /* UVM_HOTPLUG */
+
+bool
+uvm_physseg_valid(uvm_physseg_t upm)
+{
+       struct uvm_physseg *ps;
+
+       if (upm == UVM_PHYSSEG_TYPE_INVALID ||
+           upm == UVM_PHYSSEG_TYPE_INVALID_EMPTY ||
+           upm == UVM_PHYSSEG_TYPE_INVALID_OVERFLOW)
+               return false;
+
+       /*
+        * This is the delicate init dance -
+        * needs to go with the dance.
+        */
+       if (uvm.page_init_done != true)
+               return true;
+
+       ps = HANDLE_TO_PHYSSEG_NODE(upm);
+
+       /* Extra checks needed only post uvm_page_init() */
+       if (ps->pgs == NULL)
+               return false;
+
+       /* XXX: etc. */
+
+       return true;
+
+}
+
+/*
+ * Boot protocol dictates that these must be able to return partially
+ * initialised segments.
+ */
+paddr_t
+uvm_physseg_get_start(uvm_physseg_t upm)
+{
+       if (uvm_physseg_valid(upm) == false)
+               return (paddr_t) -1;
+
+       return HANDLE_TO_PHYSSEG_NODE(upm)->start;
+}
+
+paddr_t
+uvm_physseg_get_end(uvm_physseg_t upm)
+{
+       if (uvm_physseg_valid(upm) == false)
+               return (paddr_t) -1;
+
+       return HANDLE_TO_PHYSSEG_NODE(upm)->end;
+}
+
+paddr_t
+uvm_physseg_get_avail_start(uvm_physseg_t upm)
+{
+       if (uvm_physseg_valid(upm) == false)
+               return (paddr_t) -1;
+
+       return HANDLE_TO_PHYSSEG_NODE(upm)->avail_start;
+}
+
+paddr_t
+uvm_physseg_get_avail_end(uvm_physseg_t upm)
+{
+       if (uvm_physseg_valid(upm) == false)
+               return (paddr_t) -1;
+
+       return HANDLE_TO_PHYSSEG_NODE(upm)->avail_end;
+}
+
+struct vm_page *
+uvm_physseg_get_pg(uvm_physseg_t upm, paddr_t idx)
+{
+       /* XXX: uvm_physseg_valid() */
+       return &HANDLE_TO_PHYSSEG_NODE(upm)->pgs[idx];
+}
+
+#ifdef __HAVE_PMAP_PHYSSEG
+struct pmap_physseg *
+uvm_physseg_get_pmseg(uvm_physseg_t upm)
+{
+       /* XXX: uvm_physseg_valid() */
+       return &(HANDLE_TO_PHYSSEG_NODE(upm)->pmseg);
+}
+#endif
+
+int
+uvm_physseg_get_free_list(uvm_physseg_t upm)
+{
+       return HANDLE_TO_PHYSSEG_NODE(upm)->free_list;
+}
+
+u_int
+uvm_physseg_get_start_hint(uvm_physseg_t upm)
+{
+       return HANDLE_TO_PHYSSEG_NODE(upm)->start_hint;
+}
+
+bool
+uvm_physseg_set_start_hint(uvm_physseg_t upm, u_int start_hint)
+{
+       if (uvm_physseg_valid(upm) == false)
+               return false;
+
+       HANDLE_TO_PHYSSEG_NODE(upm)->start_hint = start_hint;
+       return true;
+}
+
+void
+uvm_physseg_init_seg(uvm_physseg_t upm, struct vm_page *pgs)
+{
+       psize_t i;
+       psize_t n;
+       paddr_t paddr;
+       struct uvm_physseg *seg;
+
+       KASSERT(upm != UVM_PHYSSEG_TYPE_INVALID && pgs != NULL);
+
+       seg = HANDLE_TO_PHYSSEG_NODE(upm);
+       KASSERT(seg != NULL);
+       KASSERT(seg->pgs == NULL);
+
+       n = seg->end - seg->start;
+       seg->pgs = pgs;
+
+       /* init and free vm_pages (we've already zeroed them) */
+       paddr = ctob(seg->start);
+       for (i = 0 ; i < n ; i++, paddr += PAGE_SIZE) {
+               seg->pgs[i].phys_addr = paddr;
+#ifdef __HAVE_VM_PAGE_MD
+               VM_MDPAGE_INIT(&seg->pgs[i]);
+#endif
+               if (atop(paddr) >= seg->avail_start &&
+                   atop(paddr) < seg->avail_end) {
+                       uvmexp.npages++;
+                       mutex_enter(&uvm_pageqlock);
+                       /* add page to free pool */
+                       uvm_pagefree(&seg->pgs[i]);
+                       mutex_exit(&uvm_pageqlock);
+               }
+       }
+}
+
+void
+uvm_physseg_seg_chomp_slab(uvm_physseg_t upm, struct vm_page *pgs, size_t n)
+{
+       struct uvm_physseg *seg = HANDLE_TO_PHYSSEG_NODE(upm);
+
+       /* One per segment at boot */
+#define UVM_PHYSSEG_BOOT_UNPLUG_MAX VM_PHYSSEG_MAX /* max number of pre-boot unplug()s allowed */
+       static struct extent_region erboot[UVM_PHYSSEG_BOOT_UNPLUG_MAX];
+
+       if (__predict_false(uvm.page_init_done == false)) {
+               seg->ext = extent_create("Boot time slab", (u_long) pgs, (u_long) (pgs + n), erboot, sizeof(erboot), 0);
+       } else {
+               seg->ext = extent_create("Hotplug slab", (u_long) pgs, (u_long) (pgs + n), NULL, 0, 0);
+       }
+
+       KASSERT(seg->ext != NULL);
+
+}
+
+struct vm_page *
+uvm_physseg_seg_alloc_from_slab(uvm_physseg_t upm, size_t pages)
+{
+       int err;
+       struct uvm_physseg *seg;
+       struct vm_page *pgs = NULL;
+
+       seg = HANDLE_TO_PHYSSEG_NODE(upm);
+
+       KASSERT(pages > 0);
+
+       if (__predict_false(seg->ext == NULL)) {
+               /*
+                * This is a situation unique to boot time.
+                * It shouldn't happen at any point other than from
+                * the first uvm_page.c:uvm_page_init() call
+                * Since we're in a loop, we can get away with the
+                * below.
+                */
+               KASSERT(uvm.page_init_done != true);
+
+               seg->ext = HANDLE_TO_PHYSSEG_NODE(uvm_physseg_get_prev(upm))->ext;
+
+               KASSERT(seg->ext != NULL);
+       }
+
+       /* We allocate enough for this segment */
+       err = extent_alloc(seg->ext, sizeof(*pgs) * pages, 1, 0, EX_BOUNDZERO, (u_long *)&pgs);
+
+       if (err != 0) {
+#ifdef DEBUG
+               printf("%s: extent_alloc failed with error: %d \n",
+                   __func__, err);
+#endif
+       }
+
+       return pgs;
+}
+
+/*
+ * uvm_page_physload: load physical memory into VM system
+ *
+ * => all args are PFs
+ * => all pages in start/end get vm_page structures
+ * => areas marked by avail_start/avail_end get added to the free page pool
+ * => we are limited to VM_PHYSSEG_MAX physical memory segments
+ */
+
+uvm_physseg_t
+uvm_page_physload(paddr_t start, paddr_t end, paddr_t avail_start,
+    paddr_t avail_end, int free_list)
+{
+       struct uvm_physseg *ps;
+       uvm_physseg_t upm;
+
+       if (uvmexp.pagesize == 0)
+               panic("uvm_page_physload: page size not set!");
+       if (free_list >= VM_NFREELIST || free_list < VM_FREELIST_DEFAULT)
+               panic("uvm_page_physload: bad free list %d", free_list);
+       if (start >= end)
+               panic("uvm_page_physload: start >= end");
+
+       if (uvm_physseg_plug(start, end - start, &upm) == false) {
+               panic("uvm_physseg_plug() failed at boot.");
+               /* NOTREACHED */
+               return UVM_PHYSSEG_TYPE_INVALID; /* XXX: correct type */
+       }
+
+       ps = HANDLE_TO_PHYSSEG_NODE(upm);
+
+       /* Legacy */
+       ps->avail_start = avail_start;
+       ps->avail_end = avail_end;
+
+       ps->free_list = free_list; /* XXX: */
+
+
+       return upm;
+}
+
+bool
+uvm_physseg_unplug(paddr_t pfn, size_t pages)
+{
+       uvm_physseg_t upm;
+       paddr_t off = 0, start, end;
+       struct uvm_physseg *seg;
+
+       upm = uvm_physseg_find(pfn, &off);
+
+       if (!uvm_physseg_valid(upm)) {
+               printf("%s: Tried to unplug from unknown offset\n", __func__);
+               return false;
+       }
+
+       seg = HANDLE_TO_PHYSSEG_NODE(upm);
+
+       start = uvm_physseg_get_start(upm);
+       end = uvm_physseg_get_end(upm);
+
+       if (end < (pfn + pages)) {
+               printf("%s: Tried to unplug oversized span \n", __func__);
+               return false;
+       }
+
+#ifndef DIAGNOSTIC
+       (void) start;
+#endif
+       KASSERT(pfn == start + off); /* sanity */
+
+       if (__predict_true(uvm.page_init_done == true)) {
+               /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
+               if (extent_free(seg->ext, (u_long)(seg->pgs + off), sizeof(struct vm_page) * pages, EX_MALLOCOK | EX_NOWAIT) != 0)
+                       return false;
+       }
+
+       if (off == 0 && (pfn + pages) == end) {
+#if defined(UVM_HOTPLUG) /* rbtree implementation */
+               int segcount = 0;
+               struct uvm_physseg *current_ps;
+               /* Complete segment */
+               if (uvm_physseg_graph.nentries == 1)
+                       panic("%s: out of memory!", __func__);
+
+               if (__predict_true(uvm.page_init_done == true)) {
+                       RB_TREE_FOREACH(current_ps, &(uvm_physseg_graph.rb_tree)) {
+                               if (seg->ext == current_ps->ext)
+                                       segcount++;
+                       }
+                       KASSERT(segcount > 0);
+
+                       if (segcount == 1) {
+                               extent_destroy(seg->ext);
+                       }
+
+                       /*
+                        * We assume that the unplug will succeed from
+                        *  this point onwards
+                        */
+                       uvmexp.npages -= (int) pages;
+               }
+
+               rb_tree_remove_node(&(uvm_physseg_graph.rb_tree), upm);
+               memset(seg, 0, sizeof(struct uvm_physseg));
+               uvm_physseg_free(seg, sizeof(struct uvm_physseg));
+               uvm_physseg_graph.nentries--;
+#else /* UVM_HOTPLUG */
+               int x;
+               if (vm_nphysmem == 1)
+                       panic("uvm_page_physget: out of memory!");
+               vm_nphysmem--;
+               for (x = upm ; x < vm_nphysmem ; x++)
+                       /* structure copy */
+                       VM_PHYSMEM_PTR_SWAP(x, x + 1);
+#endif /* UVM_HOTPLUG */
+               /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
+               return true;
+       }
+
+       if (off > 0 &&
+           (pfn + pages) < end) {
+#if defined(UVM_HOTPLUG) /* rbtree implementation */
+               /* middle chunk - need a new segment */
+               struct uvm_physseg *ps, *current_ps;
+               ps = uvm_physseg_alloc(sizeof (struct uvm_physseg));
+               if (ps == NULL) {
+                       printf("%s: Unable to allocated new fragment vm_physseg \n",
+                           __func__);
+                       return false;
+               }
+
+               /* Remove middle chunk */
+               if (__predict_true(uvm.page_init_done == true)) {
+                       KASSERT(seg->ext != NULL);
+                       ps->ext = seg->ext;
+
+                       /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
+                       /*
+                        * We assume that the unplug will succeed from
+                        *  this point onwards
+                        */
+                       uvmexp.npages -= (int) pages;
+               }
+
+               ps->start = pfn + pages;
+               ps->avail_start = ps->start; /* XXX: Legacy */
+
+               ps->end = seg->end;
+               ps->avail_end = ps->end; /* XXX: Legacy */
+
+               seg->end = pfn;
+               seg->avail_end = seg->end; /* XXX: Legacy */
+
+
+               /*
+                * The new pgs array points to the beginning of the
+                * tail fragment.
+                */
+               if (__predict_true(uvm.page_init_done == true))
+                       ps->pgs = seg->pgs + off + pages;
+
+               current_ps = rb_tree_insert_node(&(uvm_physseg_graph.rb_tree), ps);
+               if (current_ps != ps) {
+                       panic("uvm_page_physload: Duplicate address range detected!");
+               }
+               uvm_physseg_graph.nentries++;
+#else /* UVM_HOTPLUG */
+               panic("%s: can't unplug() from the middle of a segment without"
+                   "UVM_HOTPLUG\n",  __func__);
+               /* NOTREACHED */
+#endif /* UVM_HOTPLUG */
+               return true;
+       }
+
+       if (off == 0 && (pfn + pages) < end) {
+               /* Remove front chunk */
+               if (__predict_true(uvm.page_init_done == true)) {
+                       /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
+                       /*
+                        * We assume that the unplug will succeed from
+                        *  this point onwards
+                        */
+                       uvmexp.npages -= (int) pages;
+               }
+
+               /* Truncate */
+               seg->start = pfn + pages;
+               seg->avail_start = seg->start; /* XXX: Legacy */
+
+               /*
+                * Move the pgs array start to the beginning of the
+                * tail end.
+                */
+               if (__predict_true(uvm.page_init_done == true))
+                       seg->pgs += pages;
+
+               return true;
+       }
+
+       if (off > 0 && (pfn + pages) == end) {
+               /* back chunk */
+
+
+               /* Truncate! */
+               seg->end = pfn;
+               seg->avail_end = seg->end; /* XXX: Legacy */
+
+               uvmexp.npages -= (int) pages;
+
+               return true;
+       }
+
+       printf("%s: Tried to unplug unknown range \n", __func__);
+
+       return false;
+}
Index: sys/uvm/uvm_physseg.h
===================================================================
RCS file: sys/uvm/uvm_physseg.h
diff -N sys/uvm/uvm_physseg.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/uvm/uvm_physseg.h       13 Dec 2016 12:44:35 -0000
@@@@ -0,0 +1,118 @@@@
+/* $NetBSD$ */
+
+/*
+ * Consolidated API from uvm_page.c and others.
+ * Consolidated and designed by Cherry G. Mathew <cherry@@zyx.in>
+ */
+
+#ifndef _UVM_UVM_PHYSSEG_H_
+#define _UVM_UVM_PHYSSEG_H_
+
+#if defined(_KERNEL_OPT)
+#include "opt_uvm_hotplug.h"
+#endif
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+/*
+ * No APIs are explicitly #included in uvm_physseg.c
+ */
+
+#if defined(UVM_HOTPLUG) /* rbtree impementation */
+#define PRIxPHYSSEG "p"
+
+/*
+ * These are specific values of invalid constants for uvm_physseg_t.
+ * uvm_physseg_valid() == false on any of the below constants.
+ *
+ * Specific invalid constants encapsulate specific explicit failure
+ * scenarios (see the comments next to them)
+ */
+
+#define UVM_PHYSSEG_TYPE_INVALID NULL /* Generic invalid value */
+#define UVM_PHYSSEG_TYPE_INVALID_EMPTY NULL /* empty segment access */
+#define UVM_PHYSSEG_TYPE_INVALID_OVERFLOW NULL /* ran off the end of the last segment */
+
+typedef struct uvm_physseg * uvm_physseg_t;
+
+#else  /* UVM_HOTPLUG */
+
+#define PRIxPHYSSEG "d"
+
+/*
+ * These are specific values of invalid constants for uvm_physseg_t.
+ * uvm_physseg_valid() == false on any of the below constants.
+ *
+ * Specific invalid constants encapsulate specific explicit failure
+ * scenarios (see the comments next to them)
+ */
+
+#define UVM_PHYSSEG_TYPE_INVALID -1 /* Generic invalid value */
+#define UVM_PHYSSEG_TYPE_INVALID_EMPTY -1 /* empty segment access */
+#define UVM_PHYSSEG_TYPE_INVALID_OVERFLOW (uvm_physseg_get_last() + 1) /* ran off the end of the last segment */
+
+typedef int uvm_physseg_t;
+#endif /* UVM_HOTPLUG */
+
+void uvm_physseg_init(void);
+
+bool uvm_physseg_valid(uvm_physseg_t);
+
+/*
+ * Return start/end pfn of given segment
+ * Returns: -1 if the segment number is invalid
+ */
+paddr_t uvm_physseg_get_start(uvm_physseg_t);
+paddr_t uvm_physseg_get_end(uvm_physseg_t);
+
+paddr_t uvm_physseg_get_avail_start(uvm_physseg_t);
+paddr_t uvm_physseg_get_avail_end(uvm_physseg_t);
+
+struct vm_page * uvm_physseg_get_pg(uvm_physseg_t, paddr_t);
+
+#ifdef __HAVE_PMAP_PHYSSEG
+struct pmap_physseg * uvm_physseg_get_pmseg(uvm_physseg_t);
+#endif
+
+int uvm_physseg_get_free_list(uvm_physseg_t);
+u_int uvm_physseg_get_start_hint(uvm_physseg_t);
+bool uvm_physseg_set_start_hint(uvm_physseg_t, u_int);
+
+/*
+ * Functions to help walk the list of segments.
+ * Returns: NULL if the segment number is invalid
+ */
+uvm_physseg_t uvm_physseg_get_next(uvm_physseg_t);
+uvm_physseg_t uvm_physseg_get_prev(uvm_physseg_t);
+uvm_physseg_t uvm_physseg_get_first(void);
+uvm_physseg_t uvm_physseg_get_last(void);
+
+
+/* Return the frame number of the highest registered physical page frame */
+paddr_t uvm_physseg_get_highest_frame(void);
+
+/* Actually, uvm_page_physload takes PF#s which need their own type */
+uvm_physseg_t uvm_page_physload(paddr_t, paddr_t, paddr_t,
+    paddr_t, int);
+
+bool uvm_page_physunload(uvm_physseg_t, int, paddr_t *);
+bool uvm_page_physunload_force(uvm_physseg_t, int, paddr_t *);
+
+uvm_physseg_t uvm_physseg_find(paddr_t, psize_t *);
+
+bool uvm_physseg_plug(paddr_t, size_t, uvm_physseg_t *);
+bool uvm_physseg_unplug(paddr_t, size_t);
+
+#if defined(PMAP_STEAL_MEMORY)
+/*
+ * XXX: Legacy: This needs to be upgraded to a full pa management
+ * layer.
+ */
+void uvm_physseg_set_avail_start(uvm_physseg_t, paddr_t);
+void uvm_physseg_set_avail_end(uvm_physseg_t, paddr_t);
+#endif /* PMAP_STEAL_MEMORY */
+
+#endif /* _UVM_UVM_PHYSSEG_H_ */
+
Index: sys/uvm/pmap/pmap.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/pmap/pmap.c,v
retrieving revision 1.25
diff -p -u -r1.25 pmap.c
--- sys/uvm/pmap/pmap.c 1 Dec 2016 02:15:08 -0000       1.25
+++ sys/uvm/pmap/pmap.c 13 Dec 2016 12:44:35 -0000
@@@@ -112,6 +112,7 @@@@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.2
#include <sys/atomic.h>

#include <uvm/uvm.h>
+#include <uvm/uvm_physseg.h>

#if defined(MULTIPROCESSOR) && defined(PMAP_VIRTUAL_CACHE_ALIASES) \
    && !defined(PMAP_NO_PV_UNCACHED)
@@@@ -452,37 +453,39 @@@@ pmap_steal_memory(vsize_t size, vaddr_t
       size_t npgs;
       paddr_t pa;
       vaddr_t va;
-       struct vm_physseg *maybe_seg = NULL;
-       u_int maybe_bank = vm_nphysseg;
+
+       uvm_physseg_t maybe_bank = UVM_PHYSMEM_TYPE_INVALID;

       size = round_page(size);
       npgs = atop(size);

       aprint_debug("%s: need %zu pages\n", __func__, npgs);

-       for (u_int bank = 0; bank < vm_nphysseg; bank++) {
-               struct vm_physseg * const seg = VM_PHYSMEM_PTR(bank);
+       for (uvm_physseg_t bank = uvm_physseg_get_first();
+            uvm_physseg_valid(bank);
+            bank = uvm_physseg_get_next(bank)) {
+
               if (uvm.page_init_done == true)
                       panic("pmap_steal_memory: called _after_ bootstrap");

-               aprint_debug("%s: seg %u: %#"PRIxPADDR" %#"PRIxPADDR" %#"PRIxPADDR" %#"PRIxPADDR"\n",
+               aprint_debug("%s: seg %"PRIxPHYSMEM": %#"PRIxPADDR" %#"PRIxPADDR" %#"PRIxPADDR" %#"PRIxPADDR"\n",
                   __func__, bank,
-                   seg->avail_start, seg->start,
-                   seg->avail_end, seg->end);
+                   uvm_physseg_get_avail_start(bank), uvm_physseg_get_start(bank),
+                   uvm_physseg_get_avail_end(bank), uvm_physseg_get_end(bank));

-               if (seg->avail_start != seg->start
-                   || seg->avail_start >= seg->avail_end) {
-                       aprint_debug("%s: seg %u: bad start\n", __func__, bank);
+               if (uvm_physseg_get_avail_start(bank) != uvm_physseg_get_start(bank)
+                   || uvm_physseg_get_avail_start(bank) >= uvm_physseg_get_avail_end(bank)) {
+                       aprint_debug("%s: seg %"PRIxPHYSMEM": bad start\n", __func__, bank);
                       continue;
               }

-               if (seg->avail_end - seg->avail_start < npgs) {
-                       aprint_debug("%s: seg %u: too small for %zu pages\n",
+               if (uvm_physseg_get_avail_end(bank) - uvm_physseg_get_avail_start(bank) < npgs) {
+                       aprint_debug("%s: seg %"PRIxPHYSMEM": too small for %zu pages\n",
                           __func__, bank, npgs);
                       continue;
               }

-               if (!pmap_md_ok_to_steal_p(seg, npgs)) {
+               if (!pmap_md_ok_to_steal_p(bank, npgs)) {
                       continue;
               }

@@@@ -490,44 +493,24 @@@@ pmap_steal_memory(vsize_t size, vaddr_t
                * Always try to allocate from the segment with the least
                * amount of space left.
                */
-#define VM_PHYSMEM_SPACE(s)    ((s)->avail_end - (s)->avail_start)
-               if (maybe_seg == NULL
-                   || VM_PHYSMEM_SPACE(seg) < VM_PHYSMEM_SPACE(maybe_seg)) {
-                       maybe_seg = seg;
+#define VM_PHYSMEM_SPACE(b)    ((uvm_physseg_get_avail_end(b)) - (uvm_physseg_get_avail_start(b)))
+               if (uvm_physseg_valid(maybe_bank) == false
+                   || VM_PHYSMEM_SPACE(bank) < VM_PHYSMEM_SPACE(maybe_bank)) {
                       maybe_bank = bank;
               }
       }

-       if (maybe_seg) {
-               struct vm_physseg * const seg = maybe_seg;
-               u_int bank = maybe_bank;
-
+       if (uvm_physseg_valid(maybe_bank)) {
+               const uvm_physseg_t bank = maybe_bank;
+
               /*
                * There are enough pages here; steal them!
                */
-               pa = ptoa(seg->avail_start);
-               seg->avail_start += npgs;
-               seg->start += npgs;
-
-               /*
-                * Have we used up this segment?
-                */
-               if (seg->avail_start == seg->end) {
-                       if (vm_nphysseg == 1)
-                               panic("pmap_steal_memory: out of memory!");
+               pa = ptoa(uvm_physseg_get_start(bank));
+               uvm_physseg_unplug(atop(pa), npgs);

-                       aprint_debug("%s: seg %u: %zu pages stolen (removed)\n",
-                           __func__, bank, npgs);
-                       /* Remove this segment from the list. */
-                       vm_nphysseg--;
-                       for (u_int x = bank; x < vm_nphysseg; x++) {
-                               /* structure copy */
-                               VM_PHYSMEM_PTR_SWAP(x, x + 1);
-                       }
-               } else {
-                       aprint_debug("%s: seg %u: %zu pages stolen (%#"PRIxPADDR" left)\n",
-                           __func__, bank, npgs, VM_PHYSMEM_SPACE(seg));
-               }
+               aprint_debug("%s: seg %"PRIxPHYSMEM": %zu pages stolen (%#"PRIxPADDR" left)\n",
+                   __func__, bank, npgs, VM_PHYSMEM_SPACE(bank));

               va = pmap_md_map_poolpage(pa, size);
               memset((void *)va, 0, size);
@


1.8
log
@Remove leading untracked file mess in the diff
@
text
@d7 1
a7 1
+++ sys/uvm/Makefile    20 Nov 2016 07:20:20 -0000
d13 1
a13 1
+       uvm_map.h uvm_object.h uvm_page.h uvm_physmem.h \
d20 5
a24 5
retrieving revision 1.26
diff -p -u -r1.26 files.uvm
--- sys/uvm/files.uvm   12 Aug 2016 13:40:21 -0000      1.26
+++ sys/uvm/files.uvm   20 Nov 2016 07:20:20 -0000
@@@@ -14,6 +14,7 @@@@ defparam opt_pagermap.h           PAGER_MAP_SIZE
d32 1
a32 1
@@@@ -41,6 +42,7 @@@@ file      uvm/uvm_pdaemon.c               uvm
d36 1
a36 1
+file   uvm/uvm_physmem.c               uvm
d46 1
a46 1
+++ sys/uvm/uvm.h       20 Nov 2016 07:20:20 -0000
d51 1
a51 1
+#include <uvm/uvm_physmem.h>
d61 1
a61 1
+++ sys/uvm/uvm_extern.h        20 Nov 2016 07:20:22 -0000
d78 1
a78 1
+++ sys/uvm/uvm_page.c  20 Nov 2016 07:20:24 -0000
d114 20
a133 1
@@@@ -337,11 +326,9 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d139 1
a139 1
+       uvm_physmem_t bank;
d146 1
a146 1
@@@@ -369,7 +356,7 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d151 1
a151 1
+       if (uvm_physmem_get_last() == UVM_PHYSMEM_TYPE_INVALID)
d155 1
a155 1
@@@@ -381,9 +368,11 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d163 4
a166 4
+       for (bank = uvm_physmem_get_first();
+            uvm_physmem_valid(bank) ;
+            bank = uvm_physmem_get_next(bank)) {
+               freepages += (uvm_physmem_get_end(bank) - uvm_physmem_get_start(bank));
d170 1
a170 1
@@@@ -428,31 +417,20 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d179 9
a187 10
-
+       for (bank = uvm_physmem_get_first(),
+                uvm_physmem_seg_chomp_slab(bank, pagearray, pagecount);
+            uvm_physmem_valid(bank);
+            bank = uvm_physmem_get_next(bank)) {
+
+               n = uvm_physmem_get_end(bank) - uvm_physmem_get_start(bank);
+               uvm_physmem_seg_slab_alloc(bank, n);
+               uvm_physmem_init_seg(bank, pagearray);
+
d211 1
a211 1
@@@@ -625,92 +603,42 @@@@ static bool uvm_page_physget_freelist(pa
d217 1
a217 1
+       uvm_physmem_t lcv;
d222 1
a222 1
+       for (lcv = uvm_physmem_get_last() ; uvm_physmem_valid(lcv) ; lcv = uvm_physmem_get_prev(lcv))
d225 1
a225 1
+               for (lcv = uvm_physmem_get_first() ; uvm_physmem_valid(lcv) ; lcv = uvm_physmem_get_next(lcv))
d282 1
a282 1
+               for (lcv = uvm_physmem_get_last() ; uvm_physmem_valid(lcv); lcv = uvm_physmem_get_prev(lcv))
d285 1
a285 1
+               for (lcv = uvm_physmem_get_first() ; uvm_physmem_valid(lcv) ; lcv = uvm_physmem_get_next(lcv))
d323 1
a323 1
@@@@ -727,228 +655,6 @@@@ uvm_page_physget(paddr_t *paddrp)
d552 1
a552 1
@@@@ -956,12 +662,12 @@@@ struct vm_page *
d559 1
a559 1
+       uvm_physmem_t   upm;
d564 3
a566 3
+       upm = vm_physseg_find(pf, &off);
+       if (upm != UVM_PHYSMEM_TYPE_INVALID)
+               return uvm_physmem_get_pg(upm, off);
d570 1
a570 1
@@@@ -985,7 +691,8 @@@@ uvm_page_recolor(int newncolors)
d580 1
a580 1
@@@@ -1094,6 +801,7 @@@@ uvm_cpu_attach(struct cpu_info *ci)
d588 1
a588 1
@@@@ -1219,7 +927,8 @@@@ struct vm_page *
d598 1
a598 1
@@@@ -2005,7 +1714,7 @@@@ bool
d603 1
a603 1
+       return (vm_physseg_find(atop(pa), NULL) != UVM_PHYSMEM_TYPE_INVALID);
d607 1
a607 1
@@@@ -2015,11 +1724,11 @@@@ uvm_pageismanaged(paddr_t pa)
d612 1
a612 1
+       uvm_physmem_t upm;
d617 3
a619 3
+       upm = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), NULL);
+       KASSERT(upm != UVM_PHYSMEM_TYPE_INVALID);
+       return uvm_physmem_get_free_list(upm);
d623 1
a623 1
@@@@ -2135,7 +1844,8 @@@@ uvm_page_printit(struct vm_page *pg, boo
d628 1
a628 1
+       uvm_physmem_t i;
d633 1
a633 1
@@@@ -2143,8 +1853,14 @@@@ uvm_page_printall(void (*pr)(const char
d639 5
a643 5
+       for (i = uvm_physmem_get_first();
+            uvm_physmem_valid(i);
+            i = uvm_physmem_get_next(i)) {
+               for (pfn = uvm_physmem_get_start(i);
+                    pfn <= uvm_physmem_get_end(i);
d656 1
a656 1
+++ sys/uvm/uvm_page.h  20 Nov 2016 07:20:25 -0000
d725 1
a725 1
+++ sys/uvm/uvm_pglist.c        20 Nov 2016 07:20:25 -0000
d731 1
a731 1
+uvm_pglistalloc_c_ps(uvm_physmem_t psi, int num, paddr_t low, paddr_t high,
d750 1
a750 1
+       if (high <= uvm_physmem_get_avail_start(psi) || low >= uvm_physmem_get_avail_end(psi))
d759 3
a761 3
+       candidate = roundup2(max(low, uvm_physmem_get_avail_start(psi) +
+               uvm_physmem_get_start_hint(psi)), alignment);
+       limit = min(high, uvm_physmem_get_avail_end(psi));
d773 1
a773 1
+                       if (uvm_physmem_get_start_hint(psi) == 0 || second_pass) {
d783 3
a785 3
+                       candidate = roundup2(max(low, uvm_physmem_get_avail_start(psi)), alignment);
+                       limit = min(limit, uvm_physmem_get_avail_start(psi) +
+                           uvm_physmem_get_start_hint(psi));
d794 1
a794 1
+               if (vm_physseg_find(candidate, &cidx) != psi)
d797 1
a797 1
+               if (cidx != candidate - uvm_physmem_get_start(psi))
d800 1
a800 1
+               if (vm_physseg_find(candidate + num - 1, &cidx) != psi)
d803 1
a803 1
+               if (cidx != candidate - uvm_physmem_get_start(psi) + num - 1)
d807 1
a807 1
+               candidateidx = candidate - uvm_physmem_get_start(psi);
d816 1
a816 1
+                       if (VM_PAGE_IS_FREE(uvm_physmem_get_pg(psi, idx)) == 0) {
d825 2
a826 2
+                               idxpa = VM_PAGE_TO_PHYS(uvm_physmem_get_pg(psi, idx));
+                               lastidxpa = VM_PAGE_TO_PHYS(uvm_physmem_get_pg(psi, idx));
d835 1
a835 1
+                               KDASSERT(VM_PAGE_IS_FREE(uvm_physmem_get_pg(psi, candidateidx + skip)));
d846 1
a846 1
+               uvm_pglist_add(uvm_physmem_get_pg(psi, idx), rlist);
d854 4
a857 4
+       uvm_physmem_set_start_hint(psi, candidate + num -
+           uvm_physmem_get_avail_start(psi));
+       KASSERTMSG(uvm_physmem_get_start_hint(psi) <=
+           uvm_physmem_get_avail_end(psi) - uvm_physmem_get_avail_start(psi),
d862 3
a864 3
+           uvm_physmem_get_start_hint(psi), uvm_physmem_get_start_hint(psi),
+           uvm_physmem_get_avail_end(psi), uvm_physmem_get_avail_start(psi),
+           uvm_physmem_get_avail_end(psi) - uvm_physmem_get_avail_start(psi));
d877 1
a877 1
+       uvm_physmem_t psi;
d886 1
a886 1
+               for (psi = uvm_physmem_get_last(); uvm_physmem_valid(psi); psi = uvm_physmem_get_prev(psi))
d890 1
a890 1
+               for (psi = uvm_physmem_get_first(); uvm_physmem_valid(psi); psi = uvm_physmem_get_next(psi))
d896 1
a896 1
+                       if (uvm_physmem_get_free_list(psi) != fl)
d909 1
a909 1
+uvm_pglistalloc_s_ps(uvm_physmem_t psi, int num, paddr_t low, paddr_t high,
d925 4
a928 4
+       KASSERT(uvm_physmem_get_start(psi) <= uvm_physmem_get_avail_start(psi));
+       KASSERT(uvm_physmem_get_start(psi) <= uvm_physmem_get_avail_end(psi));
+       KASSERT(uvm_physmem_get_avail_start(psi) <= uvm_physmem_get_end(psi));
+       KASSERT(uvm_physmem_get_avail_end(psi) <= uvm_physmem_get_end(psi));
d936 4
a939 4
+       candidate = max(low, uvm_physmem_get_avail_start(psi) +
+           uvm_physmem_get_start_hint(psi));
+       limit = min(high, uvm_physmem_get_avail_end(psi));
+       pg = uvm_physmem_get_pg(psi, candidate - uvm_physmem_get_start(psi));
d946 2
a947 2
+       if (high <= uvm_physmem_get_avail_start(psi) ||
+           low >= uvm_physmem_get_avail_end(psi))
d954 1
a954 1
+                       if (uvm_physmem_get_start_hint(psi) == 0 || second_pass) {
d962 4
a965 4
+                       candidate = max(low, uvm_physmem_get_avail_start(psi));
+                       limit = min(limit, uvm_physmem_get_avail_start(psi) +
+                           uvm_physmem_get_start_hint(psi));
+                       pg = uvm_physmem_get_pg(psi, candidate - uvm_physmem_get_start(psi));
d979 1
a979 1
+                       const uvm_physmem_t bank = vm_physseg_find(candidate, &cidx);
d981 1
a981 1
+                           "vm_physseg_find(%#x) (%"PRIxPHYSMEM ") != psi %"PRIxPHYSMEM,
d983 3
a985 3
+                       KDASSERTMSG(cidx == candidate - uvm_physmem_get_start(psi),
+                           "vm_physseg_find(%#x): %#"PRIxPADDR" != off %"PRIxPADDR,
+                            candidate, cidx, candidate - uvm_physmem_get_start(psi));
d995 3
a997 3
+       uvm_physmem_set_start_hint(psi, candidate + 1 - uvm_physmem_get_avail_start(psi));
+       KASSERTMSG(uvm_physmem_get_start_hint(psi) <= uvm_physmem_get_avail_end(psi) -
+           uvm_physmem_get_avail_start(psi),
d1002 5
a1006 5
+           uvm_physmem_get_start_hint(psi),
+           uvm_physmem_get_start_hint(psi),
+           uvm_physmem_get_avail_end(psi),
+           uvm_physmem_get_avail_start(psi),
+           uvm_physmem_get_avail_end(psi) - uvm_physmem_get_avail_start(psi));
d1018 1
a1018 1
+       uvm_physmem_t psi;
d1028 1
a1028 1
+               for (psi = uvm_physmem_get_last(); uvm_physmem_valid(psi); psi = uvm_physmem_get_prev(psi))
d1032 1
a1032 1
+               for (psi = uvm_physmem_get_first(); uvm_physmem_valid(psi); psi = uvm_physmem_get_next(psi))
d1038 1
a1038 1
+                       if (uvm_physmem_get_free_list(psi) != fl)
d1046 1
a1046 1
Index: sys/uvm/uvm_physmem.c
d1048 2
a1049 2
RCS file: sys/uvm/uvm_physmem.c
diff -N sys/uvm/uvm_physmem.c
d1051 2
a1052 2
+++ sys/uvm/uvm_physmem.c       20 Nov 2016 07:20:25 -0000
@@@@ -0,0 +1,1337 @@@@
d1136 1
a1136 1
+#include <uvm/uvm_physmem.h>
d1157 12
d1171 2
a1172 2
+#define        HANDLE_TO_PHYSMEM_NODE(h)       ((struct uvm_physseg *)(h))
+#define                PHYSMEM_NODE_TO_HANDLE(u)       ((uvm_physmem_t)(u))
d1207 1
a1207 1
+
d1212 1
a1212 1
+uvm_physmem_alloc(size_t sz)
d1227 1
a1227 1
+
d1232 1
a1232 1
+
d1237 1
a1237 1
+uvm_physmem_free(void *p, size_t sz)
d1253 1
a1253 1
+
d1260 1
a1260 1
+
d1265 1
a1265 1
+
d1282 1
a1282 1
+uvm_physmem_plug(paddr_t pfn, size_t pages, uvm_physmem_t *psp)
d1291 4
a1294 2
+       uvm_physmem_t upm;
+       upm = vm_physseg_find(pfn, &off);
a1295 2
+       ps = HANDLE_TO_PHYSMEM_NODE(upm);
+
d1299 1
a1299 1
+
d1304 1
a1304 1
+       ps = uvm_physmem_alloc(sizeof (struct uvm_physseg));
d1317 1
a1317 1
+
d1326 1
a1326 1
+
d1339 1
a1339 1
+                       pgs = uvm_physmem_seg_slab_alloc(current_ps, pages);
d1362 1
a1362 1
+                               uvm_physmem_free(ps, sizeof(struct uvm_physseg));
d1366 1
a1366 1
+                       uvm_physmem_seg_chomp_slab(ps, slab, (size_t) slabpages);
d1368 1
a1368 1
+                       pgs = uvm_physmem_seg_slab_alloc(ps, pages);
d1371 1
a1371 1
+                               printf("unable to uvm_physmem_seg_slab_alloc() from backend\n");
d1385 1
a1385 1
+
d1400 2
a1401 2
+        * vm_physseg_find() to succeed. For this, the node needs to
+        * be inserted *before* uvm_physmem_init_seg() happens.
d1404 1
a1404 1
+        * uvm_physmem_init_seg() is called later on and separately
d1408 1
a1408 1
+
d1410 1
a1410 1
+               uvm_physmem_init_seg(ps, pgs);
d1419 1
a1419 1
+uvm_physmem_compare_nodes(void *ctx, const void *nnode1, const void *nnode2)
d1435 1
a1435 1
+uvm_physmem_compare_key(void *ctx, const void *nnode, const void *pkey)
d1450 3
a1452 3
+static const rb_tree_ops_t uvm_physmem_tree_ops = {
+       .rbto_compare_nodes = uvm_physmem_compare_nodes,
+       .rbto_compare_key = uvm_physmem_compare_key,
d1458 1
a1458 1
+ * uvm_physmem_init: init the physmem
d1464 2
a1465 2
+uvm_physmem_init(void) {
+       rb_tree_init(&(uvm_physseg_graph.rb_tree), &uvm_physmem_tree_ops);
d1469 2
a1470 2
+uvm_physmem_t
+uvm_physmem_get_next(uvm_physmem_t upm)
d1472 1
a1472 1
+       return (uvm_physmem_t) rb_tree_iterate(&(uvm_physseg_graph.rb_tree), upm,
d1476 2
a1477 2
+uvm_physmem_t
+uvm_physmem_get_prev(uvm_physmem_t upm)
d1479 1
a1479 1
+       return (uvm_physmem_t) rb_tree_iterate(&(uvm_physseg_graph.rb_tree), upm,
d1483 2
a1484 2
+uvm_physmem_t
+uvm_physmem_get_last(void)
d1486 1
a1486 1
+       return (uvm_physmem_t) RB_TREE_MAX(&(uvm_physseg_graph.rb_tree));
d1489 2
a1490 2
+uvm_physmem_t
+uvm_physmem_get_first(void)
d1492 1
a1492 1
+       return (uvm_physmem_t) RB_TREE_MIN(&(uvm_physseg_graph.rb_tree));
d1496 1
a1496 1
+uvm_physmem_get_highest_frame(void)
d1499 1
a1499 1
+           (uvm_physmem_t) RB_TREE_MAX(&(uvm_physseg_graph.rb_tree));
d1509 1
a1509 1
+uvm_page_physunload(uvm_physmem_t upm, int freelist, paddr_t *paddrp)
d1513 1
a1513 1
+       seg = HANDLE_TO_PHYSMEM_NODE(upm);
d1537 1
a1537 1
+               return uvm_physmem_unplug(seg->avail_start, 1);
d1544 1
a1544 1
+               return uvm_physmem_unplug(seg->avail_end - 1, 1);
d1551 1
a1551 1
+uvm_page_physunload_force(uvm_physmem_t upm, int freelist, paddr_t *paddrp)
d1555 1
a1555 1
+       seg = HANDLE_TO_PHYSMEM_NODE(upm);
d1564 1
a1564 1
+
d1566 1
a1566 1
+       return uvm_physmem_unplug(seg->avail_start, 1);
d1573 2
a1574 2
+uvm_physmem_t
+vm_physseg_find(paddr_t pframe, psize_t *offp)
d1588 1
a1588 1
+uvm_physmem_set_avail_start(uvm_physmem_t upm, paddr_t avail_start)
d1590 1
a1590 1
+       struct uvm_physseg *ps = HANDLE_TO_PHYSMEM_NODE(upm);
d1594 1
a1594 1
+       avail_end = uvm_physmem_get_avail_end(upm);
d1599 1
a1599 1
+void uvm_physmem_set_avail_end(uvm_physmem_t upm, paddr_t avail_end)
d1601 1
a1601 1
+       struct uvm_physseg *ps = HANDLE_TO_PHYSMEM_NODE(upm);
d1605 1
a1605 1
+       avail_start = uvm_physmem_get_avail_start(upm);
d1628 2
a1629 2
+#define        HANDLE_TO_PHYSMEM_NODE(h)       (VM_PHYSMEM_PTR((int)h))
+#define                PHYSMEM_NODE_TO_HANDLE(u)       ((int)((vsize_t) (u - vm_physmem) / sizeof(struct uvm_physseg)))
d1636 1
a1636 1
+uvm_physmem_init(void) {
d1642 1
a1642 1
+uvm_physmem_get_next(uvm_physmem_t lcv)
d1648 1
a1648 1
+uvm_physmem_get_prev(uvm_physmem_t lcv)
d1654 1
a1654 1
+uvm_physmem_get_last(void)
d1660 1
a1660 1
+uvm_physmem_get_first(void)
d1666 1
a1666 1
+uvm_physmem_get_highest_frame(void)
d1686 1
a1686 1
+uvm_page_physunload(uvm_physmem_t psi, int freelist, paddr_t *paddrp)
d1738 1
a1738 1
+uvm_page_physunload_force(uvm_physmem_t psi, int freelist, paddr_t *paddrp)
d1769 1
a1769 1
+uvm_physmem_plug(paddr_t pfn, size_t pages, uvm_physmem_t *psp)
d1777 2
a1778 2
+       uvm_physmem_t upm;
+       upm = vm_physseg_find(pfn, &off);
d1780 1
a1780 1
+        if (uvm_physmem_valid(upm)) /* XXX; do we allow "update" plugs ? */
d1788 1
a1788 1
+
d1803 1
a1803 1
+                       *psp = UVM_PHYSMEM_TYPE_INVALID_OVERFLOW;
d1897 1
a1897 1
+vm_physseg_find(paddr_t pframe, psize_t *offp)
d1967 1
a1967 1
+#else
d1989 1
a1989 1
+uvm_physmem_valid(uvm_physmem_t upm)
d1993 3
a1995 3
+       if (upm == UVM_PHYSMEM_TYPE_INVALID ||
+           upm == UVM_PHYSMEM_TYPE_INVALID_EMPTY ||
+           upm == UVM_PHYSMEM_TYPE_INVALID_OVERFLOW)
d2005 1
a2005 1
+       ps = HANDLE_TO_PHYSMEM_NODE(upm);
d2022 1
a2022 1
+uvm_physmem_get_start(uvm_physmem_t upm)
d2024 1
a2024 1
+       if (uvm_physmem_valid(upm) == false)
d2027 1
a2027 1
+       return HANDLE_TO_PHYSMEM_NODE(upm)->start;
d2031 1
a2031 1
+uvm_physmem_get_end(uvm_physmem_t upm)
d2033 1
a2033 1
+       if (uvm_physmem_valid(upm) == false)
d2036 1
a2036 1
+       return HANDLE_TO_PHYSMEM_NODE(upm)->end;
d2040 1
a2040 1
+uvm_physmem_get_avail_start(uvm_physmem_t upm)
d2042 1
a2042 1
+       if (uvm_physmem_valid(upm) == false)
d2045 1
a2045 1
+       return HANDLE_TO_PHYSMEM_NODE(upm)->avail_start;
d2049 1
a2049 1
+uvm_physmem_get_avail_end(uvm_physmem_t upm)
d2051 1
a2051 1
+       if (uvm_physmem_valid(upm) == false)
d2054 1
a2054 1
+       return HANDLE_TO_PHYSMEM_NODE(upm)->avail_end;
d2058 1
a2058 1
+uvm_physmem_get_pg(uvm_physmem_t upm, paddr_t idx)
d2060 2
a2061 2
+       /* XXX: uvm_physmem_valid() */
+       return &HANDLE_TO_PHYSMEM_NODE(upm)->pgs[idx];
d2066 1
a2066 1
+uvm_physmem_get_pmseg(uvm_physmem_t upm)
d2068 2
a2069 2
+       /* XXX: uvm_physmem_valid() */
+       return &(HANDLE_TO_PHYSMEM_NODE(upm)->pmseg);
d2074 1
a2074 1
+uvm_physmem_get_free_list(uvm_physmem_t upm)
d2076 1
a2076 1
+       return HANDLE_TO_PHYSMEM_NODE(upm)->free_list;
d2080 1
a2080 1
+uvm_physmem_get_start_hint(uvm_physmem_t upm)
d2082 1
a2082 1
+       return HANDLE_TO_PHYSMEM_NODE(upm)->start_hint;
d2086 1
a2086 1
+uvm_physmem_set_start_hint(uvm_physmem_t upm, u_int start_hint)
d2088 1
a2088 1
+       if (uvm_physmem_valid(upm) == false)
d2091 1
a2091 1
+       HANDLE_TO_PHYSMEM_NODE(upm)->start_hint = start_hint;
d2096 1
a2096 1
+uvm_physmem_init_seg(uvm_physmem_t upm, struct vm_page *pgs)
d2103 1
a2103 1
+       KASSERT(upm != UVM_PHYSMEM_TYPE_INVALID && pgs != NULL);
d2105 1
a2105 1
+       seg = HANDLE_TO_PHYSMEM_NODE(upm);
d2108 1
a2108 1
+
d2131 1
a2131 1
+uvm_physmem_seg_chomp_slab(uvm_physmem_t upm, struct vm_page *pgs, size_t n)
d2133 2
a2134 2
+       struct uvm_physseg *seg = HANDLE_TO_PHYSMEM_NODE(upm);
+
d2136 2
a2137 2
+#define UVM_PHYSMEM_BOOT_UNPLUG_MAX VM_PHYSSEG_MAX /* max number of pre-boot unplug()s allowed */
+       static struct extent_region erboot[UVM_PHYSMEM_BOOT_UNPLUG_MAX];
d2150 1
a2150 1
+uvm_physmem_seg_slab_alloc(uvm_physmem_t upm, size_t pages)
d2156 1
a2156 1
+       seg = HANDLE_TO_PHYSMEM_NODE(upm);
d2169 3
a2171 3
+
+               seg->ext = HANDLE_TO_PHYSMEM_NODE(uvm_physmem_get_prev(PHYSMEM_NODE_TO_HANDLE(seg)))->ext;
+
d2197 1
a2197 1
+uvm_physmem_t
d2202 2
a2203 2
+       uvm_physmem_t upm;
+
d2211 4
a2214 2
+       if (uvm_physmem_plug(start, end - start, &upm) == false) {
+               return UVM_PHYSMEM_TYPE_INVALID; /* XXX: correct type */
d2217 2
a2218 2
+       ps = HANDLE_TO_PHYSMEM_NODE(upm);
+
d2230 1
a2230 1
+uvm_physmem_unplug(paddr_t pfn, size_t pages)
d2232 1
a2232 1
+       uvm_physmem_t upm;
a2234 2
+
+       upm = vm_physseg_find(pfn, &off);
d2236 3
a2238 1
+       if (!uvm_physmem_valid(upm)) {
d2243 4
a2246 4
+       seg = HANDLE_TO_PHYSMEM_NODE(upm);
+
+       start = uvm_physmem_get_start(upm);
+       end = uvm_physmem_get_end(upm);
d2264 1
a2264 1
+       if (off == 0 && (pfn + pages) == end) {
d2292 1
a2292 1
+               uvm_physmem_free(seg, sizeof(struct uvm_physseg));
d2309 1
a2309 1
+#if defined(UVM_HOTPLUG) /* rbtree implementation */
d2312 1
a2312 1
+               ps = uvm_physmem_alloc(sizeof (struct uvm_physseg));
d2348 1
a2348 1
+
d2358 1
a2358 1
+#endif /* UVM_HOTPLUG */
d2383 1
a2383 1
+
d2396 1
a2396 1
+
d2399 1
a2399 1
+
d2401 1
a2401 1
+
d2404 1
a2404 1
Index: sys/uvm/uvm_physmem.h
d2406 2
a2407 2
RCS file: sys/uvm/uvm_physmem.h
diff -N sys/uvm/uvm_physmem.h
d2409 2
a2410 2
+++ sys/uvm/uvm_physmem.h       20 Nov 2016 07:20:25 -0000
@@@@ -0,0 +1,124 @@@@
d2418 2
a2419 2
+#ifndef _UVM_UVM_PHYSMEM_H_
+#define _UVM_UVM_PHYSMEM_H_
d2430 1
a2430 1
+ * No APIs are explicitly #included in uvm_physmem.c
d2434 1
a2434 1
+#define PRIxPHYSMEM "p"
d2437 2
a2438 2
+ * These are specific values of invalid constants for uvm_physmem_t.
+ * uvm_physmem_valid() == false on any of the below constants.
d2444 3
a2446 3
+#define UVM_PHYSMEM_TYPE_INVALID NULL /* Generic invalid value */
+#define UVM_PHYSMEM_TYPE_INVALID_EMPTY NULL /* empty segment access */
+#define UVM_PHYSMEM_TYPE_INVALID_OVERFLOW NULL /* ran off the end of the last segment */
d2448 1
a2448 1
+typedef struct uvm_physseg * uvm_physmem_t;
d2452 1
a2452 1
+#define PRIxPHYSMEM "d"
d2455 2
a2456 2
+ * These are specific values of invalid constants for uvm_physmem_t.
+ * uvm_physmem_valid() == false on any of the below constants.
d2462 3
a2464 3
+#define UVM_PHYSMEM_TYPE_INVALID -1 /* Generic invalid value */
+#define UVM_PHYSMEM_TYPE_INVALID_EMPTY -1 /* empty segment access */
+#define UVM_PHYSMEM_TYPE_INVALID_OVERFLOW (uvm_physmem_get_last() + 1) /* ran off the end of the last segment */
d2466 1
a2466 1
+typedef int uvm_physmem_t;
d2469 1
a2469 7
+void uvm_physmem_init(void);
+void uvm_physmem_init_seg(uvm_physmem_t, struct vm_page *);
+void uvm_physmem_seg_chomp_slab(uvm_physmem_t,
+    struct vm_page *, size_t);
+
+/* returns a pgs array */
+struct vm_page *uvm_physmem_seg_slab_alloc(uvm_physmem_t, size_t);
d2471 1
a2471 1
+bool uvm_physmem_valid(uvm_physmem_t);
d2477 2
a2478 2
+paddr_t uvm_physmem_get_start(uvm_physmem_t);
+paddr_t uvm_physmem_get_end(uvm_physmem_t);
d2480 2
a2481 2
+paddr_t uvm_physmem_get_avail_start(uvm_physmem_t);
+paddr_t uvm_physmem_get_avail_end(uvm_physmem_t);
d2483 1
a2483 1
+struct vm_page * uvm_physmem_get_pg(uvm_physmem_t, paddr_t);
d2486 1
a2486 1
+struct pmap_physseg * uvm_physmem_get_pmseg(uvm_physmem_t);
d2489 3
a2491 3
+int uvm_physmem_get_free_list(uvm_physmem_t);
+u_int uvm_physmem_get_start_hint(uvm_physmem_t);
+bool uvm_physmem_set_start_hint(uvm_physmem_t, u_int);
d2497 4
a2500 4
+uvm_physmem_t uvm_physmem_get_next(uvm_physmem_t);
+uvm_physmem_t uvm_physmem_get_prev(uvm_physmem_t);
+uvm_physmem_t uvm_physmem_get_first(void);
+uvm_physmem_t uvm_physmem_get_last(void);
d2504 1
a2504 1
+paddr_t uvm_physmem_get_highest_frame(void);
d2507 1
a2507 1
+uvm_physmem_t uvm_page_physload(paddr_t, paddr_t, paddr_t,
d2510 2
a2511 2
+bool uvm_page_physunload(uvm_physmem_t, int, paddr_t *);
+bool uvm_page_physunload_force(uvm_physmem_t, int, paddr_t *);
d2513 1
a2513 1
+uvm_physmem_t vm_physseg_find(paddr_t, psize_t *);
d2515 2
a2516 2
+bool uvm_physmem_plug(paddr_t, size_t, uvm_physmem_t *);
+bool uvm_physmem_unplug(paddr_t, size_t);
d2523 2
a2524 2
+void uvm_physmem_set_avail_start(uvm_physmem_t, paddr_t);
+void uvm_physmem_set_avail_end(uvm_physmem_t, paddr_t);
d2527 1
a2527 1
+#endif /* _UVM_UVM_PHYSMEM_H_ */
d2532 4
a2535 4
retrieving revision 1.22
diff -p -u -r1.22 pmap.c
--- sys/uvm/pmap/pmap.c 16 Sep 2016 17:27:09 -0000      1.22
+++ sys/uvm/pmap/pmap.c 20 Nov 2016 07:20:26 -0000
d2540 1
a2540 1
+#include <uvm/uvm_physmem.h>
d2551 1
a2551 1
+       uvm_physmem_t maybe_bank = UVM_PHYSMEM_TYPE_INVALID;
d2560 3
a2562 3
+       for (uvm_physmem_t bank = uvm_physmem_get_first();
+            uvm_physmem_valid(bank);
+            bank = uvm_physmem_get_next(bank)) {
d2572 2
a2573 2
+                   uvm_physmem_get_avail_start(bank), uvm_physmem_get_start(bank),
+                   uvm_physmem_get_avail_end(bank), uvm_physmem_get_end(bank));
d2578 2
a2579 2
+               if (uvm_physmem_get_avail_start(bank) != uvm_physmem_get_start(bank)
+                   || uvm_physmem_get_avail_start(bank) >= uvm_physmem_get_avail_end(bank)) {
d2586 1
a2586 1
+               if (uvm_physmem_get_avail_end(bank) - uvm_physmem_get_avail_start(bank) < npgs) {
d2605 2
a2606 2
+#define VM_PHYSMEM_SPACE(b)    ((uvm_physmem_get_avail_end(b)) - (uvm_physmem_get_avail_start(b)))
+               if (uvm_physmem_valid(maybe_bank) == false
d2616 2
a2617 2
+       if (uvm_physmem_valid(maybe_bank)) {
+               const uvm_physmem_t bank = maybe_bank;
d2632 2
a2633 2
+               pa = ptoa(uvm_physmem_get_start(bank));
+               uvm_physmem_unplug(atop(pa), npgs);
@


1.7
log
@Some of the changes that Chuck suggested.
@
text
@a0 6
? sys/uvm/files_BACKUP_21538.uvm
? sys/uvm/files_BASE_21538.uvm
? sys/uvm/files_LOCAL_21538.uvm
? sys/uvm/files_REMOTE_21538.uvm
? sys/uvm/uvm_physmem_new.c
? sys/uvm/uvm_physmem_support.c
@


1.6
log
@options UVM_HOTPLUG
@
text
@d1 6
d11 1
a11 1
diff -u -p -r1.9 Makefile
d13 1
a13 1
+++ sys/uvm/Makefile    17 Nov 2016 15:38:54 -0000
d27 1
a27 1
diff -u -p -r1.26 files.uvm
d29 1
a29 1
+++ sys/uvm/files.uvm   17 Nov 2016 15:38:54 -0000
d50 1
a50 1
diff -u -p -r1.66 uvm.h
d52 1
a52 1
+++ sys/uvm/uvm.h       17 Nov 2016 15:38:54 -0000
a60 116
Index: sys/uvm/uvm_amap.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_amap.c,v
retrieving revision 1.107
diff -u -p -r1.107 uvm_amap.c
--- sys/uvm/uvm_amap.c  8 Apr 2012 20:47:10 -0000       1.107
+++ sys/uvm/uvm_amap.c  17 Nov 2016 15:38:56 -0000
@@@@ -37,7 +37,9 @@@@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_amap.c,v 1.107 2012/04/08 20:47:10 chs Exp $");

+#ifdef _KERNEL_OPT
#include "opt_uvmhist.h"
+#endif

#include <sys/param.h>
#include <sys/systm.h>
@@@@ -830,7 +832,7 @@@@ amap_copy(struct vm_map *map, struct vm_
       }

       /*
-        * First check and see if we are the only map entry referencing
+        * First check and see if we are the only map entry referencing
        * he amap we currently have.  If so, then just take it over instead
        * of copying it.  Note that we are reading am_ref without lock held
        * as the value value can only be one if we have the only reference
Index: sys/uvm/uvm_anon.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_anon.c,v
retrieving revision 1.63
diff -u -p -r1.63 uvm_anon.c
--- sys/uvm/uvm_anon.c  25 Oct 2013 20:08:11 -0000      1.63
+++ sys/uvm/uvm_anon.c  17 Nov 2016 15:38:56 -0000
@@@@ -32,7 +32,9 @@@@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_anon.c,v 1.63 2013/10/25 20:08:11 martin Exp $");

+#ifdef _KERNEL_OPT
#include "opt_uvmhist.h"
+#endif

#include <sys/param.h>
#include <sys/systm.h>
@@@@ -303,7 +305,7 @@@@ uvm_anon_lockloanpg(struct vm_anon *anon
                               /*
                                * someone locking the object has a chance to
                                * lock us right now
-                                *
+                                *
                                * XXX Better than yielding but inadequate.
                                */
                               kpause("livelock", false, 1, anon->an_lock);
Index: sys/uvm/uvm_bio.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_bio.c,v
retrieving revision 1.83
diff -u -p -r1.83 uvm_bio.c
--- sys/uvm/uvm_bio.c   27 May 2015 19:43:40 -0000      1.83
+++ sys/uvm/uvm_bio.c   17 Nov 2016 15:38:58 -0000
@@@@ -36,8 +36,10 @@@@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_bio.c,v 1.83 2015/05/27 19:43:40 rmind Exp $");

+#ifdef _KERNEL_OPT
#include "opt_uvmhist.h"
#include "opt_ubc.h"
+#endif

#include <sys/param.h>
#include <sys/systm.h>
@@@@ -783,6 +785,7 @@@@ ubc_zerorange(struct uvm_object *uobj, o
       }
}

+#ifdef _KERNEL_OPT
/*
 * ubc_purge: disassociate ubc_map structures from an empty uvm_object.
 */
@@@@ -816,3 +819,4 @@@@ ubc_purge(struct uvm_object *uobj)
       }
       mutex_exit(ubc_object.uobj.vmobjlock);
}
+#endif
Index: sys/uvm/uvm_device.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_device.c,v
retrieving revision 1.64
diff -u -p -r1.64 uvm_device.c
--- sys/uvm/uvm_device.c        14 Dec 2014 23:48:58 -0000      1.64
+++ sys/uvm/uvm_device.c        17 Nov 2016 15:38:58 -0000
@@@@ -34,7 +34,9 @@@@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_device.c,v 1.64 2014/12/14 23:48:58 chs Exp $");

+#ifdef _KERNEL_OPT
#include "opt_uvmhist.h"
+#endif

#include <sys/param.h>
#include <sys/systm.h>
@@@@ -95,6 +97,7 @@@@ udv_init(void)
       mutex_init(&udv_lock, MUTEX_DEFAULT, IPL_NONE);
}

+#ifdef _KERNEL_OPT
/*
 * udv_attach
 *
@@@@ -255,6 +258,7 @@@@ udv_attach(dev_t device, vm_prot_t acces
       }
       /*NOTREACHED*/
}
+#endif

/*
 * udv_reference
d65 1
a65 1
diff -u -p -r1.198 uvm_extern.h
d67 1
a67 1
+++ sys/uvm/uvm_extern.h        17 Nov 2016 15:38:59 -0000
a77 371
Index: sys/uvm/uvm_fault.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_fault.c,v
retrieving revision 1.197
diff -u -p -r1.197 uvm_fault.c
--- sys/uvm/uvm_fault.c 22 Jun 2015 06:24:17 -0000      1.197
+++ sys/uvm/uvm_fault.c 17 Nov 2016 15:39:01 -0000
@@@@ -34,7 +34,9 @@@@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_fault.c,v 1.197 2015/06/22 06:24:17 matt Exp $");

+#ifdef _KERNEL_OPT
#include "opt_uvmhist.h"
+#endif

#include <sys/param.h>
#include <sys/systm.h>
@@@@ -277,7 +279,9 @@@@ uvmfault_anonget(struct uvm_faultinfo *u
    struct vm_anon *anon)
{
       struct vm_page *pg;
+#ifdef _KERNEL_OPT
       int error;
+#endif

       UVMHIST_FUNC("uvmfault_anonget"); UVMHIST_CALLED(maphist);
       KASSERT(mutex_owned(anon->an_lock));
@@@@ -290,7 +294,9 @@@@ uvmfault_anonget(struct uvm_faultinfo *u
       } else {
               curlwp->l_ru.ru_majflt++;
       }
+#ifdef _KERNEL_OPT
       error = 0;
+#endif

       /*
        * Loop until we get the anon data, or fail.
Index: sys/uvm/uvm_init.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_init.c,v
retrieving revision 1.46
diff -u -p -r1.46 uvm_init.c
--- sys/uvm/uvm_init.c  3 Apr 2015 01:03:42 -0000       1.46
+++ sys/uvm/uvm_init.c  17 Nov 2016 15:39:01 -0000
@@@@ -68,6 +68,7 @@@@ kmutex_t uvm_fpageqlock;
kmutex_t uvm_kentry_lock;
kmutex_t uvm_swap_data_lock;

+#ifdef _KERNEL_OPT
/*
 * uvm_init: init the VM system.   called from kern/init_main.c.
 */
@@@@ -184,3 +185,4 @@@@ uvm_init(void)

       uvm_ra_init();
}
+#endif
Index: sys/uvm/uvm_km.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_km.c,v
retrieving revision 1.141
diff -u -p -r1.141 uvm_km.c
--- sys/uvm/uvm_km.c    27 Jul 2016 16:45:00 -0000      1.141
+++ sys/uvm/uvm_km.c    17 Nov 2016 15:39:02 -0000
@@@@ -154,9 +154,11 @@@@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_km.c,v 1.141 2016/07/27 16:45:00 maxv Exp $");

+#ifdef _KERNEL_OPT
#include "opt_uvmhist.h"

#include "opt_kmempages.h"
+#endif

#ifndef NKMEMPAGES
#define NKMEMPAGES 0
@@@@ -189,7 +191,9 @@@@ __KERNEL_RCSID(0, "$NetBSD: uvm_km.c,v 1
 * global data structures
 */

+#ifdef _KERNEL_OPT
struct vm_map *kernel_map = NULL;
+#endif

/*
 * local data structues
@@@@ -199,7 +203,9 @@@@ static struct vm_map            kernel_map_store;
static struct vm_map_entry     kernel_image_mapent_store;
static struct vm_map_entry     kernel_kmem_mapent_store;

+#ifdef _KERNEL_OPT
int nkmempages = 0;
+#endif
vaddr_t kmembase;
vsize_t kmemsize;

@@@@ -367,6 +373,7 @@@@ uvm_km_init(void)
       kmem_init();
}

+#ifdef _KERNEL_OPT
/*
 * uvm_km_suballoc: allocate a submap in the kernel map.   once a submap
 * is allocated all references to that area of VM must go through it.  this
@@@@ -429,6 +436,7 @@@@ uvm_km_suballoc(struct vm_map *map, vadd

       return(submap);
}
+#endif

/*
 * uvm_km_pgremove: remove pages from a kernel uvm_object and KVA.
@@@@ -575,6 +583,7 @@@@ uvm_km_check_empty(struct vm_map *map, v
}
#endif /* defined(DEBUG) */

+#ifdef _KERNEL_OPT
/*
 * uvm_km_alloc: allocate an area of kernel memory.
 *
@@@@ -707,7 +716,9 @@@@ uvm_km_alloc(struct vm_map *map, vsize_t
       UVMHIST_LOG(maphist,"<- done (kva=0x%x)", kva,0,0,0);
       return(kva);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_km_protect: change the protection of an allocated area
 */
@@@@ -752,6 +763,7 @@@@ uvm_km_free(struct vm_map *map, vaddr_t

       uvm_unmap1(map, addr, addr + size, UVM_FLAG_VAONLY);
}
+#endif

/* Sanity; must specify both or none. */
#if (defined(PMAP_MAP_POOLPAGE) || defined(PMAP_UNMAP_POOLPAGE)) && \
@@@@ -759,6 +771,7 @@@@ uvm_km_free(struct vm_map *map, vaddr_t
#error Must specify MAP and UNMAP together.
#endif

+#ifdef _KERNEL_OPT
int
uvm_km_kmem_alloc(vmem_t *vm, vmem_size_t size, vm_flag_t flags,
    vmem_addr_t *addr)
@@@@ -853,7 +866,9 @@@@ again:

       return 0;
}
+#endif

+#ifdef _KERNEL_OPT
void
uvm_km_kmem_free(vmem_t *vm, vmem_addr_t addr, size_t size)
{
@@@@ -873,6 +888,7 @@@@ uvm_km_kmem_free(vmem_t *vm, vmem_addr_t

       vmem_free(vm, addr, size);
}
+#endif

bool
uvm_km_va_starved_p(void)
Index: sys/uvm/uvm_loan.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_loan.c,v
retrieving revision 1.83
diff -u -p -r1.83 uvm_loan.c
--- sys/uvm/uvm_loan.c  30 Jul 2012 23:56:48 -0000      1.83
+++ sys/uvm/uvm_loan.c  17 Nov 2016 15:39:02 -0000
@@@@ -107,8 +107,10 @@@@ static int     uvm_loananon(struct uvm_fault
static int     uvm_loanuobj(struct uvm_faultinfo *, void ***,
                            int, vaddr_t);
static int     uvm_loanzero(struct uvm_faultinfo *, void ***, int);
+#ifdef _KERNEL_OPT
static void    uvm_unloananon(struct vm_anon **, int);
static void    uvm_unloanpage(struct vm_page **, int);
+#endif
static int     uvm_loanpage(struct vm_page **, int);


@@@@ -222,6 +224,7 @@@@ uvm_loanentry(struct uvm_faultinfo *ufi,
 * normal functions
 */

+#ifdef _KERNEL_OPT
/*
 * uvm_loan: loan pages in a map out to anons or to the kernel
 *
@@@@ -327,6 +330,7 @@@@ fail:
       UVMHIST_LOG(loanhist, "error %d", error,0,0,0);
       return (error);
}
+#endif

/*
 * uvm_loananon: loan a page from an anon out
@@@@ -500,6 +504,7 @@@@ uvm_loanpage(struct vm_page **pgpp, int
 */
#define        UVM_LOAN_GET_CHUNK      16

+#ifdef _KERNEL_OPT
/*
 * uvm_loanuobjpages: loan pages from a uobj out (O->K)
 *
@@@@ -601,6 +606,7 @@@@ fail:

       return error;
}
+#endif

/*
 * uvm_loanuobj: loan a page from a uobj out
@@@@ -929,6 +935,7 @@@@ again:
}


+#ifdef _KERNEL_OPT
/*
 * uvm_unloananon: kill loans on anons (basically a normal ref drop)
 *
@@@@ -953,7 +960,9 @@@@ uvm_unloananon(struct vm_anon **aloans,
       uvm_anon_freelst(amap, to_free);
#endif /* notdef */
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_unloanpage: kill loans on pages loaned out to the kernel
 *
@@@@ -1021,7 +1030,9 @@@@ uvm_unloanpage(struct vm_page **ploans,
       }
       mutex_exit(&uvm_pageqlock);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_unloan: kill loans on pages or anons.
 */
@@@@ -1035,6 +1046,7 @@@@ uvm_unloan(void *v, int npages, int flag
               uvm_unloanpage(v, npages);
       }
}
+#endif

/*
 * Minimal pager for uvm_loanzero_object.  We need to provide a "put"
@@@@ -1098,6 +1110,7 @@@@ uvm_loan_init(void)
       UVMHIST_INIT(loanhist, 300);
}

+#ifdef _KERNEL_OPT
/*
 * uvm_loanbreak: break loan on a uobj page
 *
@@@@ -1182,6 +1195,7 @@@@ uvm_loanbreak(struct vm_page *uobjpage)

       return pg;
}
+#endif

int
uvm_loanbreak_anon(struct vm_anon *anon, struct uvm_object *uobj)
Index: sys/uvm/uvm_map.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_map.c,v
retrieving revision 1.341
diff -u -p -r1.341 uvm_map.c
--- sys/uvm/uvm_map.c   6 Aug 2016 15:13:14 -0000       1.341
+++ sys/uvm/uvm_map.c   17 Nov 2016 15:39:05 -0000
@@@@ -68,10 +68,12 @@@@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.341 2016/08/06 15:13:14 maxv Exp $");

+#ifdef _KERNEL_OPT
#include "opt_ddb.h"
#include "opt_uvmhist.h"
#include "opt_uvm.h"
#include "opt_sysv.h"
+#endif

#include <sys/param.h>
#include <sys/systm.h>
@@@@ -87,8 +89,10 @@@@ __KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v
#include <sys/sysctl.h>
#ifndef __USER_VA0_IS_SAFE
#include <sys/kauth.h>
+#ifdef _KERNEL_OPT
#include "opt_user_va0_disable_default.h"
#endif
+#endif

#include <sys/shm.h>

@@@@ -2944,6 +2948,7 @@@@ uvm_map_submap(struct vm_map *map, vaddr
       return error;
}

+#ifdef _KERNEL_OPT
/*
 * uvm_map_protect: change map protection
 *
@@@@ -3091,6 +3096,7 @@@@ uvm_map_protect(struct vm_map *map, vadd
}

#undef  MASK
+#endif

/*
 * uvm_map_inherit: set inheritance code for range of addrs in map.
@@@@ -3958,6 +3964,7 @@@@ uvmspace_alloc(vaddr_t vmin, vaddr_t vma
       return (vm);
}

+#ifdef _KERNEL_OPT
/*
 * uvmspace_init: initialize a vmspace structure.
 *
@@@@ -3986,6 +3993,7 @@@@ uvmspace_init(struct vmspace *vm, struct
       vm->vm_refcnt = 1;
       UVMHIST_LOG(maphist,"<- done",0,0,0,0);
}
+#endif

/*
 * uvmspace_share: share a vmspace between two processes
@@@@ -4138,6 +4146,7 @@@@ uvmspace_exec(struct lwp *l, vaddr_t sta
       }
}

+#ifdef _KERNEL_OPT
/*
 * uvmspace_addref: add a referece to a vmspace.
 */
@@@@ -4154,7 +4163,9 @@@@ uvmspace_addref(struct vmspace *vm)
       vm->vm_refcnt++;
       mutex_exit(&map->misc_lock);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvmspace_free: free a vmspace data structure
 */
@@@@ -4202,6 +4213,7 @@@@ uvmspace_free(struct vmspace *vm)
       pmap_destroy(map->pmap);
       pool_cache_put(&uvm_vmspace_cache, vm);
}
+#endif

static struct vm_map_entry *
uvm_mapent_clone(struct vm_map *new_map, struct vm_map_entry *old_entry,
@@@@ -4672,6 +4684,7 @@@@ uvm_map_reference(struct vm_map *map)
       mutex_exit(&map->misc_lock);
}

+#ifdef _KERNEL_OPT
bool
vm_map_starved_p(struct vm_map *map)
{
@@@@ -4685,6 +4698,7 @@@@ vm_map_starved_p(struct vm_map *map)
       }
       return false;
}
+#endif

void
uvm_map_lock_entry(struct vm_map_entry *entry)
d82 1
a82 1
diff -u -p -r1.187 uvm_page.c
d84 2
a85 15
+++ sys/uvm/uvm_page.c  17 Nov 2016 15:39:06 -0000
@@@@ -68,10 +68,12 @@@@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v 1.187 2015/04/11 19:24:13 joerg Exp $");

+#ifdef _KERNEL_OPT
#include "opt_ddb.h"
#include "opt_uvm.h"
#include "opt_uvmhist.h"
#include "opt_readahead.h"
+#endif

#include <sys/param.h>
#include <sys/systm.h>
@@@@ -81,24 +83,13 @@@@ __KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v
d111 1
a111 1
@@@@ -116,7 +107,7 @@@@ int vm_page_reserve_kernel = UVM_RESERVE
d120 1
a120 36
@@@@ -152,6 +143,7 @@@@ vaddr_t uvm_zerocheckkva;
static void uvm_pageinsert(struct uvm_object *, struct vm_page *);
static void uvm_pageremove(struct uvm_object *, struct vm_page *);

+#ifdef _KERNEL_OPT
/*
 * per-object tree of pages
 */
@@@@ -170,7 +162,9 @@@@ uvm_page_compare_nodes(void *ctx, const
               return 1;
       return 0;
}
+#endif

+#ifdef _KERNEL_OPT
static signed int
uvm_page_compare_key(void *ctx, const void *n, const void *key)
{
@@@@ -184,13 +178,16 @@@@ uvm_page_compare_key(void *ctx, const vo
               return 1;
       return 0;
}
+#endif

+#ifdef _KERNEL_OPT
const rb_tree_ops_t uvm_page_tree_ops = {
       .rbto_compare_nodes = uvm_page_compare_nodes,
       .rbto_compare_key = uvm_page_compare_key,
       .rbto_node_offset = offsetof(struct vm_page, rb_node),
       .rbto_context = NULL
};
+#endif

/*
 * inline functions
@@@@ -337,11 +334,9 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d133 1
a133 1
@@@@ -369,7 +364,7 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d142 1
a142 1
@@@@ -381,9 +376,11 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d157 1
a157 1
@@@@ -428,31 +425,20 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d199 1
a199 1
@@@@ -625,92 +611,42 @@@@ static bool uvm_page_physget_freelist(pa
d223 7
a229 1
-
d247 1
a247 7
+               /* Try to match at front or back on unused segment */
+               if (uvm_page_physunload(lcv, freelist, paddrp) == false) {
+                       if (paddrp == NULL) /* freelist fail, try next */
+                               continue;
+               } else
+                       return true;

d311 1
a311 2
@@@@ -726,228 +662,7 @@@@ uvm_page_physget(paddr_t *paddrp)
}
d314 1
a314 1
-/*
d536 1
a536 2
+#ifdef _KERNEL_OPT
/*
d539 2
a540 1
@@@@ -956,21 +671,24 @@@@ struct vm_page *
a556 10
+#endif

+#ifdef _KERNEL_OPT
paddr_t
uvm_vm_page_to_phys(const struct vm_page *pg)
{

       return pg->phys_addr;
}
+#endif
d558 1
a558 3
/*
 * uvm_page_recolor: Recolor the pages if the new bucket count is
@@@@ -985,7 +703,8 @@@@ uvm_page_recolor(int newncolors)
d568 1
a568 1
@@@@ -1094,6 +813,7 @@@@ uvm_cpu_attach(struct cpu_info *ci)
d576 1
a576 19
@@@@ -1110,6 +830,7 @@@@ attachrnd:

}

+#ifdef _KERNEL_OPT
/*
 * uvm_pagealloc_pgfl: helper routine for uvm_pagealloc_strat
 */
@@@@ -1196,7 +917,9 @@@@ uvm_pagealloc_pgfl(struct uvm_cpu *ucpu,

       return (pg);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_pagealloc_strat: allocate vm_page from a particular free list.
 *
@@@@ -1219,7 +942,8 @@@@ struct vm_page *
d586 1
a586 121
@@@@ -1389,6 +1113,7 @@@@ uvm_pagealloc_strat(struct uvm_object *o
       mutex_spin_exit(&uvm_fpageqlock);
       return (NULL);
}
+#endif

/*
 * uvm_pagereplace: replace a page with another
@@@@ -1481,6 +1206,7 @@@@ uvm_pagezerocheck(struct vm_page *pg)
}
#endif /* DEBUG */

+#ifdef _KERNEL_OPT
/*
 * uvm_pagefree: free page
 *
@@@@ -1632,7 +1358,9 @@@@ uvm_pagefree(struct vm_page *pg)

       mutex_spin_exit(&uvm_fpageqlock);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_page_unbusy: unbusy an array of pages.
 *
@@@@ -1676,6 +1404,7 @@@@ uvm_page_unbusy(struct vm_page **pgs, in
               }
       }
}
+#endif

#if defined(UVM_PAGE_TRKOWN)
/*
@@@@ -1831,6 +1560,7 @@@@ uvm_pageidlezero(void)
       mutex_spin_exit(&uvm_fpageqlock);
}

+#ifdef _KERNEL_OPT
/*
 * uvm_pagelookup: look up a page
 *
@@@@ -1852,7 +1582,9 @@@@ uvm_pagelookup(struct uvm_object *obj, v
               (pg->flags & PG_BUSY) != 0);
       return pg;
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_pagewire: wire the page, thus removing it from the daemon's grasp
 *
@@@@ -1875,7 +1607,9 @@@@ uvm_pagewire(struct vm_page *pg)
       }
       pg->wire_count++;
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_pageunwire: unwire the page.
 *
@@@@ -1893,7 +1627,9 @@@@ uvm_pageunwire(struct vm_page *pg)
               uvmexp.wired--;
       }
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_pagedeactivate: deactivate page
 *
@@@@ -1912,7 +1648,9 @@@@ uvm_pagedeactivate(struct vm_page *pg)
       KASSERT(pg->wire_count != 0 || uvmpdpol_pageisqueued_p(pg));
       uvmpdpol_pagedeactivate(pg);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_pageactivate: activate page
 *
@@@@ -1936,7 +1674,9 @@@@ uvm_pageactivate(struct vm_page *pg)
       }
       uvmpdpol_pageactivate(pg);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_pagedequeue: remove a page from any paging queue
 */
@@@@ -1951,7 +1691,9 @@@@ uvm_pagedequeue(struct vm_page *pg)

       uvmpdpol_pagedequeue(pg);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_pageenqueue: add a page to a paging queue without activating.
 * used where a page is not really demanded (yet).  eg. read-ahead
@@@@ -1967,7 +1709,9 @@@@ uvm_pageenqueue(struct vm_page *pg)
       }
       uvmpdpol_pageenqueue(pg);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_pagezero: zero fill a page
 *
@@@@ -1981,6 +1725,7 @@@@ uvm_pagezero(struct vm_page *pg)
       pg->flags &= ~PG_CLEAN;
       pmap_zero_page(VM_PAGE_TO_PHYS(pg));
}
+#endif

/*
 * uvm_pagecopy: copy a page
@@@@ -2005,7 +1750,7 @@@@ bool
d595 1
a595 1
@@@@ -2015,13 +1760,14 @@@@ uvm_pageismanaged(paddr_t pa)
a609 1
+#ifdef _KERNEL_OPT
d611 1
a611 11
 * uvm_page_locked_p: return true if object associated with page is
 * locked.  this is a weak check for runtime assertions only.
@@@@ -2039,6 +1785,7 @@@@ uvm_page_locked_p(struct vm_page *pg)
       }
       return true;
}
+#endif

#if defined(DDB) || defined(DEBUGPRINT)

@@@@ -2135,7 +1882,8 @@@@ uvm_page_printit(struct vm_page *pg, boo
d621 1
a621 1
@@@@ -2143,8 +1891,14 @@@@ uvm_page_printall(void (*pr)(const char
d642 1
a642 1
diff -u -p -r1.80 uvm_page.h
d644 1
a644 1
+++ sys/uvm/uvm_page.h  17 Nov 2016 15:39:06 -0000
a706 270
Index: sys/uvm/uvm_pager.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_pager.c,v
retrieving revision 1.110
diff -u -p -r1.110 uvm_pager.c
--- sys/uvm/uvm_pager.c 1 Mar 2014 18:32:01 -0000       1.110
+++ sys/uvm/uvm_pager.c 17 Nov 2016 15:39:06 -0000
@@@@ -34,9 +34,11 @@@@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_pager.c,v 1.110 2014/03/01 18:32:01 christos Exp $");

+#ifdef _KERNEL_OPT
#include "opt_uvmhist.h"
#include "opt_readahead.h"
#include "opt_pagermap.h"
+#endif

#include <sys/param.h>
#include <sys/systm.h>
@@@@ -159,6 +161,7 @@@@ uvm_pager_init(void)
       }
}

+#ifdef _KERNEL_OPT
/*
 * uvm_pagermapin: map pages into KVA (pager_map) for I/O that needs mappings
 *
@@@@ -238,7 +241,9 @@@@ enter:
       UVMHIST_LOG(maphist, "<- done (KVA=0x%x)", kva,0,0,0);
       return(kva);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_pagermapout: remove pager_map mapping
 *
@@@@ -284,6 +289,7 @@@@ uvm_pagermapout(vaddr_t kva, int npages)
               uvm_unmap_detach(entries, 0);
       UVMHIST_LOG(maphist,"<- done",0,0,0,0);
}
+#endif

/*
 * interrupt-context iodone handler for single-buf i/os
@@@@ -306,12 +312,16 @@@@ uvm_aio_aiodone_pages(struct vm_page **p
       struct vm_page *pg;
       kmutex_t *slock;
       int pageout_done;       /* number of PG_PAGEOUT pages processed */
+#ifdef _KERNEL_OPT
       int swslot;
+#endif
       int i;
       bool swap;
       UVMHIST_FUNC("uvm_aio_aiodone_pages"); UVMHIST_CALLED(ubchist);

+#ifdef _KERNEL_OPT
       swslot = 0;
+#endif
       pageout_done = 0;
       slock = NULL;
       uobj = NULL;
@@@@ -378,7 +388,9 @@@@ uvm_aio_aiodone_pages(struct vm_page **p
                */

               if (error) {
+#ifdef _KERNEL_OPT
                       int slot;
+#endif
                       if (!write) {
                               pg->flags |= PG_RELEASED;
                               continue;
@@@@ -389,9 +401,15 @@@@ uvm_aio_aiodone_pages(struct vm_page **p
                               }
                               pg->flags &= ~PG_CLEAN;
                               uvm_pageactivate(pg);
+#ifdef _KERNEL_OPT
                               slot = 0;
-                       } else
+#endif
+                       }
+#ifdef _KERNEL_OPT
+                       else
                               slot = SWSLOT_BAD;
+#endif
+

#if defined(VMSWAP)
                       if (swap) {
@@@@ -518,6 +536,7 @@@@ uvm_aio_aiodone(struct buf *bp)
       putiobuf(bp);
}

+#ifdef _KERNEL_OPT
/*
 * uvm_pageratop: convert KVAs in the pager map back to their page
 * structures.
@@@@ -536,3 +555,4 @@@@ uvm_pageratop(vaddr_t kva)
       KASSERT(pg != NULL);
       return (pg);
}
+#endif
Index: sys/uvm/uvm_pdaemon.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_pdaemon.c,v
retrieving revision 1.108
diff -u -p -r1.108 uvm_pdaemon.c
--- sys/uvm/uvm_pdaemon.c       25 Oct 2013 20:28:33 -0000      1.108
+++ sys/uvm/uvm_pdaemon.c       17 Nov 2016 15:39:07 -0000
@@@@ -68,8 +68,10 @@@@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uvm_pdaemon.c,v 1.108 2013/10/25 20:28:33 martin Exp $");

+#ifdef _KERNEL_OPT
#include "opt_uvmhist.h"
#include "opt_readahead.h"
+#endif

#include <sys/param.h>
#include <sys/proc.h>
@@@@ -98,6 +100,7 @@@@ UVMHIST_DEFINE(pdhist);

#define        UVMPD_NUMTRYLOCKOWNER   16

+#ifdef _KERNEL_OPT
/*
 * local prototypes
 */
@@@@ -105,14 +108,18 @@@@ UVMHIST_DEFINE(pdhist);
static void    uvmpd_scan(void);
static void    uvmpd_scan_queue(void);
static void    uvmpd_tune(void);
+#endif

+#ifdef _KERNEL_OPT
static unsigned int uvm_pagedaemon_waiters;
+#endif

/*
 * XXX hack to avoid hangs when large processes fork.
 */
u_int uvm_extrapages;

+#ifdef _KERNEL_OPT
/*
 * uvm_wait: wait (sleep) for the page daemon to free some pages
 *
@@@@ -161,7 +168,9 @@@@ uvm_wait(const char *wmsg)
       wakeup(&uvm.pagedaemon);                /* wake the daemon! */
       UVM_UNLOCK_AND_WAIT(&uvmexp.free, &uvm_fpageqlock, false, wmsg, timo);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_kick_pdaemon: perform checks to determine if we need to
 * give the pagedaemon a nudge, and do so if necessary.
@@@@ -182,7 +191,9 @@@@ uvm_kick_pdaemon(void)
               wakeup(&uvm.pagedaemon);
       }
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvmpd_tune: tune paging parameters
 *
@@@@ -221,7 +232,9 @@@@ uvmpd_tune(void)
       UVMHIST_LOG(pdhist, "<- done, freemin=%d, freetarg=%d, wiredmax=%d",
             uvmexp.freemin, uvmexp.freetarg, uvmexp.wiredmax, 0);
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvm_pageout: the main loop for the pagedaemon
 */
@@@@ -345,6 +358,7 @@@@ uvm_pageout(void *arg)
       /*NOTREACHED*/
}

+#endif

/*
 * uvm_aiodone_worker: a workqueue callback for the aiodone daemon.
@@@@ -364,6 +378,7 @@@@ uvm_aiodone_worker(struct work *wk, void
       (*bp->b_iodone)(bp);
}

+#ifdef _KERNEL_OPT
void
uvm_pageout_start(int npages)
{
@@@@ -372,7 +387,9 @@@@ uvm_pageout_start(int npages)
       uvmexp.paging += npages;
       mutex_spin_exit(&uvm_fpageqlock);
}
+#endif

+#ifdef _KERNEL_OPT
void
uvm_pageout_done(int npages)
{
@@@@ -393,6 +410,7 @@@@ uvm_pageout_done(int npages)
       }
       mutex_spin_exit(&uvm_fpageqlock);
}
+#endif

/*
 * uvmpd_trylockowner: trylock the page's owner.
@@@@ -640,6 +658,7 @@@@ uvmpd_trydropswap(struct vm_page *pg)

#endif /* defined(VMSWAP) */

+#ifdef _KERNEL_OPT
/*
 * uvmpd_scan_queue: scan an replace candidate list for pages
 * to clean or free.
@@@@ -915,7 +934,9 @@@@ uvmpd_scan_queue(void)
       mutex_enter(&uvm_pageqlock);
#endif /* defined(VMSWAP) */
}
+#endif

+#ifdef _KERNEL_OPT
/*
 * uvmpd_scan: scan the page queues and attempt to meet our targets.
 *
@@@@ -967,6 +988,7 @@@@ uvmpd_scan(void)
               module_thread_kick();
       }
}
+#endif

/*
 * uvm_reclaimable: decide whether to wait for pagedaemon.
@@@@ -1015,6 +1037,7 @@@@ uvm_reclaimable(void)
       return false;
}

+#ifdef _KERNEL_OPT
void
uvm_estimatepageable(int *active, int *inactive)
{
@@@@ -1022,3 +1045,4 @@@@ uvm_estimatepageable(int *active, int *i
       uvmpdpol_estimatepageable(active, inactive);
}

+#endif
Index: sys/uvm/uvm_pdpolicy_clock.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_pdpolicy_clock.c,v
retrieving revision 1.17
diff -u -p -r1.17 uvm_pdpolicy_clock.c
--- sys/uvm/uvm_pdpolicy_clock.c        30 Jan 2012 17:21:52 -0000      1.17
+++ sys/uvm/uvm_pdpolicy_clock.c        17 Nov 2016 15:39:07 -0000
@@@@ -348,10 +348,12 @@@@ uvmpdpol_pageenqueue(struct vm_page *pg)
       uvmpdpol_pageactivate(pg);
}

+#ifdef _KERNEL_OPT
void
uvmpdpol_anfree(struct vm_anon *an)
{
}
+#endif

bool
uvmpdpol_pageisqueued_p(struct vm_page *pg)
d711 1
a711 1
diff -u -p -r1.67 uvm_pglist.c
d713 1
a713 1
+++ sys/uvm/uvm_pglist.c        17 Nov 2016 15:39:07 -0000
d1039 2
a1040 2
+++ sys/uvm/uvm_physmem.c       17 Nov 2016 15:39:08 -0000
@@@@ -0,0 +1,1331 @@@@
d1129 1
a1129 1
+struct vm_physseg {
d1147 1
a1147 1
+#define        HANDLE_TO_PHYSMEM_NODE(h)       ((struct vm_physseg *)(h))
d1151 1
a1151 1
+struct vm_physmem {
d1156 1
a1156 1
+static struct vm_physmem vm_physmem;
d1185 1
a1185 1
+static struct vm_physseg uvm_physseg[VM_PHYSSEG_MAX];
d1197 1
a1197 1
+               if (sz % sizeof(struct vm_physseg))
d1199 1
a1199 1
+                           "of struct vm_physseg at boot\n", __func__);
d1201 1
a1201 1
+               size_t n = sz / sizeof(struct vm_physseg);
d1231 2
a1232 2
+               if (sz % sizeof(struct vm_physseg))
+                       panic("%s: tried to free size other than struct vm_physseg"
d1242 4
a1245 4
+       if ((struct vm_physseg *)p >= uvm_physseg &&
+           (struct vm_physseg *)p < (uvm_physseg + VM_PHYSSEG_MAX)) {
+               if (sz % sizeof(struct vm_physseg))
+                       panic("%s: tried to free() other than struct vm_physseg"
d1248 1
a1248 1
+               if ((sz / sizeof(struct vm_physseg)) >= VM_PHYSSEG_MAX)
d1262 1
a1262 1
+       struct vm_physseg *ps, *current_ps = NULL;
d1280 1
a1280 1
+       ps = uvm_physmem_alloc(sizeof (struct vm_physseg));
d1310 1
a1310 1
+       RB_TREE_FOREACH(current_ps, &(vm_physmem.rb_tree)) {
d1338 1
a1338 1
+                               uvm_physmem_free(ps, sizeof(struct vm_physseg));
d1363 1
a1363 1
+        * now insert us in the proper place in vm_physmem.rb_tree
d1366 1
a1366 1
+       current_ps = rb_tree_insert_node(&(vm_physmem.rb_tree), ps);
d1370 1
a1370 1
+       vm_physmem.nentries++;
d1397 2
a1398 2
+       const struct vm_physseg *enode1 = nnode1;
+       const struct vm_physseg *enode2 = nnode2;
d1413 1
a1413 1
+       const struct vm_physseg *enode = nnode;
d1416 1
a1416 1
+       if((enode->start <= pa) && (pa < enode->end))
d1429 1
a1429 1
+       .rbto_node_offset = offsetof(struct vm_physseg, rb_node),
d1441 2
a1442 2
+       rb_tree_init(&(vm_physmem.rb_tree), &uvm_physmem_tree_ops);
+       vm_physmem.nentries = 0;
d1448 1
a1448 1
+       return (uvm_physmem_t) rb_tree_iterate(&(vm_physmem.rb_tree), upm,
d1455 1
a1455 1
+       return (uvm_physmem_t) rb_tree_iterate(&(vm_physmem.rb_tree), upm,
d1462 1
a1462 1
+       return (uvm_physmem_t) RB_TREE_MAX(&(vm_physmem.rb_tree));
d1468 1
a1468 1
+       return (uvm_physmem_t) RB_TREE_MIN(&(vm_physmem.rb_tree));
d1474 2
a1475 2
+       struct vm_physseg *ps =
+           (uvm_physmem_t) RB_TREE_MAX(&(vm_physmem.rb_tree));
d1487 1
a1487 1
+       struct vm_physseg *seg;
d1529 1
a1529 1
+       struct vm_physseg *seg;
d1552 1
a1552 1
+       struct vm_physseg * ps = NULL;
d1554 1
a1554 1
+       ps = rb_tree_find_node(&(vm_physmem.rb_tree), &pframe);
d1566 1
a1566 1
+       struct vm_physseg *ps = HANDLE_TO_PHYSMEM_NODE(upm);
d1568 4
d1577 6
a1582 1
+       struct vm_physseg *ps = HANDLE_TO_PHYSMEM_NODE(upm);
d1605 1
a1605 1
+#define                PHYSMEM_NODE_TO_HANDLE(u)       ((int)((vsize_t) (u - vm_physmem) / sizeof(struct vm_physseg)))
d1607 1
a1607 1
+static struct vm_physseg vm_physmem[VM_PHYSSEG_MAX];   /* XXXCDC: uvm.physmem */
d1646 1
a1646 1
+       struct vm_physseg *ps;
d1665 1
a1665 1
+       struct vm_physseg *seg;
d1717 1
a1717 1
+       struct vm_physseg *seg;
d1749 1
a1749 1
+       struct vm_physseg *ps;
d1756 1
a1756 3
+       ps = HANDLE_TO_PHYSMEM_NODE(upm);
+
+       if (ps != NULL) /* XXX; do we allow "update" plugs ? */
a1767 1
+
d1862 1
a1862 1
+static inline int vm_physseg_find_contig(struct vm_physseg *, int, paddr_t, psize_t *);
d1864 1
a1864 1
+static inline int vm_physseg_find_bsearch(struct vm_physseg *, int, paddr_t, psize_t *);
d1866 1
a1866 1
+static inline int vm_physseg_find_linear(struct vm_physseg *, int, paddr_t, psize_t *);
d1887 1
a1887 1
+vm_physseg_find_contig(struct vm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
d1902 1
a1902 1
+vm_physseg_find_bsearch(struct vm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
d1946 1
a1946 1
+vm_physseg_find_linear(struct vm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
d1967 1
a1967 1
+       struct vm_physseg *ps;
d2077 1
a2077 1
+       struct vm_physseg *seg;
d2109 1
a2109 1
+       struct vm_physseg *seg = HANDLE_TO_PHYSMEM_NODE(upm);
d2129 1
a2129 1
+       struct vm_physseg *seg;
d2177 1
a2177 1
+       struct vm_physseg *ps;
d2208 1
a2208 1
+       struct vm_physseg *seg;
d2241 1
a2241 1
+               struct vm_physseg *current_ps;
d2243 1
a2243 1
+               if (vm_physmem.nentries == 1)
d2247 1
a2247 1
+                       RB_TREE_FOREACH(current_ps, &(vm_physmem.rb_tree)) {
d2264 4
a2267 4
+               rb_tree_remove_node(&(vm_physmem.rb_tree), upm);
+               memset(seg, 0, sizeof(struct vm_physseg));
+               uvm_physmem_free(seg, sizeof(struct vm_physseg));
+               vm_physmem.nentries--;
d2285 2
a2286 2
+               struct vm_physseg *ps, *current_ps;
+               ps = uvm_physmem_alloc(sizeof (struct vm_physseg));
d2323 1
a2323 1
+               current_ps = rb_tree_insert_node(&(vm_physmem.rb_tree), ps);
d2327 1
a2327 1
+               vm_physmem.nentries++;
d2383 1
a2383 1
+++ sys/uvm/uvm_physmem.h       17 Nov 2016 15:39:08 -0000
d2422 1
a2422 1
+typedef struct vm_physseg * uvm_physmem_t;
d2513 1
a2513 1
diff -u -p -r1.22 pmap.c
d2515 2
a2516 14
+++ sys/uvm/pmap/pmap.c 17 Nov 2016 15:39:09 -0000
@@@@ -95,9 +95,11 @@@@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.2
 *     and to when physical maps must be made correct.
 */

+#ifdef _KERNEL_OPT
#include "opt_modular.h"
#include "opt_multiprocessor.h"
#include "opt_sysv.h"
+#endif

#define __PMAP_PRIVATE

@@@@ -112,6 +114,7 @@@@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.2
d2524 1
a2524 1
@@@@ -452,37 +455,39 @@@@ pmap_steal_memory(vsize_t size, vaddr_t
d2577 1
a2577 1
@@@@ -490,44 +495,24 @@@@ pmap_steal_memory(vsize_t size, vaddr_t
d2605 1
a2605 3
+               pa = ptoa(uvm_physmem_get_start(bank));
+               uvm_physmem_unplug(atop(pa), npgs);

d2612 3
a2614 1
-
@


1.5
log
@hotplug with balloon(4) implementation.
Includes skrll@@ patches.
@
text
@d7 1
a7 1
+++ sys/uvm/Makefile    13 Nov 2016 10:38:26 -0000
d23 10
a32 2
+++ sys/uvm/files.uvm   13 Nov 2016 10:38:26 -0000
@@@@ -41,6 +41,7 @@@@ file      uvm/uvm_pdaemon.c               uvm
d46 1
a46 1
+++ sys/uvm/uvm.h       13 Nov 2016 10:38:32 -0000
d61 1
a61 1
+++ sys/uvm/uvm_amap.c  13 Nov 2016 10:39:03 -0000
d87 1
a87 1
+++ sys/uvm/uvm_anon.c  13 Nov 2016 10:39:05 -0000
d113 1
a113 1
+++ sys/uvm/uvm_bio.c   13 Nov 2016 10:39:09 -0000
d144 1
a144 1
+++ sys/uvm/uvm_device.c        13 Nov 2016 10:39:10 -0000
d177 1
a177 1
+++ sys/uvm/uvm_extern.h        13 Nov 2016 10:39:13 -0000
d194 1
a194 1
+++ sys/uvm/uvm_fault.c 13 Nov 2016 10:39:25 -0000
d231 1
a231 1
+++ sys/uvm/uvm_init.c  13 Nov 2016 10:39:25 -0000
d251 1
a251 1
+++ sys/uvm/uvm_km.c    13 Nov 2016 10:39:29 -0000
d358 1
a358 1
+++ sys/uvm/uvm_loan.c  13 Nov 2016 10:39:37 -0000
d460 1
a460 1
+++ sys/uvm/uvm_map.c   13 Nov 2016 10:39:52 -0000
d565 1
a565 1
+++ sys/uvm/uvm_page.c  13 Nov 2016 10:40:03 -0000
d1335 1
a1335 1
+++ sys/uvm/uvm_page.h  13 Nov 2016 10:40:13 -0000
d1404 1
a1404 1
+++ sys/uvm/uvm_pager.c 13 Nov 2016 10:40:13 -0000
d1506 1
a1506 1
+++ sys/uvm/uvm_pdaemon.c       13 Nov 2016 10:40:20 -0000
d1654 1
a1654 1
+++ sys/uvm/uvm_pdpolicy_clock.c        13 Nov 2016 10:40:20 -0000
d1674 1
a1674 1
+++ sys/uvm/uvm_pglist.c        13 Nov 2016 10:40:29 -0000
d2000 2
a2001 2
+++ sys/uvm/uvm_physmem.c       13 Nov 2016 10:40:29 -0000
@@@@ -0,0 +1,924 @@@@
a2086 3
+#define        HANDLE_TO_PHYSMEM_NODE(h)       ((struct vm_physseg *)(h))
+#define                PHYSMEM_NODE_TO_HANDLE(u)       ((uvm_physmem_t)(u))
+
d2106 6
a2354 155
+bool
+uvm_physmem_unplug(paddr_t pfn, size_t pages)
+{
+       int segcount = 0;
+       uvm_physmem_t upm;
+       paddr_t off = 0, start, end;
+       struct vm_physseg *seg, *current_ps;
+
+       upm = vm_physseg_find(pfn, &off);
+
+       if (!uvm_physmem_valid(upm)) {
+               printf("%s: Tried to unplug from unknown offset\n", __func__);
+               return false;
+       }
+
+       seg = HANDLE_TO_PHYSMEM_NODE(upm);
+
+       start = uvm_physmem_get_start(upm);
+       end = uvm_physmem_get_end(upm);
+
+       if (end < (pfn + pages)) {
+               printf("%s: Tried to unplug oversized span \n", __func__);
+               return false;
+       }
+
+       KASSERT(pfn == start + off); /* sanity */
+
+       if (__predict_true(uvm.page_init_done == true)) {
+               /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
+               if (extent_free(seg->ext, (u_long)seg->pgs + off, pages, EX_NOWAIT) != 0)
+                       return false;
+       }
+
+       if (off == 0 && (pfn + pages) == end) {
+               /* Complete segment */
+               if (vm_physmem.nentries == 1)
+                       panic("%s: out of memory!", __func__);
+
+               if (__predict_true(uvm.page_init_done == true)) {
+                       RB_TREE_FOREACH(current_ps, &(vm_physmem.rb_tree)) {
+                               if (seg->ext == current_ps->ext)
+                                       segcount++;
+                       }
+                       KASSERT(segcount > 0);
+
+                       if (segcount == 1) {
+                               extent_destroy(seg->ext);
+                       }
+
+                       /*
+                        * We assume that the unplug will succeed from
+                        *  this point onwards
+                        */
+                       uvmexp.npages -= (int) pages;
+               }
+
+               rb_tree_remove_node(&(vm_physmem.rb_tree), upm);
+               uvm_physmem_free(seg, sizeof(struct vm_physseg));
+               vm_physmem.nentries--;
+
+               /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
+               return true;
+       }
+
+       if (off > 0 &&
+           (pfn + pages) < end) {
+               /* middle chunk - need a new segment */
+               struct vm_physseg *ps;
+               ps = uvm_physmem_alloc(sizeof (struct vm_physseg));
+               if (ps == NULL) {
+                       printf("%s: Unable to allocated new fragment vm_physseg \n",
+                           __func__);
+                       return false;
+               }
+
+               /* Remove middle chunk */
+               if (__predict_true(uvm.page_init_done == true)) {
+                       KASSERT(seg->ext != NULL);
+                       ps->ext = seg->ext;
+
+                       /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
+                       /*
+                        * We assume that the unplug will succeed from
+                        *  this point onwards
+                        */
+                       uvmexp.npages -= (int) pages;
+               }
+
+               ps->start = pfn + pages;
+               ps->avail_start = ps->start; /* XXX: Legacy */
+
+               ps->end = seg->end;
+               ps->avail_end = ps->end; /* XXX: Legacy */
+
+               seg->end = pfn;
+               seg->avail_end = seg->end; /* XXX: Legacy */
+
+
+               /*
+                * The new pgs array points to the beginning of the
+                * tail fragment.
+                */
+               ps->pgs = seg->pgs + off + pages;
+
+               current_ps = rb_tree_insert_node(&(vm_physmem.rb_tree), ps);
+               if (current_ps != ps) {
+                       panic("uvm_page_physload: Duplicate address range detected!");
+               }
+               vm_physmem.nentries++;
+
+               return true;
+       }
+
+       if (off == 0 && (pfn + pages) < end) {
+               /* Remove front chunk */
+               if (__predict_true(uvm.page_init_done == true)) {
+                       /* XXX: KASSERT() that seg->pgs[] are not on any uvm lists */
+                       /*
+                        * We assume that the unplug will succeed from
+                        *  this point onwards
+                        */
+                       uvmexp.npages -= (int) pages;
+               }
+
+               /* Truncate */
+               seg->start = pfn + pages;
+               seg->avail_start = seg->start; /* XXX: Legacy */
+
+               /*
+                * Move the pgs array start to the beginning of the
+                * tail end.
+                */
+               seg->pgs += pages;
+
+               return true;
+       }
+
+       if (off > 0 && (pfn + pages) == end) {
+               /* back chunk */
+
+
+               /* Truncate! */
+               seg->end = pfn;
+               seg->avail_end = seg->end; /* XXX: Legacy */
+
+               uvmexp.npages -= (int) pages;
+
+               return true;
+       }
+
+       printf("%s: Tried to unplug unknown range \n", __func__);
+
+       return false;
+}
+
d2406 16
a2421 2
+void
+uvm_physmem_seg_chomp_slab(struct vm_physseg *seg, struct vm_page *pgs, size_t n)
d2423 2
a2424 3
+       /* One per segment at boot */
+#define UVM_PHYSMEM_BOOT_UNPLUG_MAX 32 /* max number of pre-boot unplug()s allowed */
+       static struct extent_region erboot[UVM_PHYSMEM_BOOT_UNPLUG_MAX];
d2426 5
a2430 5
+       if (__predict_false(uvm.page_init_done == false)) {
+               seg->ext = extent_create("Boot time slab", (u_long) pgs, (u_long) (pgs + n), erboot, sizeof(erboot), EX_MALLOCOK);
+       } else {
+               seg->ext = extent_create("Hotplug slab", (u_long) pgs, (u_long) (pgs + n), NULL, 0, EX_MALLOCOK);
+       }
d2432 5
a2436 1
+       KASSERT(seg->ext != NULL);
d2438 1
d2441 6
a2446 2
+struct vm_page *
+uvm_physmem_seg_slab_alloc(uvm_physmem_t upm, size_t pages)
a2447 1
+       int err;
a2448 1
+       struct vm_page *pgs = NULL;
d2452 17
a2468 1
+       KASSERT(pages > 0);
d2470 5
a2474 13
+       if (__predict_false(seg->ext == NULL)) {
+               /*
+                * This is a situation unique to boot time.
+                * It shouldn't happen at any point other than from
+                * the first uvm_page.c:uvm_page_init() call
+                * Since we're in a loop, we can get away with the
+                * below.
+                */
+               KASSERT(uvm.page_init_done != true);
+
+               seg->ext = HANDLE_TO_PHYSMEM_NODE(uvm_physmem_get_prev(PHYSMEM_NODE_TO_HANDLE(seg)))->ext;
+
+               KASSERT(seg->ext != NULL);
d2477 5
a2481 8
+       /* We allocate enough for this segment */
+       err = extent_alloc(seg->ext, sizeof(*pgs) * pages, 1, 0, EX_BOUNDZERO, (u_long *)&pgs);
+
+       if (err != 0) {
+#ifdef DEBUG
+               printf("%s: extent_alloc failed with error: %d \n",
+                   __func__, err);
+#endif
d2484 1
a2484 1
+       return pgs;
d2487 76
d2564 103
a2666 1
+uvm_physmem_init_seg(uvm_physmem_t upm, struct vm_page *pgs)
d2668 1
a2668 3
+       psize_t i;
+       psize_t n;
+       paddr_t paddr;
d2671 81
a2751 1
+       KASSERT(upm != NULL && pgs != NULL);
d2753 70
a2822 1
+       seg = HANDLE_TO_PHYSMEM_NODE(upm);
d2824 6
a2829 2
+       n = seg->end - seg->start;
+       seg->pgs = pgs;
d2831 6
a2836 6
+       /* init and free vm_pages (we've already zeroed them) */
+       paddr = ctob(seg->start);
+       for (i = 0 ; i < n ; i++, paddr += PAGE_SIZE) {
+               seg->pgs[i].phys_addr = paddr;
+#ifdef __HAVE_VM_PAGE_MD
+               VM_MDPAGE_INIT(&seg->pgs[i]);
d2838 74
a2911 7
+               if (atop(paddr) >= seg->avail_start &&
+                   atop(paddr) < seg->avail_end) {
+                       uvmexp.npages++;
+                       mutex_enter(&uvm_pageqlock);
+                       /* add page to free pool */
+                       uvm_pagefree(&seg->pgs[i]);
+                       mutex_exit(&uvm_pageqlock);
d2914 32
d3026 2
a3027 2
+uvm_physmem_t
+uvm_physmem_get_next(uvm_physmem_t upm)
d3029 4
a3032 3
+       return (uvm_physmem_t) rb_tree_iterate(&(vm_physmem.rb_tree), upm,
+           RB_DIR_RIGHT);
+}
d3034 1
a3034 6
+uvm_physmem_t
+uvm_physmem_get_prev(uvm_physmem_t upm)
+{
+       return (uvm_physmem_t) rb_tree_iterate(&(vm_physmem.rb_tree), upm,
+           RB_DIR_LEFT);
+}
d3036 6
a3041 5
+uvm_physmem_t
+uvm_physmem_get_last(void)
+{
+       return (uvm_physmem_t) RB_TREE_MAX(&(vm_physmem.rb_tree));
+}
d3043 16
a3058 4
+uvm_physmem_t
+uvm_physmem_get_first(void)
+{
+       return (uvm_physmem_t) RB_TREE_MIN(&(vm_physmem.rb_tree));
d3061 2
a3062 2
+bool
+uvm_physmem_valid(uvm_physmem_t upm)
d3064 5
a3068 49
+       struct vm_physseg *ps;
+
+       if (upm == NULL)
+               return false;
+
+       /*
+        * This is the delicate init dance -
+        * needs to go with the dance.
+        */
+       if (uvm.page_init_done != true)
+               return true;
+
+       ps = HANDLE_TO_PHYSMEM_NODE(upm);
+
+       /* Extra checks needed only post uvm_page_init() */
+       if (ps->pgs == NULL)
+               return false;
+
+       /* XXX: etc. */
+
+       return true;
+
+}
+
+
+paddr_t
+uvm_physmem_get_highest_frame(void)
+{
+       struct vm_physseg *ps =
+           (uvm_physmem_t) RB_TREE_MAX(&(vm_physmem.rb_tree));
+
+       return ps->end - 1;
+}
+
+/*
+ * uvm_page_physunload: unload physical memory and return it to
+ * caller.
+ */
+bool
+uvm_page_physunload(uvm_physmem_t upm, int freelist, paddr_t *paddrp)
+{
+       struct vm_physseg *seg;
+
+       seg = HANDLE_TO_PHYSMEM_NODE(upm);
+
+       if (seg->free_list != freelist) {
+               paddrp = NULL;
+               return false;
+       }
d3070 4
a3073 18
+       /*
+        * During cold boot, what we're about to unplug hasn't been
+        * put on the uvm freelist, nor has uvmexp.npages been
+        * updated. (This happens in uvm_page.c:uvm_page_init())
+        *
+        * For hotplug, we assume here that the pages being unloaded
+        * here are completely out of sight of uvm (ie; not on any uvm
+        * lists), and that  uvmexp.npages has been suitably
+        * decremented before we're called.
+        *
+        * XXX: will avail_end == start if avail_start < avail_end?
+        */
+
+       /* try from front */
+       if (seg->avail_start == seg->start &&
+           seg->avail_start < seg->avail_end) {
+               *paddrp = ctob(seg->avail_start);
+               return uvm_physmem_unplug(seg->avail_start, 1);
d3076 1
a3076 6
+       /* try from rear */
+       if (seg->avail_end == seg->end &&
+           seg->avail_start < seg->avail_end) {
+               *paddrp = ctob(seg->avail_end - 1);
+               return uvm_physmem_unplug(seg->avail_end - 1, 1);
+       }
a3077 1
+       return false;
d3080 2
a3081 2
+bool
+uvm_page_physunload_force(uvm_physmem_t upm, int freelist, paddr_t *paddrp)
d3083 1
d3085 1
d3089 25
a3113 4
+       /* any room in this bank? */
+       if (seg->avail_start >= seg->avail_end) {
+               paddrp = NULL;
+               return false; /* nope */
d3116 1
a3116 4
+       *paddrp = ctob(seg->avail_start);
+
+       /* Always unplug from front */
+       return uvm_physmem_unplug(seg->avail_start, 1);
a3118 1
+
d3133 2
a3134 1
+
d3142 1
a3142 1
+       if (uvm_physmem_plug(start, end - start, &ps) == false) {
d3146 2
d3155 1
a3155 1
+       return ps;
d3158 111
a3269 7
+/*
+ * vm_physseg_find: find vm_physseg structure that belongs to a PA
+ */
+uvm_physmem_t
+vm_physseg_find(paddr_t pframe, psize_t *offp)
+{
+       struct vm_physseg * ps = NULL;
d3271 30
a3300 1
+       ps = rb_tree_find_node(&(vm_physmem.rb_tree), &pframe);
d3302 3
a3304 2
+       if(ps != NULL && offp != NULL)
+               *offp = pframe - ps->start;
d3306 9
a3314 2
+       return ps;
+}
d3316 2
a3317 5
+#if defined(PMAP_STEAL_MEMORY)
+void
+uvm_physmem_set_avail_start(uvm_physmem_t upm, paddr_t avail_start)
+{
+       struct vm_physseg *ps = HANDLE_TO_PHYSMEM_NODE(upm);
a3318 6
+       KASSERT(avail_start < avail_end && avail_start >= ps->start);
+       ps->avail_start = avail_start;
+}
+void uvm_physmem_set_avail_end(uvm_physmem_t upm, paddr_t avail_end)
+{
+       struct vm_physseg *ps = HANDLE_TO_PHYSMEM_NODE(upm);
d3320 3
a3322 1
+       KASSERT(avail_end > avail_start && avail_end <= ps->end);
d3324 8
a3331 1
+       ps->avail_end = avail_end;
a3332 2
+
+#endif /* PMAP_STEAL_MEMORY */
d3338 2
a3339 2
+++ sys/uvm/uvm_physmem.h       13 Nov 2016 10:40:41 -0000
@@@@ -0,0 +1,99 @@@@
d3350 4
d3362 1
d3379 19
d3399 1
a3401 1
+void uvm_physmem_init_seg(uvm_physmem_t, struct vm_page *);
d3463 1
d3470 1
a3470 1
+++ sys/uvm/pmap/pmap.c 13 Nov 2016 10:40:55 -0000
@


1.4
log
@Move to the rbtree implementation. tests + MD stuff
'
@
text
@d7 1
a7 1
+++ sys/uvm/Makefile    30 Oct 2016 16:48:42 -0000
d23 1
a23 1
+++ sys/uvm/files.uvm   30 Oct 2016 16:48:42 -0000
d38 1
a38 1
+++ sys/uvm/uvm.h       30 Oct 2016 16:48:42 -0000
d53 1
a53 1
+++ sys/uvm/uvm_amap.c  30 Oct 2016 16:48:43 -0000
d79 1
a79 1
+++ sys/uvm/uvm_anon.c  30 Oct 2016 16:48:43 -0000
d105 1
a105 1
+++ sys/uvm/uvm_bio.c   30 Oct 2016 16:48:44 -0000
d136 1
a136 1
+++ sys/uvm/uvm_device.c        30 Oct 2016 16:48:44 -0000
d169 1
a169 1
+++ sys/uvm/uvm_extern.h        30 Oct 2016 16:48:44 -0000
d186 1
a186 1
+++ sys/uvm/uvm_fault.c 30 Oct 2016 16:48:44 -0000
d223 1
a223 1
+++ sys/uvm/uvm_init.c  30 Oct 2016 16:48:44 -0000
d243 1
a243 1
+++ sys/uvm/uvm_km.c    30 Oct 2016 16:48:45 -0000
d350 1
a350 1
+++ sys/uvm/uvm_loan.c  30 Oct 2016 16:48:46 -0000
d452 1
a452 1
+++ sys/uvm/uvm_map.c   30 Oct 2016 16:48:57 -0000
d557 1
a557 1
+++ sys/uvm/uvm_page.c  30 Oct 2016 16:48:59 -0000
d571 8
a578 1
@@@@ -87,18 +89,6 @@@@ __KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v
d597 1
a597 1
@@@@ -116,7 +106,7 @@@@ int vm_page_reserve_kernel = UVM_RESERVE
d606 1
a606 1
@@@@ -152,6 +142,7 @@@@ vaddr_t uvm_zerocheckkva;
d614 1
a614 1
@@@@ -170,7 +161,9 @@@@ uvm_page_compare_nodes(void *ctx, const
d624 1
a624 1
@@@@ -184,13 +177,16 @@@@ uvm_page_compare_key(void *ctx, const vo
d641 1
a641 1
@@@@ -337,11 +333,9 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d654 1
a654 1
@@@@ -369,7 +363,7 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d663 1
a663 1
@@@@ -381,9 +375,11 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d678 1
a678 1
@@@@ -428,31 +424,16 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d682 1
a682 3
+       for (bank = uvm_physmem_get_first();
+            uvm_physmem_valid(bank);
+            bank = uvm_physmem_get_next(bank)) {
d687 6
d694 1
d696 1
a696 1

d720 1
a720 1
@@@@ -625,92 +606,42 @@@@ static bool uvm_page_physget_freelist(pa
d731 1
a731 1
+       for (lcv = uvm_physmem_get_last() ; lcv >= uvm_physmem_get_first() ; lcv = uvm_physmem_get_prev(lcv))
d734 1
a734 1
+               for (lcv = uvm_physmem_get_first() ; lcv <= uvm_physmem_get_last() ; lcv = uvm_physmem_get_next(lcv))
d744 1
a744 7
+               /* Try to match at front or back on unused segment */
+               if (uvm_page_physunload(lcv, freelist, paddrp) == false) {
+                       if (paddrp == NULL) /* freelist fail, try next */
+                               continue;
+               } else
+                       return true;

d762 7
a768 1
-
d791 1
a791 1
+       for (lcv = uvm_physmem_get_last() ; lcv >= uvm_physmem_get_first() ; lcv = uvm_physmem_get_prev(lcv))
d794 1
a794 1
+               for (lcv = uvm_physmem_get_first() ; lcv <= uvm_physmem_get_last() ; lcv = uvm_physmem_get_next(lcv))
d832 1
a832 1
@@@@ -726,228 +657,7 @@@@ uvm_page_physget(paddr_t *paddrp)
d1062 1
a1062 1
@@@@ -956,21 +666,24 @@@@ struct vm_page *
d1092 1
a1092 1
@@@@ -985,7 +698,8 @@@@ uvm_page_recolor(int newncolors)
d1102 1
a1102 1
@@@@ -1094,6 +808,7 @@@@ uvm_cpu_attach(struct cpu_info *ci)
d1110 1
a1110 1
@@@@ -1110,6 +825,7 @@@@ attachrnd:
d1118 1
a1118 1
@@@@ -1196,7 +912,9 @@@@ uvm_pagealloc_pgfl(struct uvm_cpu *ucpu,
d1128 1
a1128 1
@@@@ -1219,7 +937,8 @@@@ struct vm_page *
d1138 1
a1138 1
@@@@ -1389,6 +1108,7 @@@@ uvm_pagealloc_strat(struct uvm_object *o
d1146 1
a1146 1
@@@@ -1481,6 +1201,7 @@@@ uvm_pagezerocheck(struct vm_page *pg)
d1154 1
a1154 1
@@@@ -1632,7 +1353,9 @@@@ uvm_pagefree(struct vm_page *pg)
d1164 1
a1164 1
@@@@ -1676,6 +1399,7 @@@@ uvm_page_unbusy(struct vm_page **pgs, in
d1172 1
a1172 1
@@@@ -1831,6 +1555,7 @@@@ uvm_pageidlezero(void)
d1180 1
a1180 1
@@@@ -1852,7 +1577,9 @@@@ uvm_pagelookup(struct uvm_object *obj, v
d1190 1
a1190 1
@@@@ -1875,7 +1602,9 @@@@ uvm_pagewire(struct vm_page *pg)
d1200 1
a1200 1
@@@@ -1893,7 +1622,9 @@@@ uvm_pageunwire(struct vm_page *pg)
d1210 1
a1210 1
@@@@ -1912,7 +1643,9 @@@@ uvm_pagedeactivate(struct vm_page *pg)
d1220 1
a1220 1
@@@@ -1936,7 +1669,9 @@@@ uvm_pageactivate(struct vm_page *pg)
d1230 1
a1230 1
@@@@ -1951,7 +1686,9 @@@@ uvm_pagedequeue(struct vm_page *pg)
d1240 1
a1240 1
@@@@ -1967,7 +1704,9 @@@@ uvm_pageenqueue(struct vm_page *pg)
d1250 1
a1250 1
@@@@ -1981,6 +1720,7 @@@@ uvm_pagezero(struct vm_page *pg)
d1258 1
a1258 1
@@@@ -2005,7 +1745,7 @@@@ bool
d1267 1
a1267 1
@@@@ -2015,13 +1755,14 @@@@ uvm_pageismanaged(paddr_t pa)
d1286 1
a1286 1
@@@@ -2039,6 +1780,7 @@@@ uvm_page_locked_p(struct vm_page *pg)
d1294 1
a1294 1
@@@@ -2135,7 +1877,8 @@@@ uvm_page_printit(struct vm_page *pg, boo
d1304 1
a1304 1
@@@@ -2143,8 +1886,14 @@@@ uvm_page_printall(void (*pr)(const char
d1327 1
a1327 1
+++ sys/uvm/uvm_page.h  30 Oct 2016 16:48:59 -0000
d1396 1
a1396 1
+++ sys/uvm/uvm_pager.c 30 Oct 2016 16:48:59 -0000
d1498 1
a1498 1
+++ sys/uvm/uvm_pdaemon.c       30 Oct 2016 16:48:59 -0000
d1646 1
a1646 1
+++ sys/uvm/uvm_pdpolicy_clock.c        30 Oct 2016 16:48:59 -0000
d1666 1
a1666 1
+++ sys/uvm/uvm_pglist.c        30 Oct 2016 16:48:59 -0000
d1912 1
a1912 2
+                       paddr_t cidx = 0;
                       const int bank = vm_physseg_find(candidate, &cidx);
d1919 2
d1922 1
a1922 1
+                           "vm_physseg_find(%#x) (%d) != psi %"PRIxPHYSMEM,
d1992 2
a1993 2
+++ sys/uvm/uvm_physmem.c       30 Oct 2016 16:48:59 -0000
@@@@ -0,0 +1,645 @@@@
d2060 1
a2060 1
+ * rbtree backing implementation by:
d2070 1
d2075 1
d2080 1
d2092 1
a2092 1
+       struct  vm_page *lastpg;        /* vm_page structure for end */
d2109 13
d2159 1
a2159 1
+       return kmem_zalloc(sz, KM_SLEEP);
d2206 292
d2551 56
d2614 1
a2614 1
+       KASSERT(upm != NULL);
a2617 2
+       KASSERT(seg->pgs == NULL);
+
a2619 1
+       seg->lastpg = seg->pgs + n;
d2631 1
d2634 1
a2763 3
+       if (ps->lastpg == NULL)
+               return false;
+
d2772 1
a2772 1
+uvm_physmem_get_highest(void)
d2777 1
a2777 1
+       return ps->end;
d2797 9
a2805 1
+        * XXX: why is uvmexp.npages not updated?
d2813 1
a2813 11
+               seg->avail_start++;
+               seg->start++;
+               /* nothing left?   nuke it */
+               if (seg->avail_start == seg->end) {
+                       if (vm_physmem.nentries == 1)
+                               panic("uvm_page_physunload: out of memory!");
+                       rb_tree_remove_node(&(vm_physmem.rb_tree), upm);
+                       uvm_physmem_free(upm, sizeof(struct vm_physseg));
+                       vm_physmem.nentries--;
+               }
+               return (true);
d2820 1
a2820 11
+               seg->avail_end--;
+               seg->end--;
+               /* nothing left?   nuke it */
+               if (seg->avail_end == seg->start) {
+                       if (vm_physmem.nentries == 1)
+                               panic("uvm_page_physunload: out of memory!");
+                       rb_tree_remove_node(&(vm_physmem.rb_tree), upm);
+                       uvm_physmem_free(upm, sizeof(struct vm_physseg));
+                       vm_physmem.nentries--;
+               }
+               return (true);
d2840 3
a2842 13
+       seg->avail_start++;
+       /* truncate! */
+       seg->start = seg->avail_start;
+
+       /* nothing left?   nuke it */
+       if (seg->avail_start == seg->end) {
+               if (vm_physmem.nentries == 1)
+                       panic("uvm_page_physunload: out of memory!");
+               rb_tree_remove_node(&(vm_physmem.rb_tree), upm);
+               uvm_physmem_free(upm, sizeof(struct vm_physseg));
+               vm_physmem.nentries--;
+       }
+       return (true);
d2859 1
a2859 4
+       int preload;
+       psize_t npages;
+       struct vm_page *pgs;
+       struct vm_physseg *ps, *current_ps;
d2868 2
a2869 40
+       /*
+        * do we have room?
+        */
+
+       ps = uvm_physmem_alloc(sizeof (struct vm_physseg));
+       if (ps == NULL) {
+               printf("uvm_page_physload: unable to load physical memory "
+                   "segment\n");
+               printf("\t%d segments allocated, ignoring 0x%llx -> 0x%llx\n",
+                   VM_PHYSSEG_MAX, (long long)start, (long long)end);
+               printf("\tincrease VM_PHYSSEG_MAX\n");
+               return UVM_PHYSMEM_TYPE_INVALID_OVERFLOW;
+       }
+
+       /*
+        * check to see if this is a "preload" (i.e. uvm_page_init hasn't been
+        * called yet, so kmem is not available).
+        */
+
+       preload = 1; /* We are going to assume it is a preload */
+       RB_TREE_FOREACH(current_ps, &(vm_physmem.rb_tree)) {
+               /* If there are non NULL pages then we are not in a preload */
+               if (current_ps->pgs) {
+                       preload = 0;
+                       break;
+               }
+       }
+
+       current_ps = NULL;
+
+       /*
+        * if VM is already running, attempt to kmem_alloc vm_page structures
+        */
+
+       if (!preload) {
+               npages = end - start;
+               pgs = kmem_zalloc(sizeof *pgs * npages, KM_SLEEP);
+       } else {
+               pgs = NULL;
+               npages = 0;
d2872 1
a2872 3
+
+       ps->start = start;
+       ps->end = end;
d2876 1
a2876 33
+       ps->pgs = pgs;
+       ps->lastpg = pgs + npages;
+
+       ps->free_list = free_list;
+
+       /*
+        * now insert us in the proper place in vm_physmem.rb_tree
+        */
+
+       current_ps = rb_tree_insert_node(&(vm_physmem.rb_tree), ps);
+       if (current_ps != ps) {
+               panic("uvm_page_physload: Duplicate address range detected!");
+       }
+       vm_physmem.nentries++;
+
+       if (!preload) {
+               paddr_t i;
+               paddr_t paddr;
+
+               /* init and free vm_pages (we've already zeroed them) */
+               paddr = ctob(ps->start);
+               for (i = 0 ; i < npages ; i++, paddr += PAGE_SIZE) {
+                       ps->pgs[i].phys_addr = paddr;
+#ifdef __HAVE_VM_PAGE_MD
+                       VM_MDPAGE_INIT(&ps->pgs[i]);
+#endif
+                       if (atop(paddr) >= ps->avail_start &&
+                           atop(paddr) < ps->avail_end) {
+                               uvmexp.npages++;
+                               /* add page to free pool */
+                               uvm_pagefree(&ps->pgs[i]);
+                       }
+               }
a2877 4
+               physmem += npages;
+
+               uvmpdpol_reinit();
+       }
d2898 20
d2923 2
a2924 2
+++ sys/uvm/uvm_physmem.h       30 Oct 2016 16:48:59 -0000
@@@@ -0,0 +1,83 @@@@
d2943 1
a2943 1
+#define PRIxPHYSMEM "d"
d2960 3
d2964 2
a2965 1
+void uvm_physmem_init_seg(uvm_physmem_t, struct vm_page *);
d3000 1
a3000 1
+paddr_t uvm_physmem_get_highest(void);
d3011 12
d3030 1
a3030 1
+++ sys/uvm/pmap/pmap.c 30 Oct 2016 16:49:00 -0000
d3074 2
a3075 1
               aprint_debug("%s: seg %u: %#"PRIxPADDR" %#"PRIxPADDR" %#"PRIxPADDR" %#"PRIxPADDR"\n",
d3079 1
a3079 1
+                   uvm_physmem_get_avail_start(bank),uvm_physmem_get_start(bank),
d3084 1
d3087 1
a3087 1
                       aprint_debug("%s: seg %u: bad start\n", __func__, bank);
d3092 1
d3094 1
a3094 1
                       aprint_debug("%s: seg %u: too small for %zu pages\n",
d3104 1
a3104 1
@@@@ -490,44 +495,32 @@@@ pmap_steal_memory(vsize_t size, vaddr_t
d3113 1
a3113 1
+               if (uvm_physmem_valid(maybe_bank == false)
a3123 1
+               paddr_t stolenpa;
a3124 1
+               int freelist;
d3132 3
a3134 1
-
d3154 1
a3154 10
+               freelist = uvm_physmem_get_free_list(bank);
+               uvm_page_physunload_force(bank, freelist, &pa);
+               stolenpa = pa;
+
+               KASSERT(npgs > 0);
+               /* XXX: This loop assumes linear pa allocation */
+               while(pa + ptoa(npgs - 1) > stolenpa)
+                       uvm_page_physunload_force(bank, freelist, &stolenpa);
+
+               aprint_debug("%s: seg %u: %zu pages stolen (%#"PRIxPADDR" left)\n",
@


1.3
log
@Chop off unknown file listings in the diff.
@
text
@d7 1
a7 1
+++ sys/uvm/Makefile    28 Oct 2016 08:23:14 -0000
d23 1
a23 1
+++ sys/uvm/files.uvm   28 Oct 2016 08:23:14 -0000
d38 1
a38 1
+++ sys/uvm/uvm.h       28 Oct 2016 08:23:14 -0000
d53 1
a53 1
+++ sys/uvm/uvm_amap.c  28 Oct 2016 08:23:15 -0000
d79 1
a79 1
+++ sys/uvm/uvm_anon.c  28 Oct 2016 08:23:15 -0000
d105 1
a105 1
+++ sys/uvm/uvm_bio.c   28 Oct 2016 08:23:16 -0000
d136 1
a136 1
+++ sys/uvm/uvm_device.c        28 Oct 2016 08:23:16 -0000
d169 1
a169 1
+++ sys/uvm/uvm_extern.h        28 Oct 2016 08:23:16 -0000
d186 1
a186 1
+++ sys/uvm/uvm_fault.c 28 Oct 2016 08:23:18 -0000
d223 1
a223 1
+++ sys/uvm/uvm_init.c  28 Oct 2016 08:23:18 -0000
d243 1
a243 1
+++ sys/uvm/uvm_km.c    28 Oct 2016 08:23:18 -0000
d350 1
a350 1
+++ sys/uvm/uvm_loan.c  28 Oct 2016 08:23:19 -0000
d452 1
a452 1
+++ sys/uvm/uvm_map.c   28 Oct 2016 08:23:21 -0000
d557 1
a557 1
+++ sys/uvm/uvm_page.c  28 Oct 2016 08:23:22 -0000
d634 1
a634 1
@@@@ -337,11 +333,8 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d640 2
a641 1
-       int lcv;
a643 1
+       uvm_physmem_t lcv;
d647 1
a647 1
@@@@ -369,7 +362,7 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d652 1
a652 1
+       if (uvm_physmem_get_last() == -1)
d656 1
a656 1
@@@@ -381,9 +374,11 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d664 4
a667 4
+       for (lcv = uvm_physmem_get_first();
+            lcv <= uvm_physmem_get_last() ;
+            lcv = uvm_physmem_get_next(lcv)) {
+               freepages += (uvm_physmem_get_end(lcv) - uvm_physmem_get_start(lcv));
d671 1
a671 1
@@@@ -428,31 +423,16 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
d675 3
a677 3
+       for (lcv = uvm_physmem_get_first();
+            lcv <= uvm_physmem_get_last();
+            lcv = uvm_physmem_get_next(lcv)) {
d682 2
a683 2
+               n = uvm_physmem_get_end(lcv) - uvm_physmem_get_start(lcv);
+               uvm_physmem_init_seg(lcv, pagearray);
d708 1
a708 1
@@@@ -625,92 +605,42 @@@@ static bool uvm_page_physget_freelist(pa
d732 7
a738 1
-
d756 1
a756 7
+               /* Try to match at front or back on unused segment */
+               if (uvm_page_physunload(lcv, freelist, paddrp) == false) {
+                       if (paddrp == NULL) /* freelist fail, try next */
+                               continue;
+               } else
+                       return true;

d820 1
a820 1
@@@@ -726,228 +656,7 @@@@ uvm_page_physget(paddr_t *paddrp)
d1050 1
a1050 1
@@@@ -956,21 +665,24 @@@@ struct vm_page *
d1055 1
d1057 1
a1057 1
       int     psi;
d1059 2
a1060 2
       psi = vm_physseg_find(pf, &off);
       if (psi != -1)
d1062 3
a1064 1
+               return uvm_physmem_get_pg(psi, off);
d1080 1
a1080 1
@@@@ -985,7 +697,8 @@@@ uvm_page_recolor(int newncolors)
d1086 1
a1086 1
+       uvm_physmem_t lcv;
d1090 9
a1098 10
@@@@ -1076,7 +789,7 @@@@ uvm_cpu_attach(struct cpu_info *ci)
       struct pgfreelist pgfl;
       struct uvm_cpu *ucpu;
       vsize_t bucketcount;
-       int lcv;
+       uvm_physmem_t lcv;

       if (CPU_IS_PRIMARY(ci)) {
               /* Already done in uvm_page_init(). */
@@@@ -1110,6 +823,7 @@@@ attachrnd:
d1106 1
a1106 1
@@@@ -1196,7 +910,9 @@@@ uvm_pagealloc_pgfl(struct uvm_cpu *ucpu,
d1116 1
a1116 1
@@@@ -1219,7 +935,8 @@@@ struct vm_page *
d1122 1
a1122 1
+       uvm_physmem_t lcv;
d1126 1
a1126 1
@@@@ -1389,6 +1106,7 @@@@ uvm_pagealloc_strat(struct uvm_object *o
d1134 1
a1134 1
@@@@ -1481,6 +1199,7 @@@@ uvm_pagezerocheck(struct vm_page *pg)
d1142 1
a1142 1
@@@@ -1632,7 +1351,9 @@@@ uvm_pagefree(struct vm_page *pg)
d1152 1
a1152 1
@@@@ -1676,6 +1397,7 @@@@ uvm_page_unbusy(struct vm_page **pgs, in
d1160 1
a1160 1
@@@@ -1831,6 +1553,7 @@@@ uvm_pageidlezero(void)
d1168 1
a1168 1
@@@@ -1852,7 +1575,9 @@@@ uvm_pagelookup(struct uvm_object *obj, v
d1178 1
a1178 1
@@@@ -1875,7 +1600,9 @@@@ uvm_pagewire(struct vm_page *pg)
d1188 1
a1188 1
@@@@ -1893,7 +1620,9 @@@@ uvm_pageunwire(struct vm_page *pg)
d1198 1
a1198 1
@@@@ -1912,7 +1641,9 @@@@ uvm_pagedeactivate(struct vm_page *pg)
d1208 1
a1208 1
@@@@ -1936,7 +1667,9 @@@@ uvm_pageactivate(struct vm_page *pg)
d1218 1
a1218 1
@@@@ -1951,7 +1684,9 @@@@ uvm_pagedequeue(struct vm_page *pg)
d1228 1
a1228 1
@@@@ -1967,7 +1702,9 @@@@ uvm_pageenqueue(struct vm_page *pg)
d1238 1
a1238 1
@@@@ -1981,6 +1718,7 @@@@ uvm_pagezero(struct vm_page *pg)
d1246 10
a1255 1
@@@@ -2015,13 +1753,14 @@@@ uvm_pageismanaged(paddr_t pa)
d1260 1
a1260 1
+       uvm_physmem_t lcv;
d1262 2
a1263 2
       lcv = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), NULL);
       KASSERT(lcv != -1);
d1265 3
a1267 1
+       return uvm_physmem_get_free_list(lcv);
d1274 1
a1274 1
@@@@ -2039,6 +1778,7 @@@@ uvm_page_locked_p(struct vm_page *pg)
d1282 1
a1282 1
@@@@ -2135,7 +1875,8 @@@@ uvm_page_printit(struct vm_page *pg, boo
d1292 1
a1292 1
@@@@ -2143,8 +1884,14 @@@@ uvm_page_printall(void (*pr)(const char
d1315 1
a1315 1
+++ sys/uvm/uvm_page.h  28 Oct 2016 08:23:22 -0000
d1363 1
a1363 1
@@@@ -366,10 +333,14 @@@@ bool uvm_page_locked_p(struct vm_page *)
a1367 1
+int vm_physseg_find(paddr_t, psize_t *);
d1384 1
a1384 1
+++ sys/uvm/uvm_pager.c 28 Oct 2016 08:23:22 -0000
d1486 1
a1486 1
+++ sys/uvm/uvm_pdaemon.c       28 Oct 2016 08:23:23 -0000
d1634 1
a1634 1
+++ sys/uvm/uvm_pdpolicy_clock.c        28 Oct 2016 08:23:23 -0000
d1654 1
a1654 1
+++ sys/uvm/uvm_pglist.c        28 Oct 2016 08:23:23 -0000
d1979 2
a1980 2
+++ sys/uvm/uvm_physmem.c       28 Oct 2016 08:23:23 -0000
@@@@ -0,0 +1,638 @@@@
d2047 2
d2064 1
a2064 11
+/*
+ * physical memory config is stored in vm_physmem.
+ */
+
+#define        VM_PHYSMEM_PTR(i)       (&vm_physmem[i])
+#if VM_PHYSSEG_MAX == 1
+#define VM_PHYSMEM_PTR_SWAP(i, j) /* impossible */
+#else
+#define VM_PHYSMEM_PTR_SWAP(i, j) \
+       do { vm_physmem[(i)] = vm_physmem[(j)]; } while (0)
+#endif
d2070 1
d2085 124
d2210 12
a2221 3
+static struct vm_physseg vm_physmem[VM_PHYSSEG_MAX];   /* XXXCDC: uvm.physmem */
+static int vm_nphysseg;                                /* XXXCDC: uvm.nphysseg */
+#define        vm_nphysmem     vm_nphysseg
d2225 2
a2226 2
+       /* XXX: Provisioning for rb_tree related init(s) */
+       return;
d2230 1
a2230 1
+uvm_physmem_init_seg(uvm_physmem_t lcv, struct vm_page *pgs)
d2237 1
a2237 1
+       KASSERT(lcv >= 0 && lcv < vm_nphysmem);
d2239 1
a2239 1
+       seg = VM_PHYSMEM_PTR(lcv);
d2268 1
a2268 1
+uvm_physmem_get_start(uvm_physmem_t lcv)
d2270 1
a2270 1
+       if (uvm_physmem_valid(lcv) == false)
d2273 1
a2273 1
+       return VM_PHYSMEM_PTR(lcv)->start;
d2277 1
a2277 1
+uvm_physmem_get_end(uvm_physmem_t lcv)
d2279 1
a2279 1
+       if (uvm_physmem_valid(lcv) == false)
d2282 1
a2282 1
+       return VM_PHYSMEM_PTR(lcv)->end;
d2286 1
a2286 1
+uvm_physmem_get_avail_start(uvm_physmem_t lcv)
d2288 1
a2288 1
+       if (uvm_physmem_valid(lcv) == false)
d2291 1
a2291 1
+       return VM_PHYSMEM_PTR(lcv)->avail_start;
d2295 1
a2295 1
+uvm_physmem_get_avail_end(uvm_physmem_t lcv)
d2297 1
a2297 1
+       if (uvm_physmem_valid(lcv) == false)
d2300 1
a2300 1
+       return VM_PHYSMEM_PTR(lcv)->avail_end;
d2304 1
a2304 1
+uvm_physmem_get_pg(uvm_physmem_t lcv, paddr_t idx)
d2307 1
a2307 1
+       return &VM_PHYSMEM_PTR(lcv)->pgs[idx];
d2312 1
a2312 1
+uvm_physmem_get_pmseg(uvm_physmem_t lcv)
d2315 1
a2315 1
+       return &VM_PHYSMEM_PTR(lcv)->pmseg;
d2320 1
a2320 1
+uvm_physmem_get_free_list(uvm_physmem_t lcv)
d2322 1
a2322 1
+       return VM_PHYSMEM_PTR(lcv)->free_list;
d2326 1
a2326 1
+uvm_physmem_get_start_hint(uvm_physmem_t lcv)
d2328 1
a2328 1
+       return VM_PHYSMEM_PTR(lcv)->start_hint;
d2332 1
a2332 1
+uvm_physmem_set_start_hint(uvm_physmem_t lcv, u_int start_hint)
d2334 1
a2334 1
+       if (uvm_physmem_valid(lcv) == false)
d2337 1
a2337 1
+       VM_PHYSMEM_PTR(lcv)->start_hint = start_hint;
d2341 2
a2342 2
+int
+uvm_physmem_get_next(uvm_physmem_t lcv)
d2344 2
a2345 1
+       return (lcv + 1);
d2348 2
a2349 2
+int
+uvm_physmem_get_prev(uvm_physmem_t lcv)
d2351 2
a2352 1
+       return (lcv - 1);
d2355 1
a2355 1
+int
d2358 1
a2358 1
+       return (vm_nphysseg - 1);
d2361 1
a2361 1
+int
d2364 1
a2364 1
+       return 0;
d2368 1
a2368 1
+uvm_physmem_valid(uvm_physmem_t lcv)
d2372 1
a2372 4
+       if (lcv < 0)
+               return false;
+
+       if (lcv >= vm_nphysseg)
d2382 1
a2382 1
+       ps = VM_PHYSMEM_PTR(lcv);
d2401 2
a2402 3
+       int lcv;
+       paddr_t last = 0;
+       struct vm_physseg *ps;
d2404 1
a2404 7
+       for (lcv = 0; lcv < vm_nphysseg; lcv++) {
+               ps = VM_PHYSMEM_PTR(lcv);
+               if (last < ps->end)
+                       last = ps->end;
+       }
+
+       return last;
d2412 1
a2412 1
+uvm_page_physunload(uvm_physmem_t psi, int freelist, paddr_t *paddrp)
a2413 1
+       int x;
d2416 1
a2416 1
+       seg = VM_PHYSMEM_PTR(psi);
d2423 5
d2436 5
a2440 6
+                       if (vm_nphysmem == 1)
+                               panic("uvm_page_physget: out of memory!");
+                       vm_nphysmem--;
+                       for (x = psi ; x < vm_nphysmem ; x++)
+                               /* structure copy */
+                               VM_PHYSMEM_PTR_SWAP(x, x + 1);
d2453 5
a2457 6
+                       if (vm_nphysmem == 1)
+                               panic("uvm_page_physget: out of memory!");
+                       vm_nphysmem--;
+                       for (x = psi ; x < vm_nphysmem ; x++)
+                               /* structure copy */
+                               VM_PHYSMEM_PTR_SWAP(x, x + 1);
d2466 1
a2466 1
+uvm_page_physunload_force(uvm_physmem_t psi, int freelist, paddr_t *paddrp)
a2467 1
+       int x;
d2470 1
a2470 1
+       seg = VM_PHYSMEM_PTR(psi);
d2485 5
a2489 6
+               if (vm_nphysmem == 1)
+                       panic("uvm_page_physget: out of memory!");
+               vm_nphysmem--;
+               for (x = psi ; x < vm_nphysmem ; x++)
+                       /* structure copy */
+                       VM_PHYSMEM_PTR_SWAP(x, x + 1);
d2508 1
a2508 1
+       int preload, lcv;
d2511 1
a2511 1
+       struct vm_physseg *ps;
d2524 2
a2525 1
+       if (vm_nphysmem == VM_PHYSSEG_MAX) {
d2539 5
a2543 2
+       for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) {
+               if (VM_PHYSMEM_PTR(lcv)->pgs)
d2545 1
d2547 2
a2548 1
+       preload = (lcv == vm_nphysmem);
a2561 37
+       /*
+        * now insert us in the proper place in vm_physmem[]
+        */
+
+#if (VM_PHYSSEG_STRAT == VM_PSTRAT_RANDOM)
+       /* random: put it at the end (easy!) */
+       ps = VM_PHYSMEM_PTR(vm_nphysmem);
+#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
+       {
+               int x;
+               /* sort by address for binary search */
+               for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
+                       if (start < VM_PHYSMEM_PTR(lcv)->start)
+                               break;
+               ps = VM_PHYSMEM_PTR(lcv);
+               /* move back other entries, if necessary ... */
+               for (x = vm_nphysmem ; x > lcv ; x--)
+                       /* structure copy */
+                       VM_PHYSMEM_PTR_SWAP(x, x - 1);
+       }
+#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BIGFIRST)
+       {
+               int x;
+               /* sort by largest segment first */
+               for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
+                       if ((end - start) >
+                           (VM_PHYSMEM_PTR(lcv)->end - VM_PHYSMEM_PTR(lcv)->start))
+                               break;
+               ps = VM_PHYSMEM_PTR(lcv);
+               /* move back other entries, if necessary ... */
+               for (x = vm_nphysmem ; x > lcv ; x--)
+                       /* structure copy */
+                       VM_PHYSMEM_PTR_SWAP(x, x - 1);
+       }
+#else
+       panic("uvm_page_physload: unknown physseg strategy selected!");
+#endif
d2572 10
a2581 1
+       vm_nphysmem++;
d2607 1
a2607 1
+       return lcv;
a2609 11
+/*
+ * when VM_PHYSSEG_MAX is 1, we can simplify these functions
+ */
+
+#if VM_PHYSSEG_MAX == 1
+static inline int vm_physseg_find_contig(struct vm_physseg *, int, paddr_t, psize_t *);
+#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
+static inline int vm_physseg_find_bsearch(struct vm_physseg *, int, paddr_t, psize_t *);
+#else
+static inline int vm_physseg_find_linear(struct vm_physseg *, int, paddr_t, psize_t *);
+#endif
d2614 1
a2614 1
+int
d2617 1
d2619 1
a2619 8
+#if VM_PHYSSEG_MAX == 1
+       return vm_physseg_find_contig(vm_physmem, vm_nphysseg, pframe, offp);
+#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
+       return vm_physseg_find_bsearch(vm_physmem, vm_nphysseg, pframe, offp);
+#else
+       return vm_physseg_find_linear(vm_physmem, vm_nphysseg, pframe, offp);
+#endif
+}
d2621 2
a2622 4
+#if VM_PHYSSEG_MAX == 1
+static inline int
+vm_physseg_find_contig(struct vm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
+{
d2624 1
a2624 7
+       /* 'contig' case */
+       if (pframe >= segs[0].start && pframe < segs[0].end) {
+               if (offp)
+                       *offp = pframe - segs[0].start;
+               return(0);
+       }
+       return(-1);
a2625 64
+
+#elif (VM_PHYSSEG_STRAT == VM_PSTRAT_BSEARCH)
+
+static inline int
+vm_physseg_find_bsearch(struct vm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
+{
+       /* binary search for it */
+       int     start, len, guess;
+
+       /*
+        * if try is too large (thus target is less than try) we reduce
+        * the length to trunc(len/2) [i.e. everything smaller than "try"]
+        *
+        * if the try is too small (thus target is greater than try) then
+        * we set the new start to be (try + 1).   this means we need to
+        * reduce the length to (round(len/2) - 1).
+        *
+        * note "adjust" below which takes advantage of the fact that
+        *  (round(len/2) - 1) == trunc((len - 1) / 2)
+        * for any value of len we may have
+        */
+
+       for (start = 0, len = nsegs ; len != 0 ; len = len / 2) {
+               guess = start + (len / 2);      /* try in the middle */
+
+               /* start past our try? */
+               if (pframe >= segs[guess].start) {
+                       /* was try correct? */
+                       if (pframe < segs[guess].end) {
+                               if (offp)
+                                       *offp = pframe - segs[guess].start;
+                               return guess;            /* got it */
+                       }
+                       start = guess + 1;      /* next time, start here */
+                       len--;                  /* "adjust" */
+               } else {
+                       /*
+                        * pframe before try, just reduce length of
+                        * region, done in "for" loop
+                        */
+               }
+       }
+       return(-1);
+}
+
+#else
+
+static inline int
+vm_physseg_find_linear(struct vm_physseg *segs, int nsegs, paddr_t pframe, psize_t *offp)
+{
+       /* linear search for it */
+       int     lcv;
+
+       for (lcv = 0; lcv < nsegs; lcv++) {
+               if (pframe >= segs[lcv].start &&
+                   pframe < segs[lcv].end) {
+                       if (offp)
+                               *offp = pframe - segs[lcv].start;
+                       return(lcv);               /* got it */
+               }
+       }
+       return(-1);
+}
+#endif
d2631 1
a2631 1
+++ sys/uvm/uvm_physmem.h       28 Oct 2016 08:23:23 -0000
d2656 1
a2656 1
+ *
a2659 4
+
+#define UVM_PHYSMEM_TYPE_INVALID -1 /* Generic invalid value */
+#define UVM_PHYSMEM_TYPE_INVALID_EMPTY -1 /* empty segment access */
+#define UVM_PHYSMEM_TYPE_INVALID_OVERFLOW (uvm_physmem_get_last() + 1) /* ran off the end of the last segment */
d2661 5
a2665 1
+typedef int uvm_physmem_t;
d2695 1
a2695 1
+ * Returns: -1 if the segment number is invalid
d2722 1
a2722 1
+++ sys/uvm/pmap/pmap.c 28 Oct 2016 08:23:24 -0000
@


1.2
log
@Immutable uvm_physmem_t test, shakedown of tests to make
sure that the semantics are clear.
Tested on amd64
@
text
@a0 5
? sys/uvm/files_BACKUP_21538.uvm
? sys/uvm/files_BASE_21538.uvm
? sys/uvm/files_LOCAL_21538.uvm
? sys/uvm/files_REMOTE_21538.uvm
? sys/uvm/uvm_physmem_new.c
@


1.1
log
@Initial revision
@
text
@d1 5
d12 1
a12 1
+++ sys/uvm/Makefile    20 Oct 2016 14:19:24 -0000
d28 1
a28 1
+++ sys/uvm/files.uvm   20 Oct 2016 14:19:24 -0000
d43 1
a43 1
+++ sys/uvm/uvm.h       20 Oct 2016 14:19:24 -0000
d58 1
a58 1
+++ sys/uvm/uvm_amap.c  20 Oct 2016 14:19:24 -0000
d84 1
a84 1
+++ sys/uvm/uvm_anon.c  20 Oct 2016 14:19:24 -0000
d110 1
a110 1
+++ sys/uvm/uvm_bio.c   20 Oct 2016 14:19:25 -0000
d141 1
a141 1
+++ sys/uvm/uvm_device.c        20 Oct 2016 14:19:25 -0000
d174 1
a174 1
+++ sys/uvm/uvm_extern.h        20 Oct 2016 14:19:25 -0000
d191 1
a191 1
+++ sys/uvm/uvm_fault.c 20 Oct 2016 14:19:26 -0000
d228 1
a228 1
+++ sys/uvm/uvm_init.c  20 Oct 2016 14:19:26 -0000
d248 1
a248 1
+++ sys/uvm/uvm_km.c    20 Oct 2016 14:19:27 -0000
d355 1
a355 1
+++ sys/uvm/uvm_loan.c  20 Oct 2016 14:19:28 -0000
d457 1
a457 1
+++ sys/uvm/uvm_map.c   20 Oct 2016 14:19:30 -0000
d562 1
a562 1
+++ sys/uvm/uvm_page.c  20 Oct 2016 14:19:30 -0000
d676 1
a676 1
@@@@ -428,31 +423,19 @@@@ uvm_page_init(vaddr_t *kvm_startp, vaddr
a682 4
+
+               n = uvm_physmem_get_end(lcv) - uvm_physmem_get_start(lcv);
+               n = ((n + 1) << PAGE_SHIFT) /
+                   (PAGE_SIZE + sizeof(struct vm_page));
d687 1
d713 1
a713 1
@@@@ -625,92 +608,42 @@@@ static bool uvm_page_physget_freelist(pa
d825 1
a825 1
@@@@ -726,228 +659,7 @@@@ uvm_page_physget(paddr_t *paddrp)
d1055 1
a1055 1
@@@@ -956,21 +668,24 @@@@ struct vm_page *
d1082 1
a1082 1
@@@@ -985,7 +700,8 @@@@ uvm_page_recolor(int newncolors)
d1092 1
a1092 1
@@@@ -1076,7 +792,7 @@@@ uvm_cpu_attach(struct cpu_info *ci)
d1101 1
a1101 1
@@@@ -1110,6 +826,7 @@@@ attachrnd:
d1109 1
a1109 1
@@@@ -1196,7 +913,9 @@@@ uvm_pagealloc_pgfl(struct uvm_cpu *ucpu,
d1119 1
a1119 1
@@@@ -1219,7 +938,8 @@@@ struct vm_page *
d1129 1
a1129 1
@@@@ -1389,6 +1109,7 @@@@ uvm_pagealloc_strat(struct uvm_object *o
d1137 1
a1137 1
@@@@ -1481,6 +1202,7 @@@@ uvm_pagezerocheck(struct vm_page *pg)
d1145 1
a1145 1
@@@@ -1632,7 +1354,9 @@@@ uvm_pagefree(struct vm_page *pg)
d1155 1
a1155 1
@@@@ -1676,6 +1400,7 @@@@ uvm_page_unbusy(struct vm_page **pgs, in
d1163 1
a1163 1
@@@@ -1831,6 +1556,7 @@@@ uvm_pageidlezero(void)
d1171 1
a1171 1
@@@@ -1852,7 +1578,9 @@@@ uvm_pagelookup(struct uvm_object *obj, v
d1181 1
a1181 1
@@@@ -1875,7 +1603,9 @@@@ uvm_pagewire(struct vm_page *pg)
d1191 1
a1191 1
@@@@ -1893,7 +1623,9 @@@@ uvm_pageunwire(struct vm_page *pg)
d1201 1
a1201 1
@@@@ -1912,7 +1644,9 @@@@ uvm_pagedeactivate(struct vm_page *pg)
d1211 1
a1211 1
@@@@ -1936,7 +1670,9 @@@@ uvm_pageactivate(struct vm_page *pg)
d1221 1
a1221 1
@@@@ -1951,7 +1687,9 @@@@ uvm_pagedequeue(struct vm_page *pg)
d1231 1
a1231 1
@@@@ -1967,7 +1705,9 @@@@ uvm_pageenqueue(struct vm_page *pg)
d1241 1
a1241 1
@@@@ -1981,6 +1721,7 @@@@ uvm_pagezero(struct vm_page *pg)
d1249 1
a1249 1
@@@@ -2015,13 +1756,14 @@@@ uvm_pageismanaged(paddr_t pa)
d1266 1
a1266 1
@@@@ -2039,6 +1781,7 @@@@ uvm_page_locked_p(struct vm_page *pg)
d1274 1
a1274 1
@@@@ -2135,7 +1878,8 @@@@ uvm_page_printit(struct vm_page *pg, boo
d1284 1
a1284 1
@@@@ -2143,8 +1887,14 @@@@ uvm_page_printall(void (*pr)(const char
d1307 1
a1307 1
+++ sys/uvm/uvm_page.h  20 Oct 2016 14:19:31 -0000
d1377 1
a1377 1
+++ sys/uvm/uvm_pager.c 20 Oct 2016 14:19:31 -0000
d1479 1
a1479 1
+++ sys/uvm/uvm_pdaemon.c       20 Oct 2016 14:19:31 -0000
d1627 1
a1627 1
+++ sys/uvm/uvm_pdpolicy_clock.c        20 Oct 2016 14:19:31 -0000
d1647 1
a1647 1
+++ sys/uvm/uvm_pglist.c        20 Oct 2016 14:19:32 -0000
d1972 2
a1973 2
+++ sys/uvm/uvm_physmem.c       20 Oct 2016 14:19:32 -0000
@@@@ -0,0 +1,635 @@@@
a2110 3
+       n = ((n + 1) << PAGE_SHIFT) /
+           (PAGE_SIZE + sizeof(struct vm_page));
+
d2304 1
d2322 1
d2354 2
d2379 1
a2379 1
+void
d2405 1
a2405 1
+               return;
d2503 2
d2555 1
a2555 1
+       u_int   start, len, guess;
d2617 2
a2618 2
+++ sys/uvm/uvm_physmem.h       20 Oct 2016 14:19:32 -0000
@@@@ -0,0 +1,72 @@@@
d2638 12
a2649 1
+#define UVM_PHYSMEM_TYPE_INVALID -1
d2693 1
a2693 1
+void uvm_page_physload(paddr_t, paddr_t, paddr_t,
d2708 1
a2708 1
+++ sys/uvm/pmap/pmap.c 20 Oct 2016 14:19:33 -0000
@