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

Re: [Xen-devel] [PATCH v3 20/24] xen/passthrough: Extend XEN_DOMCTL_assign_device to support DT device



On Tue, 13 Jan 2015, Julien Grall wrote:
> TODO: Update the commit message
> 
> A device node is described by a path. It will be used to retrieved the
> node in the device tree and assign the related device to the domain.
> 
> Only device protected by an IOMMU can be assigned to a guest.
> 
> Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx>
> Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
> Cc: Wei Liu <wei.liu2@xxxxxxxxxx>
> Cc: Jan Beulich <jbeulich@xxxxxxxx>
> 
> ---
>     Changes in v2:
>         - Use a different number for XEN_DOMCTL_assign_dt_device
> ---
>  tools/libxc/include/xenctrl.h         | 10 ++++
>  tools/libxc/xc_domain.c               | 95 ++++++++++++++++++++++++++++++++--
>  xen/drivers/passthrough/device_tree.c | 97 
> +++++++++++++++++++++++++++++++++--
>  xen/drivers/passthrough/iommu.c       |  7 +++
>  xen/drivers/passthrough/pci.c         | 43 +++++++++++-----
>  xen/include/public/domctl.h           | 15 +++++-
>  xen/include/xen/iommu.h               |  3 ++
>  7 files changed, 249 insertions(+), 21 deletions(-)
> 
> diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
> index d66571f..db45475 100644
> --- a/tools/libxc/include/xenctrl.h
> +++ b/tools/libxc/include/xenctrl.h
> @@ -2055,6 +2055,16 @@ int xc_deassign_device(xc_interface *xch,
>                       uint32_t domid,
>                       uint32_t machine_bdf);
>  
> +int xc_assign_dt_device(xc_interface *xch,
> +                        uint32_t domid,
> +                        char *path);
> +int xc_test_assign_dt_device(xc_interface *xch,
> +                             uint32_t domid,
> +                             char *path);
> +int xc_deassign_dt_device(xc_interface *xch,
> +                          uint32_t domid,
> +                          char *path);
> +
>  int xc_domain_memory_mapping(xc_interface *xch,
>                               uint32_t domid,
>                               unsigned long first_gfn,
> diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
> index eb066cf..bca3aee 100644
> --- a/tools/libxc/xc_domain.c
> +++ b/tools/libxc/xc_domain.c
> @@ -1637,7 +1637,8 @@ int xc_assign_device(
>  
>      domctl.cmd = XEN_DOMCTL_assign_device;
>      domctl.domain = domid;
> -    domctl.u.assign_device.machine_sbdf = machine_sbdf;
> +    domctl.u.assign_device.dev = XEN_DOMCTL_DEV_PCI;
> +    domctl.u.assign_device.u.pci.machine_sbdf = machine_sbdf;
>  
>      return do_domctl(xch, &domctl);
>  }
> @@ -1686,7 +1687,8 @@ int xc_test_assign_device(
>  
>      domctl.cmd = XEN_DOMCTL_test_assign_device;
>      domctl.domain = domid;
> -    domctl.u.assign_device.machine_sbdf = machine_sbdf;
> +    domctl.u.assign_device.dev = XEN_DOMCTL_DEV_PCI;
> +    domctl.u.assign_device.u.pci.machine_sbdf = machine_sbdf;
>  
>      return do_domctl(xch, &domctl);
>  }
> @@ -1700,11 +1702,96 @@ int xc_deassign_device(
>  
>      domctl.cmd = XEN_DOMCTL_deassign_device;
>      domctl.domain = domid;
> -    domctl.u.assign_device.machine_sbdf = machine_sbdf;
> - 
> +    domctl.u.assign_device.dev = XEN_DOMCTL_DEV_PCI;
> +    domctl.u.assign_device.u.pci.machine_sbdf = machine_sbdf;
> +
>      return do_domctl(xch, &domctl);
>  }
>  
> +int xc_assign_dt_device(
> +    xc_interface *xch,
> +    uint32_t domid,
> +    char *path)
> +{
> +    int rc;
> +    size_t size = strlen(path);
> +    DECLARE_DOMCTL;
> +    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
> +
> +    if ( xc_hypercall_bounce_pre(xch, path) )
> +        return -1;
> +
> +    domctl.cmd = XEN_DOMCTL_assign_device;
> +    domctl.domain = (domid_t)domid;
> +
> +    domctl.u.assign_device.dev = XEN_DOMCTL_DEV_DT;
> +    domctl.u.assign_device.u.dt.size = size;
> +    set_xen_guest_handle(domctl.u.assign_device.u.dt.path, path);
> +
> +    rc = do_domctl(xch, &domctl);
> +
> +    xc_hypercall_bounce_post(xch, path);
> +
> +    return rc;
> +}
> +
> +int xc_test_assign_dt_device(
> +    xc_interface *xch,
> +    uint32_t domid,
> +    char *path)
> +{
> +    int rc;
> +    size_t size = strlen(path);
> +    DECLARE_DOMCTL;
> +    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
> +
> +    if ( xc_hypercall_bounce_pre(xch, path) )
> +        return -1;
> +
> +    domctl.cmd = XEN_DOMCTL_test_assign_device;
> +    domctl.domain = (domid_t)domid;
> +
> +    domctl.u.assign_device.dev = XEN_DOMCTL_DEV_DT;
> +    domctl.u.assign_device.u.dt.size = size;
> +    set_xen_guest_handle(domctl.u.assign_device.u.dt.path, path);
> +
> +    rc = do_domctl(xch, &domctl);
> +
> +    xc_hypercall_bounce_post(xch, path);
> +
> +    return rc;
> +}
> +
> +int xc_deassign_dt_device(
> +    xc_interface *xch,
> +    uint32_t domid,
> +    char *path)
> +{
> +    int rc;
> +    size_t size = strlen(path);
> +    DECLARE_DOMCTL;
> +    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
> +
> +    if ( xc_hypercall_bounce_pre(xch, path) )
> +        return -1;
> +
> +    domctl.cmd = XEN_DOMCTL_deassign_device;
> +    domctl.domain = (domid_t)domid;
> +
> +    domctl.u.assign_device.dev = XEN_DOMCTL_DEV_DT;
> +    domctl.u.assign_device.u.dt.size = size;
> +    set_xen_guest_handle(domctl.u.assign_device.u.dt.path, path);
> +
> +    rc = do_domctl(xch, &domctl);
> +
> +    xc_hypercall_bounce_post(xch, path);
> +
> +    return rc;
> +}
> +
> +
> +
> +
>  int xc_domain_update_msi_irq(
>      xc_interface *xch,
>      uint32_t domid,
> diff --git a/xen/drivers/passthrough/device_tree.c 
> b/xen/drivers/passthrough/device_tree.c
> index d9b486e..11deb1d 100644
> --- a/xen/drivers/passthrough/device_tree.c
> +++ b/xen/drivers/passthrough/device_tree.c
> @@ -1,9 +1,6 @@
>  /*
>   * Code to passthrough a device tree node to a guest
>   *
> - * TODO: This contains only the necessary code to protected device passed to
> - * dom0. It will need some updates when device passthrough will is added.
> - *
>   * Julien Grall <julien.grall@xxxxxxxxxx>
>   * Copyright (c) 2014 Linaro Limited.
>   *
> @@ -20,6 +17,7 @@
>  
>  #include <xen/lib.h>
>  #include <xen/sched.h>
> +#include <xen/guest_access.h>
>  #include <xen/iommu.h>
>  #include <xen/device_tree.h>
>  
> @@ -85,6 +83,20 @@ fail:
>      return rc;
>  }
>  
> +static bool_t iommu_dt_device_is_assigned(const struct dt_device_node *dev)
> +{
> +    bool_t assigned = 0;
> +
> +    if ( !dt_device_is_protected(dev) )
> +        return 1;

Why return true here?


> +    spin_lock(&dtdevs_lock);
> +    assigned = !list_empty(&dev->domain_list);
> +    spin_unlock(&dtdevs_lock);
> +
> +    return assigned;
> +}
> +
>  int iommu_dt_domain_init(struct domain *d)
>  {
>      struct hvm_iommu *hd = domain_hvm_iommu(d);
> @@ -111,3 +123,82 @@ int iommu_release_dt_devices(struct domain *d)
>  
>      return 0;
>  }
> +
> +int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
> +                       XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
> +{
> +    int ret;
> +    struct dt_device_node *dev;
> +
> +    /* TODO: How to deal with XSM? */
> +    /* TODO: Do we need to check is_dying? Mostly to protect against
> +     * hypercall trying to passthrough a device while we are
> +     * dying.
> +     */
> +
> +    switch ( domctl->cmd )
> +    {
> +    case XEN_DOMCTL_assign_device:
> +        ret = -ENOSYS;
> +        if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_DT )
> +            break;
> +
> +        ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
> +                                    domctl->u.assign_device.u.dt.size,
> +                                    &dev);
> +        if ( ret )
> +            break;
> +
> +        ret = iommu_assign_dt_device(d, dev);
> +
> +        if ( ret )
> +            printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
> +                   " to dom%u failed (%d)\n",
> +                   dt_node_full_name(dev), d->domain_id, ret);
> +        break;
> +
> +    case XEN_DOMCTL_deassign_device:
> +        ret = -ENOSYS;
> +        if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_DT )
> +            break;
> +
> +        ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
> +                                    domctl->u.assign_device.u.dt.size,
> +                                    &dev);
> +        if ( ret )
> +            break;
> +
> +        ret = iommu_deassign_dt_device(d, dev);
> +
> +        if ( ret )
> +            printk(XENLOG_G_ERR "XEN_DOMCTL_assign_dt_device: assign \"%s\""
> +                   " to dom%u failed (%d)\n",
> +                   dt_node_full_name(dev), d->domain_id, ret);
> +        break;
> +
> +    case XEN_DOMCTL_test_assign_device:
> +        ret = -ENOSYS;
> +        if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_DT )
> +            break;
> +
> +        ret = dt_find_node_by_gpath(domctl->u.assign_device.u.dt.path,
> +                                    domctl->u.assign_device.u.dt.size,
> +                                    &dev);
> +        if ( ret )
> +            break;
> +
> +        if ( iommu_dt_device_is_assigned(dev) )
> +        {
> +            printk(XENLOG_G_ERR "%s already assigned, or not protected\n",
> +                   dt_node_full_name(dev));
> +            ret = -EINVAL;
> +        }
> +        break;
> +
> +    default:
> +        ret = -ENOSYS;
> +        break;
> +    }
> +
> +    return ret;
> +}
> diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
> index 8915244..02d5ec1 100644
> --- a/xen/drivers/passthrough/iommu.c
> +++ b/xen/drivers/passthrough/iommu.c
> @@ -337,6 +337,13 @@ int iommu_do_domctl(
>      ret = iommu_do_pci_domctl(domctl, d, u_domctl);
>  #endif
>  
> +    if ( ret != -ENOSYS )
> +        return ret;
> +
> +#ifdef HAS_DEVICE_TREE
> +    ret = iommu_do_dt_domctl(domctl, d, u_domctl);
> +#endif
> +
>      return ret;
>  }
>  
> diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
> index 9a47a37..ecc0cd1 100644
> --- a/xen/drivers/passthrough/pci.c
> +++ b/xen/drivers/passthrough/pci.c
> @@ -1497,6 +1497,7 @@ int iommu_do_pci_domctl(
>      u16 seg;
>      u8 bus, devfn;
>      int ret = 0;
> +    uint32_t machine_sbdf;
>  
>      switch ( domctl->cmd )
>      {
> @@ -1533,13 +1534,19 @@ int iommu_do_pci_domctl(
>      break;
>  
>      case XEN_DOMCTL_test_assign_device:
> -        ret = xsm_test_assign_device(XSM_HOOK, 
> domctl->u.assign_device.machine_sbdf);
> +        ret = -ENOSYS;
> +        if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_PCI )
> +            break;
> +
> +        machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
> +
> +        ret = xsm_test_assign_device(XSM_HOOK, machine_sbdf);
>          if ( ret )
>              break;
>  
> -        seg = domctl->u.assign_device.machine_sbdf >> 16;
> -        bus = (domctl->u.assign_device.machine_sbdf >> 8) & 0xff;
> -        devfn = domctl->u.assign_device.machine_sbdf & 0xff;
> +        seg = machine_sbdf >> 16;
> +        bus = (machine_sbdf >> 8) & 0xff;
> +        devfn = machine_sbdf & 0xff;
>  
>          if ( device_assigned(seg, bus, devfn) )
>          {
> @@ -1551,19 +1558,25 @@ int iommu_do_pci_domctl(
>          break;
>  
>      case XEN_DOMCTL_assign_device:
> +        ret = -ENOSYS;
> +        if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_PCI )
> +            break;
> +
>          if ( unlikely(d->is_dying) )
>          {
>              ret = -EINVAL;
>              break;
>          }
>  
> -        ret = xsm_assign_device(XSM_HOOK, d, 
> domctl->u.assign_device.machine_sbdf);
> +        machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
> +
> +        ret = xsm_assign_device(XSM_HOOK, d, machine_sbdf);
>          if ( ret )
>              break;
>  
> -        seg = domctl->u.assign_device.machine_sbdf >> 16;
> -        bus = (domctl->u.assign_device.machine_sbdf >> 8) & 0xff;
> -        devfn = domctl->u.assign_device.machine_sbdf & 0xff;
> +        seg = machine_sbdf >> 16;
> +        bus = (machine_sbdf >> 8) & 0xff;
> +        devfn = machine_sbdf & 0xff;
>  
>          ret = device_assigned(seg, bus, devfn) ?:
>                assign_device(d, seg, bus, devfn);
> @@ -1579,13 +1592,19 @@ int iommu_do_pci_domctl(
>          break;
>  
>      case XEN_DOMCTL_deassign_device:
> -        ret = xsm_deassign_device(XSM_HOOK, d, 
> domctl->u.assign_device.machine_sbdf);
> +        ret = -ENOSYS;
> +        if ( domctl->u.assign_device.dev != XEN_DOMCTL_DEV_PCI )
> +            break;
> +
> +        machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
> +
> +        ret = xsm_deassign_device(XSM_HOOK, d, machine_sbdf);
>          if ( ret )
>              break;
>  
> -        seg = domctl->u.assign_device.machine_sbdf >> 16;
> -        bus = (domctl->u.assign_device.machine_sbdf >> 8) & 0xff;
> -        devfn = domctl->u.assign_device.machine_sbdf & 0xff;
> +        seg = machine_sbdf >> 16;
> +        bus = (machine_sbdf >> 8) & 0xff;
> +        devfn = machine_sbdf & 0xff;
>  
>          spin_lock(&pcidevs_lock);
>          ret = deassign_device(d, seg, bus, devfn);
> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> index b742b23..d905ab0 100644
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -475,12 +475,23 @@ typedef struct xen_domctl_sendtrigger 
> xen_domctl_sendtrigger_t;
>  DEFINE_XEN_GUEST_HANDLE(xen_domctl_sendtrigger_t);
>  
>  
> -/* Assign PCI device to HVM guest. Sets up IOMMU structures. */
> +/* Assign a device to a guest. Sets up IOMMU structures. */
>  /* XEN_DOMCTL_assign_device */
>  /* XEN_DOMCTL_test_assign_device */
>  /* XEN_DOMCTL_deassign_device */
> +#define XEN_DOMCTL_DEV_PCI      0
> +#define XEN_DOMCTL_DEV_DT       1
>  struct xen_domctl_assign_device {
> -    uint32_t  machine_sbdf;   /* machine PCI ID of assigned device */
> +    uint32_t dev;   /* XEN_DOMCTL_DEV_* */
> +    union {
> +        struct {
> +            uint32_t machine_sbdf;   /* machine PCI ID of assigned device */
> +        } pci;
> +        struct {
> +            uint32_t size; /* Length of the path */
> +            XEN_GUEST_HANDLE_64(char) path; /* path to the device tree node 
> */
> +        } dt;
> +    } u;
>  };
>  typedef struct xen_domctl_assign_device xen_domctl_assign_device_t;
>  DEFINE_XEN_GUEST_HANDLE(xen_domctl_assign_device_t);
> diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
> index d03df14..d261277 100644
> --- a/xen/include/xen/iommu.h
> +++ b/xen/include/xen/iommu.h
> @@ -119,6 +119,9 @@ int iommu_deassign_dt_device(struct domain *d, struct 
> dt_device_node *dev);
>  int iommu_dt_domain_init(struct domain *d);
>  int iommu_release_dt_devices(struct domain *d);
>  
> +int iommu_do_dt_domctl(struct xen_domctl *, struct domain *,
> +                       XEN_GUEST_HANDLE_PARAM(xen_domctl_t));
> +
>  #endif /* HAS_DEVICE_TREE */
>  
>  struct page_info;
> -- 
> 2.1.4
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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