Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/mips/mips Fix a bug introduced by me in 1.214 where...
details: https://anonhg.NetBSD.org/src/rev/088d1e93a3a4
branches: trunk
changeset: 346119:088d1e93a3a4
user: skrll <skrll%NetBSD.org@localhost>
date: Mon Jun 27 07:12:18 2016 +0000
description:
Fix a bug introduced by me in 1.214 where unmanaged mappings would be
affected by calls to pmap_page_protect which is wrong. Now PV_KENTER
mappings are left intact.
Thanks to chuq for spotting my mistake and reviewing this diff.
Thanks to everyone who tested it as well.
diffstat:
sys/arch/mips/mips/pmap.c | 170 +++++++++++++++++++++++++++++++++++++--------
1 files changed, 138 insertions(+), 32 deletions(-)
diffs (226 lines):
diff -r 60e1d932a644 -r 088d1e93a3a4 sys/arch/mips/mips/pmap.c
--- a/sys/arch/mips/mips/pmap.c Mon Jun 27 05:29:32 2016 +0000
+++ b/sys/arch/mips/mips/pmap.c Mon Jun 27 07:12:18 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.220 2015/11/05 06:26:15 pgoyette Exp $ */
+/* $NetBSD: pmap.c,v 1.221 2016/06/27 07:12:18 skrll 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.220 2015/11/05 06:26:15 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.221 2016/06/27 07:12:18 skrll Exp $");
/*
* Manages physical address maps.
@@ -302,6 +302,7 @@
(pm) == curlwp->l_proc->p_vmspace->vm_map.pmap)
/* Forward function declarations */
+void pmap_page_remove(struct vm_page *);
void pmap_remove_pv(pmap_t, vaddr_t, struct vm_page *, bool);
void pmap_enter_pv(pmap_t, vaddr_t, struct vm_page *, u_int *, int);
pt_entry_t *pmap_pte(pmap_t, vaddr_t);
@@ -1054,6 +1055,10 @@
while (pv != NULL) {
const pmap_t pmap = pv->pv_pmap;
const uint16_t gen = PG_MD_PVLIST_GEN(md);
+ if (pv->pv_va & PV_KENTER) {
+ pv = pv->pv_next;
+ continue;
+ }
va = trunc_page(pv->pv_va);
PG_MD_PVLIST_UNLOCK(md);
pmap_protect(pmap, va, va + PAGE_SIZE, prot);
@@ -1078,17 +1083,7 @@
if (pmap_clear_mdpage_attributes(md, PG_MD_EXECPAGE)) {
PMAP_COUNT(exec_uncached_page_protect);
}
- (void)PG_MD_PVLIST_LOCK(md, false);
- pv = &md->pvh_first;
- while (pv->pv_pmap != NULL) {
- const pmap_t pmap = pv->pv_pmap;
- va = trunc_page(pv->pv_va);
- PG_MD_PVLIST_UNLOCK(md);
- pmap_remove(pmap, va, va + PAGE_SIZE);
- pmap_update(pmap);
- (void)PG_MD_PVLIST_LOCK(md, false);
- }
- PG_MD_PVLIST_UNLOCK(md);
+ pmap_page_remove(pg);
}
}
@@ -2060,6 +2055,32 @@
/******************** pv_entry management ********************/
static void
+pmap_check_alias(struct vm_page *pg)
+{
+#ifdef MIPS3_PLUS /* XXX mmu XXX */
+#ifndef MIPS3_NO_PV_UNCACHED
+ struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
+
+ if (MIPS_HAS_R4K_MMU && PG_MD_UNCACHED_P(md)) {
+ /*
+ * Page is currently uncached, check if alias mapping has been
+ * removed. If it was, then reenable caching.
+ */
+ pv_entry_t pv = &md->pvh_first;
+ pv_entry_t pv0 = pv->pv_next;
+
+ for (; pv0; pv0 = pv0->pv_next) {
+ if (mips_cache_badalias(pv->pv_va, pv0->pv_va))
+ break;
+ }
+ if (pv0 == NULL)
+ pmap_page_cache(pg, true);
+ }
+#endif
+#endif /* MIPS3_PLUS */
+}
+
+static void
pmap_check_pvlist(struct vm_page_md *md)
{
#ifdef PARANOIADIAG
@@ -2276,6 +2297,109 @@
}
/*
+ * Remove this page from all physical maps in which it resides.
+ * Reflects back modify bits to the pager.
+ */
+void
+pmap_page_remove(struct vm_page *pg)
+{
+ struct vm_page_md * const md = VM_PAGE_TO_MD(pg);
+
+ (void)PG_MD_PVLIST_LOCK(md, true);
+ pmap_check_pvlist(md);
+
+ pv_entry_t pv = &md->pvh_first;
+ if (pv->pv_pmap == NULL) {
+ PG_MD_PVLIST_UNLOCK(md);
+ return;
+ }
+
+ pv_entry_t npv;
+ pv_entry_t pvp = NULL;
+
+ kpreempt_disable();
+ for (; pv != NULL; pv = npv) {
+ npv = pv->pv_next;
+ if (pv->pv_va & PV_KENTER) {
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) {
+ printf("%s: %p %p, %"PRIxVADDR" skip\n",
+ __func__, pv, pv->pv_pmap, pv->pv_va);
+ }
+#endif
+ /*
+ * pvp is non-null when we already have a PV_KENTER
+ * pv in pvh_first; otherwise we haven't seen a
+ * PV_KENTER pv and we need to copy this one to
+ * pvh_first
+ */
+ if (pvp) {
+ /*
+ * The previous PV_KENTER pv needs to point to
+ * this PV_KENTER pv
+ */
+ pvp->pv_next = pv;
+ } else {
+ pv_entry_t fpv = &md->pvh_first;
+ *fpv = *pv;
+ }
+ /* Assume no more - it'll get fixed if there are */
+ pv->pv_next = NULL;
+ pvp = pv;
+ continue;
+ }
+
+
+ const pmap_t pmap = pv->pv_pmap;
+ vaddr_t va = trunc_page(pv->pv_va);
+ pt_entry_t *pte = pmap_pte(pmap, va);
+
+#ifdef DEBUG
+ if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) {
+ printf("%s: %p %p, %"PRIxVADDR", %p\n",
+ __func__, pv, pmap, va, pte);
+ }
+#endif
+
+ KASSERT(pte);
+ if (mips_pg_wired(pte->pt_entry))
+ pmap->pm_stats.wired_count--;
+ pmap->pm_stats.resident_count--;
+
+ if (pmap == pmap_kernel()) {
+ if (MIPS_HAS_R4K_MMU)
+ /* See above about G bit */
+ pte->pt_entry = MIPS3_PG_NV | MIPS3_PG_G;
+ else
+ pte->pt_entry = MIPS1_PG_NV;
+ } else {
+ pte->pt_entry = mips_pg_nv_bit();
+ }
+ /*
+ * Flush the TLB for the given address.
+ */
+ pmap_tlb_invalidate_addr(pmap, va);
+
+ /*
+ * non-null means this is a non-pvh_first pv, so we should
+ * free it.
+ */
+ if (pvp) {
+ pmap_pv_free(pv);
+ } else {
+ pv->pv_pmap = NULL;
+ pv->pv_next = NULL;
+ }
+ }
+ pmap_check_alias(pg);
+
+ pmap_check_pvlist(md);
+
+ kpreempt_enable();
+ PG_MD_PVLIST_UNLOCK(md);
+}
+
+/*
* Remove a physical to virtual address translation.
* If cache was inhibited on this page, and there are no more cache
* conflicts, restore caching.
@@ -2330,25 +2454,7 @@
pv->pv_next = npv->pv_next;
}
}
-#ifdef MIPS3_PLUS /* XXX mmu XXX */
-#ifndef MIPS3_NO_PV_UNCACHED
- if (MIPS_HAS_R4K_MMU && PG_MD_UNCACHED_P(md)) {
- /*
- * Page is currently uncached, check if alias mapping has been
- * removed. If it was, then reenable caching.
- */
- pv = &md->pvh_first;
- pv_entry_t pv0 = pv->pv_next;
-
- for (; pv0; pv0 = pv0->pv_next) {
- if (mips_cache_badalias(pv->pv_va, pv0->pv_va))
- break;
- }
- if (pv0 == NULL)
- pmap_page_cache(pg, true);
- }
-#endif
-#endif /* MIPS3_PLUS */
+ pmap_check_alias(pg);
pmap_check_pvlist(md);
PG_MD_PVLIST_UNLOCK(md);
Home |
Main Index |
Thread Index |
Old Index