summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorattilio <attilio@FreeBSD.org>2013-03-17 23:39:52 +0000
committerattilio <attilio@FreeBSD.org>2013-03-17 23:39:52 +0000
commitd500d6361abe652aef27a2c034835bc2a60155ad (patch)
tree660c72c3a1b0cbf41943fa591b5ed5d1f31c50f6 /sys/i386
parenta69d85af8b2642ba2d10b8aa37bc58a3123ec1c6 (diff)
parent960294c20051941b358bdc3d71e05fa682614d6f (diff)
downloadFreeBSD-src-d500d6361abe652aef27a2c034835bc2a60155ad.zip
FreeBSD-src-d500d6361abe652aef27a2c034835bc2a60155ad.tar.gz
MFC
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/i386/pmap.c43
-rw-r--r--sys/i386/xen/pmap.c40
2 files changed, 83 insertions, 0 deletions
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
index ba63e21..6499986 100644
--- a/sys/i386/i386/pmap.c
+++ b/sys/i386/i386/pmap.c
@@ -4205,6 +4205,49 @@ pmap_copy_page(vm_page_t src, vm_page_t dst)
mtx_unlock(&sysmaps->lock);
}
+void
+pmap_copy_pages(vm_page_t ma[], vm_offset_t a_offset, vm_page_t mb[],
+ vm_offset_t b_offset, int xfersize)
+{
+ struct sysmaps *sysmaps;
+ vm_page_t a_pg, b_pg;
+ char *a_cp, *b_cp;
+ vm_offset_t a_pg_offset, b_pg_offset;
+ int cnt;
+
+ sysmaps = &sysmaps_pcpu[PCPU_GET(cpuid)];
+ mtx_lock(&sysmaps->lock);
+ if (*sysmaps->CMAP1 != 0)
+ panic("pmap_copy_pages: CMAP1 busy");
+ if (*sysmaps->CMAP2 != 0)
+ 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);
+ b_pg = mb[b_offset >> PAGE_SHIFT];
+ 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);
+ *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);
+ a_cp = sysmaps->CADDR1 + a_pg_offset;
+ b_cp = sysmaps->CADDR2 + b_pg_offset;
+ bcopy(a_cp, b_cp, cnt);
+ a_offset += cnt;
+ b_offset += cnt;
+ xfersize -= cnt;
+ }
+ *sysmaps->CMAP1 = 0;
+ *sysmaps->CMAP2 = 0;
+ sched_unpin();
+ mtx_unlock(&sysmaps->lock);
+}
+
/*
* Returns true if the pmap's pv is one of the first
* 16 pvs linked to from this page. This count may
diff --git a/sys/i386/xen/pmap.c b/sys/i386/xen/pmap.c
index 3c7c3f5..0f7a80f 100644
--- a/sys/i386/xen/pmap.c
+++ b/sys/i386/xen/pmap.c
@@ -3448,6 +3448,46 @@ pmap_copy_page(vm_page_t src, vm_page_t dst)
mtx_unlock(&sysmaps->lock);
}
+void
+pmap_copy_pages(vm_page_t ma[], vm_offset_t a_offset, vm_page_t mb[],
+ vm_offset_t b_offset, int xfersize)
+{
+ struct sysmaps *sysmaps;
+ vm_page_t a_pg, b_pg;
+ char *a_cp, *b_cp;
+ vm_offset_t a_pg_offset, b_pg_offset;
+ int cnt;
+
+ sysmaps = &sysmaps_pcpu[PCPU_GET(cpuid)];
+ mtx_lock(&sysmaps->lock);
+ if (*sysmaps->CMAP1 != 0)
+ panic("pmap_copy_pages: CMAP1 busy");
+ if (*sysmaps->CMAP2 != 0)
+ panic("pmap_copy_pages: CMAP2 busy");
+ sched_pin();
+ while (xfersize > 0) {
+ a_pg = ma[a_offset >> PAGE_SHIFT];
+ a_pg_offset = a_offset & PAGE_MASK;
+ cnt = min(xfersize, PAGE_SIZE - a_pg_offset);
+ b_pg = mb[b_offset >> PAGE_SHIFT];
+ b_pg_offset = b_offset & PAGE_MASK;
+ cnt = min(cnt, PAGE_SIZE - b_pg_offset);
+ PT_SET_MA(sysmaps->CADDR1, PG_V | VM_PAGE_TO_MACH(a_pg) | PG_A);
+ PT_SET_MA(sysmaps->CADDR2, PG_V | PG_RW |
+ VM_PAGE_TO_MACH(b_pg) | PG_A | PG_M);
+ a_cp = sysmaps->CADDR1 + a_pg_offset;
+ b_cp = sysmaps->CADDR2 + b_pg_offset;
+ bcopy(a_cp, b_cp, cnt);
+ a_offset += cnt;
+ b_offset += cnt;
+ xfersize -= cnt;
+ }
+ PT_SET_MA(sysmaps->CADDR1, 0);
+ PT_SET_MA(sysmaps->CADDR2, 0);
+ sched_unpin();
+ mtx_unlock(&sysmaps->lock);
+}
+
/*
* Returns true if the pmap's pv is one of the first
* 16 pvs linked to from this page. This count may
OpenPOWER on IntegriCloud