Files
xen/tools/tests/resource/test-resource.c
T
Andrew Cooper 0263dc9069 tests/resource: Fix HVM guest in !SHADOW builds
Right now, test-resource always creates HVM Shadow guests.  But if Xen has
SHADOW compiled out, running the test yields:

  $./test-resource
  XENMEM_acquire_resource tests
  Test x86 PV
    Created d1
    Test grant table
  Test x86 PVH
    Skip: 95 - Operation not supported

and doesn't really test HVM guests, but doesn't fail either.

There's nothing paging-mode-specific about this test, so default to HAP if
possible and provide a more specific message if neither HAP or Shadow are
available.

As we've got physinfo to hand, also provide more specific message about the
absence of PV or HVM support.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Roger Pau Monné <roger.pau@citrix.com>
2024-03-01 20:14:19 +00:00

283 lines
7.8 KiB
C

#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <xenctrl.h>
#include <xenforeignmemory.h>
#include <xengnttab.h>
#include <xen-tools/common-macros.h>
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 xc_physinfo_t physinfo;
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);
#if defined(__x86_64__) || defined(__i386__)
if ( t->create.flags & XEN_DOMCTL_CDF_hvm )
{
if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_hvm) )
{
printf(" Skip: HVM not available\n");
continue;
}
/*
* On x86, use HAP guests if possible, but skip if neither HAP nor
* SHADOW is available.
*/
if ( physinfo.capabilities & XEN_SYSCTL_PHYSCAP_hap )
t->create.flags |= XEN_DOMCTL_CDF_hap;
else if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_shadow) )
{
printf(" Skip: Neither HAP or SHADOW available\n");
continue;
}
}
else
{
if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_pv) )
{
printf(" Skip: PV not available\n");
continue;
}
}
#endif
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)
{
int rc;
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");
rc = xc_physinfo(xch, &physinfo);
if ( rc )
err(1, "Failed to obtain physinfo");
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:
*/