#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;
uint32_t pad;
};
+/*
+ * Sets up an unmap notification within the page, so that the other side can do
+ * cleanup if this side crashes. Required to implement cross-domain robust
+ * mutexes or close notification on communication channels.
+ *
+ * Each mapped page only supports one notification; multiple calls referring to
+ * the same page overwrite the previous notification. You must clear the
+ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
+ * to occur.
+ */
+#define IOCTL_GNTDEV_SET_UNMAP_NOTIFY \
+_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntdev_unmap_notify))
+struct ioctl_gntdev_unmap_notify {
+ /* IN parameters */
+ /* Index of a byte in the page */
+ uint64_t index;
+ /* Action(s) to take on unmap */
+ uint32_t action;
+ /* Event channel to notify */
+ uint32_t event_channel_port;
+};
+
+/* Clear (set to zero) the byte specified by index */
+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
+/* Send an interrupt on the indicated event channel */
+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
+/*
+ * Sets up an unmap notification within the page, so that the other side can do
+ * cleanup if this side crashes. Required to implement cross-domain robust
+ * mutexes or close notification on communication channels.
+ *
+ * Each mapped page only supports one notification; multiple calls referring to
+ * the same page overwrite the previous notification. You must clear the
+ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
+ * to occur.
+ */
+#define IOCTL_GNTALLOC_SET_UNMAP_NOTIFY \
+_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntalloc_unmap_notify))
+struct ioctl_gntalloc_unmap_notify {
+ /* IN parameters */
+ /* Index of a byte in the page */
+ uint64_t index;
+ /* Action(s) to take on unmap */
+ uint32_t action;
+ /* Event channel to notify */
+ uint32_t event_channel_port;
+};
+
+/* Clear (set to zero) the byte specified by index */
+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
+/* Send an interrupt on the indicated event channel */
+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
int a_fd;
int d_fd;
+struct shr_page {
+ uint64_t id;
+ char buffer[64];
+ uint8_t notifies[8];
+};
+
struct data {
- uint64_t* mem;
+ struct shr_page* mem;
int handle;
} items[128];
-void sa(int id) {
+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)
+ 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);
+ return;
+ }
+ int i=0;
+ while (items[i].mem) i++;
+ items[i].mem = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, a_fd, arg.index);
+ if (items[i].mem == MAP_FAILED) {
+ items[i].mem = 0;
+ printf("mmap failed: SHOULD NOT HAPPEN\n");
+ return;
}
+ items[i].handle = arg.index;
+ printf("Created shared page with domain %d, grant #%d. Mapped locally at %d=%p\n",
+ id, arg.gref_ids[0], arg.index, items[i].mem);
+
+ items[i].mem->id = rand() | ((long)(getpid()) << 32);
+ items[i].mem->notifies[0] = 1;
+ struct ioctl_gntalloc_unmap_notify uarg = {
+ .index = arg.index + offsetof(struct shr_page, notifies[0]),
+ .action = UNMAP_NOTIFY_CLEAR_BYTE
+ };
+ rv = ioctl(a_fd, IOCTL_GNTALLOC_SET_UNMAP_NOTIFY, &uarg);
+ if (rv)
+ printf("gntalloc unmap notify error: %s (rv=%d)\n", strerror(errno), rv);
}
void sd(int ref) {
int rv = ioctl(a_fd, IOCTL_GNTALLOC_DEALLOC_GREF, &arg);
if (rv)
printf("src-del error: %s (rv=%d)\n", strerror(errno), rv);
+ else
+ printf("Stopped offering grant at offset %d\n", ref);
}
void mm(int domid, int refid) {
.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);
+ if (rv) {
+ printf("Could not map grant %d.%d: %s (rv=%d)\n", domid, refid, strerror(errno), rv);
+ return;
}
+ int i=0,j=1;
+ while (items[i].mem) i++;
+ items[i].mem = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, d_fd, arg.index);
+ if (items[i].mem == MAP_FAILED) {
+ items[i].mem = 0;
+ printf("Could not map grant %d.%d: %s (map failed)\n", domid, refid, strerror(errno), rv);
+ return;
+ }
+ items[i].handle = arg.index;
+ printf("Mapped grant %d.%d as %d=%p\n", domid, refid, arg.index, items[i].mem);
+
+ while (items[i].mem->notifies[j]) j++;
+ items[i].mem->notifies[j] = 1;
+ struct ioctl_gntalloc_unmap_notify uarg = {
+ .index = arg.index + offsetof(struct shr_page, notifies[j]),
+ .action = UNMAP_NOTIFY_CLEAR_BYTE
+ };
+ rv = ioctl(d_fd, IOCTL_GNTDEV_SET_UNMAP_NOTIFY, &uarg);
+ if (rv)
+ printf("gntdev unmap notify error: %s (rv=%d)\n", strerror(errno), rv);
}
void gu(int index) {
int rv = ioctl(d_fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &arg);
if (rv)
printf("gu error: %s (rv=%d)\n", strerror(errno), rv);
+ else
+ printf("Unhooked mapped grant at offset %d\n", index);
}
void mu(void* addr) {
items[i].mem = 0;
i++;
}
+ printf("Unmapped page at %p\n", addr);
}
-int bump;
-
-void show() {
+void show(char* word) {
int i;
+ int wlen = strlen(word);
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;
+ memmove(items[i].mem->buffer + wlen, items[i].mem->buffer, 63 - wlen);
+ memcpy(items[i].mem->buffer, word, wlen);
+ printf("%02d(%ld,%d): id %16lx n=%d%d%d%d%d%d%d%d b=%s\n",
+ i, items[i].mem, items[i].handle, items[i].mem->id,
+ items[i].mem->notifies[0], items[i].mem->notifies[1], items[i].mem->notifies[2], items[i].mem->notifies[3],
+ items[i].mem->notifies[4], items[i].mem->notifies[5], items[i].mem->notifies[6], items[i].mem->notifies[7],
+ items[i].mem->buffer);
}
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"
+ "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
+ "adel <gntref> delete <add> internal\n"
+ "ddel <index> delete <map> internal\n"
+ "unmap <address> unmap memory\n"
+ "show show all pages\n"
+ "<word> append word to all mapped pages, show\n"
+ " PID %x\n", getpid()
);
while (1) {
char line[80];
- char word[30];
+ char word[80];
long a, b;
printf("\n> ");
fflush(stdout);
fgets(line, 80, stdin);
sscanf(line, "%s %ld %ld", word, &a, &b);
- if (!strcmp(word, "src-add")) {
+ if (!strcmp(word, "add")) {
sa(a);
- } else if (!strcmp(word, "src-del")) {
- sd(a);
} else if (!strcmp(word, "map")) {
mm(a, b);
- } else if (!strcmp(word, "gu")) {
+ } else if (!strcmp(word, "adel")) {
+ sd(a);
+ } else if (!strcmp(word, "ddel")) {
gu(a);
} else if (!strcmp(word, "unmap")) {
mu((void*)a);
+ } else if (!strcmp(word, "show")) {
+ show("");
} else {
- show();
+ show(word);
}
}
}