Module Name: src Committed By: bouyer Date: Sat Aug 27 14:34:55 UTC 2016
Modified Files: src/sys/arch/mips/mips [netbsd-6]: pmap.c Log Message: Pull up following revision(s) (requested by skrll in ticket #1390): sys/arch/mips/mips/pmap.c: revision 1.221 sys/arch/mips/mips/pmap.c: revision 1.222 sys/arch/mips/mips/pmap.c: revision 1.223 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. Fix PR/51288 reproducable panic on evbmips64-eb (erlite) pmap_page_remove from the previous change neglected to terminate the pv list correctly when it started with an initial unmanaged mapping and subsequent managed mappings. Fix this. Fix MIPS3_NO_PV_UNCACHED alias handling by looping through the pv_list looking for bad aliases and removing the bad entries. That is, revert to the code before the matt-mips64 merge. Additionally, fix the pmap_update call to not use the (recently removed/freed) pv for the pmap_t. Fixes the following two PRs PR/49903: Panic during installation on WorkPad Z50 (hpcmips) whilst uncompressing base.tgz PR/51226: Install bug for hpcmips NetBSD V7 using FTP Full installation To generate a diff of this commit: cvs rdiff -u -r1.207.2.3 -r1.207.2.4 src/sys/arch/mips/mips/pmap.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/arch/mips/mips/pmap.c diff -u src/sys/arch/mips/mips/pmap.c:1.207.2.3 src/sys/arch/mips/mips/pmap.c:1.207.2.4 --- src/sys/arch/mips/mips/pmap.c:1.207.2.3 Wed Jun 11 15:38:05 2014 +++ src/sys/arch/mips/mips/pmap.c Sat Aug 27 14:34:55 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.207.2.3 2014/06/11 15:38:05 msaitoh Exp $ */ +/* $NetBSD: pmap.c,v 1.207.2.4 2016/08/27 14:34:55 bouyer 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.207.2.3 2014/06/11 15:38:05 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.207.2.4 2016/08/27 14:34:55 bouyer Exp $"); /* * Manages physical address maps. @@ -316,6 +316,7 @@ u_int pmap_page_colormask; (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); @@ -1063,6 +1064,10 @@ pmap_page_protect(struct vm_page *pg, vm 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); @@ -1087,17 +1092,7 @@ pmap_page_protect(struct vm_page *pg, vm 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); } } @@ -2069,6 +2064,32 @@ pmap_set_modified(paddr_t pa) /******************** 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 @@ -2155,12 +2176,12 @@ again: * be mapped with one index at any given time. */ - if (mips_cache_badalias(pv->pv_va, va)) { - for (npv = pv; npv; npv = npv->pv_next) { - vaddr_t nva = trunc_page(npv->pv_va); - pmap_remove(npv->pv_pmap, nva, - nva + PAGE_SIZE); - pmap_update(npv->pv_pmap); + for (npv = pv; npv; npv = npv->pv_next) { + vaddr_t nva = trunc_page(npv->pv_va); + pmap_t npm = npv->pv_pmap; + if (mips_cache_badalias(nva, va)) { + pmap_remove(npm, nva, nva + PAGE_SIZE); + pmap_update(npm); goto again; } } @@ -2283,6 +2304,114 @@ again: } /* + * 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 + KASSERT(pv->pv_pmap == pmap_kernel()); + + /* Assume no more - it'll get fixed if there are */ + pv->pv_next = NULL; + + /* + * 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; + KASSERT(fpv->pv_pmap == pmap_kernel()); + } + 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) { + KASSERT(pvp->pv_pmap == pmap_kernel()); + KASSERT(pvp->pv_next == NULL); + 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. @@ -2337,25 +2466,7 @@ pmap_remove_pv(pmap_t pmap, vaddr_t va, 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);