--- /dev/null
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+struct ioctl_gntdev_grant_ref {
+ /* The domain ID of the grant to be mapped. */
+ uint32_t domid;
+ /* The grant reference of the grant to be mapped. */
+ uint32_t ref;
+};
+
+/*
+ * Allocates a new page and creates a new grant reference.
+ */
+#define IOCTL_GNTALLOC_ALLOC_GREF \
+_IOC(_IOC_NONE, 'G', 5, sizeof(struct ioctl_gntalloc_alloc_gref))
+struct ioctl_gntalloc_alloc_gref {
+ /* IN parameters */
+ /* The ID of the domain to be given access to the grants. */
+ uint16_t domid;
+ /* Flags for this mapping */
+ uint16_t flags;
+ /* Number of pages to map */
+ uint32_t count;
+ /* OUT parameters */
+ /* The offset to be used on a subsequent call to mmap(). */
+ uint64_t index;
+ /* The grant references of the newly created grant, one per page */
+ /* Variable size, depending on count */
+ uint32_t gref_ids[1];
+};
+
+#define GNTALLOC_FLAG_WRITABLE 1
+
+/*
+ * Deallocates the grant reference, allowing the associated page to be freed if
+ * no other domains are using it.
+ */
+#define IOCTL_GNTALLOC_DEALLOC_GREF \
+_IOC(_IOC_NONE, 'G', 6, sizeof(struct ioctl_gntalloc_dealloc_gref))
+struct ioctl_gntalloc_dealloc_gref {
+ /* IN parameters */
+ /* The offset returned in the map operation */
+ uint64_t index;
+ /* Number of references to unmap */
+ uint32_t count;
+};
+
+#define IOCTL_GNTDEV_MAP_GRANT_REF \
+_IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_gntdev_map_grant_ref))
+struct ioctl_gntdev_map_grant_ref {
+ /* IN parameters */
+ /* The number of grants to be mapped. */
+ uint32_t count;
+ uint32_t pad;
+ /* OUT parameters */
+ /* The offset to be used on a subsequent call to mmap(). */
+ uint64_t index;
+ /* Variable IN parameter. */
+ /* Array of grant references, of size @count. */
+ struct ioctl_gntdev_grant_ref refs[1];
+};
+#define GNTDEV_MAP_WRITABLE 0x1
+
+#define IOCTL_GNTDEV_UNMAP_GRANT_REF \
+_IOC(_IOC_NONE, 'G', 1, sizeof(struct ioctl_gntdev_unmap_grant_ref))
+struct ioctl_gntdev_unmap_grant_ref {
+ /* IN parameters */
+ /* The offset was returned by the corresponding map operation. */
+ uint64_t index;
+ /* The number of pages to be unmapped. */
+ uint32_t count;
+ uint32_t pad;
+};
+
+
+int a_fd;
+int d_fd;
+
+struct data {
+ uint64_t* mem;
+ int handle;
+} items[128];
+
+void sa(int id) {
+ struct ioctl_gntalloc_alloc_gref arg = {
+ .domid = id,
+ .flags = GNTALLOC_FLAG_WRITABLE,
+ .count = 1
+ };
+ int rv = ioctl(a_fd, IOCTL_GNTALLOC_ALLOC_GREF, &arg);
+ if (rv)
+ printf("src-add error: %s (rv=%d)\n", strerror(errno), rv);
+ else {
+ int i=0;
+ while (items[i].mem) i++;
+ items[i].mem = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, a_fd, arg.index);
+ items[i].handle = arg.index;
+ printf("src-add mapped %d at %d=%ld\n", arg.gref_ids[0], arg.index, items[i].mem);
+ }
+}
+
+void sd(int ref) {
+ struct ioctl_gntalloc_dealloc_gref arg = {
+ .index = ref,
+ .count = 1
+ };
+
+ int rv = ioctl(a_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg);
+ if (rv)
+ printf("src-del error: %s (rv=%d)\n", strerror(errno), rv);
+}
+
+void mm(int domid, int refid) {
+ struct ioctl_gntdev_map_grant_ref arg = {
+ .count = 1,
+ .refs[0].domid = domid,
+ .refs[0].ref = refid,
+ };
+ int rv = ioctl(d_fd, IOCTL_GNTDEV_MAP_GRANT_REF, &arg);
+ if (rv)
+ printf("mm error: %s (rv=%d)\n", strerror(errno), rv);
+ else {
+ int i=0;
+ while (items[i].mem) i++;
+ items[i].mem = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, d_fd, arg.index);
+ items[i].handle = arg.index;
+ printf("mapped index %d at %ld\n", arg.index, items[i].mem);
+ }
+}
+
+void gu(int index) {
+ struct ioctl_gntdev_unmap_grant_ref arg = {
+ .index = index,
+ .count = 1,
+ };
+ int rv = ioctl(d_fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &arg);
+ if (rv)
+ printf("gu error: %s (rv=%d)\n", strerror(errno), rv);
+}
+
+void mu(void* addr) {
+ int i = 0;
+ munmap(addr, 4096);
+ while (i < 128)
+ {
+ if (items[i].mem == addr)
+ items[i].mem = 0;
+ i++;
+ }
+}
+
+int bump;
+
+void show() {
+ int i;
+ for(i=0; i < 128; i++) {
+ if (!items[i].mem)
+ continue;
+ uint64_t val = items[i].mem[0];
+ uint64_t repl = val + bump;
+ printf("%02d(%ld,%d): current %16lx new %16lx\n", i, items[i].mem, items[i].handle, val, repl);
+ items[i].mem[0] = repl;
+ }
+ printf("END\n");
+}
+
+int main(int argc, char** argv) {
+ a_fd = open("/dev/xen/gntalloc", O_RDWR);
+ d_fd = open("/dev/xen/gntdev", O_RDWR);
+ bump = 1 << (2 * (getpid() % 12));
+ printf(
+ "src-add <domid> return gntref, address\n"
+ "map <domid> <ref> return index, address\n"
+ "src-del <gntref> no rv\n"
+ "gu <index> no rv\n"
+ "unmap <address> no rv\n"
+ "show print and change mapped items\n"
+ " This process bumps by %x\n",
+ bump
+ );
+ while (1) {
+ char line[80];
+ char word[30];
+ long a, b;
+ printf("\n> ");
+ fflush(stdout);
+ fgets(line, 80, stdin);
+ sscanf(line, "%s %ld %ld", word, &a, &b);
+ if (!strcmp(word, "src-add")) {
+ sa(a);
+ } else if (!strcmp(word, "src-del")) {
+ sd(a);
+ } else if (!strcmp(word, "map")) {
+ mm(a, b);
+ } else if (!strcmp(word, "gu")) {
+ gu(a);
+ } else if (!strcmp(word, "unmap")) {
+ mu((void*)a);
+ } else {
+ show();
+ }
+ }
+}