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
|