diff options
author | neel <neel@FreeBSD.org> | 2013-07-03 23:21:25 +0000 |
---|---|---|
committer | neel <neel@FreeBSD.org> | 2013-07-03 23:21:25 +0000 |
commit | bfcf8b6dd678beced16df63a3c17f7740eebbe86 (patch) | |
tree | 9e6fe5349f1192ad97c561454b29a0152d2e8762 | |
parent | 468b664f74fc046f41935be989f161a0d85878c0 (diff) | |
download | FreeBSD-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.c | 12 |
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)); |