svn commit: r210846 - in head/sys/mips: include mips

Jayachandran C. jchandra at FreeBSD.org
Wed Aug 4 14:12:10 UTC 2010


Author: jchandra
Date: Wed Aug  4 14:12:09 2010
New Revision: 210846
URL: http://svn.freebsd.org/changeset/base/210846

Log:
  Add 3 level page tables for MIPS in n64.
  
  - 32 bit compilation will still use old 2 level page tables
  - re-arrange pmap code so that adding another level is easier
  - pmap code for 3 level page tables for n64
  - update TLB handler to traverse 3 levels in n64
  
  Reviewed by:	jmallett

Modified:
  head/sys/mips/include/param.h
  head/sys/mips/include/vmparam.h
  head/sys/mips/mips/exception.S
  head/sys/mips/mips/genassym.c
  head/sys/mips/mips/pmap.c

Modified: head/sys/mips/include/param.h
==============================================================================
--- head/sys/mips/include/param.h	Wed Aug  4 14:03:23 2010	(r210845)
+++ head/sys/mips/include/param.h	Wed Aug  4 14:12:09 2010	(r210846)
@@ -107,8 +107,18 @@
 #define	NPTEPG		(PAGE_SIZE/(sizeof (pt_entry_t)))
 #define	NPDEPG		(PAGE_SIZE/(sizeof (pd_entry_t)))
 
+#if defined(__mips_n64)
+#define	SEGSHIFT	31		/* LOG2(NBSEG) */
+#define	NBSEG		(1ul << SEGSHIFT)	/* bytes/segment */
+#define	PDRSHIFT	22              /* second level */
+#define	PDRMASK		((1 << PDRSHIFT) - 1)
+#else
 #define	SEGSHIFT	22		/* LOG2(NBSEG) */
 #define	NBSEG		(1 << SEGSHIFT)	/* bytes/segment */
+#define	PDRSHIFT	SEGSHIFT	/* alias for SEG in 32 bit */
+#define	PDRMASK		((1 << PDRSHIFT) - 1)
+#endif
+#define	NBPDR		(1 << PDRSHIFT)	/* bytes/pagedir */
 #define	SEGMASK		(NBSEG-1)	/* byte offset into segment */
 
 #define	MAXPAGESIZES	1		/* maximum number of supported page sizes */
@@ -119,7 +129,7 @@
 /*
  * The kernel stack needs to be aligned on a (PAGE_SIZE * 2) boundary.
  */
-#define	KSTACK_PAGES		2	/* kernel stack*/
+#define	KSTACK_PAGES		2	/* kernel stack */
 #define	KSTACK_GUARD_PAGES	2	/* pages of kstack guard; 0 disables */
 
 #define	UPAGES			2

Modified: head/sys/mips/include/vmparam.h
==============================================================================
--- head/sys/mips/include/vmparam.h	Wed Aug  4 14:03:23 2010	(r210845)
+++ head/sys/mips/include/vmparam.h	Wed Aug  4 14:12:09 2010	(r210846)
@@ -185,7 +185,7 @@
  *	  allocations use HIGHMEM if available, and then DEFAULT. 
  *	- HIGHMEM for other pages 
  */
-#ifdef __mips_n64
+#if 0 /* Not yet, change n64 to use xkphys */
 #define	VM_NFREELIST		1
 #define	VM_FREELIST_DEFAULT	0
 #define	VM_FREELIST_DIRECT	VM_FREELIST_DEFAULT

Modified: head/sys/mips/mips/exception.S
==============================================================================
--- head/sys/mips/mips/exception.S	Wed Aug  4 14:03:23 2010	(r210845)
+++ head/sys/mips/mips/exception.S	Wed Aug  4 14:12:09 2010	(r210846)
@@ -137,7 +137,15 @@ MipsDoTLBMiss:
 	PTR_L		k1, 0(k1)			#08: k1=seg entry
 	MFC0		k0, MIPS_COP_0_BAD_VADDR	#09: k0=bad address (again)
 	beq		k1, zero, 2f			#0a: ==0 -- no page table
-	srl		k0, PAGE_SHIFT - 2		#0b: k0=VPN (aka va>>10)
+#ifdef __mips_n64
+	PTR_SRL		k0, PDRSHIFT - PTRSHIFT		# k0=VPN
+	andi		k0, k0, PTRMASK			# k0=pde offset
+	PTR_ADDU	k1, k0, k1			# k1=pde entry address
+	PTR_L		k1, 0(k1)			# k1=pde entry
+	MFC0		k0, MIPS_COP_0_BAD_VADDR	# k0=bad address (again)
+	beq		k1, zero, 2f			# ==0 -- no page table
+#endif
+	PTR_SRL		k0, PAGE_SHIFT - 2		#0b: k0=VPN (aka va>>10)
 	andi		k0, k0, 0xff8			#0c: k0=page tab offset
 	PTR_ADDU	k1, k1, k0			#0d: k1=pte address
 	lw		k0, 0(k1)			#0e: k0=lo0 pte
@@ -836,6 +844,18 @@ NLEAF(MipsTLBInvalidException)
 	beqz		k1, 3f
 	nop
 
+#ifdef __mips_n64
+	MFC0		k0, MIPS_COP_0_BAD_VADDR
+	PTR_SRL		k0, PDRSHIFT - PTRSHIFT		# k0=pde offset (almost)
+	beq		k1, zero, MipsKernGenException	# ==0 -- no pde tab
+	andi		k0, k0, PTRMASK			# k0=pde offset
+	PTR_ADDU	k1, k0, k1			# k1=pde entry address
+	PTR_L		k1, 0(k1)			# k1=pde entry
+
+	/* Validate pde table pointer.  */
+	beqz		k1, 3f
+	nop
+#endif
 	MFC0		k0, MIPS_COP_0_BAD_VADDR	# k0=bad address (again)
 	PTR_SRL		k0, PAGE_SHIFT - 2		# k0=VPN
 	andi		k0, k0, 0xffc			# k0=page tab offset
@@ -996,6 +1016,14 @@ NLEAF(MipsTLBMissException)
 	PTR_L		k1, 0(k1)			# k1=seg entry
 	MFC0		k0, MIPS_COP_0_BAD_VADDR	# k0=bad address (again)
 	beq		k1, zero, MipsKernGenException	# ==0 -- no page table
+#ifdef __mips_n64
+	PTR_SRL		k0, PDRSHIFT - PTRSHIFT		# k0=VPN
+	andi		k0, k0, PTRMASK			# k0=pde offset
+	PTR_ADDU	k1, k0, k1			# k1=pde entry address
+	PTR_L		k1, 0(k1)			# k1=pde entry
+	MFC0		k0, MIPS_COP_0_BAD_VADDR	# k0=bad address (again)
+  	beq		k1, zero, MipsKernGenException	# ==0 -- no page table
+#endif
 	PTR_SRL		k0, PAGE_SHIFT - 2		# k0=VPN
 	andi		k0, k0, 0xff8			# k0=page tab offset
 	PTR_ADDU	k1, k1, k0			# k1=pte address

Modified: head/sys/mips/mips/genassym.c
==============================================================================
--- head/sys/mips/mips/genassym.c	Wed Aug  4 14:03:23 2010	(r210845)
+++ head/sys/mips/mips/genassym.c	Wed Aug  4 14:12:09 2010	(r210846)
@@ -93,6 +93,7 @@ ASSYM(SIGFPE, SIGFPE);
 ASSYM(PAGE_SHIFT, PAGE_SHIFT);
 ASSYM(PAGE_SIZE, PAGE_SIZE);
 ASSYM(PAGE_MASK, PAGE_MASK);
+ASSYM(PDRSHIFT, PDRSHIFT);
 ASSYM(SEGSHIFT, SEGSHIFT);
 ASSYM(NPTEPG, NPTEPG);
 ASSYM(TDF_NEEDRESCHED, TDF_NEEDRESCHED);

Modified: head/sys/mips/mips/pmap.c
==============================================================================
--- head/sys/mips/mips/pmap.c	Wed Aug  4 14:03:23 2010	(r210845)
+++ head/sys/mips/mips/pmap.c	Wed Aug  4 14:12:09 2010	(r210846)
@@ -69,6 +69,8 @@
 __FBSDID("$FreeBSD$");
 
 #include "opt_msgbuf.h"
+#include "opt_ddb.h"
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/proc.h>
@@ -76,6 +78,9 @@ __FBSDID("$FreeBSD$");
 #include <sys/vmmeter.h>
 #include <sys/mman.h>
 #include <sys/smp.h>
+#ifdef DDB
+#include <ddb/ddb.h>
+#endif
 
 #include <vm/vm.h>
 #include <vm/vm_param.h>
@@ -125,22 +130,20 @@ __FBSDID("$FreeBSD$");
  *     is defined such that it ends immediately after NPDEPG*NPTEPG*PAGE_SIZE,
  *     so we end up getting NUSERPGTBLS of 0.
  */
-#define	pmap_segshift(v)	(((v) >> SEGSHIFT) & (NPDEPG - 1))
-#define	segtab_pde(m, v)	((m)[pmap_segshift((v))])
-
-#if defined(__mips_n64)
-#define	NUSERPGTBLS		(NPDEPG)
+#define	pmap_seg_index(v)	(((v) >> SEGSHIFT) & (NPDEPG - 1))
+#define	pmap_pde_index(v)	(((v) >> PDRSHIFT) & (NPDEPG - 1))
+#define	pmap_pte_index(v)	(((v) >> PAGE_SHIFT) & (NPTEPG - 1))
+#define	pmap_pde_pindex(v)	((v) >> PDRSHIFT)
+
+#ifdef __mips_n64
+#define	NUPDE			(NPDEPG * NPDEPG)
+#define	NUSERPGTBLS		(NUPDE + NPDEPG)
 #else
-#define	NUSERPGTBLS		(pmap_segshift(VM_MAXUSER_ADDRESS))
+#define	NUPDE			(NPDEPG)
+#define	NUSERPGTBLS		(NUPDE)
 #endif
-#define	mips_segtrunc(va)	((va) & ~SEGMASK)
-#define	is_kernel_pmap(x)	((x) == kernel_pmap)
 
-/*
- * Given a virtual address, get the offset of its PTE within its page
- * directory page.
- */
-#define	PDE_OFFSET(va)	(((vm_offset_t)(va) >> PAGE_SHIFT) & (NPTEPG - 1))
+#define	is_kernel_pmap(x)	((x) == kernel_pmap)
 
 struct pmap kernel_pmap_store;
 pd_entry_t *kernel_segmap;
@@ -151,10 +154,9 @@ vm_offset_t virtual_end;	/* VA of last a
 static int nkpt;
 unsigned pmap_max_asid;		/* max ASID supported by the system */
 
-
 #define	PMAP_ASID_RESERVED	0
 
-vm_offset_t kernel_vm_end;
+vm_offset_t kernel_vm_end = VM_MIN_KERNEL_ADDRESS;
 
 static void pmap_asid_alloc(pmap_t pmap);
 
@@ -179,11 +181,10 @@ static void pmap_remove_page(struct pmap
 static void pmap_remove_entry(struct pmap *pmap, vm_page_t m, vm_offset_t va);
 static boolean_t pmap_try_insert_pv_entry(pmap_t pmap, vm_page_t mpte,
     vm_offset_t va, vm_page_t m);
-static __inline void
-pmap_invalidate_page(pmap_t pmap, vm_offset_t va);
+static __inline void pmap_invalidate_page(pmap_t pmap, vm_offset_t va);
+static int _pmap_unwire_pte_hold(pmap_t pmap, vm_offset_t va, vm_page_t m);
 
 static vm_page_t pmap_allocpte(pmap_t pmap, vm_offset_t va, int flags);
-
 static vm_page_t _pmap_allocpte(pmap_t pmap, unsigned ptepindex, int flags);
 static int pmap_unuse_pt(pmap_t, vm_offset_t, vm_page_t);
 static int init_pte_prot(vm_offset_t va, vm_page_t m, vm_prot_t prot);
@@ -259,35 +260,70 @@ static struct local_sysmaps sysmap_lmem[
 	intr_restore(intr)
 #endif
 
-static inline pt_entry_t *
+/*
+ * Page table entry lookup routines.
+ */
+static __inline pd_entry_t *
 pmap_segmap(pmap_t pmap, vm_offset_t va)
 {
-	if (pmap->pm_segtab != NULL)
-		return (segtab_pde(pmap->pm_segtab, va));
-	else
+	return (&pmap->pm_segtab[pmap_seg_index(va)]);
+}
+
+#ifdef __mips_n64
+static __inline pd_entry_t *
+pmap_pdpe_to_pde(pd_entry_t *pdpe, vm_offset_t va)
+{
+	pd_entry_t *pde;
+
+	pde = (pd_entry_t *)*pdpe;
+	return (&pde[pmap_pde_index(va)]);
+}
+
+static __inline pd_entry_t *
+pmap_pde(pmap_t pmap, vm_offset_t va)
+{
+	pd_entry_t *pdpe;
+
+	pdpe = pmap_segmap(pmap, va);
+	if (pdpe == NULL || *pdpe == NULL)
 		return (NULL);
+
+	return (pmap_pdpe_to_pde(pdpe, va));
+}
+#else
+static __inline pd_entry_t *
+pmap_pdpe_to_pde(pd_entry_t *pdpe, vm_offset_t va)
+{
+	return pdpe;
+}
+
+static __inline 
+pd_entry_t *pmap_pde(pmap_t pmap, vm_offset_t va)
+{
+	return pmap_segmap(pmap, va);
+}
+#endif
+
+static __inline pt_entry_t *
+pmap_pde_to_pte(pd_entry_t *pde, vm_offset_t va)
+{
+	pt_entry_t *pte;
+
+	pte = (pt_entry_t *)*pde;
+	return (&pte[pmap_pte_index(va)]);
 }
 
-/*
- *	Routine:	pmap_pte
- *	Function:
- *		Extract the page table entry associated
- *		with the given map/virtual_address pair.
- */
 pt_entry_t *
 pmap_pte(pmap_t pmap, vm_offset_t va)
 {
-	pt_entry_t *pdeaddr;
+	pd_entry_t *pde;
 
-	if (pmap) {
-		pdeaddr = pmap_segmap(pmap, va);
-		if (pdeaddr) {
-			return pdeaddr + PDE_OFFSET(va);
-		}
-	}
-	return ((pt_entry_t *)0);
-}
+	pde = pmap_pde(pmap, va);
+	if (pde == NULL || *pde == NULL)
+		return (NULL);
 
+	return (pmap_pde_to_pte(pde, va));
+}
 
 vm_offset_t
 pmap_steal_memory(vm_size_t size)
@@ -326,12 +362,69 @@ pmap_steal_memory(vm_size_t size)
  * Bootstrap the system enough to run with virtual memory.  This
  * assumes that the phys_avail array has been initialized.
  */
+static void 
+pmap_create_kernel_pagetable(void)
+{
+	int i, j;
+	vm_offset_t ptaddr;
+	pt_entry_t *pte;
+#ifdef __mips_n64
+	pd_entry_t *pde;
+	vm_offset_t pdaddr;
+	int npt, npde;
+#endif
+
+	/*
+	 * Allocate segment table for the kernel
+	 */
+	kernel_segmap = (pd_entry_t *)pmap_steal_memory(PAGE_SIZE);
+
+	/*
+	 * Allocate second level page tables for the kernel
+	 */
+#ifdef __mips_n64
+	npde = howmany(NKPT, NPDEPG);
+	pdaddr = pmap_steal_memory(PAGE_SIZE * npde);
+#endif
+	nkpt = NKPT;
+	ptaddr = pmap_steal_memory(PAGE_SIZE * nkpt);
+
+	/*
+	 * The R[4-7]?00 stores only one copy of the Global bit in the
+	 * translation lookaside buffer for each 2 page entry. Thus invalid
+	 * entrys must have the Global bit set so when Entry LO and Entry HI
+	 * G bits are anded together they will produce a global bit to store
+	 * in the tlb.
+	 */
+	for (i = 0, pte = (pt_entry_t *)ptaddr; i < (nkpt * NPTEPG); i++, pte++)
+		*pte = PTE_G;
+
+#ifdef __mips_n64
+	for (i = 0,  npt = nkpt; npt > 0; i++) {
+		kernel_segmap[i] = (pd_entry_t)(pdaddr + i * PAGE_SIZE);
+		pde = (pd_entry_t *)kernel_segmap[i];
+
+		for (j = 0; j < NPDEPG && npt > 0; j++, npt--)
+			pde[j] = (pd_entry_t)(ptaddr + (i * NPDEPG + j) * PAGE_SIZE);
+	}
+#else
+	for (i = 0, j = pmap_seg_index(VM_MIN_KERNEL_ADDRESS); i < nkpt; i++, j++)
+		kernel_segmap[j] = (pd_entry_t)(ptaddr + (i * PAGE_SIZE));
+#endif
+
+	PMAP_LOCK_INIT(kernel_pmap);
+	kernel_pmap->pm_segtab = kernel_segmap;
+	kernel_pmap->pm_active = ~0;
+	TAILQ_INIT(&kernel_pmap->pm_pvlist);
+	kernel_pmap->pm_asid[0].asid = PMAP_ASID_RESERVED;
+	kernel_pmap->pm_asid[0].gen = 0;
+	kernel_vm_end += nkpt * NPTEPG * PAGE_SIZE;
+}
+
 void
 pmap_bootstrap(void)
 {
-	pt_entry_t *pgtab;
-	pt_entry_t *pte;
-	int i, j;
+	int i;
 #if !defined(__mips_n64)
 	int memory_larger_than_512meg = 0;
 #endif
@@ -440,66 +533,10 @@ again:
 		}
 	}
 #endif
-
-	/*
-	 * Allocate segment table for the kernel
-	 */
-	kernel_segmap = (pd_entry_t *)pmap_steal_memory(PAGE_SIZE);
-
-	/*
-	 * Allocate second level page tables for the kernel
-	 */
-	nkpt = NKPT;
-#if !defined(__mips_n64)
-	if (memory_larger_than_512meg) {
-		/*
-		 * If we have a large memory system we CANNOT afford to hit
-		 * pmap_growkernel() and allocate memory. Since we MAY end
-		 * up with a page that is NOT mappable. For that reason we
-		 * up front grab more. Normall NKPT is 120 (YMMV see pmap.h)
-		 * this gives us 480meg of kernel virtual addresses at the
-		 * cost of 120 pages (each page gets us 4 Meg). Since the
-		 * kernel starts at virtual_avail, we can use this to
-		 * calculate how many entris are left from there to the end
-		 * of the segmap, we want to allocate all of it, which would
-		 * be somewhere above 0xC0000000 - 0xFFFFFFFF which results
-		 * in about 256 entries or so instead of the 120.
-		 */
-		nkpt = (PAGE_SIZE / sizeof(pd_entry_t)) - (virtual_avail >> SEGSHIFT);
-	}
-#endif
-	pgtab = (pt_entry_t *)pmap_steal_memory(PAGE_SIZE * nkpt);
-
-	/*
-	 * The R[4-7]?00 stores only one copy of the Global bit in the
-	 * translation lookaside buffer for each 2 page entry. Thus invalid
-	 * entrys must have the Global bit set so when Entry LO and Entry HI
-	 * G bits are anded together they will produce a global bit to store
-	 * in the tlb.
-	 */
-	for (i = 0, pte = pgtab; i < (nkpt * NPTEPG); i++, pte++)
-		*pte = PTE_G;
-
-	/*
-	 * The segment table contains the KVA of the pages in the second
-	 * level page table.
-	 */
-	for (i = 0, j = (virtual_avail >> SEGSHIFT); i < nkpt; i++, j++)
-		kernel_segmap[j] = (pd_entry_t)(pgtab + (i * NPTEPG));
-
-	/*
-	 * The kernel's pmap is statically allocated so we don't have to use
-	 * pmap_create, which is unlikely to work correctly at this part of
-	 * the boot sequence (XXX and which no longer exists).
-	 */
-	PMAP_LOCK_INIT(kernel_pmap);
-	kernel_pmap->pm_segtab = kernel_segmap;
-	kernel_pmap->pm_active = ~0;
-	TAILQ_INIT(&kernel_pmap->pm_pvlist);
-	kernel_pmap->pm_asid[0].asid = PMAP_ASID_RESERVED;
-	kernel_pmap->pm_asid[0].gen = 0;
+	pmap_create_kernel_pagetable();
 	pmap_max_asid = VMNUM_PIDS;
 	mips_wr_entryhi(0);
+	mips_wr_pagemask(0);
 }
 
 /*
@@ -740,7 +777,6 @@ pmap_kenter(vm_offset_t va, vm_paddr_t p
 	pte = pmap_pte(kernel_pmap, va);
 	opte = *pte;
 	*pte = npte;
-
 	pmap_update_page(kernel_pmap, va, npte);
 }
 
@@ -858,16 +894,49 @@ pmap_qremove(vm_offset_t va, int count)
  * This routine unholds page table pages, and if the hold count
  * drops to zero, then it decrements the wire count.
  */
+static PMAP_INLINE int
+pmap_unwire_pte_hold(pmap_t pmap, vm_offset_t va, vm_page_t m)
+{
+	--m->wire_count;
+	if (m->wire_count == 0)
+		return (_pmap_unwire_pte_hold(pmap, va, m));
+	else
+		return (0);
+}
+
 static int
-_pmap_unwire_pte_hold(pmap_t pmap, vm_page_t m)
+_pmap_unwire_pte_hold(pmap_t pmap, vm_offset_t va, vm_page_t m)
 {
+	pd_entry_t *pde;
 
+	PMAP_LOCK_ASSERT(pmap, MA_OWNED);
 	/*
 	 * unmap the page table page
 	 */
-	pmap->pm_segtab[m->pindex] = 0;
-	--pmap->pm_stats.resident_count;
+#ifdef __mips_n64
+	if (m->pindex < NUPDE)
+		pde = pmap_pde(pmap, va);
+	else
+		pde = pmap_segmap(pmap, va);
+#else
+	pde = pmap_pde(pmap, va);
+#endif
+	*pde = 0;
+	pmap->pm_stats.resident_count--;
+
+#ifdef __mips_n64
+	if (m->pindex < NUPDE) {
+		pd_entry_t *pdp;
+		vm_page_t pdpg;
 
+		/*
+		 * Recursively decrement next level pagetable refcount
+		 */
+		pdp = (pd_entry_t *)*pmap_segmap(pmap, va);
+		pdpg = PHYS_TO_VM_PAGE(MIPS_KSEG0_TO_PHYS(pdp));
+		pmap_unwire_pte_hold(pmap, va, pdpg);
+	}
+#endif
 	if (pmap->pm_ptphint == m)
 		pmap->pm_ptphint = NULL;
 
@@ -879,16 +948,6 @@ _pmap_unwire_pte_hold(pmap_t pmap, vm_pa
 	return (1);
 }
 
-static PMAP_INLINE int
-pmap_unwire_pte_hold(pmap_t pmap, vm_page_t m)
-{
-	--m->wire_count;
-	if (m->wire_count == 0)
-		return (_pmap_unwire_pte_hold(pmap, m));
-	else
-		return (0);
-}
-
 /*
  * After removing a page table entry, this routine is used to
  * conditionally free the page, and manage the hold/wire counts.
@@ -903,17 +962,17 @@ pmap_unuse_pt(pmap_t pmap, vm_offset_t v
 		return (0);
 
 	if (mpte == NULL) {
-		ptepindex = pmap_segshift(va);
+		ptepindex = pmap_pde_pindex(va);
 		if (pmap->pm_ptphint &&
 		    (pmap->pm_ptphint->pindex == ptepindex)) {
 			mpte = pmap->pm_ptphint;
 		} else {
-			pteva = pmap_segmap(pmap, va);
+			pteva = *pmap_pde(pmap, va);
 			mpte = PHYS_TO_VM_PAGE(MIPS_KSEG0_TO_PHYS(pteva));
 			pmap->pm_ptphint = mpte;
 		}
 	}
-	return pmap_unwire_pte_hold(pmap, mpte);
+	return pmap_unwire_pte_hold(pmap, va, mpte);
 }
 
 void
@@ -999,7 +1058,7 @@ pmap_pinit(pmap_t pmap)
 static vm_page_t
 _pmap_allocpte(pmap_t pmap, unsigned ptepindex, int flags)
 {
-	vm_offset_t pteva;
+	vm_offset_t pageva;
 	vm_page_t m;
 
 	KASSERT((flags & (M_NOWAIT | M_WAITOK)) == M_NOWAIT ||
@@ -1029,10 +1088,41 @@ _pmap_allocpte(pmap_t pmap, unsigned pte
 	 * Map the pagetable page into the process address space, if it
 	 * isn't already there.
 	 */
+	pageva = MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(m));
 
-	pteva = MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(m));
+#ifdef __mips_n64
+	if (ptepindex >= NUPDE) {
+		pmap->pm_segtab[ptepindex - NUPDE] = (pd_entry_t)pageva;
+	} else {
+		pd_entry_t *pdep, *pde;
+		int segindex = ptepindex >> (SEGSHIFT - PDRSHIFT);
+		int pdeindex = ptepindex & (NPDEPG - 1);
+		vm_page_t pg;
+		
+		pdep = &pmap->pm_segtab[segindex];
+		if (*pdep == NULL) { 
+			/* recurse for allocating page dir */
+			if (_pmap_allocpte(pmap, NUPDE + segindex, 
+			    flags) == NULL) {
+				/* alloc failed, release current */
+				--m->wire_count;
+				atomic_subtract_int(&cnt.v_wire_count, 1);
+				vm_page_free_zero(m);
+				return (NULL);
+			}
+		} else {
+			pg = PHYS_TO_VM_PAGE(MIPS_KSEG0_TO_PHYS(*pdep));
+			pg->wire_count++;
+		}
+		/* Next level entry */
+		pde = (pd_entry_t *)*pdep;
+		pde[pdeindex] = (pd_entry_t)pageva;
+		pmap->pm_ptphint = m;
+	}
+#else
+	pmap->pm_segtab[ptepindex] = (pd_entry_t)pageva;
+#endif
 	pmap->pm_stats.resident_count++;
-	pmap->pm_segtab[ptepindex] = (pd_entry_t)pteva;
 
 	/*
 	 * Set the page table hint
@@ -1045,7 +1135,7 @@ static vm_page_t
 pmap_allocpte(pmap_t pmap, vm_offset_t va, int flags)
 {
 	unsigned ptepindex;
-	vm_offset_t pteva;
+	pd_entry_t *pde;
 	vm_page_t m;
 
 	KASSERT((flags & (M_NOWAIT | M_WAITOK)) == M_NOWAIT ||
@@ -1055,18 +1145,18 @@ pmap_allocpte(pmap_t pmap, vm_offset_t v
 	/*
 	 * Calculate pagetable page index
 	 */
-	ptepindex = pmap_segshift(va);
+	ptepindex = pmap_pde_pindex(va);
 retry:
 	/*
 	 * Get the page directory entry
 	 */
-	pteva = (vm_offset_t)pmap->pm_segtab[ptepindex];
+	pde = pmap_pde(pmap, va);
 
 	/*
 	 * If the page table page is mapped, we just increment the hold
 	 * count, and activate it.
 	 */
-	if (pteva) {
+	if (pde != NULL && *pde != NULL) {
 		/*
 		 * In order to get the page table page, try the hint first.
 		 */
@@ -1074,7 +1164,7 @@ retry:
 		    (pmap->pm_ptphint->pindex == ptepindex)) {
 			m = pmap->pm_ptphint;
 		} else {
-			m = PHYS_TO_VM_PAGE(MIPS_KSEG0_TO_PHYS(pteva));
+			m = PHYS_TO_VM_PAGE(MIPS_KSEG0_TO_PHYS(*pde));
 			pmap->pm_ptphint = m;
 		}
 		m->wire_count++;
@@ -1087,7 +1177,7 @@ retry:
 		if (m == NULL && (flags & M_WAITOK))
 			goto retry;
 	}
-	return m;
+	return (m);
 }
 
 
@@ -1137,46 +1227,44 @@ void
 pmap_growkernel(vm_offset_t addr)
 {
 	vm_page_t nkpg;
+	pd_entry_t *pde, *pdpe;
 	pt_entry_t *pte;
 	int i;
 
 	mtx_assert(&kernel_map->system_mtx, MA_OWNED);
-	if (kernel_vm_end == 0) {
-		kernel_vm_end = VM_MIN_KERNEL_ADDRESS;
-		nkpt = 0;
-		while (segtab_pde(kernel_segmap, kernel_vm_end)) {
-			kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) &
-			    ~(PAGE_SIZE * NPTEPG - 1);
-			nkpt++;
-			if (kernel_vm_end - 1 >= kernel_map->max_offset) {
-				kernel_vm_end = kernel_map->max_offset;
-				break;
-			}
-		}
-	}
-	addr = (addr + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1);
+	addr = roundup2(addr, NBSEG);
 	if (addr - 1 >= kernel_map->max_offset)
 		addr = kernel_map->max_offset;
 	while (kernel_vm_end < addr) {
-		if (segtab_pde(kernel_segmap, kernel_vm_end)) {
-			kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) &
-			    ~(PAGE_SIZE * NPTEPG - 1);
+		pdpe = pmap_segmap(kernel_pmap, kernel_vm_end);
+#ifdef __mips_n64
+		if (*pdpe == 0) {
+			/* new intermediate page table entry */
+			nkpg = pmap_alloc_pte_page(nkpt, VM_ALLOC_INTERRUPT);
+			if (nkpg == NULL)
+				panic("pmap_growkernel: no memory to grow kernel");
+			*pdpe = (pd_entry_t)MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(nkpg));
+			continue; /* try again */
+		}
+#endif
+		pde = pmap_pdpe_to_pde(pdpe, kernel_vm_end);
+		if (*pde != 0) {
+			kernel_vm_end = (kernel_vm_end + NBPDR) & ~PDRMASK;
 			if (kernel_vm_end - 1 >= kernel_map->max_offset) {
 				kernel_vm_end = kernel_map->max_offset;
 				break;
 			}
 			continue;
 		}
+
 		/*
 		 * This index is bogus, but out of the way
 		 */
- 		nkpg = pmap_alloc_pte_page(nkpt, VM_ALLOC_INTERRUPT);
+		nkpg = pmap_alloc_pte_page(nkpt, VM_ALLOC_INTERRUPT);
 		if (!nkpg)
 			panic("pmap_growkernel: no memory to grow kernel");
-
 		nkpt++;
- 		pte = (pt_entry_t *)MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(nkpg));
-  		segtab_pde(kernel_segmap, kernel_vm_end) = (pd_entry_t)pte;
+		*pde = (pd_entry_t)MIPS_PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(nkpg));
 
 		/*
 		 * The R[4-7]?00 stores only one copy of the Global bit in
@@ -1185,11 +1273,11 @@ pmap_growkernel(vm_offset_t addr)
 		 * Entry LO and Entry HI G bits are anded together they will
 		 * produce a global bit to store in the tlb.
 		 */
-		for (i = 0; i < NPTEPG; i++, pte++)
-			*pte = PTE_G;
+		pte = (pt_entry_t *)*pde;
+		for (i = 0; i < NPTEPG; i++)
+			pte[i] = PTE_G;
 
-		kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) &
-		    ~(PAGE_SIZE * NPTEPG - 1);
+		kernel_vm_end = (kernel_vm_end + NBPDR) & ~PDRMASK;
 		if (kernel_vm_end - 1 >= kernel_map->max_offset) {
 			kernel_vm_end = kernel_map->max_offset;
 			break;
@@ -1480,7 +1568,9 @@ pmap_remove_page(struct pmap *pmap, vm_o
 void
 pmap_remove(struct pmap *pmap, vm_offset_t sva, vm_offset_t eva)
 {
-	vm_offset_t va, nva;
+	vm_offset_t va_next;
+	pd_entry_t *pde, *pdpe;
+	pt_entry_t *pte;
 
 	if (pmap == NULL)
 		return;
@@ -1499,15 +1589,30 @@ pmap_remove(struct pmap *pmap, vm_offset
 		pmap_remove_page(pmap, sva);
 		goto out;
 	}
-	for (va = sva; va < eva; va = nva) {
-		if (pmap_segmap(pmap, va) == NULL) {
-			nva = mips_segtrunc(va + NBSEG);
+	for (; sva < eva; sva = va_next) {
+		pdpe = pmap_segmap(pmap, sva);
+#ifdef __mips_n64
+		if (*pdpe == 0) {
+			va_next = (sva + NBSEG) & ~SEGMASK;
+			if (va_next < sva)
+				va_next = eva;
 			continue;
 		}
-		pmap_remove_page(pmap, va);
-		nva = va + PAGE_SIZE;
-	}
+#endif
+		va_next = (sva + NBPDR) & ~PDRMASK;
+		if (va_next < sva)
+			va_next = eva;
 
+		pde = pmap_pdpe_to_pde(pdpe, sva);
+		if (*pde == 0)
+			continue;
+		if (va_next > eva)
+			va_next = eva;
+		for (pte = pmap_pde_to_pte(pde, sva); sva != va_next; 
+		    pte++, sva += PAGE_SIZE) {
+			pmap_remove_page(pmap, sva);
+		}
+	}
 out:
 	vm_page_unlock_queues();
 	PMAP_UNLOCK(pmap);
@@ -1596,6 +1701,8 @@ void
 pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
 {
 	pt_entry_t *pte;
+	pd_entry_t *pde, *pdpe;
+	vm_offset_t va_next;
 
 	if (pmap == NULL)
 		return;
@@ -1609,44 +1716,53 @@ pmap_protect(pmap_t pmap, vm_offset_t sv
 
 	vm_page_lock_queues();
 	PMAP_LOCK(pmap);
-	while (sva < eva) {
+	for (; sva < eva; sva = va_next) {
 		pt_entry_t pbits, obits;
 		vm_page_t m;
-		vm_offset_t pa;
+		vm_paddr_t pa;
 
-		/*
-		 * If segment table entry is empty, skip this segment.
-		 */
-		if (pmap_segmap(pmap, sva) == NULL) {
-			sva = mips_segtrunc(sva + NBSEG);
+		pdpe = pmap_segmap(pmap, sva);
+#ifdef __mips_n64
+		if (*pdpe == 0) {
+			va_next = (sva + NBSEG) & ~SEGMASK;
+			if (va_next < sva)
+				va_next = eva;
 			continue;
 		}
-		/*
-		 * If pte is invalid, skip this page
-		 */
-		pte = pmap_pte(pmap, sva);
-		if (!pte_test(pte, PTE_V)) {
-			sva += PAGE_SIZE;
+#endif
+		va_next = (sva + NBPDR) & ~PDRMASK;
+		if (va_next < sva)
+			va_next = eva;
+
+		pde = pmap_pdpe_to_pde(pdpe, sva);
+		if (pde == NULL || *pde == NULL)
 			continue;
-		}
-retry:
-		obits = pbits = *pte;
-		pa = TLBLO_PTE_TO_PA(pbits);
+		if (va_next > eva)
+			va_next = eva;
 
-		if (page_is_managed(pa) && pte_test(&pbits, PTE_D)) {
-			m = PHYS_TO_VM_PAGE(pa);
-			vm_page_dirty(m);
-			m->md.pv_flags &= ~PV_TABLE_MOD;
-		}
-		pte_clear(&pbits, PTE_D);
-		pte_set(&pbits, PTE_RO);
+		for (pte = pmap_pde_to_pte(pde, sva); sva != va_next; pte++,
+		     sva += PAGE_SIZE) {
 
-		if (pbits != *pte) {
-			if (!atomic_cmpset_int((u_int *)pte, obits, pbits))
-				goto retry;
-			pmap_update_page(pmap, sva, pbits);
+			/* Skip invalid PTEs */
+			if (!pte_test(pte, PTE_V))
+				continue;
+retry:
+			obits = pbits = *pte;
+			pa = TLBLO_PTE_TO_PA(pbits);
+			if (page_is_managed(pa) && pte_test(&pbits, PTE_D)) {
+				m = PHYS_TO_VM_PAGE(pa);
+				vm_page_dirty(m);
+				m->md.pv_flags &= ~PV_TABLE_MOD;
+			}
+			pte_clear(&pbits, PTE_D);
+			pte_set(&pbits, PTE_RO);
+			
+			if (pbits != *pte) {
+				if (!atomic_cmpset_int((u_int *)pte, obits, pbits))
+					goto retry;
+				pmap_update_page(pmap, sva, pbits);
+			}
 		}
-		sva += PAGE_SIZE;
 	}
 	vm_page_unlock_queues();
 	PMAP_UNLOCK(pmap);
@@ -1899,32 +2015,32 @@ pmap_enter_quick_locked(pmap_t pmap, vm_
 	 * creating it here.
 	 */
 	if (va < VM_MAXUSER_ADDRESS) {
+		pd_entry_t *pde;
 		unsigned ptepindex;
-		vm_offset_t pteva;
 
 		/*
 		 * Calculate pagetable page index
 		 */
-		ptepindex = pmap_segshift(va);
+		ptepindex = pmap_pde_pindex(va);
 		if (mpte && (mpte->pindex == ptepindex)) {
 			mpte->wire_count++;
 		} else {
 			/*
 			 * Get the page directory entry
 			 */
-			pteva = (vm_offset_t)pmap->pm_segtab[ptepindex];
+			pde = pmap_pde(pmap, va);
 
 			/*
 			 * If the page table page is mapped, we just
 			 * increment the hold count, and activate it.
 			 */
-			if (pteva) {
+			if (pde && *pde != 0) {
 				if (pmap->pm_ptphint &&
 				    (pmap->pm_ptphint->pindex == ptepindex)) {
 					mpte = pmap->pm_ptphint;
 				} else {
 					mpte = PHYS_TO_VM_PAGE(
-						MIPS_KSEG0_TO_PHYS(pteva));
+						MIPS_KSEG0_TO_PHYS(*pde));
 					pmap->pm_ptphint = mpte;
 				}
 				mpte->wire_count++;
@@ -1954,7 +2070,7 @@ pmap_enter_quick_locked(pmap_t pmap, vm_
 	if ((m->flags & (PG_FICTITIOUS | PG_UNMANAGED)) == 0 &&
 	    !pmap_try_insert_pv_entry(pmap, mpte, va, m)) {
 		if (mpte != NULL) {
-			pmap_unwire_pte_hold(pmap, mpte);
+			pmap_unwire_pte_hold(pmap, va, mpte);
 			mpte = NULL;
 		}
 		return (mpte);
@@ -2506,21 +2622,19 @@ pmap_changebit(vm_page_t m, int bit, boo
 
 		PMAP_LOCK(pv->pv_pmap);
 		pte = pmap_pte(pv->pv_pmap, pv->pv_va);
-
 		if (setem) {
-			*(int *)pte |= bit;
+			*pte |= bit;
 			pmap_update_page(pv->pv_pmap, pv->pv_va, *pte);
 		} else {
-			vm_offset_t pbits = *(vm_offset_t *)pte;
+			pt_entry_t pbits = *pte;
 
 			if (pbits & bit) {
 				if (bit == PTE_D) {
-					if (pbits & PTE_D) {
+					if (pbits & PTE_D)
 						vm_page_dirty(m);
-					}
-					*(int *)pte = (pbits & ~PTE_D) | PTE_RO;
+					*pte = (pbits & ~PTE_D) | PTE_RO;
 				} else {
-					*(int *)pte = pbits & ~bit;
+					*pte = pbits & ~bit;
 				}
 				pmap_update_page(pv->pv_pmap, pv->pv_va, *pte);
 			}
@@ -2658,13 +2772,15 @@ pmap_is_modified(vm_page_t m)
 boolean_t
 pmap_is_prefaultable(pmap_t pmap, vm_offset_t addr)
 {
+	pd_entry_t *pde;
 	pt_entry_t *pte;
 	boolean_t rv;
 
 	rv = FALSE;
 	PMAP_LOCK(pmap);
-	if (pmap_segmap(pmap, addr) != NULL) {
-		pte = pmap_pte(pmap, addr);
+	pde = pmap_pde(pmap, addr);
+	if (pde != NULL && *pde != 0) {
+		pte = pmap_pde_to_pte(pde, addr);
 		rv = (*pte == 0);
 	}
 	PMAP_UNLOCK(pmap);
@@ -2927,74 +3043,65 @@ pmap_align_tlb(vm_offset_t *addr)
 	return;
 }
 
-int pmap_pid_dump(int pid);
-
-int
-pmap_pid_dump(int pid)
+DB_SHOW_COMMAND(ptable, ddb_pid_dump)
 {
 	pmap_t pmap;
+	struct thread *td = NULL;
 	struct proc *p;
-	int npte = 0;
-	int index;
-
-	sx_slock(&allproc_lock);
-	LIST_FOREACH(p, &allproc, p_list) {
-		if (p->p_pid != pid)
-			continue;
-
-		if (p->p_vmspace) {
-			int i, j;
+	int i, j, k;
+	vm_paddr_t pa;
+	vm_offset_t va;
 
-			printf("vmspace is %p\n",
-			       p->p_vmspace);
-			index = 0;
+	if (have_addr) {
+		td = db_lookup_thread(addr, TRUE);
+		if (td == NULL) {
+			db_printf("Invalid pid or tid");
+			return;
+		}
+		p = td->td_proc;
+		if (p->p_vmspace == NULL) {
+			db_printf("No vmspace for process");
+			return;
+		}
 			pmap = vmspace_pmap(p->p_vmspace);
-			printf("pmap asid:%x generation:%x\n",
+	} else
+		pmap = kernel_pmap;
+
+	db_printf("pmap:%p segtab:%p asid:%x generation:%x\n",
+	    pmap, pmap->pm_segtab,
 			       pmap->pm_asid[0].asid,
 			       pmap->pm_asid[0].gen);
-			for (i = 0; i < NUSERPGTBLS; i++) {
-				pd_entry_t *pde;
-				pt_entry_t *pte;
-				unsigned base = i << SEGSHIFT;
-
-				pde = &pmap->pm_segtab[i];
-				if (pde && *pde != 0) {
-					for (j = 0; j < 1024; j++) {
-						vm_offset_t va = base +
-						(j << PAGE_SHIFT);
-
-						pte = pmap_pte(pmap, va);
-						if (pte && pte_test(pte, PTE_V)) {
-							vm_offset_t pa;
-							vm_page_t m;
-
-							pa = TLBLO_PFN_TO_PA(*pte);
-							m = PHYS_TO_VM_PAGE(pa);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list