diff --git a/tools/tests/paging-mempool/Makefile b/tools/tests/paging-mempool/Makefile index a1e12584ce..7444d81b84 100644 --- a/tools/tests/paging-mempool/Makefile +++ b/tools/tests/paging-mempool/Makefile @@ -25,9 +25,13 @@ uninstall: CFLAGS += $(CFLAGS_xeninclude) CFLAGS += $(CFLAGS_libxenctrl) +CFLAGS += $(CFLAGS_libxendevicemodel) +CFLAGS += $(CFLAGS_libxenforeignmemory) CFLAGS += $(APPEND_CFLAGS) LDFLAGS += $(LDLIBS_libxenctrl) +LDFLAGS += $(LDLIBS_libxendevicemodel) +LDFLAGS += $(LDLIBS_libxenforeignmemory) LDFLAGS += $(APPEND_LDFLAGS) %.o: Makefile diff --git a/tools/tests/paging-mempool/test-paging-mempool.c b/tools/tests/paging-mempool/test-paging-mempool.c index 9ef8252126..3c87925288 100644 --- a/tools/tests/paging-mempool/test-paging-mempool.c +++ b/tools/tests/paging-mempool/test-paging-mempool.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -19,10 +20,15 @@ static unsigned int nr_failures; }) static xc_interface *xch; +static xendevicemodel_handle *dh; +static xenforeignmemory_handle *fh; static uint32_t domid; static struct xen_domctl_createdomain create = { - .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap, + .flags = (XEN_DOMCTL_CDF_hvm | + XEN_DOMCTL_CDF_hap | + XEN_DOMCTL_CDF_iommu | + 0), .max_vcpus = 1, .max_grant_frames = 1, .grant_opts = XEN_DOMCTL_GRANT_version(1), @@ -146,6 +152,191 @@ static int test_paging_mempool_size(void) return 0; } +static int mark_guest_mem(xen_pfn_t gfn, size_t count) +{ + xen_pfn_t gfns[count]; + uint32_t *mem; + size_t i; + int rc; + + for ( i = 0; i < count; ++i ) + gfns[i] = gfn + i; + + mem = xenforeignmemory_map(fh, domid, PROT_READ | PROT_WRITE, + count, gfns, NULL); + if ( !mem ) + return fail(" Fail: mark mem foreign map: %d - %s\n", + errno, strerror(errno)); + + for ( i = 0; i < count; ++i ) + { + uint32_t *mark = &mem[i << 10]; + + *mark = ~i; + } + + rc = xenforeignmemory_unmap(fh, mem, count); + if ( rc ) + return fail(" Fail: mark mem foreign unmap: %d - %s\n", + errno, strerror(errno)); + + return 0; +} + +static int check_guest_marks(xen_pfn_t gfn, uint32_t mark_start, size_t count) +{ + xen_pfn_t gfns[count]; + int errs[count]; + uint32_t *mem; + size_t i; + int rc = 0; + + for ( i = 0; i < count; ++i ) + gfns[i] = gfn + i; + + mem = xenforeignmemory_map(fh, domid, PROT_READ, + count, gfns, errs); + if ( !mem ) + return fail(" Fail: check mark foreign map: %d - %s\n", + errno, strerror(errno)); + + for ( i = 0; i < count; ++i ) + { + uint32_t *mark = &mem[i << 10]; + uint32_t exp = ~(mark_start + i); + + if ( errs[i] ) + { + rc = -1; + fail(" Fail: check mark unable to map gfn %05lx: %d\n", + gfns[i], errs[i]); + continue; + } + + if ( *mark == exp ) + continue; + + fail(" Fail: check mark: gfn %05lx expecting %08x (%u), got %08x (%u)\n", + gfns[i], exp, ~exp, *mark, ~*mark); + rc = -1; + } + + if ( xenforeignmemory_unmap(fh, mem, count) ) + return fail(" Fail: check marks foreign unmap: %d - %s\n", + errno, strerror(errno)); + + return rc; +} + +static int test_p2m_relocate_memory(void) +{ +#define GFN_2M ((2UL << 20) >> 12) +#define GFN_4M ((4UL << 20) >> 12) + + xen_pfn_t physmap[] = { GFN_2M }; + int rc; + + /* + * Inherited state of the domain: + * - Unlimited allocation + * - XEN_DOMCTL_CDF_iommu, which causes xendevicemodel_relocate_memory() + * to undergo continuations every 16 pages + * + * Construction of the test: + * - Populate 2M at 2M, mark the pages. + */ + printf("Test p2m memory relocation\n"); + + rc = xc_domain_populate_physmap_exact( + xch, domid, ARRAY_SIZE(physmap), + 9 /* order 2M */, 0 /* flags */, physmap); + if ( rc ) + return fail(" Fail: populate physmap: %d - %s\n", + errno, strerror(errno)); + + rc = mark_guest_mem(GFN_2M, 1 << 9 /* order 2M */); + if ( rc ) + return rc; + + /* Sanity check the start and end markers. */ + if ( (rc = check_guest_marks(GFN_2M, 0, 8)) || + (rc = check_guest_marks(GFN_4M - 8, 512 - 8, 8)) ) + return rc; + + +#define GFN_PAIR(g, c) (g), ((g) + (c) - 1) + + /* + * Move the final 32 pages below 4M forward by 32 pages. All destination + * GFNs free, and no overlap. + */ + printf(" Test forward, no overlap: GFNs [%lx...%lx] -> [%lx...%lx]\n", + GFN_PAIR(GFN_4M - 32, 32), GFN_PAIR(GFN_4M, 32)); + + rc = xendevicemodel_relocate_memory(dh, domid, 32, GFN_4M - 32, GFN_4M); + if ( rc ) + return fail(" Fail: relocate memory: %d - %s\n", + errno, strerror(errno)); + + rc = check_guest_marks(GFN_4M, 512 - 32, 32); + if ( rc ) + return rc; + + /* + * Move the next 32 pages below 4M forward by 1 page. The region is + * almost completely overlapping. + */ + printf(" Test forward, overlapping: GFNs [%lx...%lx] -> [%lx...%lx]\n", + GFN_PAIR(GFN_4M - 64, 32), GFN_PAIR(GFN_4M - 63, 32)); + + rc = xendevicemodel_relocate_memory(dh, domid, 32, GFN_4M - 64, GFN_4M - 63); + if ( rc ) + return fail(" Fail: relocate memory: %d - %s\n", + errno, strerror(errno)); + + rc = check_guest_marks(GFN_4M - 63, 512 - 64, 32); + if ( rc ) + return rc; + + /* + * Move the first 32 pages above 2M backwards by 32 pages. All + * destination GFNs free, and no overlap. + */ + printf(" Test backwards, no overlap: GFNs [%lx...%lx] -> [%lx...%lx]\n", + GFN_PAIR(GFN_2M, 32), GFN_PAIR(GFN_2M - 32, 32)); + + rc = xendevicemodel_relocate_memory(dh, domid, 32, GFN_2M, GFN_2M - 32); + if ( rc ) + return fail(" Fail: relocate memory: %d - %s\n", + errno, strerror(errno)); + + rc = check_guest_marks(GFN_2M - 32, 0, 32); + if ( rc ) + return rc; + + /* + * Move the next 32 pages above 2M backwards by 1 page. The region is + * almost completely overlapping. + */ + printf(" Test backwards, overlapping: GFNs [%lx...%lx] -> [%lx...%lx]\n", + GFN_PAIR(GFN_2M + 32, 32), GFN_PAIR(GFN_2M + 31, 32)); + + rc = xendevicemodel_relocate_memory(dh, domid, 32, GFN_2M + 32, GFN_2M + 31); + if ( rc ) + return fail(" Fail: relocate memory: %d - %s\n", + errno, strerror(errno)); + + rc = check_guest_marks(GFN_2M + 31, 32, 32); + if ( rc ) + return rc; + + return 0; + +#undef GFN_PAIR +#undef GFN_4M +#undef GFN_2M +} + static int run_tests(void) { int rc; @@ -154,6 +345,10 @@ static int run_tests(void) if ( rc ) return rc; + rc = test_p2m_relocate_memory(); + if ( rc ) + return rc; + return 0; } @@ -167,6 +362,14 @@ int main(int argc, char **argv) if ( !xch ) err(1, "xc_interface_open"); + dh = xendevicemodel_open(NULL, 0); + if ( !dh ) + err(1, "xendevicemodel_open"); + + fh = xenforeignmemory_open(NULL, 0); + if ( !fh ) + err(1, "xenforeignmemory_open"); + rc = xc_domain_create(xch, &domid, &create); if ( rc ) { diff --git a/xen/common/memory.c b/xen/common/memory.c index c90517e846..3672bda025 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -962,7 +962,7 @@ int xenmem_add_to_physmap(struct domain *d, struct xen_add_to_physmap *xatp, unsigned int done = 0; long rc = 0, adjust = 1; union add_to_physmap_extra extra = {}; - struct page_info *pages[16]; + struct page_info *pages[16]; /* If changing this, adjust test-paging-mempool too */ if ( !paging_mode_translate(d) ) {