[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v6] Userspace grant communication
Changes since v5: - Added a tested xen version to workaround in #4 - Cleaned up variable names & structures - Clarified some of the cleanup in gntalloc - Removed copyright statement from public-domain files [PATCH 1/6] xen-gntdev: Change page limit to be global instead of per-open [PATCH 2/6] xen-gntdev: Use find_vma rather than iterating our vma list manually [PATCH 3/6] xen-gntdev: Add reference counting to maps [PATCH 4/6] xen-gntdev: Support mapping in HVM domains [PATCH 5/6] xen-gntalloc: Userspace grant allocation driver [PATCH 6/6] xen/gntalloc,gntdev: Add unmap notify ioctl Test/Demo code (also updated): #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; }; /* * 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 { struct shr_page* 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); 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) { 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); else printf("Stopped offering grant at offset %d\n", ref); } 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("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) { 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); else printf("Unhooked mapped grant at offset %d\n", index); } void mu(void* addr) { int i = 0; munmap(addr, 4096); while (i < 128) { if (items[i].mem == addr) items[i].mem = 0; i++; } printf("Unmapped page at %p\n", addr); } void show(char* word) { int i; int wlen = strlen(word); for(i=0; i < 128; i++) { if (!items[i].mem) continue; 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); printf( "add <domid> return gntref, address\n" "map <domid> <ref> return index, address\n" "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[80]; long a, b; printf("\n> "); fflush(stdout); fgets(line, 80, stdin); sscanf(line, "%s %ld %ld", word, &a, &b); if (!strcmp(word, "add")) { sa(a); } else if (!strcmp(word, "map")) { mm(a, b); } 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(word); } } } _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |