[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 25 of 25] libxc: refactor Linux OS interface into a separate file



# HG changeset patch
# User Ian Campbell <ian.campbell@xxxxxxxxxx>
# Date 1291369007 0
# Node ID 96554e113aa1b7de6ba5296fcd438d63a6b7179a
# Parent  4ffab774457dc03d8956113799076cb173522811
libxc: refactor Linux OS interface into a separate file.

This helps ensure that the osdep abstraction is complete by
allowing us to avoid including xc_private.h.

All the other OS backends could benefit from the same treatment but
since I cannot compile test I did not do this.

Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>

diff -r 4ffab774457d -r 96554e113aa1 tools/libxc/Makefile
--- a/tools/libxc/Makefile      Fri Dec 03 09:36:47 2010 +0000
+++ b/tools/libxc/Makefile      Fri Dec 03 09:36:47 2010 +0000
@@ -34,7 +34,7 @@ CTRL_SRCS-y       += xtl_core.c
 CTRL_SRCS-y       += xtl_core.c
 CTRL_SRCS-y       += xtl_logger_stdio.c
 CTRL_SRCS-$(CONFIG_X86) += xc_pagetab.c
-CTRL_SRCS-$(CONFIG_Linux) += xc_linux.c
+CTRL_SRCS-$(CONFIG_Linux) += xc_linux.c xc_linux_osdep.c
 CTRL_SRCS-$(CONFIG_SunOS) += xc_solaris.c
 CTRL_SRCS-$(CONFIG_NetBSD) += xc_netbsd.c
 CTRL_SRCS-$(CONFIG_MiniOS) += xc_minios.c
diff -r 4ffab774457d -r 96554e113aa1 tools/libxc/xc_linux.c
--- a/tools/libxc/xc_linux.c    Fri Dec 03 09:36:47 2010 +0000
+++ b/tools/libxc/xc_linux.c    Fri Dec 03 09:36:47 2010 +0000
@@ -2,9 +2,6 @@
  *
  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
- *
- * xc_gnttab functions:
- * Copyright (c) 2007-2008, D G Murray <Derek.Murray@xxxxxxxxxxxx>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,436 +19,6 @@
  */
 
 #include "xc_private.h"
-
-#include <xen/memory.h>
-#include <xen/sys/evtchn.h>
-#include <xen/sys/gntdev.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-static xc_osdep_handle linux_privcmd_open(xc_interface *xch)
-{
-    int flags, saved_errno;
-    int fd = open("/proc/xen/privcmd", O_RDWR);
-
-    if ( fd == -1 )
-    {
-        PERROR("Could not obtain handle on privileged command interface");
-        return XC_OSDEP_OPEN_ERROR;
-    }
-
-    /* Although we return the file handle as the 'xc handle' the API
-       does not specify / guarentee that this integer is in fact
-       a file handle. Thus we must take responsiblity to ensure
-       it doesn't propagate (ie leak) outside the process */
-    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
-    {
-        PERROR("Could not get file handle flags");
-        goto error;
-    }
-
-    flags |= FD_CLOEXEC;
-
-    if ( fcntl(fd, F_SETFD, flags) < 0 )
-    {
-        PERROR("Could not set file handle flags");
-        goto error;
-    }
-
-    return (xc_osdep_handle)fd;
-
- error:
-    saved_errno = errno;
-    close(fd);
-    errno = saved_errno;
-    return XC_OSDEP_OPEN_ERROR;
-}
-
-static int linux_privcmd_close(xc_interface *xch, xc_osdep_handle h)
-{
-    int fd = (int)h;
-    return close(fd);
-}
-
-static int linux_privcmd_hypercall(xc_interface *xch, xc_osdep_handle h, 
privcmd_hypercall_t *hypercall)
-{
-    int fd = (int)h;
-    return ioctl(fd, IOCTL_PRIVCMD_HYPERCALL, hypercall);
-}
-
-static int xc_map_foreign_batch_single(int fd, uint32_t dom,
-                                       xen_pfn_t *mfn, unsigned long addr)
-{
-    privcmd_mmapbatch_t ioctlx;
-    int rc;
-
-    ioctlx.num = 1;
-    ioctlx.dom = dom;
-    ioctlx.addr = addr;
-    ioctlx.arr = mfn;
-
-    do
-    {
-        *mfn ^= XEN_DOMCTL_PFINFO_PAGEDTAB;
-        usleep(100);
-        rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
-    }
-    while ( (rc < 0) && (errno == ENOENT) );
-
-    return rc;
-}
-
-static void *linux_privcmd_map_foreign_batch(xc_interface *xch, 
xc_osdep_handle h,
-                                             uint32_t dom, int prot,
-                                             xen_pfn_t *arr, int num)
-{
-    int fd = (int)h;
-    privcmd_mmapbatch_t ioctlx;
-    void *addr;
-    int rc;
-
-    addr = mmap(NULL, num << XC_PAGE_SHIFT, prot, MAP_SHARED, fd, 0);
-    if ( addr == MAP_FAILED )
-    {
-        PERROR("xc_map_foreign_batch: mmap failed");
-        return NULL;
-    }
-
-    ioctlx.num = num;
-    ioctlx.dom = dom;
-    ioctlx.addr = (unsigned long)addr;
-    ioctlx.arr = arr;
-
-    rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
-    if ( (rc < 0) && (errno == ENOENT) )
-    {
-        int i;
-
-        for ( i = 0; i < num; i++ )
-        {
-            if ( (arr[i] & XEN_DOMCTL_PFINFO_LTAB_MASK) ==
-                 XEN_DOMCTL_PFINFO_PAGEDTAB )
-            {
-                unsigned long paged_addr = (unsigned long)addr + (i << 
XC_PAGE_SHIFT);
-                rc = xc_map_foreign_batch_single(fd, dom, &arr[i],
-                                                 paged_addr);
-                if ( rc < 0 )
-                    goto out;
-            }
-        }
-    }
-
- out:
-    if ( rc < 0 )
-    {
-        int saved_errno = errno;
-        PERROR("xc_map_foreign_batch: ioctl failed");
-        (void)munmap(addr, num << XC_PAGE_SHIFT);
-        errno = saved_errno;
-        return NULL;
-    }
-
-    return addr;
-}
-
-static void *linux_privcmd_map_foreign_bulk(xc_interface *xch, xc_osdep_handle 
h,
-                                            uint32_t dom, int prot,
-                                            const xen_pfn_t *arr, int *err, 
unsigned int num)
-{
-    int fd = (int)h;
-    privcmd_mmapbatch_v2_t ioctlx;
-    void *addr;
-    unsigned int i;
-    int rc;
-
-    addr = mmap(NULL, (unsigned long)num << XC_PAGE_SHIFT, prot, MAP_SHARED,
-                fd, 0);
-    if ( addr == MAP_FAILED )
-    {
-        PERROR("xc_map_foreign_batch: mmap failed");
-        return NULL;
-    }
-
-    ioctlx.num = num;
-    ioctlx.dom = dom;
-    ioctlx.addr = (unsigned long)addr;
-    ioctlx.arr = arr;
-    ioctlx.err = err;
-
-    rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);
-
-    if ( rc < 0 && errno == ENOENT )
-    {
-        for ( i = rc = 0; rc == 0 && i < num; i++ )
-        {
-            if ( err[i] != -ENOENT )
-                continue;
-
-            ioctlx.num = 1;
-            ioctlx.dom = dom;
-            ioctlx.addr = (unsigned long)addr + ((unsigned 
long)i<<XC_PAGE_SHIFT);
-            ioctlx.arr = arr + i;
-            ioctlx.err = err + i;
-            do {
-                usleep(100);
-                rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);
-            } while ( rc < 0 && err[i] == -ENOENT );
-        }
-    }
-
-    if ( rc < 0 && errno == EINVAL && (int)num > 0 )
-    {
-        /*
-         * IOCTL_PRIVCMD_MMAPBATCH_V2 is not supported - fall back to
-         * IOCTL_PRIVCMD_MMAPBATCH.
-         */
-        xen_pfn_t *pfn = malloc(num * sizeof(*pfn));
-
-        if ( pfn )
-        {
-            privcmd_mmapbatch_t ioctlx;
-
-            memcpy(pfn, arr, num * sizeof(*arr));
-
-            ioctlx.num = num;
-            ioctlx.dom = dom;
-            ioctlx.addr = (unsigned long)addr;
-            ioctlx.arr = pfn;
-
-            rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
-
-            rc = rc < 0 ? -errno : 0;
-
-            for ( i = 0; i < num; ++i )
-            {
-                switch ( pfn[i] ^ arr[i] )
-                {
-                case 0:
-                    err[i] = rc != -ENOENT ? rc : 0;
-                    continue;
-                default:
-                    err[i] = -EINVAL;
-                    continue;
-                case XEN_DOMCTL_PFINFO_PAGEDTAB:
-                    if ( rc != -ENOENT )
-                    {
-                        err[i] = rc ?: -EINVAL;
-                        continue;
-                    }
-                    rc = xc_map_foreign_batch_single(fd, dom, pfn + i,
-                        (unsigned long)addr + ((unsigned 
long)i<<XC_PAGE_SHIFT));
-                    if ( rc < 0 )
-                    {
-                        rc = -errno;
-                        break;
-                    }
-                    rc = -ENOENT;
-                    continue;
-                }
-                break;
-            }
-
-            free(pfn);
-
-            if ( rc == -ENOENT && i == num )
-                rc = 0;
-            else if ( rc )
-            {
-                errno = -rc;
-                rc = -1;
-            }
-        }
-        else
-        {
-            errno = -ENOMEM;
-            rc = -1;
-        }
-    }
-
-    if ( rc < 0 )
-    {
-        int saved_errno = errno;
-
-        PERROR("xc_map_foreign_bulk: ioctl failed");
-        (void)munmap(addr, (unsigned long)num << XC_PAGE_SHIFT);
-        errno = saved_errno;
-        return NULL;
-    }
-
-    return addr;
-}
-
-static void *linux_privcmd_map_foreign_range(xc_interface *xch, 
xc_osdep_handle h,
-                                             uint32_t dom, int size, int prot,
-                                             unsigned long mfn)
-{
-    xen_pfn_t *arr;
-    int num;
-    int i;
-    void *ret;
-
-    num = (size + XC_PAGE_SIZE - 1) >> XC_PAGE_SHIFT;
-    arr = calloc(num, sizeof(xen_pfn_t));
-
-    for ( i = 0; i < num; i++ )
-        arr[i] = mfn + i;
-
-    ret = xc_map_foreign_pages(xch, dom, prot, arr, num);
-    free(arr);
-    return ret;
-}
-
-static void *linux_privcmd_map_foreign_ranges(xc_interface *xch, 
xc_osdep_handle h,
-                                              uint32_t dom, size_t size, int 
prot,
-                                              size_t chunksize, 
privcmd_mmap_entry_t entries[],
-                                              int nentries)
-{
-    xen_pfn_t *arr;
-    int num_per_entry;
-    int num;
-    int i;
-    int j;
-    void *ret;
-
-    num_per_entry = chunksize >> XC_PAGE_SHIFT;
-    num = num_per_entry * nentries;
-    arr = calloc(num, sizeof(xen_pfn_t));
-
-    for ( i = 0; i < nentries; i++ )
-        for ( j = 0; j < num_per_entry; j++ )
-            arr[i * num_per_entry + j] = entries[i].mfn + j;
-
-    ret = xc_map_foreign_pages(xch, dom, prot, arr, num);
-    free(arr);
-    return ret;
-}
-
-static struct xc_osdep_ops linux_privcmd_ops = {
-    .open = &linux_privcmd_open,
-    .close = &linux_privcmd_close,
-
-    .u.privcmd = {
-        .hypercall = &linux_privcmd_hypercall,
-
-        .map_foreign_batch = &linux_privcmd_map_foreign_batch,
-        .map_foreign_bulk = &linux_privcmd_map_foreign_bulk,
-        .map_foreign_range = &linux_privcmd_map_foreign_range,
-        .map_foreign_ranges = &linux_privcmd_map_foreign_ranges,
-    },
-};
-
-#define DEVXEN "/dev/xen/"
-
-static xc_osdep_handle linux_evtchn_open(xc_evtchn *xce)
-{
-    int fd = open(DEVXEN "evtchn", O_RDWR);
-    if ( fd == -1 )
-        return XC_OSDEP_OPEN_ERROR;
-
-    return (xc_osdep_handle)fd;
-}
-
-static int linux_evtchn_close(xc_evtchn *xce, xc_osdep_handle h)
-{
-    int fd = (int)h;
-    return close(fd);
-}
-
-static int linux_evtchn_fd(xc_evtchn *xce, xc_osdep_handle h)
-{
-    return (int)h;
-}
-
-static int linux_evtchn_notify(xc_evtchn *xce, xc_osdep_handle h, 
evtchn_port_t port)
-{
-    int fd = (int)h;
-    struct ioctl_evtchn_notify notify;
-
-    notify.port = port;
-
-    return ioctl(fd, IOCTL_EVTCHN_NOTIFY, &notify);
-}
-
-static evtchn_port_or_error_t
-linux_evtchn_bind_unbound_port(xc_evtchn *xce, xc_osdep_handle h, int domid)
-{
-    int fd = (int)h;
-    struct ioctl_evtchn_bind_unbound_port bind;
-
-    bind.remote_domain = domid;
-
-    return ioctl(fd, IOCTL_EVTCHN_BIND_UNBOUND_PORT, &bind);
-}
-
-static evtchn_port_or_error_t
-linux_evtchn_bind_interdomain(xc_evtchn *xce, xc_osdep_handle h, int domid,
-                              evtchn_port_t remote_port)
-{
-    int fd = (int)h;
-    struct ioctl_evtchn_bind_interdomain bind;
-
-    bind.remote_domain = domid;
-    bind.remote_port = remote_port;
-
-    return ioctl(fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
-}
-
-static evtchn_port_or_error_t
-linux_evtchn_bind_virq(xc_evtchn *xce, xc_osdep_handle h, unsigned int virq)
-{
-    int fd = (int)h;
-    struct ioctl_evtchn_bind_virq bind;
-
-    bind.virq = virq;
-
-    return ioctl(fd, IOCTL_EVTCHN_BIND_VIRQ, &bind);
-}
-
-static int linux_evtchn_unbind(xc_evtchn *xce, xc_osdep_handle h, 
evtchn_port_t port)
-{
-    int fd = (int)h;
-    struct ioctl_evtchn_unbind unbind;
-
-    unbind.port = port;
-
-    return ioctl(fd, IOCTL_EVTCHN_UNBIND, &unbind);
-}
-
-static evtchn_port_or_error_t linux_evtchn_pending(xc_evtchn *xce, 
xc_osdep_handle h)
-{
-    int fd = (int)h;
-    evtchn_port_t port;
-
-    if ( read(fd, &port, sizeof(port)) != sizeof(port) )
-        return -1;
-
-    return port;
-}
-
-static int linux_evtchn_unmask(xc_evtchn *xce, xc_osdep_handle h, 
evtchn_port_t port)
-{
-    int fd = (int)h;
-
-    if ( write(fd, &port, sizeof(port)) != sizeof(port) )
-        return -1;
-    return 0;
-}
-
-static struct xc_osdep_ops linux_evtchn_ops = {
-    .open = &linux_evtchn_open,
-    .close = &linux_evtchn_close,
-
-    .u.evtchn = {
-        .fd = &linux_evtchn_fd,
-        .notify = &linux_evtchn_notify,
-        .bind_unbound_port = &linux_evtchn_bind_unbound_port,
-        .bind_interdomain = &linux_evtchn_bind_interdomain,
-        .bind_virq = &linux_evtchn_bind_virq,
-        .unbind = &linux_evtchn_unbind,
-        .pending = &linux_evtchn_pending,
-        .unmask = &linux_evtchn_unmask,
-    },
-};
 
 /* Optionally flush file to disk and discard page cache */
 void discard_file_cache(xc_interface *xch, int fd, int flush) 
@@ -488,214 +55,6 @@ void discard_file_cache(xc_interface *xc
     errno = saved_errno;
 }
 
-static xc_osdep_handle linux_gnttab_open(xc_gnttab *xcg)
-{
-    int fd = open(DEVXEN "gntdev", O_RDWR);
-
-    if ( fd == -1 )
-        return XC_OSDEP_OPEN_ERROR;
-
-    return (xc_osdep_handle)fd;
-}
-
-static int linux_gnttab_close(xc_gnttab *xcg, xc_osdep_handle h)
-{
-    int fd = (int)h;
-    return close(fd);
-}
-
-static void *linux_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("xc_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("xc_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 *linux_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 *linux_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 linux_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 int linux_gnttab_set_max_grants(xc_gnttab *xcg, xc_osdep_handle h, 
uint32_t count)
-{
-    int fd = (int)h;
-    struct ioctl_gntdev_set_max_grants set_max;
-    int rc;
-
-    set_max.count = count;
-    if ( (rc = ioctl(fd, IOCTL_GNTDEV_SET_MAX_GRANTS, &set_max)) )
-        return rc;
-
-    return 0;
-}
-
-static struct xc_osdep_ops linux_gnttab_ops = {
-    .open = &linux_gnttab_open,
-    .close = &linux_gnttab_close,
-
-    .u.gnttab = {
-        .map_grant_ref = &linux_gnttab_map_grant_ref,
-        .map_grant_refs = &linux_gnttab_map_grant_refs,
-        .map_domain_grant_refs = &linux_gnttab_map_domain_grant_refs,
-        .munmap = &linux_gnttab_munmap,
-        .set_max_grants = &linux_gnttab_set_max_grants,
-    },
-};
-
-static struct xc_osdep_ops *linux_osdep_init(xc_interface *xch, enum 
xc_osdep_type type)
-{
-    switch ( type )
-    {
-    case XC_OSDEP_PRIVCMD:
-        return &linux_privcmd_ops;
-    case XC_OSDEP_EVTCHN:
-        return &linux_evtchn_ops;
-    case XC_OSDEP_GNTTAB:
-        return &linux_gnttab_ops;
-    default:
-        return NULL;
-    }
-}
-
-xc_osdep_info_t xc_osdep_info = {
-    .name = "Linux Native OS interface",
-    .init = &linux_osdep_init,
-    .fake = 0,
-};
-
 /*
  * Local variables:
  * mode: C
diff -r 4ffab774457d -r 96554e113aa1 tools/libxc/xc_linux_osdep.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxc/xc_linux_osdep.c      Fri Dec 03 09:36:47 2010 +0000
@@ -0,0 +1,685 @@
+/******************************************************************************
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ * xc_gnttab functions:
+ * Copyright (c) 2007-2008, D G Murray <Derek.Murray@xxxxxxxxxxxx>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <xen/memory.h>
+#include <xen/sys/evtchn.h>
+#include <xen/sys/gntdev.h>
+
+#include "xenctrl.h"
+#include "xenctrlosdep.h"
+
+#define ERROR(_m, _a...)  xc_osdep_log(xch,XTL_ERROR,XC_INTERNAL_ERROR,_m , ## 
_a )
+#define PERROR(_m, _a...) xc_osdep_log(xch,XTL_ERROR,XC_INTERNAL_ERROR,_m \
+                  " (%d = %s)", ## _a , errno, xc_strerror(xch, errno))
+
+static xc_osdep_handle linux_privcmd_open(xc_interface *xch)
+{
+    int flags, saved_errno;
+    int fd = open("/proc/xen/privcmd", O_RDWR);
+
+    if ( fd == -1 )
+    {
+        PERROR("Could not obtain handle on privileged command interface");
+        return XC_OSDEP_OPEN_ERROR;
+    }
+
+    /* Although we return the file handle as the 'xc handle' the API
+       does not specify / guarentee that this integer is in fact
+       a file handle. Thus we must take responsiblity to ensure
+       it doesn't propagate (ie leak) outside the process */
+    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
+    {
+        PERROR("Could not get file handle flags");
+        goto error;
+    }
+
+    flags |= FD_CLOEXEC;
+
+    if ( fcntl(fd, F_SETFD, flags) < 0 )
+    {
+        PERROR("Could not set file handle flags");
+        goto error;
+    }
+
+    return (xc_osdep_handle)fd;
+
+ error:
+    saved_errno = errno;
+    close(fd);
+    errno = saved_errno;
+    return XC_OSDEP_OPEN_ERROR;
+}
+
+static int linux_privcmd_close(xc_interface *xch, xc_osdep_handle h)
+{
+    int fd = (int)h;
+    return close(fd);
+}
+
+static int linux_privcmd_hypercall(xc_interface *xch, xc_osdep_handle h, 
privcmd_hypercall_t *hypercall)
+{
+    int fd = (int)h;
+    return ioctl(fd, IOCTL_PRIVCMD_HYPERCALL, hypercall);
+}
+
+static int xc_map_foreign_batch_single(int fd, uint32_t dom,
+                                       xen_pfn_t *mfn, unsigned long addr)
+{
+    privcmd_mmapbatch_t ioctlx;
+    int rc;
+
+    ioctlx.num = 1;
+    ioctlx.dom = dom;
+    ioctlx.addr = addr;
+    ioctlx.arr = mfn;
+
+    do
+    {
+        *mfn ^= XEN_DOMCTL_PFINFO_PAGEDTAB;
+        usleep(100);
+        rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
+    }
+    while ( (rc < 0) && (errno == ENOENT) );
+
+    return rc;
+}
+
+static void *linux_privcmd_map_foreign_batch(xc_interface *xch, 
xc_osdep_handle h,
+                                             uint32_t dom, int prot,
+                                             xen_pfn_t *arr, int num)
+{
+    int fd = (int)h;
+    privcmd_mmapbatch_t ioctlx;
+    void *addr;
+    int rc;
+
+    addr = mmap(NULL, num << XC_PAGE_SHIFT, prot, MAP_SHARED, fd, 0);
+    if ( addr == MAP_FAILED )
+    {
+        PERROR("xc_map_foreign_batch: mmap failed");
+        return NULL;
+    }
+
+    ioctlx.num = num;
+    ioctlx.dom = dom;
+    ioctlx.addr = (unsigned long)addr;
+    ioctlx.arr = arr;
+
+    rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
+    if ( (rc < 0) && (errno == ENOENT) )
+    {
+        int i;
+
+        for ( i = 0; i < num; i++ )
+        {
+            if ( (arr[i] & XEN_DOMCTL_PFINFO_LTAB_MASK) ==
+                 XEN_DOMCTL_PFINFO_PAGEDTAB )
+            {
+                unsigned long paged_addr = (unsigned long)addr + (i << 
XC_PAGE_SHIFT);
+                rc = xc_map_foreign_batch_single(fd, dom, &arr[i],
+                                                 paged_addr);
+                if ( rc < 0 )
+                    goto out;
+            }
+        }
+    }
+
+ out:
+    if ( rc < 0 )
+    {
+        int saved_errno = errno;
+        PERROR("xc_map_foreign_batch: ioctl failed");
+        (void)munmap(addr, num << XC_PAGE_SHIFT);
+        errno = saved_errno;
+        return NULL;
+    }
+
+    return addr;
+}
+
+static void *linux_privcmd_map_foreign_bulk(xc_interface *xch, xc_osdep_handle 
h,
+                                            uint32_t dom, int prot,
+                                            const xen_pfn_t *arr, int *err, 
unsigned int num)
+{
+    int fd = (int)h;
+    privcmd_mmapbatch_v2_t ioctlx;
+    void *addr;
+    unsigned int i;
+    int rc;
+
+    addr = mmap(NULL, (unsigned long)num << XC_PAGE_SHIFT, prot, MAP_SHARED,
+                fd, 0);
+    if ( addr == MAP_FAILED )
+    {
+        PERROR("xc_map_foreign_batch: mmap failed");
+        return NULL;
+    }
+
+    ioctlx.num = num;
+    ioctlx.dom = dom;
+    ioctlx.addr = (unsigned long)addr;
+    ioctlx.arr = arr;
+    ioctlx.err = err;
+
+    rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);
+
+    if ( rc < 0 && errno == ENOENT )
+    {
+        for ( i = rc = 0; rc == 0 && i < num; i++ )
+        {
+            if ( err[i] != -ENOENT )
+                continue;
+
+            ioctlx.num = 1;
+            ioctlx.dom = dom;
+            ioctlx.addr = (unsigned long)addr + ((unsigned 
long)i<<XC_PAGE_SHIFT);
+            ioctlx.arr = arr + i;
+            ioctlx.err = err + i;
+            do {
+                usleep(100);
+                rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);
+            } while ( rc < 0 && err[i] == -ENOENT );
+        }
+    }
+
+    if ( rc < 0 && errno == EINVAL && (int)num > 0 )
+    {
+        /*
+         * IOCTL_PRIVCMD_MMAPBATCH_V2 is not supported - fall back to
+         * IOCTL_PRIVCMD_MMAPBATCH.
+         */
+        xen_pfn_t *pfn = malloc(num * sizeof(*pfn));
+
+        if ( pfn )
+        {
+            privcmd_mmapbatch_t ioctlx;
+
+            memcpy(pfn, arr, num * sizeof(*arr));
+
+            ioctlx.num = num;
+            ioctlx.dom = dom;
+            ioctlx.addr = (unsigned long)addr;
+            ioctlx.arr = pfn;
+
+            rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
+
+            rc = rc < 0 ? -errno : 0;
+
+            for ( i = 0; i < num; ++i )
+            {
+                switch ( pfn[i] ^ arr[i] )
+                {
+                case 0:
+                    err[i] = rc != -ENOENT ? rc : 0;
+                    continue;
+                default:
+                    err[i] = -EINVAL;
+                    continue;
+                case XEN_DOMCTL_PFINFO_PAGEDTAB:
+                    if ( rc != -ENOENT )
+                    {
+                        err[i] = rc ?: -EINVAL;
+                        continue;
+                    }
+                    rc = xc_map_foreign_batch_single(fd, dom, pfn + i,
+                        (unsigned long)addr + ((unsigned 
long)i<<XC_PAGE_SHIFT));
+                    if ( rc < 0 )
+                    {
+                        rc = -errno;
+                        break;
+                    }
+                    rc = -ENOENT;
+                    continue;
+                }
+                break;
+            }
+
+            free(pfn);
+
+            if ( rc == -ENOENT && i == num )
+                rc = 0;
+            else if ( rc )
+            {
+                errno = -rc;
+                rc = -1;
+            }
+        }
+        else
+        {
+            errno = -ENOMEM;
+            rc = -1;
+        }
+    }
+
+    if ( rc < 0 )
+    {
+        int saved_errno = errno;
+
+        PERROR("xc_map_foreign_bulk: ioctl failed");
+        (void)munmap(addr, (unsigned long)num << XC_PAGE_SHIFT);
+        errno = saved_errno;
+        return NULL;
+    }
+
+    return addr;
+}
+
+static void *linux_privcmd_map_foreign_range(xc_interface *xch, 
xc_osdep_handle h,
+                                             uint32_t dom, int size, int prot,
+                                             unsigned long mfn)
+{
+    xen_pfn_t *arr;
+    int num;
+    int i;
+    void *ret;
+
+    num = (size + XC_PAGE_SIZE - 1) >> XC_PAGE_SHIFT;
+    arr = calloc(num, sizeof(xen_pfn_t));
+
+    for ( i = 0; i < num; i++ )
+        arr[i] = mfn + i;
+
+    ret = xc_map_foreign_pages(xch, dom, prot, arr, num);
+    free(arr);
+    return ret;
+}
+
+static void *linux_privcmd_map_foreign_ranges(xc_interface *xch, 
xc_osdep_handle h,
+                                              uint32_t dom, size_t size, int 
prot,
+                                              size_t chunksize, 
privcmd_mmap_entry_t entries[],
+                                              int nentries)
+{
+    xen_pfn_t *arr;
+    int num_per_entry;
+    int num;
+    int i;
+    int j;
+    void *ret;
+
+    num_per_entry = chunksize >> XC_PAGE_SHIFT;
+    num = num_per_entry * nentries;
+    arr = calloc(num, sizeof(xen_pfn_t));
+
+    for ( i = 0; i < nentries; i++ )
+        for ( j = 0; j < num_per_entry; j++ )
+            arr[i * num_per_entry + j] = entries[i].mfn + j;
+
+    ret = xc_map_foreign_pages(xch, dom, prot, arr, num);
+    free(arr);
+    return ret;
+}
+
+static struct xc_osdep_ops linux_privcmd_ops = {
+    .open = &linux_privcmd_open,
+    .close = &linux_privcmd_close,
+
+    .u.privcmd = {
+        .hypercall = &linux_privcmd_hypercall,
+
+        .map_foreign_batch = &linux_privcmd_map_foreign_batch,
+        .map_foreign_bulk = &linux_privcmd_map_foreign_bulk,
+        .map_foreign_range = &linux_privcmd_map_foreign_range,
+        .map_foreign_ranges = &linux_privcmd_map_foreign_ranges,
+    },
+};
+
+#define DEVXEN "/dev/xen/"
+
+static xc_osdep_handle linux_evtchn_open(xc_evtchn *xce)
+{
+    int fd = open(DEVXEN "evtchn", O_RDWR);
+    if ( fd == -1 )
+        return XC_OSDEP_OPEN_ERROR;
+
+    return (xc_osdep_handle)fd;
+}
+
+static int linux_evtchn_close(xc_evtchn *xce, xc_osdep_handle h)
+{
+    int fd = (int)h;
+    return close(fd);
+}
+
+static int linux_evtchn_fd(xc_evtchn *xce, xc_osdep_handle h)
+{
+    return (int)h;
+}
+
+static int linux_evtchn_notify(xc_evtchn *xce, xc_osdep_handle h, 
evtchn_port_t port)
+{
+    int fd = (int)h;
+    struct ioctl_evtchn_notify notify;
+
+    notify.port = port;
+
+    return ioctl(fd, IOCTL_EVTCHN_NOTIFY, &notify);
+}
+
+static evtchn_port_or_error_t
+linux_evtchn_bind_unbound_port(xc_evtchn *xce, xc_osdep_handle h, int domid)
+{
+    int fd = (int)h;
+    struct ioctl_evtchn_bind_unbound_port bind;
+
+    bind.remote_domain = domid;
+
+    return ioctl(fd, IOCTL_EVTCHN_BIND_UNBOUND_PORT, &bind);
+}
+
+static evtchn_port_or_error_t
+linux_evtchn_bind_interdomain(xc_evtchn *xce, xc_osdep_handle h, int domid,
+                              evtchn_port_t remote_port)
+{
+    int fd = (int)h;
+    struct ioctl_evtchn_bind_interdomain bind;
+
+    bind.remote_domain = domid;
+    bind.remote_port = remote_port;
+
+    return ioctl(fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
+}
+
+static evtchn_port_or_error_t
+linux_evtchn_bind_virq(xc_evtchn *xce, xc_osdep_handle h, unsigned int virq)
+{
+    int fd = (int)h;
+    struct ioctl_evtchn_bind_virq bind;
+
+    bind.virq = virq;
+
+    return ioctl(fd, IOCTL_EVTCHN_BIND_VIRQ, &bind);
+}
+
+static int linux_evtchn_unbind(xc_evtchn *xce, xc_osdep_handle h, 
evtchn_port_t port)
+{
+    int fd = (int)h;
+    struct ioctl_evtchn_unbind unbind;
+
+    unbind.port = port;
+
+    return ioctl(fd, IOCTL_EVTCHN_UNBIND, &unbind);
+}
+
+static evtchn_port_or_error_t linux_evtchn_pending(xc_evtchn *xce, 
xc_osdep_handle h)
+{
+    int fd = (int)h;
+    evtchn_port_t port;
+
+    if ( read(fd, &port, sizeof(port)) != sizeof(port) )
+        return -1;
+
+    return port;
+}
+
+static int linux_evtchn_unmask(xc_evtchn *xce, xc_osdep_handle h, 
evtchn_port_t port)
+{
+    int fd = (int)h;
+
+    if ( write(fd, &port, sizeof(port)) != sizeof(port) )
+        return -1;
+    return 0;
+}
+
+static struct xc_osdep_ops linux_evtchn_ops = {
+    .open = &linux_evtchn_open,
+    .close = &linux_evtchn_close,
+
+    .u.evtchn = {
+        .fd = &linux_evtchn_fd,
+        .notify = &linux_evtchn_notify,
+        .bind_unbound_port = &linux_evtchn_bind_unbound_port,
+        .bind_interdomain = &linux_evtchn_bind_interdomain,
+        .bind_virq = &linux_evtchn_bind_virq,
+        .unbind = &linux_evtchn_unbind,
+        .pending = &linux_evtchn_pending,
+        .unmask = &linux_evtchn_unmask,
+    },
+};
+
+static xc_osdep_handle linux_gnttab_open(xc_gnttab *xcg)
+{
+    int fd = open(DEVXEN "gntdev", O_RDWR);
+
+    if ( fd == -1 )
+        return XC_OSDEP_OPEN_ERROR;
+
+    return (xc_osdep_handle)fd;
+}
+
+static int linux_gnttab_close(xc_gnttab *xcg, xc_osdep_handle h)
+{
+    int fd = (int)h;
+    return close(fd);
+}
+
+static void *linux_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("xc_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("xc_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 *linux_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 *linux_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 linux_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 int linux_gnttab_set_max_grants(xc_gnttab *xcg, xc_osdep_handle h, 
uint32_t count)
+{
+    int fd = (int)h;
+    struct ioctl_gntdev_set_max_grants set_max;
+    int rc;
+
+    set_max.count = count;
+    if ( (rc = ioctl(fd, IOCTL_GNTDEV_SET_MAX_GRANTS, &set_max)) )
+        return rc;
+
+    return 0;
+}
+
+static struct xc_osdep_ops linux_gnttab_ops = {
+    .open = &linux_gnttab_open,
+    .close = &linux_gnttab_close,
+
+    .u.gnttab = {
+        .map_grant_ref = &linux_gnttab_map_grant_ref,
+        .map_grant_refs = &linux_gnttab_map_grant_refs,
+        .map_domain_grant_refs = &linux_gnttab_map_domain_grant_refs,
+        .munmap = &linux_gnttab_munmap,
+        .set_max_grants = &linux_gnttab_set_max_grants,
+    },
+};
+
+static struct xc_osdep_ops *linux_osdep_init(xc_interface *xch, enum 
xc_osdep_type type)
+{
+    switch ( type )
+    {
+    case XC_OSDEP_PRIVCMD:
+        return &linux_privcmd_ops;
+    case XC_OSDEP_EVTCHN:
+        return &linux_evtchn_ops;
+    case XC_OSDEP_GNTTAB:
+        return &linux_gnttab_ops;
+    default:
+        return NULL;
+    }
+}
+
+xc_osdep_info_t xc_osdep_info = {
+    .name = "Linux Native OS interface",
+    .init = &linux_osdep_init,
+    .fake = 0,
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.