Port-xen archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[PATCH v2 1/3] libxc: add suport for NetBSD gntdev
Add OS specific handlers for NetBSD gntdev. The main difference is
that NetBSD passes the VA where the grant should be set inside the
IOCTL_GNTDEV_MAP_GRANT_REF ioctl, instead of using mmap (this is due
to OS constraints).
Signed-off-by: Roger Pau Monné <roger.pau%citrix.com@localhost>
---
tools/include/xen-sys/NetBSD/gntdev.h | 151 ++++++++++++++++++++++++++
tools/libxc/xc_netbsd.c | 188 +++++++++++++++++++++++++++++++++
2 files changed, 339 insertions(+), 0 deletions(-)
create mode 100644 tools/include/xen-sys/NetBSD/gntdev.h
diff --git a/tools/include/xen-sys/NetBSD/gntdev.h
b/tools/include/xen-sys/NetBSD/gntdev.h
new file mode 100644
index 0000000..a25133a
--- /dev/null
+++ b/tools/include/xen-sys/NetBSD/gntdev.h
@@ -0,0 +1,151 @@
+/******************************************************************************
+ * gntdev.h
+ *
+ * Interface to /dev/xen/gntdev.
+ *
+ * Copyright (c) 2007, D G Murray
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __NetBSD_PUBLIC_GNTDEV_H__
+#define __NetBSD_PUBLIC_GNTDEV_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;
+};
+
+/*
+ * Inserts the grant references into the mapping table of an instance
+ * of gntdev. N.B. This does not perform the mapping, which is deferred
+ * until mmap() is called with @index as the offset.
+ */
+#define IOCTL_GNTDEV_MAP_GRANT_REF \
+ _IOWR('G', 0, 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;
+ uint64_t vaddr;
+ /* 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;
+};
+
+/*
+ * Removes the grant references from the mapping table of an instance of
+ * of gntdev. N.B. munmap() must be called on the relevant virtual address(es)
+ * before this ioctl is called, or an error will result.
+ */
+#define IOCTL_GNTDEV_UNMAP_GRANT_REF \
+ _IOW('G', 1, 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;
+};
+
+/*
+ * Returns the offset in the driver's address space that corresponds
+ * to @vaddr. This can be used to perform a munmap(), followed by an
+ * UNMAP_GRANT_REF ioctl, where no state about the offset is retained by
+ * the caller. The number of pages that were allocated at the same time as
+ * @vaddr is returned in @count.
+ *
+ * N.B. Where more than one page has been mapped into a contiguous range, the
+ * supplied @vaddr must correspond to the start of the range; otherwise
+ * an error will result. It is only possible to munmap() the entire
+ * contiguously-allocated range at once, and not any subrange thereof.
+ */
+#define IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR \
+ _IOWR('G', 2, struct ioctl_gntdev_get_offset_for_vaddr)
+struct ioctl_gntdev_get_offset_for_vaddr {
+ /* IN parameters */
+ /* The virtual address of the first mapped page in a range. */
+ uint64_t vaddr;
+ /* OUT parameters */
+ /* The offset that was used in the initial mmap() operation. */
+ uint64_t offset;
+ /* The number of pages mapped in the VM area that begins at @vaddr. */
+ uint32_t count;
+ uint32_t pad;
+};
+
+/*
+ * Sets the maximum number of grants that may mapped at once by this gntdev
+ * instance.
+ *
+ * N.B. This must be called before any other ioctl is performed on the device.
+ */
+#define IOCTL_GNTDEV_SET_MAX_GRANTS \
+ _IOW('G', 3, struct ioctl_gntdev_set_max_grants)
+struct ioctl_gntdev_set_max_grants {
+ /* IN parameter */
+ /* The maximum number of grants that may be mapped at once. */
+ uint32_t count;
+};
+
+/*
+ * 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 \
+ _IOW('G', 7, struct ioctl_gntdev_unmap_notify)
+struct ioctl_gntdev_unmap_notify {
+ /* IN parameters */
+ /* Offset in the file descriptor for a byte within the page. This offset
+ * is the result of the IOCTL_GNTDEV_MAP_GRANT_REF and is the same as
+ * is used with mmap(). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the
byte
+ * within the page to be cleared.
+ */
+ 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
+
+#endif /* __NetBSD_PUBLIC_GNTDEV_H__ */
diff --git a/tools/libxc/xc_netbsd.c b/tools/libxc/xc_netbsd.c
index dbcb640..1ee12db 100644
--- a/tools/libxc/xc_netbsd.c
+++ b/tools/libxc/xc_netbsd.c
@@ -21,11 +21,15 @@
#include "xc_private.h"
#include <xen/sys/evtchn.h>
+#include <xen/sys/gntdev.h>
#include <unistd.h>
#include <fcntl.h>
#include <malloc.h>
#include <sys/mman.h>
+#define ROUNDUP(_x,_w) \
+ (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
+
static xc_osdep_handle netbsd_privcmd_open(xc_interface *xch)
{
int flags, saved_errno;
@@ -390,6 +394,188 @@ void *xc_memalign(xc_interface *xch, size_t alignment,
size_t size)
return valloc(size);
}
+#define GNT_DEV_NAME "/dev/gntdev"
+
+static xc_osdep_handle netbsd_gnttab_open(xc_gnttab *xcg)
+{
+ int fd = open(GNT_DEV_NAME, O_RDWR);
+
+ if ( fd == -1 )
+ return XC_OSDEP_OPEN_ERROR;
+
+ return (xc_osdep_handle)fd;
+}
+
+static int netbsd_gnttab_close(xc_gnttab *xcg, xc_osdep_handle h)
+{
+ int fd = (int)h;
+ return close(fd);
+}
+
+static int netbsd_gnttab_set_max_grants(xc_gnttab *xch, xc_osdep_handle h,
+ uint32_t count)
+{
+ /* NetBSD doesn't implement this feature */
+ return 0;
+}
+
+static void *netbsd_gnttab_grant_map(xc_gnttab *xch, xc_osdep_handle h,
+ uint32_t count, int flags, int prot,
+ uint32_t *domids, uint32_t *refs,
+ uint32_t notify_offset,
+ evtchn_port_t notify_port)
+{
+ int fd = (int)h;
+ struct ioctl_gntdev_map_grant_ref map;
+ struct ioctl_gntdev_grant_ref *mrefs;
+ unsigned int map_size = ROUNDUP(count *
+ sizeof(struct ioctl_gntdev_map_grant_ref),
+ XC_PAGE_SHIFT);
+ void *addr = MAP_FAILED;
+ int domids_stride = 1;
+ int rv = 0;
+ struct ioctl_gntdev_unmap_notify notify;
+ int i;
+
+ if ( flags & XC_GRANT_MAP_SINGLE_DOMAIN )
+ domids_stride = 0;
+
+ if ( map_size <= XC_PAGE_SIZE )
+ mrefs = alloca(count * sizeof(struct ioctl_gntdev_map_grant_ref));
+ else
+ {
+ mrefs = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ if ( mrefs == MAP_FAILED )
+ {
+ PERROR("netbsd_gnttab_grant_map: mmap of refs failed");
+ return NULL;
+ }
+ }
+
+ map.refs = mrefs;
+
+ for ( i = 0; i < count; i++ )
+ {
+ map.refs[i].domid = domids[i * domids_stride];
+ map.refs[i].ref = refs[i];
+ }
+
+ map.count = count;
+
+ addr = mmap(NULL, XC_PAGE_SIZE * count, prot,
+ MAP_ANON | MAP_SHARED, -1, 0);
+ if ( addr == MAP_FAILED )
+ {
+ PERROR("netbsd_gnttab_grant_map: mmap of grants failed");
+ goto out;
+ }
+
+ map.vaddr = (uint64_t) addr;
+
+ if ( ioctl(fd, IOCTL_GNTDEV_MAP_GRANT_REF, &map) )
+ {
+ PERROR("netbsd_gnttab_grant_map: ioctl MAP_GRANT_REF failed");
+ munmap(addr, XC_PAGE_SIZE * count);
+ goto out;
+ }
+
+ notify.index = map.index;
+ notify.action = 0;
+ if ( notify_offset < (XC_PAGE_SIZE * count) )
+ {
+ notify.index += notify_offset;
+ notify.action |= UNMAP_NOTIFY_CLEAR_BYTE;
+ }
+ if ( notify_port != -1 )
+ {
+ notify.event_channel_port = notify_port;
+ notify.action |= UNMAP_NOTIFY_SEND_EVENT;
+ }
+ if ( notify.action )
+ rv = ioctl(fd, IOCTL_GNTDEV_SET_UNMAP_NOTIFY, ¬ify);
+ if ( rv )
+ {
+ PERROR("netbsd_gnttab_grant_map: ioctl SET_UNMAP_NOTIFY failed");
+ munmap(addr, count * XC_PAGE_SIZE);
+ addr = MAP_FAILED;
+ }
+
+ if ( addr == MAP_FAILED )
+ {
+ int saved_errno = errno;
+ struct ioctl_gntdev_unmap_grant_ref unmap_grant;
+
+ /* Unmap the driver slots used to store the grant information. */
+ PERROR("xc_gnttab_map_grant_refs: mmap failed");
+ unmap_grant.index = map.index;
+ unmap_grant.count = count;
+ ioctl(fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant);
+ errno = saved_errno;
+ addr = NULL;
+ }
+
+ out:
+ if ( map_size > XC_PAGE_SIZE )
+ munmap(mrefs, map_size);
+
+ return addr;
+}
+
+
+
+static int netbsd_gnttab_munmap(xc_gnttab *xcg, xc_osdep_handle h,
+ void *start_address, uint32_t count)
+{
+ int fd = (int)h;
+ struct ioctl_gntdev_get_offset_for_vaddr get_offset;
+ struct ioctl_gntdev_unmap_grant_ref unmap_grant;
+ int rc;
+
+ if ( start_address == NULL )
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* First, it is necessary to get the offset which was initially used to
+ * mmap() the pages.
+ */
+ get_offset.vaddr = (unsigned long)start_address;
+ if ( (rc = ioctl(fd, IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR,
+ &get_offset)) )
+ return rc;
+
+ if ( get_offset.count != count )
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Next, unmap the memory. */
+ if ( (rc = munmap(start_address, count * getpagesize())) )
+ return rc;
+
+ /* Finally, unmap the driver slots used to store the grant information. */
+ unmap_grant.index = get_offset.offset;
+ unmap_grant.count = count;
+ if ( (rc = ioctl(fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant)) )
+ return rc;
+
+ return 0;
+}
+
+static struct xc_osdep_ops netbsd_gnttab_ops = {
+ .open = &netbsd_gnttab_open,
+ .close = &netbsd_gnttab_close,
+
+ .u.gnttab = {
+ .set_max_grants = &netbsd_gnttab_set_max_grants,
+ .grant_map = &netbsd_gnttab_grant_map,
+ .munmap = &netbsd_gnttab_munmap,
+ },
+};
+
static struct xc_osdep_ops *netbsd_osdep_init(xc_interface *xch, enum
xc_osdep_type type)
{
switch ( type )
@@ -398,6 +584,8 @@ static struct xc_osdep_ops *netbsd_osdep_init(xc_interface
*xch, enum xc_osdep_t
return &netbsd_privcmd_ops;
case XC_OSDEP_EVTCHN:
return &netbsd_evtchn_ops;
+ case XC_OSDEP_GNTTAB:
+ return &netbsd_gnttab_ops;
default:
return NULL;
}
--
1.7.7.5 (Apple Git-26)
Home |
Main Index |
Thread Index |
Old Index