Module Name: src Committed By: skrll Date: Fri Jan 6 20:55:29 UTC 2012
Modified Files: src/sys/arch/hppa/hppa: pmap.c src/sys/arch/hppa/include: pmap.h Log Message: Track if a page has an executable mapping and flush the icache (and dcache) appropriately. Fixes the lang/python26 build on my C3700 (PA8700) and chuq's J6700 with PA8500. Thanks to chuq for ideas and help with this. To generate a diff of this commit: cvs rdiff -u -r1.96 -r1.97 src/sys/arch/hppa/hppa/pmap.c cvs rdiff -u -r1.35 -r1.36 src/sys/arch/hppa/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/hppa/hppa/pmap.c diff -u src/sys/arch/hppa/hppa/pmap.c:1.96 src/sys/arch/hppa/hppa/pmap.c:1.97 --- src/sys/arch/hppa/hppa/pmap.c:1.96 Fri Jan 6 08:54:05 2012 +++ src/sys/arch/hppa/hppa/pmap.c Fri Jan 6 20:55:28 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.96 2012/01/06 08:54:05 skrll Exp $ */ +/* $NetBSD: pmap.c,v 1.97 2012/01/06 20:55:28 skrll Exp $ */ /*- * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. @@ -65,7 +65,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.96 2012/01/06 08:54:05 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.97 2012/01/06 20:55:28 skrll Exp $"); #include "opt_cputype.h" @@ -209,6 +209,7 @@ static inline struct pv_entry *pmap_pv_r static inline void pmap_flush_page(struct vm_page *, bool); static int pmap_check_alias(struct vm_page *, vaddr_t, pt_entry_t); +static void pmap_syncicache_page(struct vm_page *, pmap_t, vaddr_t); static void pmap_page_physload(paddr_t, paddr_t); @@ -228,7 +229,8 @@ void pmap_dump_table(pa_space_t, vaddr_t void pmap_dump_pv(paddr_t); #endif -#define IS_IOPAGE_P(pa) ((pa) >= HPPA_IOBEGIN) +#define IS_IOPAGE_P(pa) ((pa) >= HPPA_IOBEGIN) +#define IS_PVFEXEC_P(f) (((f) & PVF_EXEC) != 0) /* un-invert PVF_REF */ #define pmap_pvh_attrs(a) \ @@ -601,6 +603,14 @@ pmap_pv_remove(struct vm_page *pg, pmap_ } } + if (IS_PVFEXEC_P(md->pvh_attrs)) { + if (md->pvh_list == NULL) { + md->pvh_attrs &= ~PVF_EXEC; + } else { + pmap_syncicache_page(pg, pmap, va); + } + } + return (pv); } @@ -1167,6 +1177,31 @@ pmap_reference(pmap_t pmap) mutex_exit(pmap->pm_lock); } + +void +pmap_syncicache_page(struct vm_page *pg, pmap_t pm, vaddr_t va) +{ + struct vm_page_md * const md = VM_PAGE_TO_MD(pg); + struct pv_entry *pve = md->pvh_list; + + for (; pve; pve = pve->pv_next) { + pmap_t fpm = pve->pv_pmap; + vaddr_t fva = pve->pv_va & PV_VAMASK; + pt_entry_t pte = pmap_vp_find(fpm, fva); + + if ((pte & PTE_PROT(TLB_DIRTY)) == 0) + continue; + + /* Don't attempt to use the mapping we're adding */ + if (pm == fpm && va == fva) + continue; + + fdcache(fpm->pm_space, fva, PAGE_SIZE); + ficache(fpm->pm_space, fva, PAGE_SIZE); + break; + } +} + /* * pmap_enter(pmap, va, pa, prot, flags) * Create a translation for the virtual address (va) to the physical @@ -1179,7 +1214,7 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd { volatile pt_entry_t *pde; pt_entry_t pte; - struct vm_page *pg, *ptp = NULL; + struct vm_page *pg = NULL, *ptp = NULL; struct pv_entry *pve = NULL; bool wired = (flags & PMAP_WIRED) != 0; @@ -1213,13 +1248,13 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd else if (!wired && (pte & PTE_PROT(TLB_WIRED))) pmap->pm_stats.wired_count--; + pg = PHYS_TO_VM_PAGE(PTE_PAGE(pte)); if (PTE_PAGE(pte) == pa) { DPRINTF(PDB_FOLLOW|PDB_ENTER, ("%s: same page\n", __func__)); goto enter; } - pg = PHYS_TO_VM_PAGE(PTE_PAGE(pte)); if (pg != NULL) { pve = pmap_pv_remove(pg, pmap, va); @@ -1257,6 +1292,17 @@ enter: /* preserve old ref & mod */ pte = pa | PTE_PROT(pmap_prot(pmap, prot)) | (pte & PTE_PROT(TLB_UNCACHEABLE|TLB_DIRTY|TLB_REFTRAP)); + + if (pg != NULL) { + struct vm_page_md * const md = VM_PAGE_TO_MD(pg); + + if ((pte & PTE_PROT(TLB_EXECUTE)) != 0 && + !IS_PVFEXEC_P(md->pvh_attrs)) { + pmap_syncicache_page(pg, pmap, va); + md->pvh_attrs |= PVF_EXEC; + } + } + if (IS_IOPAGE_P(pa)) pte |= PTE_PROT(TLB_UNCACHEABLE); if (wired) @@ -1380,9 +1426,11 @@ pmap_write_protect(pmap_t pmap, vaddr_t if (pg != NULL) { struct vm_page_md * const md = VM_PAGE_TO_MD(pg); + md->pvh_attrs |= pmap_pvh_attrs(pte); } + /* Add TLB_EXECUTE if PVF_EXEC ??? */ pmap_pte_flush(pmap, sva, pte); pte &= ~PTE_PROT(TLB_AR_MASK); pte |= pteprot; @@ -1401,8 +1449,10 @@ pmap_page_remove(struct vm_page *pg) DPRINTF(PDB_FOLLOW|PDB_PV, ("%s(%p)\n", __func__, pg)); - if (md->pvh_list == NULL) + if (md->pvh_list == NULL) { + KASSERT((md->pvh_attrs & PVF_EXEC) == 0); return; + } pvp = &md->pvh_list; for (pve = md->pvh_list; pve; pve = npve) { @@ -1438,6 +1488,7 @@ pmap_page_remove(struct vm_page *pg) } PMAP_UNLOCK(pmap); } + md->pvh_attrs &= ~PVF_EXEC; *pvp = NULL; DPRINTF(PDB_FOLLOW|PDB_PV, ("%s: leaving\n", __func__)); @@ -1651,6 +1702,7 @@ pmap_zero_page(paddr_t pa) DPRINTF(PDB_FOLLOW|PDB_PHYS, ("%s(%lx)\n", __func__, pa)); KASSERT(VM_PAGE_TO_MD(PHYS_TO_VM_PAGE(pa))->pvh_list == NULL); + KASSERT((VM_PAGE_TO_MD(PHYS_TO_VM_PAGE(pa))->pvh_attrs & PVF_EXEC) == 0); memset((void *)pa, 0, PAGE_SIZE); fdcache(HPPA_SID_KERNEL, pa, PAGE_SIZE); @@ -1676,6 +1728,7 @@ pmap_copy_page(paddr_t spa, paddr_t dpa) DPRINTF(PDB_FOLLOW|PDB_PHYS, ("%s(%lx, %lx)\n", __func__, spa, dpa)); KASSERT(VM_PAGE_TO_MD(PHYS_TO_VM_PAGE(dpa))->pvh_list == NULL); + KASSERT((VM_PAGE_TO_MD(PHYS_TO_VM_PAGE(dpa))->pvh_attrs & PVF_EXEC) == 0); pmap_flush_page(srcpg, false); Index: src/sys/arch/hppa/include/pmap.h diff -u src/sys/arch/hppa/include/pmap.h:1.35 src/sys/arch/hppa/include/pmap.h:1.36 --- src/sys/arch/hppa/include/pmap.h:1.35 Fri Jan 6 09:12:25 2012 +++ src/sys/arch/hppa/include/pmap.h Fri Jan 6 20:55:28 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.h,v 1.35 2012/01/06 09:12:25 skrll Exp $ */ +/* $NetBSD: pmap.h,v 1.36 2012/01/06 20:55:28 skrll Exp $ */ /* $OpenBSD: pmap.h,v 1.35 2007/12/14 18:32:23 deraadt Exp $ */ @@ -66,6 +66,7 @@ struct pmap { #define PVF_MOD PTE_PROT(TLB_DIRTY) /* pg/mp is modified */ #define PVF_REF PTE_PROT(TLB_REFTRAP) /* pg/mp (inv) is referenced */ #define PVF_WRITE PTE_PROT(TLB_WRITE) /* pg/mp is writable */ +#define PVF_EXEC PTE_PROT(TLB_EXECUTE) /* pg/mp is executable */ #define PVF_UNCACHEABLE PTE_PROT(TLB_UNCACHEABLE) /* pg/mp is uncacheable */ #define HPPA_MAX_PID 0xfffa