diff --git a/sys/platform/pc32/i386/pmap.c b/sys/platform/pc32/i386/pmap.c
index b07f2cf..af3b2e2 100644
--- a/sys/platform/pc32/i386/pmap.c
+++ b/sys/platform/pc32/i386/pmap.c
@@ -213,6 +213,7 @@ static vm_page_t pmap_allocpte (pmap_t pmap, vm_offset_t va);
 static int pmap_release_free_page (pmap_t pmap, vm_page_t p);
 static vm_page_t _pmap_allocpte (pmap_t pmap, unsigned ptepindex);
 static unsigned * pmap_pte_quick (pmap_t pmap, vm_offset_t va);
+static void ptbase_assert (pmap_t pmap);
 static vm_page_t pmap_page_lookup (vm_object_t object, vm_pindex_t pindex);
 static int pmap_unuse_pt (pmap_t, vm_offset_t, vm_page_t, pmap_inval_info_t);
 static vm_offset_t pmap_kmem_choose(vm_offset_t addr);
@@ -554,6 +555,18 @@ pmap_init2(void)
  * Low level helper routines.....
  ***************************************************/
 
+static void
+test_m_maps_pv(vm_page_t m, pv_entry_t pv)
+{
+	pv_entry_t spv;
+
+	TAILQ_FOREACH(spv, &m->md.pv_list, pv_list) {
+		if (pv == spv)
+			return;
+	}
+	panic("test_m_maps_pv: failed m %p pv %p\n", m, pv);
+}
+
 #if defined(PMAP_DIAGNOSTIC)
 
 /*
@@ -611,6 +624,18 @@ get_ptbase(pmap_t pmap)
 	return (unsigned *) APTmap;
 }
 
+static void
+ptbase_assert(struct pmap *pmap)
+{
+	unsigned frame = (unsigned) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
+
+	/* are we current address space or kernel? */
+	if (pmap == &kernel_pmap || frame == (((unsigned)PTDpde) & PG_FRAME)) {
+		return;
+	}
+	KKASSERT(frame == (((unsigned)APTDpde) & PG_FRAME));
+}
+
 /*
  * pmap_extract:
  *
@@ -980,6 +1005,8 @@ pmap_unwire_pte_hold(pmap_t pmap, vm_page_t m, pmap_inval_info_t info)
 /*
  * After removing a page table entry, this routine is used to
  * conditionally free the page, and manage the hold/wire counts.
+ *
+ * WARNING:  This function can block
  */
 static int
 pmap_unuse_pt(pmap_t pmap, vm_offset_t va, vm_page_t mpte,
@@ -1066,6 +1093,8 @@ pmap_pinit(struct pmap *pmap)
 	}
 	if ((ptdpg->flags & PG_ZERO) == 0)
 		bzero(pmap->pm_pdir, PAGE_SIZE);
+	else
+		pmap_page_assertzero(VM_PAGE_TO_PHYS(ptdpg));
 
 	pmap->pm_pdir[MPPTDI] = PTD[MPPTDI];
 
@@ -1253,6 +1282,8 @@ _pmap_allocpte(pmap_t pmap, unsigned ptepindex)
 		} else {
 			pmap_zero_page(ptepa);
 		}
+	} else {
+		pmap_page_assertzero(VM_PAGE_TO_PHYS(m));
 	}
 
 	m->valid = VM_PAGE_BITS_ALL;
@@ -1552,13 +1583,16 @@ pmap_remove_entry(struct pmap *pmap, vm_page_t m,
 		}
 	} else {
 		TAILQ_FOREACH(pv, &pmap->pm_pvlist, pv_plist) {
-			if (va == pv->pv_va) 
+			KKASSERT(pv->pv_pmap == pmap);
+			if (va == pv->pv_va)
 				break;
 		}
 	}
+	KKASSERT(pv);
 
 	rtval = 0;
 	if (pv) {
+		test_m_maps_pv(m, pv);
 		TAILQ_REMOVE(&m->md.pv_list, pv, pv_list);
 		m->md.pv_list_count--;
 		if (TAILQ_EMPTY(&m->md.pv_list))
@@ -1589,22 +1623,28 @@ pmap_insert_entry(pmap_t pmap, vm_offset_t va, vm_page_t mpte, vm_page_t m)
 
 	TAILQ_INSERT_TAIL(&pmap->pm_pvlist, pv, pv_plist);
 	TAILQ_INSERT_TAIL(&m->md.pv_list, pv, pv_list);
+	++pmap->pm_generation;
 	m->md.pv_list_count++;
 
 	crit_exit();
 }
 
 /*
- * pmap_remove_pte: do the things to unmap a page in a process
+ * pmap_remove_pte: do the things to unmap a page in a process.
+ *
+ * WARNING: This function may block (via pmap_remove_entry/pmap_unuse_pt),
+ *	    callers using temporary pmaps must reload them.
  */
 static int
 pmap_remove_pte(struct pmap *pmap, unsigned *ptq, vm_offset_t va,
-	pmap_inval_info_t info)
+		pmap_inval_info_t info)
 {
 	unsigned oldpte;
 	vm_page_t m;
 
+	ptbase_assert(pmap);
 	pmap_inval_add(info, pmap, va);
+	ptbase_assert(pmap);
 	oldpte = loadandclear(ptq);
 	KKASSERT(oldpte);
 	if (oldpte & PG_W)
@@ -1644,10 +1684,10 @@ pmap_remove_pte(struct pmap *pmap, unsigned *ptq, vm_offset_t va,
 /*
  * pmap_remove_page:
  *
- *	Remove a single page from a process address space.
+ * Remove a single page from a process address space.
  *
- *	This function may not be called from an interrupt if the pmap is
- *	not kernel_pmap.
+ * This function may not be called from an interrupt if the pmap is
+ * not kernel_pmap.
  */
 static void
 pmap_remove_page(struct pmap *pmap, vm_offset_t va, pmap_inval_info_t info)
@@ -1662,6 +1702,7 @@ pmap_remove_page(struct pmap *pmap, vm_offset_t va, pmap_inval_info_t info)
 		ptq = get_ptbase(pmap) + i386_btop(va);
 		if (*ptq) {
 			pmap_remove_pte(pmap, ptq, va, info);
+			/* ptq invalid */
 		}
 	}
 }
@@ -1748,7 +1789,8 @@ pmap_remove(struct pmap *pmap, vm_offset_t sva, vm_offset_t eva)
 		}
 
 		/*
-		 * NOTE: pmap_remove_pte() can block.
+		 * NOTE: pmap_remove_pte() can block and wipe the temporary
+		 *	 ptbase.
 		 */
 		for (; sindex != pdnxt; sindex++) {
 			vm_offset_t va;
@@ -1792,7 +1834,7 @@ pmap_remove_all(vm_page_t m)
 		pte = pmap_pte_quick(pv->pv_pmap, pv->pv_va);
 		pmap_inval_add(&info, pv->pv_pmap, pv->pv_va);
 		tpte = loadandclear(pte);
-
+		KKASSERT(PHYS_TO_VM_PAGE(tpte) == m);
 		if (tpte & PG_W)
 			pv->pv_pmap->pm_stats.wired_count--;
 
@@ -2049,12 +2091,28 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
 	/*
 	 * Mapping has changed, invalidate old range and fall through to
 	 * handle validating new mapping.
+	 *
+	 * Since we have a ref on the page directory page pmap_pte()
+	 * will always return non-NULL.
+	 *
+	 * NOTE: pmap_remove_pte() can block and cause the temporary ptbase
+	 *	 to get wiped.  reload the ptbase.  I'm not sure if it is
+	 *	 also possible to race another pmap_enter() but check for
+	 *	 that case too.
 	 */
-	if (opa) {
+	while (opa) {
 		int err;
+
 		err = pmap_remove_pte(pmap, pte, va, &info);
 		if (err)
 			panic("pmap_enter: pte vanished, va: %p", (void *)va);
+		pte = pmap_pte(pmap, va);
+		origpte = *(vm_offset_t *)pte;
+		opa = origpte & PG_FRAME;
+		if (opa) {
+			kprintf("pmap_enter: Warning, raced pmap %p va %p\n",
+				pmap, (void *)va);
+		}
 	}
 
 	/*
@@ -2065,6 +2123,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
 	if (pmap_initialized && 
 	    (m->flags & (PG_FICTITIOUS|PG_UNMANAGED)) == 0) {
 		pmap_insert_entry(pmap, va, mpte, m);
+		ptbase_assert(pmap);
 		pa |= PG_MANAGED;
 		vm_page_flag_set(m, PG_MAPPED);
 	}
@@ -2080,6 +2139,7 @@ validate:
 	/*
 	 * Now validate mapping with desired protection/wiring.
 	 */
+	ptbase_assert(pmap);
 	newpte = (vm_offset_t) (pa | pte_prot(pmap, prot) | PG_V);
 
 	if (wired)
@@ -2095,6 +2155,7 @@ validate:
 	 */
 	if ((origpte & ~(PG_M|PG_A)) != newpte) {
 		pmap_inval_add(&info, pmap, va);
+		ptbase_assert(pmap);
 		*pte = newpte | PG_A;
 		if (newpte & PG_RW)
 			vm_page_flag_set(m, PG_WRITEABLE);
@@ -2842,6 +2903,7 @@ pmap_remove_pages(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
 			pte = (unsigned *)vtopte(pv->pv_va);
 		else
 			pte = pmap_pte_quick(pmap, pv->pv_va);
+		KKASSERT(*pte);
 		if (pmap->pm_active)
 			pmap_inval_add(&info, pmap, pv->pv_va);
 
@@ -2857,6 +2919,7 @@ pmap_remove_pages(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
 		tpte = loadandclear(pte);
 
 		m = PHYS_TO_VM_PAGE(tpte);
+		test_m_maps_pv(m, pv);
 
 		KASSERT(m < &vm_page_array[vm_page_array_size],
 			("pmap_remove_pages: bad tpte %x", tpte));
@@ -2889,7 +2952,7 @@ pmap_remove_pages(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
 		 */
 		if (save_generation != pmap->pm_generation) {
 			kprintf("Warning: pmap_remove_pages race-A avoided\n");
-			pv = TAILQ_FIRST(&pmap->pm_pvlist);
+			npv = TAILQ_FIRST(&pmap->pm_pvlist);
 		}
 	}
 	pmap_inval_flush(&info);
diff --git a/sys/platform/pc32/include/pmap.h b/sys/platform/pc32/include/pmap.h
index f512940..680986d 100644
--- a/sys/platform/pc32/include/pmap.h
+++ b/sys/platform/pc32/include/pmap.h
@@ -82,13 +82,25 @@
  * right after I fix locore.s and the magic 28K hole
  *
  * SMP_PRIVPAGES: The per-cpu address space is 0xff80000 -> 0xffbfffff
+ *
+ * NPEDEPG	- number of pde's in the page directory (1024)
+ * NKPDE	- typically (KVA_PAGES - 2) where KVA_PAGES is typically 256
+ *
+ * This typically places PTDPTDI at the index corresponding to VM address
+ * (0xc0000000 - 4M) = bfc00000, and that is where PTmap[] is based.
+ *
+ * APTmap[] is typically based at 0xffc00000 corresponding to the page
+ * directory index of APTDPTDI.  APTDpde is self-mapped at 0xbfeffffc,
+ * the last pde entry in the pmap's page directory just before the
+ * kernel pde's start.
+ *
+ * UMAXPTDI	- highest inclusive ptd index for user space
  */
 #define	APTDPTDI	(NPDEPG-1)	/* alt ptd entry that points to APTD */
 #define MPPTDI		(APTDPTDI-1)	/* per cpu ptd entry */
 #define	KPTDI		(MPPTDI-NKPDE)	/* start of kernel virtual pde's */
 #define	PTDPTDI		(KPTDI-1)	/* ptd entry that points to ptd! */
 #define	UMAXPTDI	(PTDPTDI-1)	/* ptd entry for user space end */
-#define	UMAXPTEOFF	(NPTEPG)	/* pte entry for user space end */
 
 /*
  * XXX doesn't really belong here I guess...
diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h
index 9c312ed..e1593e7 100644
--- a/sys/vm/vm_page.h
+++ b/sys/vm/vm_page.h
@@ -621,6 +621,9 @@ vm_page_free_zero(vm_page_t m)
 	}
 
 #endif
+#ifdef INVARIANTS
+	pmap_page_assertzero(VM_PAGE_TO_PHYS(m));
+#endif
 	vm_page_flag_set(m, PG_ZERO);
 	vm_page_free_toq(m);
 }
