mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
tests/paging-mempool: Extend to test P2M relocation
XENMAPSPACE_gmfn_range was found to be buggy with overlapping ranges, and the fix is sufficiently far from clear that yours truly decided a test was in order. XENMAPSPACE_gmfn_range is exposed by xendevicemodel_relocate_memory() so take the opportunity to create a better example for others to copy. The test works as follows. Populate 2M of RAM in the guest, marking the pages so they can be identified later. Then construct four relocation test cases (overlapping vs non-overlapping, forwards vs backwards) using the marks in the guest pages to confirm that the P2M was adjusted correctly. The use of XEN_DOMCTL_CDF_iommu forces xenmem_add_to_physmap() to limit the iteration count to a maximum of 16. Use this to force a continuation and exercise more of the logic. Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> Acked-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
d53ba690b0
commit
66c982a5d3
3 files changed
+209
-2
No files matched your search
@@ -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
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <xenctrl.h>
|
||||
#include <xendevicemodel.h>
|
||||
#include <xenforeignmemory.h>
|
||||
#include <xengnttab.h>
|
||||
#include <xen-tools/common-macros.h>
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
+1
-1
@@ -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) )
|
||||
{
|
||||
|
||||