Module Name: src
Committed By: matt
Date: Thu Jul 5 16:55:11 UTC 2012
Modified Files:
src/sys/common/pmap/tlb: pmap.c pmap.h pmap_segtab.c
Log Message:
Add 3-level page table support (from MIPS). Rename a few routines.
To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 src/sys/common/pmap/tlb/pmap.c
cvs rdiff -u -r1.13 -r1.14 src/sys/common/pmap/tlb/pmap.h
cvs rdiff -u -r1.5 -r1.6 src/sys/common/pmap/tlb/pmap_segtab.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/common/pmap/tlb/pmap.c
diff -u src/sys/common/pmap/tlb/pmap.c:1.14 src/sys/common/pmap/tlb/pmap.c:1.15
--- src/sys/common/pmap/tlb/pmap.c:1.14 Wed Jul 4 11:39:42 2012
+++ src/sys/common/pmap/tlb/pmap.c Thu Jul 5 16:55:11 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.14 2012/07/04 11:39:42 matt Exp $ */
+/* $NetBSD: pmap.c,v 1.15 2012/07/05 16:55:11 matt Exp $ */
/*-
* Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.14 2012/07/04 11:39:42 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.15 2012/07/05 16:55:11 matt Exp $");
/*
* Manages physical address maps.
@@ -450,8 +450,8 @@ pmap_steal_memory(vsize_t size, vaddr_t
void
pmap_init(void)
{
- UVMHIST_INIT_STATIC(pmapexechist, pmapexechistbuf);
- UVMHIST_INIT_STATIC(pmaphist, pmaphistbuf);
+ UVMHIST_INIT_STATIC(pmapexechist, pmapexechistbuf);
+ UVMHIST_INIT_STATIC(pmaphist, pmaphistbuf);
UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist);
@@ -504,7 +504,7 @@ pmap_create(void)
pmap->pm_minaddr = VM_MIN_ADDRESS;
pmap->pm_maxaddr = VM_MAXUSER_ADDRESS;
- pmap_segtab_alloc(pmap);
+ pmap_segtab_init(pmap);
UVMHIST_LOG(pmaphist, "<- pmap %p", pmap,0,0,0);
return pmap;
@@ -530,7 +530,7 @@ pmap_destroy(pmap_t pmap)
PMAP_COUNT(destroy);
kpreempt_disable();
pmap_tlb_asid_release_all(pmap);
- pmap_segtab_free(pmap);
+ pmap_segtab_destroy(pmap);
pool_put(&pmap_pmap_pool, pmap);
kpreempt_enable();
@@ -1482,7 +1482,7 @@ pmap_enter_pv(pmap_t pmap, vaddr_t va, s
pmap, va, pg, VM_PAGE_TO_PHYS(pg));
UVMHIST_LOG(pmaphist, "nptep=%p (%#x))", npte, *npte, 0, 0);
- KASSERT(kpreempt_disabled());
+ KASSERT(kpreempt_disabled());
KASSERT(pmap != pmap_kernel() || !pmap_md_direct_mapped_vaddr_p(va));
apv = NULL;
Index: src/sys/common/pmap/tlb/pmap.h
diff -u src/sys/common/pmap/tlb/pmap.h:1.13 src/sys/common/pmap/tlb/pmap.h:1.14
--- src/sys/common/pmap/tlb/pmap.h:1.13 Wed Jul 4 11:39:42 2012
+++ src/sys/common/pmap/tlb/pmap.h Thu Jul 5 16:55:11 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.13 2012/07/04 11:39:42 matt Exp $ */
+/* $NetBSD: pmap.h,v 1.14 2012/07/05 16:55:11 matt Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -107,8 +107,8 @@ pt_entry_t *pmap_pte_reserve(struct pmap
void pmap_pte_process(struct pmap *, vaddr_t, vaddr_t, pte_callback_t,
uintptr_t);
void pmap_segtab_activate(struct pmap *, struct lwp *);
-void pmap_segtab_alloc(struct pmap *);
-void pmap_segtab_free(struct pmap *);
+void pmap_segtab_init(struct pmap *);
+void pmap_segtab_destroy(struct pmap *);
extern kmutex_t pmap_segtab_lock;
#endif /* _KERNEL */
Index: src/sys/common/pmap/tlb/pmap_segtab.c
diff -u src/sys/common/pmap/tlb/pmap_segtab.c:1.5 src/sys/common/pmap/tlb/pmap_segtab.c:1.6
--- src/sys/common/pmap/tlb/pmap_segtab.c:1.5 Wed Jul 4 11:39:42 2012
+++ src/sys/common/pmap/tlb/pmap_segtab.c Thu Jul 5 16:55:11 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap_segtab.c,v 1.5 2012/07/04 11:39:42 matt Exp $ */
+/* $NetBSD: pmap_segtab.c,v 1.6 2012/07/05 16:55:11 matt Exp $ */
/*-
* Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap_segtab.c,v 1.5 2012/07/04 11:39:42 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap_segtab.c,v 1.6 2012/07/05 16:55:11 matt Exp $");
/*
* Manages physical address maps.
@@ -134,7 +134,12 @@ pmap_segmap(struct pmap *pmap, vaddr_t v
{
struct pmap_segtab *stp = pmap->pm_segtab;
KASSERT(pmap != pmap_kernel() || !pmap_md_direct_mapped_vaddr_p(va));
- return stp->seg_tab[va >> SEGSHIFT];
+#ifdef _LP64
+ stp = stp->seg_seg[(va >> XSEGSHIFT) & (NSEGPG - 1)];
+ if (stp == NULL)
+ return NULL;
+#endif
+ return stp->seg_tab[(va >> SEGSHIFT) & (PMAP_SEGTABSIZE - 1)];
}
pt_entry_t *
@@ -147,6 +152,55 @@ pmap_pte_lookup(pmap_t pmap, vaddr_t va)
return pte + ((va >> PGSHIFT) & (NPTEPG - 1));
}
+static void
+pmap_segtab_free(struct pmap_segtab *stp)
+{
+ /*
+ * Insert the the segtab into the segtab freelist.
+ */
+ mutex_spin_enter(&pmap_segtab_lock);
+ stp->seg_tab[0] = (void *) pmap_segtab_info.free_segtab;
+ pmap_segtab_info.free_segtab = stp;
+ SEGTAB_ADD(nput, 1);
+ mutex_spin_exit(&pmap_segtab_lock);
+}
+
+static void
+pmap_segtab_release(struct pmap_segtab *stp, u_int level)
+{
+
+ for (size_t i = 0; i < PMAP_SEGTABSIZE; i++) {
+ paddr_t pa;
+#ifdef _LP64
+ if (level > 0) {
+ if (stp->seg_seg[i] != NULL) {
+ pmap_segtab_release(stp->seg_seg[i], level - 1);
+ stp->seg_seg[i] = NULL;
+ }
+ continue;
+ }
+#endif
+
+ /* get pointer to segment map */
+ pt_entry_t *pte = stp->seg_tab[i];
+ if (pte == NULL)
+ continue;
+#ifdef PARANOIADIAG
+ for (size_t j = 0; j < NPTEPG; j++) {
+ if ((pte + j)->pt_entry)
+ panic("pmap_destroy: segmap not empty");
+ }
+#endif
+
+ pa = POOL_VTOPHYS(pte);
+ uvm_pagefree(PHYS_TO_VM_PAGE(pa));
+
+ stp->seg_tab[i] = NULL;
+ }
+
+ pmap_segtab_free(stp);
+}
+
/*
* Create and return a physical map.
*
@@ -159,10 +213,11 @@ pmap_pte_lookup(pmap_t pmap, vaddr_t va)
* the map will be used in software only, and
* is bounded by that size.
*/
-void
-pmap_segtab_alloc(pmap_t pmap)
+static struct pmap_segtab *
+pmap_segtab_alloc(void)
{
struct pmap_segtab *stp;
+
again:
mutex_spin_enter(&pmap_segtab_lock);
if (__predict_true((stp = pmap_segtab_info.free_segtab) != NULL)) {
@@ -172,7 +227,7 @@ pmap_segtab_alloc(pmap_t pmap)
SEGTAB_ADD(nget, 1);
}
mutex_spin_exit(&pmap_segtab_lock);
-
+
if (__predict_false(stp == NULL)) {
struct vm_page * const stp_pg = pmap_pte_pagealloc();
@@ -187,7 +242,7 @@ pmap_segtab_alloc(pmap_t pmap)
const paddr_t stp_pa = VM_PAGE_TO_PHYS(stp_pg);
stp = (struct pmap_segtab *)POOL_PHYSTOV(stp_pa);
- const size_t n = NBPG / sizeof(struct pmap_segtab);
+ const size_t n = NBPG / sizeof(*stp);
if (n > 1) {
/*
* link all the segtabs in this page together
@@ -212,8 +267,14 @@ pmap_segtab_alloc(pmap_t pmap)
panic("pmap_create: pm_segtab.seg_tab[%zu] != 0");
}
#endif
+ return stp;
+}
- pmap->pm_segtab = stp;
+void
+pmap_segtab_init(pmap_t pmap)
+{
+
+ pmap->pm_segtab = pmap_segtab_alloc();
}
/*
@@ -222,40 +283,18 @@ pmap_segtab_alloc(pmap_t pmap)
* no valid mappings.
*/
void
-pmap_segtab_free(pmap_t pmap)
+pmap_segtab_destroy(pmap_t pmap)
{
struct pmap_segtab *stp = pmap->pm_segtab;
if (stp == NULL)
return;
- for (size_t i = 0; i < PMAP_SEGTABSIZE; i++) {
- paddr_t pa;
- /* get pointer to segment map */
- pt_entry_t *pte = stp->seg_tab[i];
- if (pte == NULL)
- continue;
-#ifdef PARANOIADIAG
- for (size_t j = 0; j < NPTEPG; j++) {
- if ((pte + j)->pt_entry)
- panic("pmap_destroy: segmap not empty");
- }
+#ifdef _LP64
+ pmap_segtab_release(stp, 1);
+#else
+ pmap_segtab_release(stp, 0);
#endif
-
- pa = POOL_VTOPHYS(pte);
- uvm_pagefree(PHYS_TO_VM_PAGE(pa));
-
- stp->seg_tab[i] = NULL;
- }
-
- /*
- * Insert the the segtab into the segtab freelist.
- */
- mutex_spin_enter(&pmap_segtab_lock);
- stp->seg_tab[0] = (void *) pmap_segtab_info.free_segtab;
- pmap_segtab_info.free_segtab = stp;
- SEGTAB_ADD(nput, 1);
- mutex_spin_exit(&pmap_segtab_lock);
}
/*
@@ -265,11 +304,17 @@ void
pmap_segtab_activate(struct pmap *pm, struct lwp *l)
{
if (l == curlwp) {
+ KASSERT(pm == l->l_proc->p_vmspace->vm_map.pmap);
if (pm == pmap_kernel()) {
l->l_cpu->ci_pmap_user_segtab = (void*)0xdeadbabe;
+#ifdef _LP64
+ l->l_cpu->ci_pmap_user_seg0tab = (void*)0xdeadbabe;
+#endif
} else {
- KASSERT(pm == l->l_proc->p_vmspace->vm_map.pmap);
l->l_cpu->ci_pmap_user_segtab = pm->pm_segtab;
+#ifdef _LP64
+ l->l_cpu->ci_pmap_user_seg0tab = pm->pm_segtab->seg_seg[0];
+#endif
}
}
}
@@ -324,6 +369,25 @@ pmap_pte_reserve(pmap_t pmap, vaddr_t va
pte = pmap_pte_lookup(pmap, va);
if (__predict_false(pte == NULL)) {
+#ifdef _LP64
+ struct pmap_segtab ** const stp_p =
+ &stp->seg_seg[(va >> XSEGSHIFT) & (NSEGPG - 1)];
+ if (__predict_false((stp = *stp_p) == NULL)) {
+ struct pmap_segtab *nstp = pmap_segtab_alloc();
+#ifdef MULTIPROCESSOR
+ struct pmap_segtab *ostp = atomic_cas_ptr(stp_p, NULL, nstp);
+ if (__predict_false(ostp != NULL)) {
+ pmap_segtab_free(nstp);
+ nstp = ostp;
+ }
+#else
+ *stp_p = nstp;
+#endif /* MULTIPROCESSOR */
+ stp = nstp;
+ }
+ KASSERT(stp == pmap->pm_segtab->seg_seg[(va >> XSEGSHIFT) & (NSE
+GPG - 1)]);
+#endif /* _LP64 */
struct vm_page * const pg = pmap_pte_pagealloc();
if (pg == NULL) {
if (flags & PMAP_CANFAIL)