#include #include #include #include #include #include #include #include #include struct gntdev_grant_copy_segment { union { void *virt; struct { grant_ref_t ref; uint16_t offset; domid_t domid; } foreign; } source, dest; uint16_t len; uint16_t flags; /* GNTCOPY_* */ int16_t status; /* GNTST_* */ }; #define IOCTL_GNTDEV_GRANT_COPY \ _IOC(_IOC_NONE, 'G', 8, sizeof(struct ioctl_gntdev_grant_copy)) struct ioctl_gntdev_grant_copy { unsigned int count; struct gntdev_grant_copy_segment *segments; }; #define NR_REFS 15 static void random_fill(char *buf, size_t len) { int fd; int r = 0; fd = open("/dev/urandom", O_RDONLY); if (fd < 0) { perror("open(/dev/urandom)"); exit(1); } while (r < len) { int ret; ret = read(fd, buf + r, len - r); if (ret < 0) { perror("read"); exit(1); } r += ret; } close(fd); } static void do_copy(struct ioctl_gntdev_grant_copy *copy, char *a, char *b) { int fd; unsigned int i; int ret; random_fill(a, NR_REFS * 4096); fd = open("/dev/xen/gntdev", O_RDWR); if (fd < 0) { perror("open(/dev/xen/gntdev)"); exit(1); } ret = ioctl(fd, IOCTL_GNTDEV_GRANT_COPY, copy); if (ret < 0) { perror("ioctl(IOCTL_GNTDEV_GRANT_COPY)"); exit(1); } close(fd); for (i = 0; i < NR_REFS; i++) { if (copy->segments[i].status != GNTST_okay) { fprintf(stderr, "[%u]: bad copy status: %d\n", i, copy->segments[i].status); exit(1); } } if (memcmp(a, b, NR_REFS * 4096) != 0) { fprintf(stderr, "a != b\n"); exit(1); } } int main(void) { xc_gntshr *gs; xc_gnttab *gt; uint32_t refs[NR_REFS]; struct gntdev_grant_copy_segment seg[NR_REFS]; struct ioctl_gntdev_grant_copy copy; char *shared; char local[4096 * NR_REFS]; unsigned int i; gs = xc_gntshr_open(NULL, 0); if (!gs) { perror("xc_gntshr_open"); exit(1); } gt = xc_gnttab_open(NULL, 0); if (!gt) { perror("xc_gnttab_open"); exit(1); } shared = xc_gntshr_share_pages(gs, 0, NR_REFS, refs, 1); if (shared == NULL) { perror("xc_gntshr_share_pages"); exit(1); } /* * 1. ref -> local */ printf("ref -> local\n"); for (i = 0; i < NR_REFS; i++) { seg[i].source.foreign.ref = refs[i]; seg[i].source.foreign.offset = 0; seg[i].source.foreign.domid = 0; seg[i].dest.virt = local + i * 4096; seg[i].len = 4096; seg[i].flags = GNTCOPY_source_gref; } copy.count = NR_REFS; copy.segments = seg; do_copy(©, shared, local); printf(" ok\n"); /* * 2. local -> ref */ printf("local -> ref\n"); for (i = 0; i < NR_REFS; i++) { seg[i].source.virt = local + i * 4096; seg[i].dest.foreign.ref = refs[i]; seg[i].dest.foreign.offset = 0; seg[i].dest.foreign.domid = 0; seg[i].len = 4096; seg[i].flags = GNTCOPY_dest_gref; } copy.count = NR_REFS; copy.segments = seg; do_copy(©, local, shared); printf(" ok\n"); return 0; }