summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/i386/i386/pmap.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
index 477ff01..e5f564a 100644
--- a/sys/i386/i386/pmap.c
+++ b/sys/i386/i386/pmap.c
@@ -1286,6 +1286,13 @@ pmap_pte_release(pt_entry_t *pte)
mtx_unlock(&PMAP2mutex);
}
+/*
+ * NB: The sequence of updating a page table followed by accesses to the
+ * corresponding pages is subject to the situation described in the "AMD64
+ * Architecture Programmer's Manual Volume 2: System Programming" rev. 3.23,
+ * "7.3.1 Special Coherency Considerations". Therefore, issuing the INVLPG
+ * right after modifying the PTE bits is crucial.
+ */
static __inline void
invlcaddr(void *caddr)
{
@@ -4240,12 +4247,12 @@ pmap_copy_page(vm_page_t src, vm_page_t dst)
if (*sysmaps->CMAP2)
panic("pmap_copy_page: CMAP2 busy");
sched_pin();
- invlpg((u_int)sysmaps->CADDR1);
- invlpg((u_int)sysmaps->CADDR2);
*sysmaps->CMAP1 = PG_V | VM_PAGE_TO_PHYS(src) | PG_A |
pmap_cache_bits(src->md.pat_mode, 0);
+ invlcaddr(sysmaps->CADDR1);
*sysmaps->CMAP2 = PG_V | PG_RW | VM_PAGE_TO_PHYS(dst) | PG_A | PG_M |
pmap_cache_bits(dst->md.pat_mode, 0);
+ invlcaddr(sysmaps->CADDR2);
bcopy(sysmaps->CADDR1, sysmaps->CADDR2, PAGE_SIZE);
*sysmaps->CMAP1 = 0;
*sysmaps->CMAP2 = 0;
@@ -4273,8 +4280,6 @@ pmap_copy_pages(vm_page_t ma[], vm_offset_t a_offset, vm_page_t mb[],
panic("pmap_copy_pages: CMAP2 busy");
sched_pin();
while (xfersize > 0) {
- invlpg((u_int)sysmaps->CADDR1);
- invlpg((u_int)sysmaps->CADDR2);
a_pg = ma[a_offset >> PAGE_SHIFT];
a_pg_offset = a_offset & PAGE_MASK;
cnt = min(xfersize, PAGE_SIZE - a_pg_offset);
@@ -4282,9 +4287,11 @@ pmap_copy_pages(vm_page_t ma[], vm_offset_t a_offset, vm_page_t mb[],
b_pg_offset = b_offset & PAGE_MASK;
cnt = min(cnt, PAGE_SIZE - b_pg_offset);
*sysmaps->CMAP1 = PG_V | VM_PAGE_TO_PHYS(a_pg) | PG_A |
- pmap_cache_bits(b_pg->md.pat_mode, 0);
+ pmap_cache_bits(a_pg->md.pat_mode, 0);
+ invlcaddr(sysmaps->CADDR1);
*sysmaps->CMAP2 = PG_V | PG_RW | VM_PAGE_TO_PHYS(b_pg) | PG_A |
PG_M | pmap_cache_bits(b_pg->md.pat_mode, 0);
+ invlcaddr(sysmaps->CADDR2);
a_cp = sysmaps->CADDR1 + a_pg_offset;
b_cp = sysmaps->CADDR2 + b_pg_offset;
bcopy(a_cp, b_cp, cnt);
OpenPOWER on IntegriCloud