$NetBSD: patch-bb,v 1.1.1.1 2011/04/06 09:10:27 cegger Exp $ --- libxc/xc_netbsd.c.orig 2011-03-29 17:09:58.000000000 +0000 +++ libxc/xc_netbsd.c @@ -21,6 +21,7 @@ #include "xc_private.h" #include +#include #include #include @@ -351,7 +352,189 @@ void discard_file_cache(xc_interface *xc errno = saved_errno; } -static struct xc_osdep_ops *netbsd_osdep_init(xc_interface *xch, enum xc_osdep_type type) +#define DEVXEN "/dev/xen/" + +static xc_osdep_handle +netbsd_gnttab_open(xc_gnttab *xcg) +{ + int fd; + + fd = open(DEVXEN "gntdev", 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 void * +netbsd_gnttab_map_grant_ref(xc_gnttab *xch, xc_osdep_handle h, + uint32_t domid, uint32_t ref, int prot) +{ + int fd = (int)h; + struct ioctl_gntdev_map_grant_ref map; + void *addr; + + map.count = 1; + map.refs[0].domid = domid; + map.refs[0].ref = ref; + + if ( ioctl(fd, IOCTL_GNTDEV_MAP_GRANT_REF, &map) ) { + PERROR("netbsd_gnttab_map_grant_ref: ioctl MAP_GRANT_REF failed"); + return NULL; + } + +mmap_again: + addr = mmap(NULL, XC_PAGE_SIZE, prot, MAP_SHARED, fd, map.index); + if ( addr == MAP_FAILED ) + { + int saved_errno = errno; + struct ioctl_gntdev_unmap_grant_ref unmap_grant; + + if ( saved_errno == EAGAIN ) + { + usleep(1000); + goto mmap_again; + } + /* Unmap the driver slots used to store the grant information. */ + PERROR("netbsd_gnttab_map_grant_ref: mmap failed"); + unmap_grant.index = map.index; + unmap_grant.count = 1; + ioctl(fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant); + errno = saved_errno; + return NULL; + } + + return addr; +} + +static void * +do_gnttab_map_grant_refs(xc_gnttab *xch, xc_osdep_handle h, + uint32_t count, uint32_t *domids, int domids_stride, + uint32_t *refs, int prot) +{ + int fd = (int)h; + struct ioctl_gntdev_map_grant_ref *map; + void *addr = NULL; + int i; + + map = malloc(sizeof(*map) + + (count - 1) * sizeof(struct ioctl_gntdev_map_grant_ref)); + if ( map == NULL ) + return NULL; + + for ( i = 0; i < count; i++ ) + { + map->refs[i].domid = domids[i * domids_stride]; + map->refs[i].ref = refs[i]; + } + + map->count = count; + + if ( ioctl(fd, IOCTL_GNTDEV_MAP_GRANT_REF, map) ) { + PERROR("xc_gnttab_map_grant_refs: ioctl MAP_GRANT_REF failed"); + goto out; + } + + addr = mmap(NULL, XC_PAGE_SIZE * count, prot, MAP_SHARED, fd, + map->index); + 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: + free(map); + + return addr; +} + +static void * +netbsd_gnttab_map_grant_refs(xc_gnttab *xcg, xc_osdep_handle h, + uint32_t count, uint32_t *domids, uint32_t *refs, int prot) +{ + return do_gnttab_map_grant_refs(xcg, h, count, domids, 1, refs, prot); +} + +static void * +netbsd_gnttab_map_domain_grant_refs(xc_gnttab *xcg, xc_osdep_handle h, + uint32_t count, uint32_t domid, uint32_t *refs, int prot) +{ + return do_gnttab_map_grant_refs(xcg, h, count, &domid, 0, refs, prot); +} + +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; + rc = ioctl(fd, IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR, &get_offset); + if ( rc ) + return rc; + + if ( get_offset.count != count ) + { + errno = EINVAL; + return -1; + } + + /* Next, unmap the memory. */ + rc = munmap(start_address, count * getpagesize()); + if ( rc ) + return rc; + + /* Finally, unmap the driver slots used to store the grant information. */ + unmap_grant.index = get_offset.offset; + unmap_grant.count = count; + rc = ioctl(fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant); + if ( rc ) + return rc; + return 0; +} + +static struct xc_osdep_ops netbsd_gnttab_ops = { + .open = &netbsd_gnttab_open, + .close = &netbsd_gnttab_close, + + .u.gnttab = { + .map_grant_ref = &netbsd_gnttab_map_grant_ref, + .map_grant_refs = &netbsd_gnttab_map_grant_refs, + .map_domain_grant_refs = &netbsd_gnttab_map_domain_grant_refs, + .munmap = &netbsd_gnttab_munmap, + }, +}; + +static struct xc_osdep_ops * +netbsd_osdep_init(xc_interface *xch, enum xc_osdep_type type) { switch ( type ) { @@ -360,8 +543,7 @@ static struct xc_osdep_ops *netbsd_osdep case XC_OSDEP_EVTCHN: return &netbsd_evtchn_ops; case XC_OSDEP_GNTTAB: - ERROR("GNTTAB interface not supported on this platform"); - return NULL; + return &netbsd_gnttab_ops; default: return NULL; }