Module Name: src
Committed By: ryo
Date: Fri Apr 27 08:07:08 UTC 2018
Modified Files:
src/sys/arch/aarch64/aarch64: pmap.c
src/sys/arch/aarch64/include: pmap.h
Log Message:
fix instability behavior of bufcache on aarch64.
* fix to return correct ref/mod when PMAP_WIRED.
* changed to keep wired flags in pte instead of pv_entry, and cleanup.
To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/aarch64/aarch64/pmap.c
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/aarch64/include/pmap.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/aarch64/aarch64/pmap.c
diff -u src/sys/arch/aarch64/aarch64/pmap.c:1.2 src/sys/arch/aarch64/aarch64/pmap.c:1.3
--- src/sys/arch/aarch64/aarch64/pmap.c:1.2 Sun Apr 1 04:35:03 2018
+++ src/sys/arch/aarch64/aarch64/pmap.c Fri Apr 27 08:07:08 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.2 2018/04/01 04:35:03 ryo Exp $ */
+/* $NetBSD: pmap.c,v 1.3 2018/04/27 08:07:08 ryo Exp $ */
/*
* Copyright (c) 2017 Ryo Shimizu <[email protected]>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.2 2018/04/01 04:35:03 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.3 2018/04/27 08:07:08 ryo Exp $");
#include "opt_arm_debug.h"
#include "opt_ddb.h"
@@ -129,8 +129,7 @@ PMAP_COUNTER(remappings, "pages remapped
PMAP_COUNTER(pv_entry_cannotalloc, "pv_entry allocation failure");
PMAP_COUNTER(unwire, "pmap_unwire call");
-PMAP_COUNTER(unwire_unmanaged, "pmap_unwire unmanaged pages");
-PMAP_COUNTER(unwire_wired, "pmap_unwire but already unwire");
+PMAP_COUNTER(unwire_failure, "pmap_unwire failure");
#else /* PMAPCOUNTERS */
#define PMAP_COUNT(name) __nothing
@@ -139,6 +138,7 @@ PMAP_COUNTER(unwire_wired, "pmap_unwire
/* saved permission bit for referenced/modified emulation */
#define LX_BLKPAG_OS_READ LX_BLKPAG_OS_0
#define LX_BLKPAG_OS_WRITE LX_BLKPAG_OS_1
+#define LX_BLKPAG_OS_WIRED LX_BLKPAG_OS_2
#define LX_BLKPAG_OS_RWMASK (LX_BLKPAG_OS_WRITE|LX_BLKPAG_OS_READ)
/* memory attributes are configured MAIR_EL1 in locore */
@@ -154,7 +154,6 @@ struct pv_entry {
vaddr_t pv_va;
paddr_t pv_pa; /* debug */
pt_entry_t *pv_ptep; /* for fast pte lookup */
- u_int pv_flags;
};
static pt_entry_t *_pmap_pte_lookup(struct pmap *, vaddr_t);
@@ -876,14 +875,6 @@ _pmap_remove_pv(struct vm_page *pg, stru
}
KASSERT(pv != NULL);
- if (pv->pv_flags & PMAP_WIRED) {
- pm->pm_stats.wired_count--;
- KDASSERT(md->mdpg_wiredcount > 0);
- if (--md->mdpg_wiredcount == 0) {
- md->mdpg_flags &= ~PMAP_WIRED;
- }
- }
-
TAILQ_REMOVE(&md->mdpg_pvhead, pv, pv_link);
PMAP_COUNT(pv_remove);
@@ -947,8 +938,6 @@ pv_dump(struct vm_page_md *md, void (*pr
pr("md=%p\n", md);
pr(" md->mdpg_flags=%08x %s\n", md->mdpg_flags,
str_vmflags(md->mdpg_flags));
- pr(" md->mdpg_kenter=%d\n", md->mdpg_kenter);
- pr(" md->mdpg_wiredcount=%d\n", md->mdpg_wiredcount);
TAILQ_FOREACH(pv, &md->mdpg_pvhead, pv_link) {
pr(" pv[%d] pv=%p\n",
@@ -959,7 +948,6 @@ pv_dump(struct vm_page_md *md, void (*pr
i, pv->pv_va, _pmap_color(pv->pv_va));
pr(" pv[%d].pv_pa =%016lx (color=%d)\n",
i, pv->pv_pa, _pmap_color(pv->pv_pa));
- pr(" pv[%d].pv_flags=%016lx\n", i, pv->pv_flags);
i++;
}
}
@@ -989,24 +977,7 @@ _pmap_enter_pv(struct vm_page *pg, struc
}
}
- if (pv != NULL) {
- /* update wired count, and mdpg_flags */
- if ((pv->pv_flags & PMAP_WIRED) && !(flags & PMAP_WIRED)) {
- /* wire -> unwire */
- pm->pm_stats.wired_count--;
- KDASSERT(md->mdpg_wiredcount > 0);
- if (--md->mdpg_wiredcount == 0) {
- md->mdpg_flags &= ~PMAP_WIRED;
- }
- } else if (!(pv->pv_flags & PMAP_WIRED) &&
- (flags & PMAP_WIRED)) {
- /* unwire -> wire */
- pm->pm_stats.wired_count++;
- md->mdpg_wiredcount++;
- md->mdpg_flags |= flags;
- }
- pv->pv_flags = flags;
- } else {
+ if (pv == NULL) {
pmap_pv_unlock(md);
/* create and link new pv */
@@ -1018,18 +989,11 @@ _pmap_enter_pv(struct vm_page *pg, struc
pv->pv_va = va;
pv->pv_pa = pa;
pv->pv_ptep = ptep;
- pv->pv_flags = flags;
pmap_pv_lock(md);
TAILQ_INSERT_HEAD(&md->mdpg_pvhead, pv, pv_link);
PMAP_COUNT(pv_enter);
- if (flags & PMAP_WIRED) {
- pm->pm_stats.wired_count++;
- if (md->mdpg_wiredcount++ == 0) {
- md->mdpg_flags |= PMAP_WIRED;
- }
- }
#ifdef PMAP_PV_DEBUG
if (!TAILQ_EMPTY(&md->mdpg_pvhead)){
printf("pv %p alias added va=%016lx -> pa=%016lx\n",
@@ -1059,6 +1023,7 @@ pmap_kremove(vaddr_t va, vsize_t size)
{
struct pmap *kpm = pmap_kernel();
vaddr_t eva;
+ int s;
UVMHIST_FUNC(__func__);
UVMHIST_CALLED(pmaphist);
@@ -1073,9 +1038,11 @@ pmap_kremove(vaddr_t va, vsize_t size)
eva = va + size;
KDASSERT(VM_MIN_KERNEL_ADDRESS <= va && eva < VM_MAX_KERNEL_ADDRESS);
+ s = splvm();
for (; va < eva; va += PAGE_SIZE) {
_pmap_remove(kpm, va, true);
}
+ splx(s);
}
static void
@@ -1101,9 +1068,9 @@ _pmap_protect_pv(struct vm_page *pg, str
/* get prot mask from pte */
pteprot = 0;
- if (pte & LX_BLKPAG_OS_READ)
+ if (pte & LX_BLKPAG_AF)
pteprot |= VM_PROT_READ;
- if (pte & LX_BLKPAG_OS_WRITE)
+ if ((pte & LX_BLKPAG_AP) == LX_BLKPAG_AP_RW)
pteprot |= VM_PROT_WRITE;
if ((pte & (LX_BLKPAG_UXN|LX_BLKPAG_PXN)) == 0)
pteprot |= VM_PROT_EXECUTE;
@@ -1174,6 +1141,7 @@ pmap_protect(struct pmap *pm, vaddr_t sv
pg = PHYS_TO_VM_PAGE(pa);
if (pg != NULL) {
+ /* get prot mask from referenced/modified */
mdattr = VM_PAGE_TO_MD(pg)->mdpg_flags &
(VM_PROT_READ | VM_PROT_WRITE);
PMAP_COUNT(protect_managed);
@@ -1359,14 +1327,18 @@ _pmap_enter(struct pmap *pm, vaddr_t va,
}
#endif
- pg = PHYS_TO_VM_PAGE(pa);
+ if (kenter)
+ pg = NULL;
+ else
+ pg = PHYS_TO_VM_PAGE(pa);
+
+#ifdef PMAPCOUNTERS
if (pg == NULL) {
PMAP_COUNT(unmanaged_mappings);
- /* XXX */
- /* panic("%s:%d", __func__, __LINE__); */
} else {
PMAP_COUNT(managed_mappings);
}
+#endif
/*
* _pmap_enter() may be called recursively. In case of
@@ -1417,8 +1389,6 @@ _pmap_enter(struct pmap *pm, vaddr_t va,
idx = l3pte_index(va);
ptep = &l3[idx]; /* as PTE */
- /* KASSERT(pg != NULL); */
-
pte = *ptep;
executable = l3pte_executable(pte);
@@ -1445,46 +1415,41 @@ _pmap_enter(struct pmap *pm, vaddr_t va,
va, l3pte_pa(pte), pa, pte);
opg = PHYS_TO_VM_PAGE(l3pte_pa(pte));
- KASSERT(opg != NULL);
-
- if (opg == pg) {
- /* XXX */
- panic("%s:%d: XXX: not supported yet",
- __func__, __LINE__);
- }
-
- _pmap_remove_pv(opg, pm, va, pte);
+ if (opg != NULL)
+ _pmap_remove_pv(opg, pm, va, pte);
}
+
+ if (pte & LX_BLKPAG_OS_WIRED)
+ pm->pm_stats.wired_count--;
+ pm->pm_stats.resident_count--;
}
/*
* _pmap_enter_pv() may call pmap_kenter() internally.
* don't allocate pv_entry (don't call _pmap_enter_pv) when kenter mode.
+ * `pg' have got to be NULL if (kenter).
*/
mdattr = VM_PROT_READ | VM_PROT_WRITE;
- if (pg) {
- if (kenter) {
- VM_PAGE_TO_MD(pg)->mdpg_kenter++;
- VM_PAGE_TO_MD(pg)->mdpg_flags |= (PMAP_WIRED | mdattr);
- VM_PAGE_TO_MD(pg)->mdpg_wiredcount++;
+ if (pg != NULL) {
+ error = _pmap_enter_pv(pg, pm, va, ptep, pa, flags);
+ if (error != 0) {
+ PMAP_COUNT(pv_entry_cannotalloc);
+ if (flags & PMAP_CANFAIL)
+ goto done;
+ panic(
+ "pmap_enter: failed to allocate pv_entry");
+ }
- pm->pm_stats.wired_count++;
+ if (flags & PMAP_WIRED) {
+ /*
+ * initial value of ref/mod are equal to prot,
+ * and pte RW are same as prot.
+ */
+ VM_PAGE_TO_MD(pg)->mdpg_flags |=
+ (prot & mdattr);
} else {
- error = _pmap_enter_pv(pg, pm, va, ptep, pa, flags);
- if (error != 0) {
- PMAP_COUNT(pv_entry_cannotalloc);
- if (flags & PMAP_CANFAIL)
- goto done;
- panic(
- "pmap_enter: failed to allocate pv_entry");
- }
-
- if (flags & PMAP_WIRED) {
- VM_PAGE_TO_MD(pg)->mdpg_flags |=
- (PMAP_WIRED | mdattr);
- } else {
- mdattr &= VM_PAGE_TO_MD(pg)->mdpg_flags;
- }
+ /* pte RW will be masked by ref/mod for ref/mod emul */
+ mdattr &= VM_PAGE_TO_MD(pg)->mdpg_flags;
}
}
@@ -1501,6 +1466,8 @@ _pmap_enter(struct pmap *pm, vaddr_t va,
attr = _pmap_pte_adjust_cacheflags(attr, flags);
if (VM_MAXUSER_ADDRESS > va)
attr |= LX_BLKPAG_APUSER;
+ if (flags & PMAP_WIRED)
+ attr |= LX_BLKPAG_OS_WIRED;
#ifdef MULTIPROCESSOR
attr |= LX_BLKPAG_SH_IS;
#endif
@@ -1520,6 +1487,8 @@ _pmap_enter(struct pmap *pm, vaddr_t va,
cpu_icache_sync_range(va, PAGE_SIZE);
}
+ if (pte & LX_BLKPAG_OS_WIRED)
+ pm->pm_stats.wired_count++;
pm->pm_stats.resident_count++;
done:
@@ -1563,33 +1532,25 @@ _pmap_remove(struct pmap *pm, vaddr_t va
return;
pa = l3pte_pa(pte);
- pg = PHYS_TO_VM_PAGE(pa);
- if (pg != NULL) {
- if (kremove) {
- struct vm_page_md *md = VM_PAGE_TO_MD(pg);
- KASSERT(md->mdpg_flags & PMAP_WIRED);
- KDASSERT(md->mdpg_kenter > 0);
+ if (kremove)
+ pg = NULL;
+ else
+ pg = PHYS_TO_VM_PAGE(pa);
- md->mdpg_kenter--;
- pm->pm_stats.wired_count--;
- KDASSERT(md->mdpg_wiredcount > 0);
- if (--md->mdpg_wiredcount == 0) {
- md->mdpg_flags &= ~PMAP_WIRED;
- }
+ if (pg != NULL)
+ _pmap_remove_pv(pg, pm, va, pte);
- } else {
- _pmap_remove_pv(pg, pm, va, pte);
- }
- pm->pm_stats.resident_count--;
- }
atomic_swap_64(ptep, 0);
-
#if 0
aarch64_tlbi_by_asid_va(pm->pm_asid, va);
#else
aarch64_tlbi_by_va(va);
#endif
+
+ if ((pte & LX_BLKPAG_OS_WIRED) != 0)
+ pm->pm_stats.wired_count--;
+ pm->pm_stats.resident_count--;
}
}
@@ -1615,6 +1576,7 @@ pmap_page_protect(struct vm_page *pg, vm
{
struct vm_page_md *md = VM_PAGE_TO_MD(pg);
struct pv_entry *pv, *pvtmp;
+ pt_entry_t opte;
KASSERT((prot & VM_PROT_READ) || !(prot & VM_PROT_WRITE));
@@ -1629,41 +1591,30 @@ pmap_page_protect(struct vm_page *pg, vm
VM_PROT_NONE) {
/* remove all pages reference to this physical page */
-
- /* XXX: todo cleanup */
pmap_pv_lock(md);
TAILQ_FOREACH_SAFE(pv, &md->mdpg_pvhead, pv_link, pvtmp) {
- if (pv->pv_flags & PMAP_WIRED) {
- pv->pv_pmap->pm_stats.wired_count--;
- KDASSERT(md->mdpg_wiredcount > 0);
- if (--md->mdpg_wiredcount == 0) {
- md->mdpg_flags &= ~PMAP_WIRED;
- }
- }
- atomic_swap_64(pv->pv_ptep, 0);
+ opte = atomic_swap_64(pv->pv_ptep, 0);
#if 0
aarch64_tlbi_by_asid_va(pv->pv_pmap->pm_asid,
pv->pv_va);
#else
aarch64_tlbi_by_va(pv->pv_va);
#endif
+ if ((opte & LX_BLKPAG_OS_WIRED) != 0)
+ pv->pv_pmap->pm_stats.wired_count--;
pv->pv_pmap->pm_stats.resident_count--;
TAILQ_REMOVE(&md->mdpg_pvhead, pv, pv_link);
PMAP_COUNT(pv_remove);
pool_cache_put(&_pmap_pv_pool, pv);
-
}
pmap_pv_unlock(md);
-
} else {
pmap_pv_lock(md);
TAILQ_FOREACH(pv, &md->mdpg_pvhead, pv_link) {
- if (!(pv->pv_flags & PMAP_WIRED)) {
- _pmap_protect_pv(pg, pv, prot);
- }
+ _pmap_protect_pv(pg, pv, prot);
}
pmap_pv_unlock(md);
}
@@ -1673,11 +1624,6 @@ void
pmap_unwire(struct pmap *pm, vaddr_t va)
{
pt_entry_t pte, *ptep;
- struct vm_page *pg;
- struct vm_page_md *md;
- struct pv_entry *pv;
- paddr_t pa;
-
UVMHIST_FUNC(__func__);
UVMHIST_CALLED(pmaphist);
@@ -1692,39 +1638,18 @@ pmap_unwire(struct pmap *pm, vaddr_t va)
ptep = _pmap_pte_lookup(pm, va);
if (ptep != NULL) {
pte = *ptep;
- if (!l3pte_valid(pte)) {
- PMAP_COUNT(unwire_unmanaged);
+ if (!l3pte_valid(pte) ||
+ ((pte & LX_BLKPAG_OS_WIRED) == 0)) {
+ /* invalid pte, or pte is not wired */
+ PMAP_COUNT(unwire_failure);
+ PM_UNLOCK(pm);
return;
}
- pa = l3pte_pa(pte);
- pg = PHYS_TO_VM_PAGE(pa);
+ pte &= ~LX_BLKPAG_OS_WIRED;
+ atomic_swap_64(ptep, pte);
- if (pg != NULL) {
- md = VM_PAGE_TO_MD(pg);
- pmap_pv_lock(md);
- if (md->mdpg_flags & PMAP_WIRED) {
- TAILQ_FOREACH(pv, &md->mdpg_pvhead, pv_link) {
- if ((va != pv->pv_va) ||
- (pm != pv->pv_pmap) ||
- !(pv->pv_flags & PMAP_WIRED)) {
- continue;
- }
-
- pv->pv_flags &= ~PMAP_WIRED;
- pm->pm_stats.wired_count--;
- KDASSERT(md->mdpg_wiredcount > 0);
- if (--md->mdpg_wiredcount == 0) {
- md->mdpg_flags &= ~PMAP_WIRED;
- PMAP_COUNT(unwire_wired);
- }
- break;
- }
- }
- pmap_pv_unlock(VM_PAGE_TO_MD(pg));
- } else {
- PMAP_COUNT(unwire_unmanaged);
- }
+ pm->pm_stats.wired_count--;
}
PM_UNLOCK(pm);
}
@@ -1993,14 +1918,16 @@ bool
pmap_is_modified(struct vm_page *pg)
{
struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
+
return (md->mdpg_flags & VM_PROT_WRITE);
}
bool
pmap_is_referenced(struct vm_page *pg)
{
- struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg);
- return (mdpg->mdpg_flags & VM_PROT_READ);
+ struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
+
+ return (md->mdpg_flags & VM_PROT_READ);
}
#ifdef DDB
Index: src/sys/arch/aarch64/include/pmap.h
diff -u src/sys/arch/aarch64/include/pmap.h:1.3 src/sys/arch/aarch64/include/pmap.h:1.4
--- src/sys/arch/aarch64/include/pmap.h:1.3 Mon Apr 9 22:26:16 2018
+++ src/sys/arch/aarch64/include/pmap.h Fri Apr 27 08:07:08 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.3 2018/04/09 22:26:16 jmcneill Exp $ */
+/* $NetBSD: pmap.h,v 1.4 2018/04/27 08:07:08 ryo Exp $ */
/*-
* Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -68,9 +68,6 @@ struct vm_page_md {
/* VM_PROT_READ means referenced, VM_PROT_WRITE means modified */
uint32_t mdpg_flags;
-
- u_int mdpg_kenter; /* num of pmap_kenter_pa()'ed */
- u_int mdpg_wiredcount; /* num of pmap_enter with PMAP_WIRED */
};
/* each mdpg_pvlock will be initialized in pmap_init() */
@@ -78,8 +75,6 @@ struct vm_page_md {
do { \
TAILQ_INIT(&(pg)->mdpage.mdpg_pvhead); \
(pg)->mdpage.mdpg_flags = 0; \
- (pg)->mdpage.mdpg_kenter = 0; \
- (pg)->mdpage.mdpg_wiredcount = 0; \
} while (/*CONSTCOND*/ 0)
#define l0pde_pa(pde) ((paddr_t)((pde) & LX_TBL_PA))