diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2003-01-30 15:38:10 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2003-01-30 15:38:10 +0000 |
commit | df20e7a3458432d3a59fa8a5e19d2e6b2e625ca8 (patch) | |
tree | 5c4c277d0537108d56a7bb89b79d25caccddcaa0 | |
parent | 35052a0c8770d0946f74df092651cd37d16ec244 (diff) |
Track if a physical page has been previously mapped executable. If it
has not been previously mapped EXE, flush it. If a writeable mapping
which is not executable occurs for the page, clear this bit.
Solves a problem where an executable page is double mapped, first without
EXE then accessed for execute at a different physical page, the cache
will behave properly.
-rw-r--r-- | sys/arch/powerpc/include/pte.h | 3 | ||||
-rw-r--r-- | sys/arch/powerpc/powerpc/pmap.c | 48 |
2 files changed, 43 insertions, 8 deletions
diff --git a/sys/arch/powerpc/include/pte.h b/sys/arch/powerpc/include/pte.h index faf10d05b23..ee121a86fc1 100644 --- a/sys/arch/powerpc/include/pte.h +++ b/sys/arch/powerpc/include/pte.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pte.h,v 1.6 2002/07/12 20:28:55 drahn Exp $ */ +/* $OpenBSD: pte.h,v 1.7 2003/01/30 15:38:09 drahn Exp $ */ /* $NetBSD: pte.h,v 1.1 1996/09/30 16:34:32 ws Exp $ */ /*- @@ -57,6 +57,7 @@ struct pte { #define PTE_CHG 0x00000080 #define PTE_WIMG 0x00000078 #define PTE_W 0x00000040 +#define PTE_EXE 0x00000040 /* only used in pmap_attr, same as PTE_W */ #define PTE_I 0x00000020 #define PTE_M 0x00000010 #define PTE_G 0x00000008 diff --git a/sys/arch/powerpc/powerpc/pmap.c b/sys/arch/powerpc/powerpc/pmap.c index bdc82597402..a221796ec10 100644 --- a/sys/arch/powerpc/powerpc/pmap.c +++ b/sys/arch/powerpc/powerpc/pmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap.c,v 1.78 2002/11/06 00:17:27 art Exp $ */ +/* $OpenBSD: pmap.c,v 1.79 2003/01/30 15:38:09 drahn Exp $ */ /* * Copyright (c) 2001, 2002 Dale Rahn. All rights reserved. @@ -457,8 +457,10 @@ pmap_enter(pm, va, pa, prot, flags) struct pte_desc *pted; struct pted_pv_head *pvh; int s; - int need_sync; + int need_sync = 0; int cache; + u_int8_t *pattr = NULL; + int first_map = 0; /* MP - Acquire lock for this pmap */ @@ -489,7 +491,27 @@ pmap_enter(pm, va, pa, prot, flags) pmap_fill_pte(pm, va, pa, pted, prot, flags, cache); - need_sync = pmap_enter_pv(pted, pvh); + if (pvh != NULL) { + pattr = pmap_find_attr(pa); /* pattr only for managed mem */ + first_map = pmap_enter_pv(pted, pvh); /* only managed mem */ + } + + /* + * We want to flush for executable pages which are not managed??? + * Always flush for the first mapping if it is executable. + * If previous mappings exist, but this is the first EXE, sync. + */ + + if (prot & VM_PROT_EXECUTE) { + need_sync = 1; + if (pvh != NULL) { + if (!first_map) + need_sync = + (*pattr & (PTE_EXE >> ATTRSHIFT)) == 0; + else if (pattr != NULL) + *pattr = 0; + } + } /* * Insert into HTAB @@ -513,12 +535,21 @@ pmap_enter(pm, va, pa, prot, flags) :: "r"(pm->pm_sr[sn]), "r"(sn << ADDR_SR_SHIFT) ); } + if (pattr != NULL) + *pattr |= (PTE_EXE >> ATTRSHIFT); + } else { + /* + * Should we be paranoid about writeable non-exec + * mappings ? if so, clear the exec tag + */ + if ((prot & VM_PROT_WRITE) && (pattr != NULL)) + *pattr &= ~(PTE_EXE >> ATTRSHIFT); } splx(s); /* only instruction sync executable pages */ - if (need_sync && (prot & VM_PROT_EXECUTE)) + if (need_sync) pmap_syncicache_user_virt(pm, va); /* MP - free pmap lock */ @@ -941,10 +972,13 @@ pteclrbits(paddr_t pa, u_int bit, u_int clear) * currently mapped. If the mapping was thrown away in * exchange for another page mapping, then this page is * not currently in the HASH. + * + * if we are not clearing bits, and have found all of the + * bits we want, we can stop */ if ((pted->pted_pte.pte_hi | (PTED_HID(pted) ? PTE_HID : 0)) == ptp->pte_hi) { - bits |= ptp->pte_lo & (PTE_REF|PTE_CHG); + bits |= ptp->pte_lo & bit; if (clear) { ptp->pte_hi &= ~PTE_VALID; __asm__ volatile ("sync"); @@ -953,11 +987,11 @@ pteclrbits(paddr_t pa, u_int bit, u_int clear) ptp->pte_lo &= ~bit; __asm__ volatile ("sync"); ptp->pte_hi |= PTE_VALID; - } + } else if (bits == bit) + break; } } - bits |= (*pattr << ATTRSHIFT) & bit; if (clear) *pattr &= ~(bit >> ATTRSHIFT); else |