summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2013-07-03 23:21:25 +0000
committerneel <neel@FreeBSD.org>2013-07-03 23:21:25 +0000
commitbfcf8b6dd678beced16df63a3c17f7740eebbe86 (patch)
tree9e6fe5349f1192ad97c561454b29a0152d2e8762
parent468b664f74fc046f41935be989f161a0d85878c0 (diff)
downloadFreeBSD-src-bfcf8b6dd678beced16df63a3c17f7740eebbe86.zip
FreeBSD-src-bfcf8b6dd678beced16df63a3c17f7740eebbe86.tar.gz
If a superpage mapping is being removed then we need to ignore the PG_PDE_PAT
bit when looking up the vm_page associated with the superpage's physical address. If the caching attribute for the mapping is write combining or write protected then the PG_PDE_PAT bit will be set and thus cause an 'off-by-one' error when looking up the vm_page. Fix this by using the PG_PS_FRAME mask to compute the physical address for a superpage mapping instead of PG_FRAME. This is a theoretical issue at this point since non-writeback attributes are currently used only for fictitious mappings and fictitious mappings are not subject to promotion. Discussed with: alc, kib MFC after: 2 weeks
-rw-r--r--sys/amd64/amd64/pmap.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index 8dcf232..e1d373c 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -4400,6 +4400,7 @@ pmap_remove_pages(pmap_t pmap)
int64_t bit;
uint64_t inuse, bitmask;
int allfree, field, freed, idx;
+ vm_paddr_t pa;
if (pmap != PCPU_GET(curpmap)) {
printf("warning: pmap_remove_pages called with non-current pmap\n");
@@ -4429,7 +4430,7 @@ pmap_remove_pages(pmap_t pmap)
pte = (pt_entry_t *)PHYS_TO_DMAP(tpte &
PG_FRAME);
pte = &pte[pmap_pte_index(pv->pv_va)];
- tpte = *pte & ~PG_PTE_PAT;
+ tpte = *pte;
}
if ((tpte & PG_V) == 0) {
panic("bad pte va %lx pte %lx",
@@ -4444,8 +4445,13 @@ pmap_remove_pages(pmap_t pmap)
continue;
}
- m = PHYS_TO_VM_PAGE(tpte & PG_FRAME);
- KASSERT(m->phys_addr == (tpte & PG_FRAME),
+ if (tpte & PG_PS)
+ pa = tpte & PG_PS_FRAME;
+ else
+ pa = tpte & PG_FRAME;
+
+ m = PHYS_TO_VM_PAGE(pa);
+ KASSERT(m->phys_addr == pa,
("vm_page_t %p phys_addr mismatch %016jx %016jx",
m, (uintmax_t)m->phys_addr,
(uintmax_t)tpte));
OpenPOWER on IntegriCloud