summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2004-09-22 07:27:23 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2004-09-22 07:27:23 +0000
commit6a3e60c8a63870fa516bda32e6c0b95b85222675 (patch)
treebe24a640fd932c34dbabe70b4cd0bf0169b1bc2b
parent11972f0b2d3e009ccce100e7a0991b23f6673c0b (diff)
Partially revert 1.9, the new mod/ref accounting has issues with mmap().
-rw-r--r--sys/arch/mips64/mips64/pmap.c394
1 files changed, 150 insertions, 244 deletions
diff --git a/sys/arch/mips64/mips64/pmap.c b/sys/arch/mips64/mips64/pmap.c
index a4c160fda49..f1bc75b0650 100644
--- a/sys/arch/mips64/mips64/pmap.c
+++ b/sys/arch/mips64/mips64/pmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap.c,v 1.10 2004/09/21 05:54:31 miod Exp $ */
+/* $OpenBSD: pmap.c,v 1.11 2004/09/22 07:27:22 miod Exp $ */
/*
* Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -38,18 +38,16 @@
#include <sys/shm.h>
#endif
+#include <uvm/uvm.h>
+
#include <machine/pte.h>
#include <machine/cpu.h>
#include <machine/autoconf.h>
#include <machine/memconf.h>
-#include <machine/vmparam.h>
#include <mips64/archtype.h>
-#include <uvm/uvm.h>
-
extern void mem_zero_page(vaddr_t);
-/* flags for pv_entry */
#define PV_UNCACHED 0x0001 /* Page is mapped unchached */
#define PV_CACHED 0x0002 /* Page has been cached */
#define PV_ATTR_MOD 0x0004
@@ -67,7 +65,6 @@ struct pool pmap_pv_pool;
int pmap_pv_lowat = PMAP_PV_LOWAT;
int pmap_alloc_tlbpid(struct proc *);
-int pmap_enter_pv(pmap_t, vaddr_t, vm_page_t, u_int *);
int pmap_page_alloc(vaddr_t *);
void pmap_page_cache(vm_page_t, int);
void pmap_remove_pv(pmap_t, vaddr_t, paddr_t);
@@ -114,9 +111,8 @@ struct {
#define PDB_WIRING 0x4000
#define PDB_PVDUMP 0x8000
-int pmapdebugflag = 0x0;
-#define pmapdebug pmapdebugflag
-#endif /* PMAPDEBUG */
+int pmapdebug = 0x0;
+#endif /* PMAPDEBUG */
struct pmap kernel_pmap_store;
@@ -281,7 +277,7 @@ pmap_page_alloc(vaddr_t *ret)
pv = pg_to_pvh(pg);
va = PHYS_TO_KSEG0(VM_PAGE_TO_PHYS(pg));
if ((pv->pv_flags & PV_CACHED) &&
- ((pv->pv_va ^ va) & CpuCacheAliasMask) != 0) {
+ ((pv->pv_va ^ va) & CpuCacheAliasMask) != 0) {
Mips_SyncDCachePage(pv->pv_va);
}
pv->pv_va = va;
@@ -390,7 +386,7 @@ pmap_destroy(pmap)
#ifdef PARANOIA
for (j = 0; j < NPTEPG; j++) {
if ((pte+j)->pt_entry)
- panic("pmap_destroy: segmap not empty");
+ panic("pmap_release: segmap not empty");
}
#endif
Mips_HitInvalidateDCache((vaddr_t)pte, PAGE_SIZE);
@@ -674,7 +670,7 @@ pmap_protect(pmap, sva, eva, prot)
/*
* Change protection on every valid mapping within this segment.
*/
- pte += (sva >> PGSHIFT) & (NPTEPG - 1);
+ pte += uvtopte(sva);
for (; sva < nssva; sva += NBPG, pte++) {
entry = pte->pt_entry;
if (!(entry & PG_V))
@@ -700,7 +696,7 @@ pmap_is_page_ro(pmap, va, entry)
vaddr_t va;
int entry;
{
- return (entry & PG_RO);
+ return(entry & PG_RO);
}
/*
@@ -738,9 +734,10 @@ pmap_page_cache(pg,mode)
pte->pt_entry = entry;
tlb_update(pv->pv_va, entry);
}
- } else {
+ }
+ else {
if ((pte = pmap_segmap(pv->pv_pmap, pv->pv_va))) {
- pte += (pv->pv_va >> PGSHIFT) & (NPTEPG - 1);
+ pte += uvtopte(pv->pv_va);
entry = pte->pt_entry;
if (entry & PG_V) {
entry = (entry & ~PG_CACHEMODE) | newmode;
@@ -801,27 +798,24 @@ pmap_enter(pmap, va, pa, prot, flags)
pg = PHYS_TO_VM_PAGE(pa);
if (pg != NULL) {
- pv_entry_t pv;
+ pv_entry_t pv, npv;
pv = pg_to_pvh(pg);
- /* Set page referenced/modified status based on flags */
- if (flags & VM_PROT_WRITE)
- pv->pv_flags |= PV_ATTR_MOD | PV_ATTR_REF;
- else if (flags & VM_PROT_ALL)
- pv->pv_flags |= PV_ATTR_REF;
-
if (!(prot & VM_PROT_WRITE)) {
npte = PG_ROPAGE;
} else {
- if ((int64_t)va < 0) {
+ if ((int)va < 0) {
/*
* Don't bother to trap on kernel writes,
* just record page as dirty.
*/
npte = PG_RWPAGE;
+#if 0 /*XXX*/
+ pg->flags &= ~PG_CLEAN;
+#endif
} else {
- if (pv->pv_flags & PV_ATTR_MOD) {
+ if (!(pg->flags & PG_CLEAN)) {
npte = PG_RWPAGE;
} else {
npte = PG_CWPAGE;
@@ -832,10 +826,105 @@ pmap_enter(pmap, va, pa, prot, flags)
#ifdef PMAPDEBUG
stat_count(enter_stats.managed);
#endif
+ /*
+ * Enter the pmap and virtual address into the
+ * physical to virtual map table.
+ */
+
+#ifdef PMAPDEBUG
+ if (pmapdebug & PDB_ENTER) {
+ printf("pmap_enter: pv %x: was %x/%x/%x\n",
+ pv, pv->pv_va, pv->pv_pmap, pv->pv_next);
+ }
+#endif
+
+ if (pv->pv_pmap == NULL) {
+ /*
+ * No entries yet, use header as the first entry
+ */
+
+#ifdef PMAPDEBUG
+ if (pmapdebug & PDB_PVENTRY) {
+ printf("pmap_enter: first pv: pmap %x va %x pa %p\n",
+ pmap, va, pa);
+ }
+ stat_count(enter_stats.firstpv);
+#endif
+
+ Mips_SyncDCachePage(pv->pv_va);
+
+ pv->pv_va = va;
+ pv->pv_flags = PV_CACHED;
+ pv->pv_pmap = pmap;
+ pv->pv_next = NULL;
+ } else {
+ if (pv->pv_flags & PV_UNCACHED) {
+ npte = (npte & ~PG_CACHEMODE) | PG_UNCACHED;
+ } else if (CpuCacheAliasMask != 0) {
+ /*
+ * There is at least one other VA mapping this page.
+ * Check if they are cache index compatible. If not
+ * remove all mappings, flush the cache and set page
+ * to be mapped uncached. Caching will be restored
+ * when pages are mapped compatible again. NOT!
+ */
+ for (npv = pv; npv; npv = npv->pv_next) {
+ /*
+ * Check cache aliasing incompatibility
+ */
+ if (((npv->pv_va ^ va) & CpuCacheAliasMask) != 0) {
+ printf("pmap_enter: uncached mapping for pa %p, va %p != %p.\n", pa, npv->pv_va, va);
+ pmap_page_cache(pg,PV_UNCACHED);
+ Mips_SyncCache();
+ pv->pv_flags &= ~PV_CACHED;
+ npte = (npte & ~PG_CACHEMODE) | PG_UNCACHED;
+ break;
+ }
+ }
+ }
+
+ /*
+ * There is at least one other VA mapping this page.
+ * Place this entry after the header.
+ *
+ * Note: the entry may already be in the table if
+ * we are only changing the protection bits.
+ */
+ for (npv = pv; npv; npv = npv->pv_next) {
+ if (pmap == npv->pv_pmap && va == npv->pv_va) {
+ goto fnd;
+ }
+ }
+
+#ifdef PMAPDEBUG
+ if (pmapdebug & PDB_PVENTRY) {
+ printf("pmap_enter: new pv: pmap %x va %x pa %p\n",
+ pmap, va, pa);
+ }
+#endif
+
+ /* can this cause us to recurse forever? */
+ npv = pmap_pv_alloc();
+ if (npv == NULL) {
+ panic("pmap_pv_alloc() failed");
+ }
+ npv->pv_va = va;
+ npv->pv_pmap = pmap;
+ npv->pv_next = pv->pv_next;
+ npv->pv_flags = pv->pv_flags;
+ pv->pv_next = npv;
+
+#ifdef PMAPDEBUG
+ if (!npv->pv_next)
+ stat_count(enter_stats.secondpv);
+#endif
+ fnd:
+ ;
+ }
} else {
/*
* Assumption: if it is not part of our managed memory
- * then it must be device memory which may be volatile.
+ * then it must be device memory which may be volitile.
*/
#ifdef PMAPDEBUG
stat_count(enter_stats.unmanaged);
@@ -848,20 +937,12 @@ pmap_enter(pmap, va, pa, prot, flags)
}
if (pmap == pmap_kernel()) {
- if (pg != NULL) {
- if (pmap_enter_pv(pmap, va, pg, &npte) != 0) {
- if (flags & PMAP_CANFAIL)
- return ENOMEM;
- panic("pmap_enter: pmap_enter_pv() failed");
- }
- }
-
pte = kvtopte(va);
npte |= vad_to_pfn(pa) | PG_ROPAGE | PG_G;
if (!(pte->pt_entry & PG_V)) {
pmap->pm_stats.resident_count++;
}
- if ((pte->pt_entry & PG_V) && pa != pfn_to_pad(pte->pt_entry)) {
+ if (pa != pfn_to_pad(pte->pt_entry)) {
pmap_remove(pmap, va, va + NBPG);
#ifdef PMAPDEBUG
stat_count(enter_stats.mchange);
@@ -873,7 +954,7 @@ pmap_enter(pmap, va, pa, prot, flags)
*/
pte->pt_entry = npte;
tlb_update(va, npte);
- return 0;
+ return (KERN_SUCCESS);
}
/*
@@ -891,15 +972,7 @@ pmap_enter(pmap, va, pa, prot, flags)
pmap_segmap(pmap, va) = pte = (pt_entry_t *)nva;
}
- if (pg != NULL) {
- if (pmap_enter_pv(pmap, va, pg, &npte) != 0) {
- if (flags & PMAP_CANFAIL)
- return ENOMEM;
- panic("pmap_enter: pmap_enter_pv() failed");
- }
- }
-
- pte += (va >> PGSHIFT) & (NPTEPG - 1);
+ pte += uvtopte(va);
/*
* Now validate mapping with desired protection/wiring.
@@ -907,6 +980,7 @@ pmap_enter(pmap, va, pa, prot, flags)
* MIPS pages in a OpenBSD page.
*/
npte |= vad_to_pfn(pa);
+
#ifdef PMAPDEBUG
if (pmapdebug & PDB_ENTER) {
printf("pmap_enter: new pte %x", npte);
@@ -916,7 +990,7 @@ pmap_enter(pmap, va, pa, prot, flags)
}
#endif
- if ((pte->pt_entry & PG_V) && pa != pfn_to_pad(pte->pt_entry)) {
+ if (pa != pfn_to_pad(pte->pt_entry)) {
pmap_remove(pmap, va, va + NBPG);
#ifdef PMAPDEBUG
stat_count(enter_stats.mchange);
@@ -933,10 +1007,9 @@ pmap_enter(pmap, va, pa, prot, flags)
/*
* If mapping a memory space address invalidate ICache.
*/
- if (pg != NULL &&
- (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) ==
- (VM_PROT_READ | VM_PROT_EXECUTE))
+ if (pg != NULL) {
Mips_InvalidateICachePage(va);
+ }
}
return 0;
@@ -958,11 +1031,10 @@ pmap_kenter_pa(va, pa, prot)
#endif
npte = vad_to_pfn(pa) | PG_G;
- if (prot & VM_PROT_WRITE) {
+ if (prot & VM_PROT_WRITE)
npte |= PG_RWPAGE;
- } else {
+ else
npte |= PG_ROPAGE;
- }
pte = kvtopte(va);
pte->pt_entry = npte;
tlb_update(va, npte);
@@ -986,9 +1058,9 @@ pmap_kenter_cache(va, pa, prot, cache)
npte = vad_to_pfn(pa) | PG_G;
if (prot & VM_PROT_WRITE) {
- npte |= PG_V | PG_M | cache;
+ npte |= PG_M | cache;
} else {
- npte |= PG_V | PG_RO | cache;
+ npte |= PG_RO | cache;
}
pte = kvtopte(va);
pte->pt_entry = npte;
@@ -1053,14 +1125,12 @@ pmap_extract(pmap, va, pa)
#endif
if (pmap == pmap_kernel()) {
- if (va >= (long)KSEG0_BASE &&
- va < (long)(KSEG0_BASE + KSEG_SIZE)) {
+ if (va >= (long)KSEG0_BASE && va < (long)(KSEG0_BASE + KSEG_SIZE)) {
*pa = (long)KSEG0_TO_PHYS(va);
} else {
#ifdef DIAGNOSTIC
if (va < VM_MIN_KERNEL_ADDRESS || va >= virtual_end) {
- printf("pmap_extract(%x, %x) -> ", pmap, va);
- panic("pmap_extract");
+ panic("pmap_extract(%x, %x)", pmap, va);
}
#endif
pte = kvtopte(va);
@@ -1073,7 +1143,7 @@ pmap_extract(pmap, va, pa)
if (!(pte = pmap_segmap(pmap, va)))
rv = FALSE;
else {
- pte += (va >> PGSHIFT) & (NPTEPG - 1);
+ pte += uvtopte(va);
*pa = pfn_to_pad(pte->pt_entry);
}
}
@@ -1082,7 +1152,7 @@ pmap_extract(pmap, va, pa)
#ifdef PMAPDEBUG
if (pmapdebug & PDB_FOLLOW) {
- printf("pmap_extract: rv %d pa %x\n", rv, *pa);
+ printf("pmap_extract: pa %x\n", *pa);
}
#endif
@@ -1098,21 +1168,7 @@ pmap_prefer(foff, vap)
paddr_t foff;
vaddr_t *vap;
{
-#if 1
- vaddr_t va = *vap;
- long d, m;
-
- m = CpuCacheAliasMask;
- if (m == 0) /* m=0 => no cache aliasing */
- return;
-
- m = (m | (m - 1)) + 1; /* Value from mask */
- d = foff - va;
- d &= (m - 1);
- *vap = va + d;
-#else
- *vap += (*vap ^ foff) & CpuCacheAliasMask;
-#endif
+ *vap += (foff - *vap) & (CpuCacheAliasMask | PAGE_MASK);
}
/*
@@ -1139,27 +1195,6 @@ pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
#endif
}
-#ifndef pmap_update
-/*
- * Require that all active physical maps contain no
- * incorrect entries NOW. [This update includes
- * forcing updates of any address map caching.]
- *
- * Generally used to insure that a thread about
- * to run will see a semantically correct world.
- */
-void
-pmap_update(pmap)
- pmap_t pmap;
-{
-#ifdef PMAPDEBUG
- if (pmapdebug & PDB_FOLLOW) {
- printf("pmap_update()\n");
- }
-#endif
-}
-#endif
-
/*
* pmap_zero_page zeros the specified (machine independent) page.
*/
@@ -1260,33 +1295,24 @@ boolean_t
pmap_clear_modify(pg)
struct vm_page *pg;
{
- pv_entry_t pv;
- boolean_t rv;
+#ifdef PMAPDEBUG
+ paddr_t pa = VM_PAGE_TO_PHYS(pg);
+#endif
+ boolean_t rv = FALSE;
#ifdef PMAPDEBUG
if (pmapdebug & PDB_FOLLOW) {
- paddr_t pa = VM_PAGE_TO_PHYS(pg);
printf("pmap_clear_modify(%x)\n", pa);
}
#endif
-
- /*
- * XXX - we should walk the pv list, and flush any dirty pages too.
- */
- pv = pg_to_pvh(pg);
- rv = (pv->pv_flags & PV_ATTR_MOD) != 0;
- pv->pv_flags &= ~PV_ATTR_MOD;
- return rv;
+ return(rv);
}
void
pmap_set_modify(pg)
struct vm_page *pg;
{
- pv_entry_t pv;
-
- pv = pg_to_pvh(pg);
- pv->pv_flags |= PV_ATTR_MOD | PV_ATTR_REF;
+ pg->flags &= ~PG_CLEAN;
}
/*
@@ -1298,20 +1324,16 @@ boolean_t
pmap_clear_reference(pg)
struct vm_page *pg;
{
- pv_entry_t pv;
- boolean_t rv;
+#ifdef PMAPDEBUG
+ paddr_t pa = VM_PAGE_TO_PHYS(pg);
+#endif
#ifdef PMAPDEBUG
if (pmapdebug & PDB_FOLLOW) {
- paddr_t pa = VM_PAGE_TO_PHYS(pg);
printf("pmap_clear_reference(%x)\n", pa);
}
#endif
-
- pv = pg_to_pvh(pg);
- rv = (pv->pv_flags & PV_ATTR_REF) != 0;
- pv->pv_flags &= ~PV_ATTR_REF;
- return rv;
+ return(FALSE);
}
/*
@@ -1324,10 +1346,7 @@ boolean_t
pmap_is_referenced(pg)
struct vm_page *pg;
{
- pv_entry_t pv;
-
- pv = pg_to_pvh(pg);
- return (pv->pv_flags & PV_ATTR_REF) != 0;
+ return (FALSE);
}
/*
@@ -1340,10 +1359,7 @@ boolean_t
pmap_is_modified(pg)
struct vm_page *pg;
{
- pv_entry_t pv;
-
- pv = pg_to_pvh(pg);
- return (pv->pv_flags & PV_ATTR_MOD) != 0;
+ return (FALSE);
}
paddr_t
@@ -1392,8 +1408,7 @@ pmap_alloc_tlbpid(p)
tlbpid_cnt = id + 1;
pmap->pm_tlbpid = id;
pmap->pm_tlbgen = tlbpid_gen;
- }
- else {
+ } else {
id = pmap->pm_tlbpid;
}
@@ -1414,111 +1429,6 @@ pmap_alloc_tlbpid(p)
}
/*
- * Enter the pmap and virtual address into the
- * physical to virtual map table.
- */
-int
-pmap_enter_pv(pmap, va, pg, npte)
- pmap_t pmap;
- vaddr_t va;
- vm_page_t pg;
- u_int *npte;
-{
- pv_entry_t pv, npv;
-#ifdef PMAPDEBUG
- paddr_t pa = VM_PAGE_TO_PHYS(pg);
-#endif
-
- pv = pg_to_pvh(pg);
-
- if (pv->pv_pmap == NULL) {
- /*
- * No entries yet, use header as the first entry
- */
-
-#ifdef PMAPDEBUG
- if (pmapdebug & PDB_PVENTRY) {
- printf("pmap_enter: first pv: pmap %x va %x pa %p\n",
- pmap, va, pa);
- }
- stat_count(enter_stats.firstpv);
-#endif
-
- Mips_SyncDCachePage(pv->pv_va);
-
- pv->pv_va = va;
- pv->pv_flags = PV_CACHED;
- pv->pv_pmap = pmap;
- pv->pv_next = NULL;
- } else {
- if (pv->pv_flags & PV_UNCACHED) {
- *npte = (*npte & ~PG_CACHEMODE) | PG_UNCACHED;
- } else if (CpuCacheAliasMask != 0) {
- /*
- * There is at least one other VA mapping this page.
- * Check if they are cache index compatible. If not
- * remove all mappings, flush the cache and set page
- * to be mapped uncached. Caching will be restored
- * when pages are mapped compatible again. NOT!
- */
- for (npv = pv; npv; npv = npv->pv_next) {
- /*
- * Check cache aliasing incompatibility
- */
- if (((npv->pv_va ^ va) & CpuCacheAliasMask) != 0) {
-#ifdef PMAPDEBUG
- printf("pmap_enter: uncached mapping for pa %p, va %p != %p.\n",
- pa, npv->pv_va, va);
-#endif
- pmap_page_cache(pg, PV_UNCACHED);
- Mips_SyncCache();
- pv->pv_flags &= ~PV_CACHED;
- *npte = (*npte & ~PG_CACHEMODE) | PG_UNCACHED;
- break;
- }
- }
- }
-
- /*
- * There is at least one other VA mapping this page.
- * Place this entry after the header.
- *
- * Note: the entry may already be in the table if
- * we are only changing the protection bits.
- */
- for (npv = pv; npv; npv = npv->pv_next) {
- if (pmap == npv->pv_pmap && va == npv->pv_va) {
- return 0;
- }
- }
-
-#ifdef PMAPDEBUG
- if (pmapdebug & PDB_PVENTRY) {
- printf("pmap_enter: new pv: pmap %x va %x pa %p\n",
- pmap, va, pa);
- }
-#endif
-
- /* can this cause us to recurse forever? */
- npv = pmap_pv_alloc();
- if (npv == NULL)
- return ENOMEM;
- npv->pv_va = va;
- npv->pv_pmap = pmap;
- npv->pv_next = pv->pv_next;
- npv->pv_flags = pv->pv_flags;
- pv->pv_next = npv;
-
-#ifdef PMAPDEBUG
- if (!npv->pv_next)
- stat_count(enter_stats.secondpv);
-#endif
- }
-
- return 0;
-}
-
-/*
* Remove a physical to virtual address translation.
* Returns TRUE if it was the last mapping and cached, else FALSE.
*/
@@ -1555,8 +1465,6 @@ pmap_remove_pv(pmap, va, pa)
if (pmap == pv->pv_pmap && va == pv->pv_va) {
npv = pv->pv_next;
if (npv) {
- npv->pv_flags |=
- (pv->pv_flags & (PV_ATTR_MOD | PV_ATTR_REF));
*pv = *npv;
pmap_pv_free(npv);
} else {
@@ -1565,23 +1473,21 @@ pmap_remove_pv(pmap, va, pa)
#ifdef PMAPDEBUG
stat_count(remove_stats.pvfirst);
#endif
- } else {
+ }
+ else {
for (npv = pv->pv_next; npv; pv = npv, npv = npv->pv_next) {
#ifdef PMAPDEBUG
stat_count(remove_stats.pvsearch);
#endif
if (pmap == npv->pv_pmap && va == npv->pv_va)
- break;
+ goto fnd;
}
- if (npv != NULL) {
- pv->pv_next = npv->pv_next;
- pmap_pv_free(npv);
- } else {
#ifdef DIAGNOSTIC
- panic("pmap_remove_pv(%x, %x, %x) not found",
- pmap, va, pa);
+ panic("pmap_remove_pv(%x, %x, %x) not found\n", pmap, va, pa);
#endif
- }
+ fnd:
+ pv->pv_next = npv->pv_next;
+ pmap_pv_free(npv);
}
}