tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

uvm physseg - put the lid on it.



Hi Everyone,

Here's a patch to put the vm physseg stuff behind bars.

I've made some pretty intrusive changes, esp. to the boot time msgbuf
stuff, so if portmasters could have a quick look at this, I'll be able
to go ahead and change the equivalents on other ports.

I have a bunch of tests that actually test these functions in userland
via rump. It's pretty cool :-)

Ultimately, I want to change the backing implementation to use an rb
tree rather than a static array, so that the plug/unplug is
dynamic. Obviously, this patch is not any attempt at an "API" - it's
just code reorg, to make the next steps easier.

Please comment, thanks.
-- 
~~cherry

diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index 5208940..503afb1 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -799,10 +799,23 @@ sparse_dump_mark(void)
 			setbit(sparse_dump_physmap, p);
 		}
 	}
-	for (i = 0; i < vm_nphysseg; i++) {
-		struct vm_physseg *seg = VM_PHYSMEM_PTR(i);
+        for (i = 0; i < VM_PHYSSEG_MAX; i++) {
+		paddr_t pfn;
 
-		for (pg = seg->pgs; pg < seg->lastpg; pg++) {
+		if (uvm_physmem_valid(i) == false)
+			break;
+
+		const paddr_t startpfn = uvm_physmem_get_start(i);
+		const paddr_t endpfn = uvm_physmem_get_end(i);
+
+		KASSERT(startpfn != -1 && endpfn != -1);
+
+		/*
+		 * We assume that seg->start to seg->end are
+		 * uvm_page_physload()ed
+		 */
+		for (pfn = startpfn; pfn <= endpfn; pfn++) {
+			pg = PHYS_TO_VM_PAGE(ptoa(pfn));
 			if (pg->uanon || (pg->pqflags & PQ_FREE) ||
 			    (pg->uobject && pg->uobject->pgops)) {
 				p = VM_PAGE_TO_PHYS(pg) / PAGE_SIZE;
@@ -1426,7 +1439,7 @@ cpu_init_idt(void)
 	struct region_descriptor region;
 
 	setregion(&region, idt, NIDT * sizeof(idt[0]) - 1);
-	lidt(&region); 
+	lidt(&region);
 #else
 	if (HYPERVISOR_set_trap_table(xen_idt))
 		panic("HYPERVISOR_set_trap_table() failed");
@@ -1444,57 +1457,30 @@ extern vector *IDTVEC(exceptions)[];
 static void
 init_x86_64_msgbuf(void)
 {
-	/* Message buffer is located at end of core. */
-	struct vm_physseg *vps;
-	psize_t sz = round_page(MSGBUFSIZE);
-	psize_t reqsz = sz;
-	int x;
-		
- search_again:
-	vps = NULL;
-
-	for (x = 0; x < vm_nphysseg; x++) {
-		vps = VM_PHYSMEM_PTR(x);
-		if (ctob(vps->avail_end) == avail_end)
-			break;
-	}
-	if (x == vm_nphysseg)
-		panic("init_x86_64: can't find end of memory");
-
-	/* Shrink so it'll fit in the last segment. */
-	if ((vps->avail_end - vps->avail_start) < atop(sz))
-		sz = ctob(vps->avail_end - vps->avail_start);
-
-	vps->avail_end -= atop(sz);
-	vps->end -= atop(sz);
-            msgbuf_p_seg[msgbuf_p_cnt].sz = sz;
-            msgbuf_p_seg[msgbuf_p_cnt++].paddr = ctob(vps->avail_end);
-
-	/* Remove the last segment if it now has no pages. */
-	if (vps->start == vps->end) {
-		for (vm_nphysseg--; x < vm_nphysseg; x++)
-			VM_PHYSMEM_PTR_SWAP(x, x + 1);
-	}
+        /* Message buffer is located at end of core. */
+	psize_t reqsz = round_page(MSGBUFSIZE);
+	psize_t sz = 0;
 
-	/* Now find where the new avail_end is. */
-	for (avail_end = 0, x = 0; x < vm_nphysseg; x++)
-		if (VM_PHYSMEM_PTR(x)->avail_end > avail_end)
-			avail_end = VM_PHYSMEM_PTR(x)->avail_end;
-	avail_end = ctob(avail_end);
+	for (sz = 0; sz < reqsz; sz += PAGE_SIZE) {
+		paddr_t stolenpa;
 
-	if (sz == reqsz)
-		return;
+		if (!uvm_page_physget(&stolenpa))
+			break;
 
-	reqsz -= sz;
-	if (msgbuf_p_cnt == VM_PHYSSEG_MAX) {
-		/* No more segments available, bail out. */
-		printf("WARNING: MSGBUFSIZE (%zu) too large, using %zu.\n",
-		    (size_t)MSGBUFSIZE, (size_t)(MSGBUFSIZE - reqsz));
-		return;
+		if (stolenpa == (msgbuf_p_seg[msgbuf_p_cnt].paddr
+			+ PAGE_SIZE)) {
+			/* contiguous: append it to current buf alloc */
+			msgbuf_p_seg[msgbuf_p_cnt].sz += PAGE_SIZE;
+		} else  {
+			/* non-contiguous: start a new msgbuf seg */
+			msgbuf_p_seg[msgbuf_p_cnt].sz = PAGE_SIZE;
+			msgbuf_p_seg[msgbuf_p_cnt++].paddr = stolenpa;
+		}
 	}
 
-	sz = reqsz;
-	goto search_again;
+	if (sz != reqsz)
+		printf("%s: could only allocate %ld bytes of requested %ld bytes\n",
+		    __func__, sz, reqsz);
 }
 
 static void
@@ -1827,7 +1813,9 @@ cpu_reset(void)
 	 * invalid and causing a fault.
 	 */
 	kpreempt_disable();
-	pmap_changeprot_local(idt_vaddr, VM_PROT_READ|VM_PROT_WRITE);           
+	pmap_changeprot_local(idt_vaddr, VM_PROT_READ|VM_PROT_WRITE);
+	pmap_changeprot_local(idt_vaddr + PAGE_SIZE,
+	    VM_PROT_READ|VM_PROT_WRITE);
 	memset((void *)idt, 0, NIDT * sizeof(idt[0]));
 	kpreempt_enable();
 	breakpoint();
@@ -1838,7 +1826,7 @@ cpu_reset(void)
 	 * entire address space and doing a TLB flush.
 	 */
 	memset((void *)PTD, 0, PAGE_SIZE);
-	tlbflush(); 
+	tlbflush();
 #endif
 #endif	/* XEN */
 
diff --git a/sys/arch/amd64/include/uvm_physmem.h b/sys/arch/amd64/include/uvm_physmem.h
new file mode 100644
index 0000000..861be35
--- /dev/null
+++ b/sys/arch/amd64/include/uvm_physmem.h
@@ -0,0 +1,9 @@
+/* $NetBSD$ */
+
+#ifndef _X86_64_UVM_PHYSMEM_H_
+#define _X86_64_UVM_PHYSMEM_H_
+
+/* Pull in Kernel API */
+#include <sys/kmem.h>
+
+#endif /* _X86_64_UVM_PHYSMEM_H_ */
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 4bf3a1d..32cd306 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -572,7 +572,7 @@ i386_tls_switch(lwp_t *l)
 	/* Update TLS segment pointers */
 	update_descriptor(&ci->ci_gdt[GUFS_SEL],
 			  (union descriptor *) &pcb->pcb_fsd);
-	update_descriptor(&ci->ci_gdt[GUGS_SEL], 
+	update_descriptor(&ci->ci_gdt[GUGS_SEL],
 			  (union descriptor *) &pcb->pcb_gsd);
 
 }
@@ -941,7 +941,7 @@ int xen_idt_idx;
 extern union descriptor tmpgdt[];
 #endif
 
-void 
+void
 cpu_init_idt(void)
 {
 #ifndef XEN
@@ -959,7 +959,7 @@ void
 initgdt(union descriptor *tgdt)
 {
 	KASSERT(tgdt != NULL);
-	
+
 	gdt = tgdt;
 #ifdef XEN
 	u_long	frames[16];
@@ -1031,57 +1031,30 @@ initgdt(union descriptor *tgdt)
 static void
 init386_msgbuf(void)
 {
-	/* Message buffer is located at end of core. */
-	struct vm_physseg *vps;
-	psize_t sz = round_page(MSGBUFSIZE);
-	psize_t reqsz = sz;
-	unsigned int x;
-
- search_again:
-	vps = NULL;
-	for (x = 0; x < vm_nphysseg; ++x) {
-		vps = VM_PHYSMEM_PTR(x);
-		if (ctob(vps->avail_end) == avail_end) {
-			break;
-		}
-	}
-	if (x == vm_nphysseg)
-		panic("init386: can't find end of memory");
-
-	/* Shrink so it'll fit in the last segment. */
-	if (vps->avail_end - vps->avail_start < atop(sz))
-		sz = ctob(vps->avail_end - vps->avail_start);
-
-	vps->avail_end -= atop(sz);
-	vps->end -= atop(sz);
-	msgbuf_p_seg[msgbuf_p_cnt].sz = sz;
-	msgbuf_p_seg[msgbuf_p_cnt++].paddr = ctob(vps->avail_end);
-
-	/* Remove the last segment if it now has no pages. */
-	if (vps->start == vps->end) {
-		for (--vm_nphysseg; x < vm_nphysseg; x++)
-			VM_PHYSMEM_PTR_SWAP(x, x + 1);
-	}
+        /* Message buffer is located at end of core. */
+	psize_t reqsz = round_page(MSGBUFSIZE);
+	psize_t sz = 0;
 
-	/* Now find where the new avail_end is. */
-	for (avail_end = 0, x = 0; x < vm_nphysseg; x++)
-		if (VM_PHYSMEM_PTR(x)->avail_end > avail_end)
-			avail_end = VM_PHYSMEM_PTR(x)->avail_end;
-	avail_end = ctob(avail_end);
+	for (sz = 0; sz < reqsz; sz += PAGE_SIZE) {
+		paddr_t stolenpa;
 
-	if (sz == reqsz)
-		return;
+		if (!uvm_page_physget(&stolenpa))
+			break;
 
-	reqsz -= sz;
-	if (msgbuf_p_cnt == VM_PHYSSEG_MAX) {
-		/* No more segments available, bail out. */
-		printf("WARNING: MSGBUFSIZE (%zu) too large, using %zu.\n",
-		    (size_t)MSGBUFSIZE, (size_t)(MSGBUFSIZE - reqsz));
-		return;
+		if (stolenpa == (msgbuf_p_seg[msgbuf_p_cnt].paddr
+			+ PAGE_SIZE)) {
+			/* contiguous: append it to current buf alloc */
+			msgbuf_p_seg[msgbuf_p_cnt].sz += PAGE_SIZE;
+		} else  {
+			/* non-contiguous: start a new msgbuf seg */
+			msgbuf_p_seg[msgbuf_p_cnt].sz = PAGE_SIZE;
+			msgbuf_p_seg[msgbuf_p_cnt++].paddr = stolenpa;
+		}
 	}
 
-	sz = reqsz;
-	goto search_again;
+	if (sz != reqsz)
+		printf("%s: could only allocate %ld bytes of requested %ld bytes\n",
+		    __func__, sz, reqsz);
 }
 
 #ifndef XEN
@@ -1235,7 +1208,7 @@ init386(paddr_t first_avail)
 #if NISA > 0 || NPCI > 0
 	x86_bus_space_init();
 #endif /* NISA > 0 || NPCI > 0 */
-	
+
 	consinit();	/* XXX SHOULD NOT BE DONE HERE */
 
 #ifdef DEBUG_MEMLOAD
@@ -1486,7 +1459,7 @@ cpu_reset(void)
 	 * 2) Write 0xf to PCI Configuration Data Register (0xcfc)
 	 *    to reset IDE controller, IDE bus, and PCI bus, and
 	 *    to trigger a system-wide reset.
-	 * 
+	 *
 	 * See AMD Geode SC1100 Processor Data Book, Revision 2.0,
 	 * sections 6.3.1, 6.3.2, and 6.4.1.
 	 */
diff --git a/sys/arch/i386/include/uvm_physmem.h b/sys/arch/i386/include/uvm_physmem.h
new file mode 100644
index 0000000..4abb905
--- /dev/null
+++ b/sys/arch/i386/include/uvm_physmem.h
@@ -0,0 +1,10 @@
+/* $NetBSD$ */
+
+#ifndef _I386_UVM_PHYSMEM_H_
+
+#define _I386_UVM_PHYSMEM_H_
+
+/* Pull in Kernel API */
+#include <sys/kmem.h>
+
+#endif /* _I386_UVM_PHYSMEM_H_ */
diff --git a/sys/arch/x86/x86/x86_machdep.c b/sys/arch/x86/x86/x86_machdep.c
index 93bffbb..0992518 100644
--- a/sys/arch/x86/x86/x86_machdep.c
+++ b/sys/arch/x86/x86/x86_machdep.c
@@ -67,6 +67,7 @@ __KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.75 2016/08/01 16:07:39 maxv Exp $"
 #include <machine/vmparam.h>
 
 #include <uvm/uvm_extern.h>
+#include <uvm/uvm_physmem.h>
 
 #include "acpica.h"
 #if NACPICA > 0
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index 5d5f630..f14d9cd 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -82,7 +82,7 @@ extern int autoniceval;         /* proc priority after autonicetime */
 extern int selwait;		/* select timeout address */
 
 extern int maxmem;		/* max memory per process */
-extern int physmem;		/* physical memory */
+extern psize_t physmem;		/* physical memory */
 
 extern dev_t dumpdev;		/* dump device */
 extern dev_t dumpcdev;		/* dump device (character equivalent) */
diff --git a/sys/uvm/Makefile b/sys/uvm/Makefile
index 61c92eb..8f2e16f 100644
--- a/sys/uvm/Makefile
+++ b/sys/uvm/Makefile
@@ -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_physmem.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
diff --git a/sys/uvm/files.uvm b/sys/uvm/files.uvm
index 5c97d8a..cdbe2e8 100644
--- a/sys/uvm/files.uvm
+++ b/sys/uvm/files.uvm
@@ -41,6 +41,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_physmem.c		uvm
 file	uvm/uvm_readahead.c		uvm
 file	uvm/uvm_stat.c                	uvm
 file	uvm/uvm_swap.c			vmswap
diff --git a/sys/uvm/pmap/pmap.c b/sys/uvm/pmap/pmap.c
index 11babcd..c8bfbad 100644
--- a/sys/uvm/pmap/pmap.c
+++ b/sys/uvm/pmap/pmap.c
@@ -95,9 +95,11 @@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.22 2016/09/16 17:27:09 matt Exp $");
  *	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
 
diff --git a/sys/uvm/uvm.h b/sys/uvm/uvm.h
index 81b38e0..4c1401d 100644
--- a/sys/uvm/uvm.h
+++ b/sys/uvm/uvm.h
@@ -57,6 +57,7 @@
 #include <uvm/uvm_object.h>
 #include <uvm/uvm_page.h>
 #include <uvm/uvm_pager.h>
+#include <uvm/uvm_physmem.h>
 #include <uvm/uvm_pdaemon.h>
 #include <uvm/uvm_swap.h>
 
diff --git a/sys/uvm/uvm_extern.h b/sys/uvm/uvm_extern.h
index a8f605f..ccc2727 100644
--- a/sys/uvm/uvm_extern.h
+++ b/sys/uvm/uvm_extern.h
@@ -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 */
diff --git a/sys/uvm/uvm_page.c b/sys/uvm/uvm_page.c
index 3d44df6..7cc925c 100644
--- a/sys/uvm/uvm_page.c
+++ b/sys/uvm/uvm_page.c
@@ -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>
@@ -87,6 +89,24 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v 1.187 2015/04/11 19:24:13 joerg Exp $")
 #include <uvm/uvm_pdpolicy.h>
 
 /*
+ * 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
+};
+
+/*
  * global vars... XXXCDC: move to uvm. structure.
  */
 
@@ -94,9 +114,11 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_page.c,v 1.187 2015/04/11 19:24:13 joerg Exp $")
  * 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 */
+#if 0
+extern struct vm_physseg vm_physmem[VM_PHYSSEG_MAX];	/* XXXCDC: uvm.physmem */
+extern int vm_nphysseg;				/* XXXCDC: uvm.nphysseg */
 #define	vm_nphysmem	vm_nphysseg
+#endif
 
 /*
  * Some supported CPUs in a given architecture don't support all
@@ -116,7 +138,7 @@ int vm_page_reserve_kernel = UVM_RESERVED_PAGES_PER_CPU;
 /*
  * physical memory size;
  */
-int physmem;
+psize_t physmem;
 
 /*
  * local variables
@@ -152,6 +174,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 +193,9 @@ uvm_page_compare_nodes(void *ctx, const void *n1, const void *n2)
 		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 +209,16 @@ uvm_page_compare_key(void *ctx, const void *n, const void *key)
 		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 +365,8 @@ uvm_page_init(vaddr_t *kvm_startp, vaddr_t *kvm_endp)
 	static struct uvm_cpu boot_cpu;
 	psize_t freepages, pagecount, bucketcount, n;
 	struct pgflbucket *bucketarray, *cpuarray;
-	struct vm_physseg *seg;
 	struct vm_page *pagearray;
 	int lcv;
-	u_int i;
-	paddr_t paddr;
 
 	KASSERT(ncpu <= 1);
 	CTASSERT(sizeof(pagearray->offset) >= sizeof(struct uvm_cpu *));
@@ -369,7 +394,7 @@ uvm_page_init(vaddr_t *kvm_startp, vaddr_t *kvm_endp)
 	 * now is to allocate vm_page structures for this memory.
 	 */
 
-	if (vm_nphysmem == 0)
+	if (uvm_physmem_get_last() == -1)
 		panic("uvm_page_bootstrap: no memory pre-allocated");
 
 	/*
@@ -381,9 +406,11 @@ uvm_page_init(vaddr_t *kvm_startp, vaddr_t *kvm_endp)
 	 */
 
 	freepages = 0;
-	for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) {
-		seg = VM_PHYSMEM_PTR(lcv);
-		freepages += (seg->end - seg->start);
+
+	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));
 	}
 
 	/*
@@ -428,31 +455,19 @@ uvm_page_init(vaddr_t *kvm_startp, vaddr_t *kvm_endp)
 	/*
 	 * init the vm_page structures and put them in the correct place.
 	 */
+	for (lcv = uvm_physmem_get_first();
+	     lcv <= uvm_physmem_get_last();
+	     lcv = uvm_physmem_get_next(lcv)) {
+
+		n = uvm_physmem_get_end(lcv) - uvm_physmem_get_start(lcv);
+		n = ((n + 1) << PAGE_SHIFT) /
+		    (PAGE_SIZE + sizeof(struct vm_page));
 
-	for (lcv = 0 ; lcv < vm_nphysmem ; lcv++) {
-		seg = VM_PHYSMEM_PTR(lcv);
-		n = seg->end - seg->start;
+		uvm_physmem_init_seg(lcv, 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 +640,42 @@ static bool uvm_page_physget_freelist(paddr_t *, int);
 static bool
 uvm_page_physget_freelist(paddr_t *paddrp, int freelist)
 {
-	struct vm_physseg *seg;
-	int lcv, x;
+	int 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_physmem_get_last() ; lcv >= uvm_physmem_get_first() ; lcv = uvm_physmem_get_prev(lcv))
 #else
-	for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
+		for (lcv = uvm_physmem_get_first() ; lcv <= uvm_physmem_get_last() ; lcv = uvm_physmem_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 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 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 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_physmem_get_last() ; lcv >= uvm_physmem_get_first() ; lcv = uvm_physmem_get_prev(lcv))
 #else
-	for (lcv = 0 ; lcv < vm_nphysmem ; lcv++)
+		for (lcv = uvm_physmem_get_first() ; lcv <= uvm_physmem_get_last() ; lcv = uvm_physmem_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
@@ -726,228 +691,7 @@ 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
-
+#ifdef _KERNEL_OPT
 /*
  * 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,21 +700,24 @@ struct vm_page *
 uvm_phys_to_vm_page(paddr_t pa)
 {
 	paddr_t pf = atop(pa);
-	int	off;
+	paddr_t	off;
 	int	psi;
 
 	psi = vm_physseg_find(pf, &off);
 	if (psi != -1)
-		return(&VM_PHYSMEM_PTR(psi)->pgs[off]);
+		return uvm_physmem_get_pg(psi, off);
 	return(NULL);
 }
+#endif
 
+#ifdef _KERNEL_OPT
 paddr_t
 uvm_vm_page_to_phys(const struct vm_page *pg)
 {
 
 	return pg->phys_addr;
 }
+#endif
 
 /*
  * uvm_page_recolor: Recolor the pages if the new bucket count is
@@ -1110,6 +857,7 @@ attachrnd:
 
 }
 
+#ifdef _KERNEL_OPT
 /*
  * uvm_pagealloc_pgfl: helper routine for uvm_pagealloc_strat
  */
@@ -1196,7 +944,9 @@ uvm_pagealloc_pgfl(struct uvm_cpu *ucpu, int flist, int try1, int try2,
 
 	return (pg);
 }
+#endif
 
+#ifdef _KERNEL_OPT
 /*
  * uvm_pagealloc_strat: allocate vm_page from a particular free list.
  *
@@ -1389,6 +1139,7 @@ uvm_pagealloc_strat(struct uvm_object *obj, voff_t off, struct vm_anon *anon,
 	mutex_spin_exit(&uvm_fpageqlock);
 	return (NULL);
 }
+#endif
 
 /*
  * uvm_pagereplace: replace a page with another
@@ -1481,6 +1232,7 @@ uvm_pagezerocheck(struct vm_page *pg)
 }
 #endif /* DEBUG */
 
+#ifdef _KERNEL_OPT
 /*
  * uvm_pagefree: free page
  *
@@ -1632,7 +1384,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 +1430,7 @@ uvm_page_unbusy(struct vm_page **pgs, int npgs)
 		}
 	}
 }
+#endif
 
 #if defined(UVM_PAGE_TRKOWN)
 /*
@@ -1831,6 +1586,7 @@ uvm_pageidlezero(void)
 	mutex_spin_exit(&uvm_fpageqlock);
 }
 
+#ifdef _KERNEL_OPT
 /*
  * uvm_pagelookup: look up a page
  *
@@ -1852,7 +1608,9 @@ uvm_pagelookup(struct uvm_object *obj, voff_t off)
 		(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 +1633,9 @@ uvm_pagewire(struct vm_page *pg)
 	}
 	pg->wire_count++;
 }
+#endif
 
+#ifdef _KERNEL_OPT
 /*
  * uvm_pageunwire: unwire the page.
  *
@@ -1893,7 +1653,9 @@ uvm_pageunwire(struct vm_page *pg)
 		uvmexp.wired--;
 	}
 }
+#endif
 
+#ifdef _KERNEL_OPT
 /*
  * uvm_pagedeactivate: deactivate page
  *
@@ -1912,7 +1674,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 +1700,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 +1717,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 +1735,9 @@ uvm_pageenqueue(struct vm_page *pg)
 	}
 	uvmpdpol_pageenqueue(pg);
 }
+#endif
 
+#ifdef _KERNEL_OPT
 /*
  * uvm_pagezero: zero fill a page
  *
@@ -1981,6 +1751,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
@@ -2019,9 +1790,10 @@ uvm_page_lookup_freelist(struct vm_page *pg)
 
 	lcv = vm_physseg_find(atop(VM_PAGE_TO_PHYS(pg)), NULL);
 	KASSERT(lcv != -1);
-	return (VM_PHYSMEM_PTR(lcv)->free_list);
+	return uvm_physmem_get_free_list(lcv);
 }
 
+#ifdef _KERNEL_OPT
 /*
  * uvm_page_locked_p: return true if object associated with page is
  * locked.  this is a weak check for runtime assertions only.
@@ -2039,6 +1811,7 @@ uvm_page_locked_p(struct vm_page *pg)
 	}
 	return true;
 }
+#endif
 
 #if defined(DDB) || defined(DEBUGPRINT)
 
@@ -2136,6 +1909,7 @@ void
 uvm_page_printall(void (*pr)(const char *, ...))
 {
 	unsigned i;
+	paddr_t pfn;
 	struct vm_page *pg;
 
 	(*pr)("%18s %4s %4s %18s %18s"
@@ -2143,8 +1917,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_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);
+		     pfn++) {
+			pg = PHYS_TO_VM_PAGE(ptoa(pfn));
+
 			(*pr)("%18p %04x %04x %18p %18p",
 			    pg, pg->flags, pg->pqflags, pg->uobject,
 			    pg->uanon);
diff --git a/sys/uvm/uvm_page.h b/sys/uvm/uvm_page.h
index 8a7529d..c9ee3f8 100644
--- a/sys/uvm/uvm_page.h
+++ b/sys/uvm/uvm_page.h
@@ -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,14 @@ bool uvm_page_locked_p(struct vm_page *);
 
 int uvm_page_lookup_freelist(struct vm_page *);
 
-int vm_physseg_find(paddr_t, int *);
+int vm_physseg_find(paddr_t, psize_t *);
 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
  */
diff --git a/sys/uvm/uvm_pglist.c b/sys/uvm/uvm_pglist.c
index f3e546a..e96f22b 100644
--- a/sys/uvm/uvm_pglist.c
+++ b/sys/uvm/uvm_pglist.c
@@ -116,11 +116,10 @@ uvm_pglist_add(struct vm_page *pg, struct pglist *rlist)
 }
 
 static int
-uvm_pglistalloc_c_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high,
+uvm_pglistalloc_c_ps(int 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
@@ -140,26 +139,26 @@ uvm_pglistalloc_c_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high,
 	/*
 	 * Make sure that physseg falls within with range to be allocated from.
 	 */
-	if (high <= ps->avail_start || low >= ps->avail_end)
+	if (high <= uvm_physmem_get_avail_start(psi) || low >= uvm_physmem_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_physmem_get_avail_start(psi) +
+		uvm_physmem_get_start_hint(psi)), alignment);
+	limit = min(high, uvm_physmem_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_physmem_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 *ps, int num, paddr_t low, paddr_t high,
 			 * 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_physmem_get_avail_start(psi)), alignment);
+			limit = min(limit, uvm_physmem_get_avail_start(psi) +
+			    uvm_physmem_get_start_hint(psi));
 			skip = 0;
 			continue;
 		}
@@ -201,7 +201,7 @@ uvm_pglistalloc_c_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high,
 		if (cidx != candidate - ps->start + num - 1)
 			panic("pgalloc contig: botch4");
 #endif
-		candidateidx = candidate - ps->start;
+		candidateidx = candidate - uvm_physmem_get_start(psi);
 		end = candidateidx + num;
 
 		/*
@@ -220,7 +220,7 @@ uvm_pglistalloc_c_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high,
 		 * 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_physmem_get_pg(psi, idx)) == 0) {
 				ok = false;
 				break;
 			}
@@ -228,7 +228,7 @@ uvm_pglistalloc_c_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high,
 #ifdef DEBUG
 			if (idx > candidateidx) {
 				idxpa = VM_PAGE_TO_PHYS(&pgs[idx]);
-				lastidxpa = VM_PAGE_TO_PHYS(&pgs[idx - 1]);
+				lastidxpa = VM_PAGE_TO_PHYS(uvm_physmem_get_pg(psi, idx));
 				if ((lastidxpa + PAGE_SIZE) != idxpa) {
 					/*
 					 * Region not contiguous.
@@ -249,7 +249,7 @@ uvm_pglistalloc_c_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high,
 
 		if (ok) {
 			while (skip-- > 0) {
-				KDASSERT(VM_PAGE_IS_FREE(&pgs[candidateidx + skip]));
+				KDASSERT(VM_PAGE_IS_FREE(uvm_physmem_get_pg(psi, candidateidx + skip)));
 			}
 #ifdef PGALLOC_VERBOSE
 			printf(": ok\n");
@@ -280,19 +280,22 @@ uvm_pglistalloc_c_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high,
 	/*
 	 * 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_physmem_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_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),
 	    "%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_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));
 
 #ifdef PGALLOC_VERBOSE
 	printf("got %d pgs\n", num);
@@ -305,7 +308,6 @@ 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 error;
 
 	/* Default to "lose". */
@@ -322,17 +324,16 @@ uvm_pglistalloc_contig(int num, paddr_t low, paddr_t high, paddr_t alignment,
 
 	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_physmem_get_last(); uvm_physmem_valid(psi); psi = uvm_physmem_get_prev(psi))
+			 
 #else
-		for (psi = 0 ; psi < vm_nphysseg ; psi++)
+		for (psi = uvm_physmem_get_first(); uvm_physmem_valid(psi); psi = uvm_physmem_get_next(psi))
 #endif
 		{
-			ps = &vm_physmem[psi];
-
-			if (ps->free_list != fl)
+			if (uvm_physmem_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,7 +359,7 @@ out:
 }
 
 static int
-uvm_pglistalloc_s_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high,
+uvm_pglistalloc_s_ps(int psi, int num, paddr_t low, paddr_t high,
     struct pglist *rlist)
 {
 	int todo, limit, candidate;
@@ -369,36 +370,39 @@ uvm_pglistalloc_s_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high,
 #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_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));
 
 	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_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));
 	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_physmem_get_avail_start(psi) ||
+	    low >= uvm_physmem_get_avail_end(psi))
 		return 0;
 
 again:
 	for (;; candidate++, pg++) {
 		if (candidate >= limit) {
-			if (ps->start_hint == 0 || second_pass) {
+			if (uvm_physmem_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_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));
 			goto again;
 		}
 #if defined(DEBUG)
@@ -426,12 +430,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_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),
 	    "%#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_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));
 
 #ifdef PGALLOC_VERBOSE
 	printf("got %d pgs\n", num - todo);
@@ -444,7 +452,6 @@ uvm_pglistalloc_simple(int num, paddr_t low, paddr_t high,
     struct pglist *rlist, int waitok)
 {
 	int fl, psi, error;
-	struct vm_physseg *ps;
 
 	/* Default to "lose". */
 	error = ENOMEM;
@@ -461,17 +468,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_physmem_get_last(); uvm_physmem_valid(psi); psi = uvm_physmem_get_prev(psi))
+			 
 #else
-		for (psi = 0 ; psi < vm_nphysseg ; psi++)
+		for (psi = uvm_physmem_get_first(); uvm_physmem_valid(psi); psi = uvm_physmem_get_next(psi))
 #endif
 		{
-			ps = &vm_physmem[psi];
-
-			if (ps->free_list != fl)
+			if (uvm_physmem_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;
diff --git a/sys/uvm/uvm_physmem.c b/sys/uvm/uvm_physmem.c
new file mode 100644
index 0000000..6da418b
--- /dev/null
+++ b/sys/uvm/uvm_physmem.c
@@ -0,0 +1,620 @@
+/* $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@localhost
+ *  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@localhost>
+ */
+
+#ifdef _KERNEL_OPT
+#include "opt_uvm.h"
+#endif
+
+#include <sys/types.h>
+
+#include <uvm/uvm.h>
+#include <uvm/uvm_page.h>
+#include <uvm/uvm_pdpolicy.h>
+#include <uvm/uvm_physmem.h>
+
+/*
+ * 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
+
+/*
+ * 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
+};
+
+
+static struct vm_physseg vm_physmem[VM_PHYSSEG_MAX];	/* XXXCDC: uvm.physmem */
+static int vm_nphysseg;				/* XXXCDC: uvm.nphysseg */
+#define	vm_nphysmem	vm_nphysseg
+
+void
+uvm_physmem_init_seg(int lcv, struct vm_page *pgs)
+{
+	psize_t i;
+	psize_t n;
+	paddr_t paddr;
+	struct vm_physseg *seg;
+
+	KASSERT(lcv >= 0 && lcv < vm_nphysmem);
+
+	seg = VM_PHYSMEM_PTR(lcv);
+
+	KASSERT(seg->pgs == NULL);
+
+	n = seg->end - seg->start;
+	n = ((n + 1) << PAGE_SHIFT) /
+	    (PAGE_SIZE + sizeof(struct vm_page));
+
+	seg->pgs = pgs;
+	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]);
+		}
+	}
+}
+
+/*
+ * Boot protocol dictates that these must be able to return partially
+ * initialised segments.
+ */
+paddr_t
+uvm_physmem_get_start(int lcv)
+{
+	if (uvm_physmem_valid(lcv) == false)
+		return (paddr_t) -1;
+
+	return VM_PHYSMEM_PTR(lcv)->start;
+}
+
+paddr_t
+uvm_physmem_get_end(int lcv)
+{
+	if (uvm_physmem_valid(lcv) == false)
+		return (paddr_t) -1;
+
+	return VM_PHYSMEM_PTR(lcv)->end;
+}
+
+paddr_t
+uvm_physmem_get_avail_start(int lcv)
+{
+	if (uvm_physmem_valid(lcv) == false)
+		return (paddr_t) -1;
+
+	return VM_PHYSMEM_PTR(lcv)->avail_start;
+}
+
+paddr_t
+uvm_physmem_get_avail_end(int lcv)
+{
+	if (uvm_physmem_valid(lcv) == false)
+		return (paddr_t) -1;
+
+	return VM_PHYSMEM_PTR(lcv)->avail_end;
+}
+
+struct vm_page *
+uvm_physmem_get_pg(int lcv, paddr_t idx)
+{
+	return &VM_PHYSMEM_PTR(lcv)->pgs[idx];
+}
+
+int
+uvm_physmem_get_free_list(int lcv)
+{
+	return VM_PHYSMEM_PTR(lcv)->free_list;
+}
+
+u_int
+uvm_physmem_get_start_hint(int lcv)
+{
+	return VM_PHYSMEM_PTR(lcv)->start_hint;
+}
+
+bool
+uvm_physmem_set_start_hint(int lcv, u_int start_hint)
+{
+	if (uvm_physmem_valid(lcv) == false)
+		return false;
+
+	VM_PHYSMEM_PTR(lcv)->start_hint = start_hint;
+	return true;
+}
+
+int
+uvm_physmem_get_next(int lcv)
+{
+	return (lcv + 1);
+}
+
+int
+uvm_physmem_get_prev(int lcv)
+{
+	return (lcv - 1);
+}
+
+int
+uvm_physmem_get_last(void)
+{
+	return (vm_nphysseg - 1);
+}
+
+int
+uvm_physmem_get_first(void)
+{
+	return 0;
+}
+
+bool
+uvm_physmem_valid(int lcv)
+{
+	struct vm_physseg *ps;
+
+	if (lcv < 0)
+		return false;
+
+	if (lcv >= vm_nphysseg)
+		return false;
+
+	/*
+	 * This is the delicate init dance -
+	 * needs to go with the dance.
+	 */
+	if (uvm.page_init_done != true)
+		return true;
+	
+	ps = VM_PHYSMEM_PTR(lcv);
+
+	/* Extra checks needed only post uvm_page_init() */
+	if (ps->pgs == NULL)
+		return false;
+
+	if (ps->lastpg == NULL)
+		return false;
+
+	/* XXX: etc. */
+
+	return true;
+
+}
+
+
+paddr_t
+uvm_physmem_get_highest(void)
+{
+	int lcv;
+	paddr_t last = 0;
+	struct vm_physseg *ps;
+
+	for (lcv = 0; lcv < vm_nphysseg; lcv++) {
+		ps = VM_PHYSMEM_PTR(lcv);
+		if (last < ps->end)
+			last = ps->end;
+	}
+
+	return last;
+}
+
+#if !defined(PMAP_STEAL_MEMORY)
+
+/*
+ * uvm_page_physunload: unload physical memory and return it to
+ * caller.
+ */
+bool
+uvm_page_physunload(int psi, int freelist, paddr_t *paddrp)
+{
+	int x;
+	struct vm_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++;
+		/* 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--;
+		/* 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(int psi, int freelist, paddr_t *paddrp)
+{
+	int x;
+	struct vm_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++;
+
+	/* 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);
+}
+
+#endif /* !defined(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) {
+		npages = end - start;
+		pgs = kmem_zalloc(sizeof *pgs * npages, KM_SLEEP);
+	} 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;
+
+	ps->pgs = pgs;
+	ps->lastpg = pgs + npages;
+
+	ps->free_list = free_list;
+	vm_nphysmem++;
+
+	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]);
+			}
+		}
+
+		physmem += npages;
+
+		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, 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
+
+/*
+ * vm_physseg_find: find vm_physseg structure that belongs to a PA
+ */
+int
+vm_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 vm_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 vm_physseg *segs, int nsegs, paddr_t pframe, psize_t *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, 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
diff --git a/sys/uvm/uvm_physmem.h b/sys/uvm/uvm_physmem.h
new file mode 100644
index 0000000..016567b
--- /dev/null
+++ b/sys/uvm/uvm_physmem.h
@@ -0,0 +1,66 @@
+/* $NetBSD$ */
+
+/*
+ * Consolidated API from uvm_page.c and others.
+ * Consolidated and designed by Cherry G. Mathew <cherry%zyx.in@localhost>
+ */
+
+#ifndef _UVM_UVM_PHYSMEM_H_
+#define _UVM_UVM_PHYSMEM_H_
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+
+/*
+ * We expect machine/uvm_physseg.h to include all API calls required
+ * to implement this API.
+ *
+ * No APIs are explicitly #included in uvm_physmem.c
+ */
+
+#include <machine/uvm_physmem.h>
+
+void uvm_physmem_init_seg(int, struct vm_page *);
+
+bool uvm_physmem_valid(int);
+
+/*
+ * Return start/end pfn of given segment
+ * Returns: -1 if the segment number is invalid
+ */
+paddr_t uvm_physmem_get_start(int);
+paddr_t uvm_physmem_get_end(int);
+
+paddr_t uvm_physmem_get_avail_start(int);
+paddr_t uvm_physmem_get_avail_end(int);
+
+struct vm_page * uvm_physmem_get_pg(int, paddr_t);
+
+int uvm_physmem_get_free_list(int);
+u_int uvm_physmem_get_start_hint(int);
+bool uvm_physmem_set_start_hint(int, u_int);
+
+/*
+ * Functions to help walk the list of segments.
+ * Returns: -1 if the segment number is invalid
+ */
+int uvm_physmem_get_next(int);
+int uvm_physmem_get_prev(int);
+int uvm_physmem_get_first(void);
+int uvm_physmem_get_last(void);
+
+
+/* Return the frame number of the highest registered physical page frame */
+paddr_t uvm_physmem_get_highest(void);
+
+/* 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);
+
+#if !defined(PMAP_STEAL_MEMORY)
+bool uvm_page_physunload(int, int, paddr_t *);
+bool uvm_page_physunload_force(int, int, paddr_t *);
+#endif /* !defined(PMAP_STEAL_MEMORY) */
+int vm_physseg_find(paddr_t, psize_t *);
+
+#endif /* _UVM_UVM_PHYSMEM_H_ */



Home | Main Index | Thread Index | Old Index