#include #include #include #include #include #include #include #include #include static unsigned int nr_failures; #define fail(fmt, ...) \ ({ \ nr_failures++; \ (void)printf(fmt, ##__VA_ARGS__); \ }) static xc_interface *xch; static xenforeignmemory_handle *fh; static xengnttab_handle *gh; static void test_gnttab(uint32_t domid, unsigned int nr_frames, unsigned long gfn) { xenforeignmemory_resource_handle *res; grant_entry_v1_t *gnttab = NULL; size_t size; int rc; uint32_t refs[nr_frames], domids[nr_frames]; void *grants; printf(" Test grant table\n"); /* Obtain the grant table resource size. */ rc = xenforeignmemory_resource_size( fh, domid, XENMEM_resource_grant_table, XENMEM_resource_grant_table_id_shared, &size); /* * A failure of this call indicates missing kernel support for size * ioctl(), or missing Xen acquire_resource support. */ if ( rc ) return fail(" Fail: Get size: %d - %s\n", errno, strerror(errno)); /* * Getting 32 frames back instead of nr_frames indicates Xen is missing * the bugfix to make size requests actually return real data. */ if ( (size >> XC_PAGE_SHIFT) != nr_frames ) return fail(" Fail: Get size: expected %u frames, got %zu\n", nr_frames, size >> XC_PAGE_SHIFT); /* Map the entire grant table. */ res = xenforeignmemory_map_resource( fh, domid, XENMEM_resource_grant_table, XENMEM_resource_grant_table_id_shared, 0, size >> XC_PAGE_SHIFT, (void **)&gnttab, PROT_READ | PROT_WRITE, 0); /* * Failure here with E2BIG indicates Xen is missing the bugfix to map * resources larger than 32 frames. */ if ( !res ) return fail(" Fail: Map grant table %d - %s\n", errno, strerror(errno)); /* Put each gref at a unique offset in its frame. */ for ( unsigned int i = 0; i < nr_frames; i++ ) { unsigned int gref = i * (XC_PAGE_SIZE / sizeof(*gnttab)) + i; refs[i] = gref; domids[i] = domid; gnttab[gref].domid = 0; gnttab[gref].frame = gfn; gnttab[gref].flags = GTF_permit_access; } /* Map grants. */ grants = xengnttab_map_grant_refs(gh, nr_frames, domids, refs, PROT_READ | PROT_WRITE); /* * Failure here indicates either that the frames were not mapped * in the correct order or xenforeignmemory_map_resource() didn't * give us the frames we asked for to begin with. */ if ( grants == NULL ) { fail(" Fail: Map grants %d - %s\n", errno, strerror(errno)); goto out; } /* Unmap grants. */ rc = xengnttab_unmap(gh, grants, nr_frames); if ( rc ) fail(" Fail: Unmap grants %d - %s\n", errno, strerror(errno)); /* Unmap grant table. */ out: rc = xenforeignmemory_unmap_resource(fh, res); if ( rc ) return fail(" Fail: Unmap grant table %d - %s\n", errno, strerror(errno)); /* * Verify that an attempt to map the status frames fails, as the domain is * in gnttab v1 mode. */ res = xenforeignmemory_map_resource( fh, domid, XENMEM_resource_grant_table, XENMEM_resource_grant_table_id_status, 0, 1, (void **)&gnttab, PROT_READ | PROT_WRITE, 0); if ( res ) { fail(" Fail: Managed to map gnttab v2 status frames in v1 mode\n"); xenforeignmemory_unmap_resource(fh, res); } } static void test_domain_configurations(void) { static struct test { const char *name; struct xen_domctl_createdomain create; } tests[] = { #if defined(__x86_64__) || defined(__i386__) { .name = "x86 PV", .create = { .max_vcpus = 2, .max_grant_frames = 40, .grant_opts = XEN_DOMCTL_GRANT_version(1), }, }, { .name = "x86 PVH", .create = { .flags = XEN_DOMCTL_CDF_hvm, .max_vcpus = 2, .max_grant_frames = 40, .grant_opts = XEN_DOMCTL_GRANT_version(1), .arch = { .emulation_flags = XEN_X86_EMU_LAPIC, }, }, }, #elif defined(__aarch64__) || defined(__arm__) { .name = "ARM", .create = { .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap, .max_vcpus = 2, .max_grant_frames = 40, .grant_opts = XEN_DOMCTL_GRANT_version(1), }, }, #endif }; for ( unsigned int i = 0; i < ARRAY_SIZE(tests); ++i ) { struct test *t = &tests[i]; uint32_t domid = 0; int rc; xen_pfn_t ram[1] = { 0 }; printf("Test %s\n", t->name); rc = xc_domain_create(xch, &domid, &t->create); if ( rc ) { if ( errno == EINVAL || errno == EOPNOTSUPP ) printf(" Skip: %d - %s\n", errno, strerror(errno)); else fail(" Domain create failure: %d - %s\n", errno, strerror(errno)); continue; } printf(" Created d%u\n", domid); rc = xc_domain_setmaxmem(xch, domid, -1); if ( rc ) { fail(" Failed to set max memory for domain: %d - %s\n", errno, strerror(errno)); goto test_done; } rc = xc_domain_populate_physmap_exact( xch, domid, ARRAY_SIZE(ram), 0, 0, ram); if ( rc ) { fail(" Failed to populate physmap domain: %d - %s\n", errno, strerror(errno)); goto test_done; } test_gnttab(domid, t->create.max_grant_frames, ram[0]); test_done: rc = xc_domain_destroy(xch, domid); if ( rc ) fail(" Failed to destroy domain: %d - %s\n", errno, strerror(errno)); } } int main(int argc, char **argv) { printf("XENMEM_acquire_resource tests\n"); xch = xc_interface_open(NULL, NULL, 0); fh = xenforeignmemory_open(NULL, 0); gh = xengnttab_open(NULL, 0); if ( !xch ) err(1, "xc_interface_open"); if ( !fh ) err(1, "xenforeignmemory_open"); if ( !gh ) err(1, "xengnttab_open"); test_domain_configurations(); return !!nr_failures; } /* * Local variables: * mode: C * c-file-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */