summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/pmap.c38
-rw-r--r--sys/i386/i386/pmap.c39
2 files changed, 45 insertions, 32 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index 17c9e64..4c188aa 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -1872,6 +1872,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
vm_paddr_t opa;
pt_entry_t origpte, newpte;
vm_page_t mpte, om;
+ boolean_t invlva;
va = trunc_page(va);
#ifdef PMAP_DIAGNOSTIC
@@ -1935,14 +1936,6 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
else if (!wired && (origpte & PG_W))
pmap->pm_stats.wired_count--;
-#if defined(PMAP_DIAGNOSTIC)
- if (pmap_nw_modified((pt_entry_t) origpte)) {
- printf(
- "pmap_enter: modified page not writable: va: 0x%lx, pte: 0x%lx\n",
- va, origpte);
- }
-#endif
-
/*
* Remove extra pte reference
*/
@@ -2014,17 +2007,30 @@ validate:
* to update the pte.
*/
if ((origpte & ~(PG_M|PG_A)) != newpte) {
- if (origpte & PG_MANAGED) {
+ if (origpte & PG_V) {
+ invlva = FALSE;
origpte = pte_load_store(pte, newpte | PG_A);
- if ((origpte & PG_M) && pmap_track_modified(va))
- vm_page_dirty(om);
- if (origpte & PG_A)
- vm_page_flag_set(om, PG_REFERENCED);
+ if (origpte & PG_A) {
+ if (origpte & PG_MANAGED)
+ vm_page_flag_set(om, PG_REFERENCED);
+ if (opa != VM_PAGE_TO_PHYS(m) || ((origpte &
+ PG_NX) == 0 && (newpte & PG_NX)))
+ invlva = TRUE;
+ }
+ if (origpte & PG_M) {
+ KASSERT((origpte & PG_RW),
+ ("pmap_enter: modified page not writable:"
+ " va: 0x%lx, pte: 0x%lx", va, origpte));
+ if ((origpte & PG_MANAGED) &&
+ pmap_track_modified(va))
+ vm_page_dirty(om);
+ if ((newpte & PG_RW) == 0)
+ invlva = TRUE;
+ }
+ if (invlva)
+ pmap_invalidate_page(pmap, va);
} else
pte_store(pte, newpte | PG_A);
- if (origpte) {
- pmap_invalidate_page(pmap, va);
- }
}
vm_page_unlock_queues();
PMAP_UNLOCK(pmap);
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
index 13d0923..f712f83 100644
--- a/sys/i386/i386/pmap.c
+++ b/sys/i386/i386/pmap.c
@@ -5,6 +5,8 @@
* All rights reserved.
* Copyright (c) 1994 David Greenman
* All rights reserved.
+ * Copyright (c) 2005 Alan L. Cox <alc@cs.rice.edu>
+ * All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
@@ -1853,6 +1855,7 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
vm_paddr_t opa;
pt_entry_t origpte, newpte;
vm_page_t mpte, om;
+ boolean_t invlva;
va &= PG_FRAME;
#ifdef PMAP_DIAGNOSTIC
@@ -1926,14 +1929,6 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
else if (!wired && (origpte & PG_W))
pmap->pm_stats.wired_count--;
-#if defined(PMAP_DIAGNOSTIC)
- if (pmap_nw_modified((pt_entry_t) origpte)) {
- printf(
- "pmap_enter: modified page not writable: va: 0x%x, pte: 0x%x\n",
- va, origpte);
- }
-#endif
-
/*
* Remove extra pte reference
*/
@@ -2003,17 +1998,29 @@ validate:
* to update the pte.
*/
if ((origpte & ~(PG_M|PG_A)) != newpte) {
- if (origpte & PG_MANAGED) {
+ if (origpte & PG_V) {
+ invlva = FALSE;
origpte = pte_load_store(pte, newpte | PG_A);
- if ((origpte & PG_M) && pmap_track_modified(va))
- vm_page_dirty(om);
- if (origpte & PG_A)
- vm_page_flag_set(om, PG_REFERENCED);
+ if (origpte & PG_A) {
+ if (origpte & PG_MANAGED)
+ vm_page_flag_set(om, PG_REFERENCED);
+ if (opa != VM_PAGE_TO_PHYS(m))
+ invlva = TRUE;
+ }
+ if (origpte & PG_M) {
+ KASSERT((origpte & PG_RW),
+ ("pmap_enter: modified page not writable:"
+ " va: 0x%x, pte: 0x%x", va, origpte));
+ if ((origpte & PG_MANAGED) &&
+ pmap_track_modified(va))
+ vm_page_dirty(om);
+ if ((prot & VM_PROT_WRITE) == 0)
+ invlva = TRUE;
+ }
+ if (invlva)
+ pmap_invalidate_page(pmap, va);
} else
pte_store(pte, newpte | PG_A);
- if (origpte) {
- pmap_invalidate_page(pmap, va);
- }
}
sched_unpin();
vm_page_unlock_queues();
OpenPOWER on IntegriCloud