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
@