[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 1/2] 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@xxxxxxxxxx> --- 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) _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |