diff mbox

[Xen-devel,RFC,09/19] xen/dts: Add hypercalls to retrieve device node information

Message ID 1402935486-29136-10-git-send-email-julien.grall@linaro.org
State Superseded, archived
Headers show

Commit Message

Julien Grall June 16, 2014, 4:17 p.m. UTC
DOM0 doesn't provide a generic way to get information about a device tree
node. If we want to do it in userspace, we will have to duplicate the
MMIO/IRQ translation from Xen. Therefore, we can let the hypervisor
doing the job for us and get nearly all the informations.

This new physdev operation will let the toolstack get the IRQ/MMIO regions
and the compatible string. Most the device node can be described with only
theses 3 items. If we need to add a specific properties, then we will have
to implement it in userspace (some idea was to use a configuration file
describing the additional properties).

The hypercall is divided in 4 parts:
    - GET_INFO: get the numbers of IRQ/MMIO and the size of the
    compatible string;
    - GET_IRQ: get the IRQ by index. If the IRQ is not routable (i.e not
    an SPIs), the errno will be set to -EINVAL;
    - GET_MMIO: get the MMIO range by index. If the base and the size of
    is not page-aligned, the errno will be set to -EINVAL;
    - GET_COMPAT: get the compatible string

All the information will be accessible if the device is not used by Xen
and protected by an IOMMU.

Signed-off-by: Julien Grall <julien.grall@linaro.org>
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Cc: Ian Campbell <ian.campbell@citrix.com>

---

I'm wondering if we can let the toolstack retrieve device information for
every device not used by Xen. This would allow embedded guys using passthrough
"easily" when their devices are not under an IOMMU.
---
 tools/libxc/xc_physdev.c      |  129 +++++++++++++++++++++++++++++++++++++++++
 tools/libxc/xenctrl.h         |   36 ++++++++++++
 xen/arch/arm/physdev.c        |   16 +++++
 xen/common/device_tree.c      |  112 +++++++++++++++++++++++++++++++++++
 xen/include/public/physdev.h  |   40 +++++++++++++
 xen/include/xen/device_tree.h |    3 +
 6 files changed, 336 insertions(+)

Comments

Stefano Stabellini June 18, 2014, 7:38 p.m. UTC | #1
On Mon, 16 Jun 2014, Julien Grall wrote:
> DOM0 doesn't provide a generic way to get information about a device tree
> node. If we want to do it in userspace, we will have to duplicate the
> MMIO/IRQ translation from Xen. Therefore, we can let the hypervisor
> doing the job for us and get nearly all the informations.
> 
> This new physdev operation will let the toolstack get the IRQ/MMIO regions
> and the compatible string. Most the device node can be described with only
> theses 3 items. If we need to add a specific properties, then we will have
> to implement it in userspace (some idea was to use a configuration file
> describing the additional properties).
> 
> The hypercall is divided in 4 parts:
>     - GET_INFO: get the numbers of IRQ/MMIO and the size of the
>     compatible string;
>     - GET_IRQ: get the IRQ by index. If the IRQ is not routable (i.e not
>     an SPIs), the errno will be set to -EINVAL;
>     - GET_MMIO: get the MMIO range by index. If the base and the size of
>     is not page-aligned, the errno will be set to -EINVAL;
>     - GET_COMPAT: get the compatible string
> 
> All the information will be accessible if the device is not used by Xen
> and protected by an IOMMU.
> 
> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> Cc: Ian Jackson <ian.jackson@eu.citrix.com>
> Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> Cc: Ian Campbell <ian.campbell@citrix.com>
> 

I know that we talked about this face to face already, but this troubles
me: is it really so uncommon for a device tree node corresponding to a
device to have a key-value pair that is critical for the initialization
of the device?

The ACPI on ARM people are discussing how to introduce these key-value
pairs in ACPI too, so I wonder if we can really dismiss them so easily
for device assignment.

Could Xen discard everything that it knows cannot be passed to the guest
(information on clocks and phandles for example), but return to the
toolstack other harmless key-value pairs, such as device specific
configurations? Maybe we could introduce PHYSDEVOP_DTDEV_GET_KEYVALUE.


> I'm wondering if we can let the toolstack retrieve device information for
> every device not used by Xen. This would allow embedded guys using passthrough
> "easily" when their devices are not under an IOMMU.
> ---
>  tools/libxc/xc_physdev.c      |  129 +++++++++++++++++++++++++++++++++++++++++
>  tools/libxc/xenctrl.h         |   36 ++++++++++++
>  xen/arch/arm/physdev.c        |   16 +++++
>  xen/common/device_tree.c      |  112 +++++++++++++++++++++++++++++++++++
>  xen/include/public/physdev.h  |   40 +++++++++++++
>  xen/include/xen/device_tree.h |    3 +
>  6 files changed, 336 insertions(+)
> 
> diff --git a/tools/libxc/xc_physdev.c b/tools/libxc/xc_physdev.c
> index cf02d85..405fe78 100644
> --- a/tools/libxc/xc_physdev.c
> +++ b/tools/libxc/xc_physdev.c
> @@ -108,3 +108,132 @@ int xc_physdev_unmap_pirq(xc_interface *xch,
>      return rc;
>  }
>  
> +int xc_physdev_dtdev_getinfo(xc_interface *xch,
> +                             char *path,
> +                             xc_dtdev_info_t *info)
> +{
> +    int rc;
> +    size_t size = strlen(path);
> +    struct physdev_dtdev_op op;
> +    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
> +
> +    if ( xc_hypercall_bounce_pre(xch, path) )
> +        return -1;
> +
> +    op.op = PHYSDEVOP_DTDEV_GET_INFO;
> +    op.plen = size;
> +    set_xen_guest_handle(op.path, path);
> +
> +    rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op));
> +
> +    xc_hypercall_bounce_post(xch, path);
> +
> +    if ( !rc )
> +    {
> +        info->num_irqs = op.u.info.num_irqs;
> +        info->num_mmios = op.u.info.num_mmios;
> +        info->compat_len = op.u.info.compat_len;
> +    }
> +
> +    return rc;
> +}
> +
> +int xc_physdev_dtdev_getirq(xc_interface *xch,
> +                            char *path,
> +                            uint32_t index,
> +                            xc_dtdev_irq_t *irq)
> +{
> +    int rc;
> +    size_t size = strlen(path);
> +    struct physdev_dtdev_op op;
> +    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
> +
> +    if ( xc_hypercall_bounce_pre(xch, path) )
> +        return -1;
> +
> +    op.op = PHYSDEVOP_DTDEV_GET_IRQ;
> +    op.plen = size;
> +    op.index = index;
> +    set_xen_guest_handle(op.path, path);
> +
> +    rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op));
> +
> +    xc_hypercall_bounce_post(xch, path);
> +
> +    if ( !rc )
> +    {
> +        irq->irq = op.u.irq.irq;
> +        irq->type = op.u.irq.type;
> +    }
> +
> +    return rc;
> +}
> +
> +int xc_physdev_dtdev_getmmio(xc_interface *xch,
> +                             char *path,
> +                             uint32_t index,
> +                             xc_dtdev_mmio_t *mmio)
> +{
> +    int rc;
> +    size_t size = strlen(path);
> +    struct physdev_dtdev_op op;
> +    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
> +
> +    if ( xc_hypercall_bounce_pre(xch, path) )
> +        return -1;
> +
> +    op.op = PHYSDEVOP_DTDEV_GET_MMIO;
> +    op.plen = size;
> +    op.index = index;
> +    set_xen_guest_handle(op.path, path);
> +
> +    rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op));
> +
> +    xc_hypercall_bounce_post(xch, path);
> +
> +    if ( !rc )
> +    {
> +        mmio->mfn = op.u.mmio.mfn;
> +        mmio->nr_mfn = op.u.mmio.nr_mfn;
> +    }
> +
> +    return rc;
> +}
> +
> +int xc_physdev_dtdev_getcompat(xc_interface *xch,
> +                               char *path,
> +                               char *compat,
> +                               uint32_t *clen)
> +{
> +    int rc;
> +    size_t size = strlen(path);
> +    struct physdev_dtdev_op op;
> +    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
> +    DECLARE_HYPERCALL_BOUNCE(compat, *clen, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
> +
> +    if ( xc_hypercall_bounce_pre(xch, path) )
> +        return -1;
> +
> +    rc = -1;
> +    if ( xc_hypercall_bounce_pre(xch, compat) )
> +        goto out;
> +
> +    op.op = PHYSDEVOP_DTDEV_GET_COMPAT;
> +    op.plen = size;
> +    set_xen_guest_handle(op.path, path);
> +
> +    op.u.compat.clen = *clen;
> +    set_xen_guest_handle(op.u.compat.compat, compat);
> +
> +    rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op));
> +
> +    if ( !rc )
> +        *clen = op.u.compat.clen;
> +
> +    xc_hypercall_bounce_post(xch, compat);
> +
> +out:
> +    xc_hypercall_bounce_post(xch, path);
> +
> +    return rc;
> +}
> diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
> index b55d857..5ad2d65 100644
> --- a/tools/libxc/xenctrl.h
> +++ b/tools/libxc/xenctrl.h
> @@ -1143,6 +1143,42 @@ int xc_physdev_pci_access_modify(xc_interface *xch,
>                                   int func,
>                                   int enable);
>  
> +typedef struct xc_dtdev_info {
> +    uint32_t num_irqs;
> +    uint32_t num_mmios;
> +    uint32_t compat_len;
> +} xc_dtdev_info_t;
> +
> +int xc_physdev_dtdev_getinfo(xc_interface *xch,
> +                             char *path,
> +                             xc_dtdev_info_t *info);
> +
> +typedef struct xc_dtdev_irq {
> +    uint32_t irq;
> +    /* TODO: Maybe an enum here? */
> +    uint32_t type;
> +} xc_dtdev_irq_t;
> +
> +int xc_physdev_dtdev_getirq(xc_interface *xch,
> +                            char *path,
> +                            uint32_t index,
> +                            xc_dtdev_irq_t *irq);
> +
> +typedef struct xc_dtdev_mmio {
> +    uint64_t mfn;
> +    uint64_t nr_mfn;
> +} xc_dtdev_mmio_t;
> +
> +int xc_physdev_dtdev_getmmio(xc_interface *xch,
> +                             char *path,
> +                             uint32_t index,
> +                             xc_dtdev_mmio_t *mmio);
> +
> +int xc_physdev_dtdev_getcompat(xc_interface *xch,
> +                               char *path,
> +                               char *compat,
> +                               uint32_t *clen);
> +
>  int xc_readconsolering(xc_interface *xch,
>                         char *buffer,
>                         unsigned int *pnr_chars,
> diff --git a/xen/arch/arm/physdev.c b/xen/arch/arm/physdev.c
> index d17589c..11c5b59 100644
> --- a/xen/arch/arm/physdev.c
> +++ b/xen/arch/arm/physdev.c
> @@ -82,6 +82,22 @@ int do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
>                  ret = -EFAULT;
>          }
>          break;
> +
> +    case PHYSDEVOP_dtdev_op:
> +        {
> +            physdev_dtdev_op_t info;
> +
> +            ret = -EFAULT;
> +            if ( copy_from_guest(&info, arg, 1) != 0 )
> +                break;
> +
> +            /* TODO: Add xsm */
> +            ret = dt_do_physdev_op(&info);
> +
> +            if ( __copy_to_guest(arg, &info, 1) )
> +                ret = -EFAULT;
> +        }
> +        break;
>      default:
>          ret = -ENOSYS;
>          break;
> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
> index fd95307..482ff8f 100644
> --- a/xen/common/device_tree.c
> +++ b/xen/common/device_tree.c
> @@ -24,6 +24,7 @@
>  #include <xen/cpumask.h>
>  #include <xen/ctype.h>
>  #include <xen/lib.h>
> +#include <xen/irq.h>
>  
>  struct dt_early_info __initdata early_info;
>  const void *device_tree_flattened;
> @@ -2021,6 +2022,117 @@ void __init dt_unflatten_host_device_tree(void)
>      dt_alias_scan();
>  }
>  
> +
> +/* TODO: I think we need a bit of caching in each device node to get the
> + * information in constant time.
> + * For now we need to translate IRQs/MMIOs every time
> + */
> +int dt_do_physdev_op(physdev_dtdev_op_t *info)
> +{
> +    struct dt_device_node *dev;
> +    int ret;
> +
> +    ret = dt_find_node_by_gpath(info->path, info->plen, &dev);
> +    if ( ret )
> +        return ret;
> +
> +    /* Only allow access to protected device and not used by Xen */
> +    if ( !dt_device_is_protected(dev) || dt_device_used_by(dev) == DOMID_XEN )
> +        return -EACCES;
> +
> +    switch ( info->op )
> +    {
> +    case PHYSDEVOP_DTDEV_GET_INFO:
> +        {
> +            const struct dt_property *compat;
> +
> +            compat = dt_find_property(dev, "compatible", NULL);
> +            /* Hopefully, this case should never happen, print error
> +             * if it occurs
> +             */
> +            if ( !compat )
> +            {
> +                dprintk(XENLOG_G_ERR, "Unable to find compatible node for %s\n",
> +                        dt_node_full_name(dev));
> +                return -EBADFD;
> +            }
> +
> +            info->u.info.num_irqs = dt_number_of_irq(dev);
> +            info->u.info.num_mmios = dt_number_of_address(dev);
> +            info->u.info.compat_len = compat->length;
> +        }
> +        break;
> +
> +    case PHYSDEVOP_DTDEV_GET_IRQ:
> +        {
> +            struct dt_irq irq;
> +
> +            ret = dt_device_get_irq(dev, info->index, &irq);
> +            if ( ret )
> +                return ret;
> +
> +            /* Check if Xen is able to route the IRQ to the guest */
> +            if ( !is_routable_irq(irq.irq) )
> +                return -EINVAL;
> +
> +            info->u.irq.irq = irq.irq;
> +            /* TODO: Translate the type into an exportable value */
> +            info->u.irq.type = irq.type;
> +        }
> +        break;
> +
> +    case PHYSDEVOP_DTDEV_GET_MMIO:
> +        {
> +            uint64_t addr, size;
> +
> +            ret = dt_device_get_address(dev, info->index, &addr, &size);
> +            if ( ret )
> +                return ret;
> +
> +            /* Make sure the address and the size are page aligned.
> +             * If not, we may passthrough MMIO regions which may belong
> +             * to another device. Deny it!
> +             */
> +            if ( (addr & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
> +            {
> +                dprintk(XENLOG_ERR, "%s: contain non-page aligned range:"
> +                        " addr = 0x%"PRIx64" size = 0x%"PRIx64"\n",
> +                        dt_node_full_name(dev), addr, size);
> +                return -EINVAL;
> +            }
> +
> +            info->u.mmio.mfn = paddr_to_pfn(addr);
> +            info->u.mmio.nr_mfn = paddr_to_pfn(size);
> +        }
> +        break;
> +
> +    case PHYSDEVOP_DTDEV_GET_COMPAT:
> +        {
> +            const struct dt_property *compat;
> +
> +            compat = dt_find_property(dev, "compatible", NULL);
> +            if ( !compat || !compat->length )
> +                return -ENOENT;
> +
> +            if ( info->u.compat.clen < compat->length )
> +                return -ENOSPC;
> +
> +            if ( copy_to_guest(info->u.compat.compat, compat->value,
> +                               compat->length) != 0 )
> +                return -EFAULT;
> +
> +            info->u.compat.clen = compat->length;
> +        }
> +        break;
> +
> +    default:
> +        return -ENOSYS;
> +    }
> +
> +
> +    return 0;
> +}
> +
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h
> index d547928..23cf673 100644
> --- a/xen/include/public/physdev.h
> +++ b/xen/include/public/physdev.h
> @@ -337,6 +337,46 @@ struct physdev_dbgp_op {
>  typedef struct physdev_dbgp_op physdev_dbgp_op_t;
>  DEFINE_XEN_GUEST_HANDLE(physdev_dbgp_op_t);
>  
> +/* Retrieve informations about a device node */
> +#define PHYSDEVOP_dtdev_op        32
> +
> +struct physdev_dtdev_op {
> +    /* IN */
> +    uint32_t plen;                  /* Length of the path */
> +    XEN_GUEST_HANDLE(char) path;    /* Path to the device tree node */
> +#define PHYSDEVOP_DTDEV_GET_INFO        0
> +#define PHYSDEVOP_DTDEV_GET_IRQ         1
> +#define PHYSDEVOP_DTDEV_GET_MMIO        2
> +#define PHYSDEVOP_DTDEV_GET_COMPAT      3
> +    uint8_t op;
> +    uint32_t pad0:24;
> +    uint32_t index;                 /* Index for the IRQ/MMIO to retrieve */
> +    /* OUT */
> +    union {
> +        struct {
> +            uint32_t num_irqs;      /* Number of IRQs */
> +            uint32_t num_mmios;     /* Number of MMIOs */
> +            uint32_t compat_len;    /* Length of the compatible string */
> +        } info;
> +        struct {
> +            /* TODO: Do we need to handle MSI-X? */
> +            uint32_t irq;           /* IRQ number */
> +            /* TODO: Describe with defines the IRQ type */
> +            uint32_t type;          /* IRQ type (i.e edge, level...) */
> +        } irq;
> +        struct {
> +            uint64_t mfn;
> +            uint64_t nr_mfn;
> +        } mmio;
> +        struct {
> +            uint32_t clen;          /* IN: Size of buffer. OUT: Size copied */
> +            XEN_GUEST_HANDLE_64(char) compat;
> +        } compat;
> +    } u;
> +};
> +typedef struct physdev_dtdev_op physdev_dtdev_op_t;
> +DEFINE_XEN_GUEST_HANDLE(physdev_dtdev_op_t);
> +
>  /*
>   * Notify that some PIRQ-bound event channels have been unmasked.
>   * ** This command is obsolete since interface version 0x00030202 and is **
> diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
> index bb33e54..3d5101c 100644
> --- a/xen/include/xen/device_tree.h
> +++ b/xen/include/xen/device_tree.h
> @@ -12,6 +12,7 @@
>  
>  #include <asm/byteorder.h>
>  #include <public/xen.h>
> +#include <public/physdev.h>
>  #include <xen/init.h>
>  #include <xen/string.h>
>  #include <xen/types.h>
> @@ -711,6 +712,8 @@ int dt_parse_phandle_with_args(const struct dt_device_node *np,
>                                 const char *cells_name, int index,
>                                 struct dt_phandle_args *out_args);
>  
> +int dt_do_physdev_op(physdev_dtdev_op_t *info);
> +
>  #endif /* __XEN_DEVICE_TREE_H */
>  
>  /*
> -- 
> 1.7.10.4
>
Julien Grall June 19, 2014, 11:58 a.m. UTC | #2
(Adding Christoffer)

On 06/18/2014 08:38 PM, Stefano Stabellini wrote:
> On Mon, 16 Jun 2014, Julien Grall wrote:
>> DOM0 doesn't provide a generic way to get information about a device tree
>> node. If we want to do it in userspace, we will have to duplicate the
>> MMIO/IRQ translation from Xen. Therefore, we can let the hypervisor
>> doing the job for us and get nearly all the informations.
>>
>> This new physdev operation will let the toolstack get the IRQ/MMIO regions
>> and the compatible string. Most the device node can be described with only
>> theses 3 items. If we need to add a specific properties, then we will have
>> to implement it in userspace (some idea was to use a configuration file
>> describing the additional properties).
>>
>> The hypercall is divided in 4 parts:
>>     - GET_INFO: get the numbers of IRQ/MMIO and the size of the
>>     compatible string;
>>     - GET_IRQ: get the IRQ by index. If the IRQ is not routable (i.e not
>>     an SPIs), the errno will be set to -EINVAL;
>>     - GET_MMIO: get the MMIO range by index. If the base and the size of
>>     is not page-aligned, the errno will be set to -EINVAL;
>>     - GET_COMPAT: get the compatible string
>>
>> All the information will be accessible if the device is not used by Xen
>> and protected by an IOMMU.
>>
>> Signed-off-by: Julien Grall <julien.grall@linaro.org>
>> Cc: Ian Jackson <ian.jackson@eu.citrix.com>
>> Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>> Cc: Ian Campbell <ian.campbell@citrix.com>
>>
> 
> I know that we talked about this face to face already, but this troubles
> me: is it really so uncommon for a device tree node corresponding to a
> device to have a key-value pair that is critical for the initialization
> of the device?

I remembered a chat with Christoffer (I think you were in CC) about
specific device properties. But I can't find it in my mailbox.

I think the idea was Xen provides the generic properties (regs,
interrupts) and we implement device specific properties in a
configuration file that could be share with KVM (IIRC, KVM has the same
needs).

> The ACPI on ARM people are discussing how to introduce these key-value
> pairs in ACPI too, so I wonder if we can really dismiss them so easily
> for device assignment.
> 
> Could Xen discard everything that it knows cannot be passed to the guest
> (information on clocks and phandles for example), but return to the
> toolstack other harmless key-value pairs, such as device specific
> configurations? Maybe we could introduce PHYSDEVOP_DTDEV_GET_KEYVALUE.

A blacklist won't work here because Xen may return properties that
contain a list of phandle (for instance see the SMMU bindings). The name
of those properties are not necessary generic.

IHMO, need to let the toolstack device whether we need to add specific
properties. Those properties can be write down in a configuration file
which will be parsed by the toolstack.
Stefano Stabellini June 19, 2014, 12:21 p.m. UTC | #3
On Thu, 19 Jun 2014, Julien Grall wrote:
> (Adding Christoffer)
> 
> On 06/18/2014 08:38 PM, Stefano Stabellini wrote:
> > On Mon, 16 Jun 2014, Julien Grall wrote:
> >> DOM0 doesn't provide a generic way to get information about a device tree
> >> node. If we want to do it in userspace, we will have to duplicate the
> >> MMIO/IRQ translation from Xen. Therefore, we can let the hypervisor
> >> doing the job for us and get nearly all the informations.
> >>
> >> This new physdev operation will let the toolstack get the IRQ/MMIO regions
> >> and the compatible string. Most the device node can be described with only
> >> theses 3 items. If we need to add a specific properties, then we will have
> >> to implement it in userspace (some idea was to use a configuration file
> >> describing the additional properties).
> >>
> >> The hypercall is divided in 4 parts:
> >>     - GET_INFO: get the numbers of IRQ/MMIO and the size of the
> >>     compatible string;
> >>     - GET_IRQ: get the IRQ by index. If the IRQ is not routable (i.e not
> >>     an SPIs), the errno will be set to -EINVAL;
> >>     - GET_MMIO: get the MMIO range by index. If the base and the size of
> >>     is not page-aligned, the errno will be set to -EINVAL;
> >>     - GET_COMPAT: get the compatible string
> >>
> >> All the information will be accessible if the device is not used by Xen
> >> and protected by an IOMMU.
> >>
> >> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> >> Cc: Ian Jackson <ian.jackson@eu.citrix.com>
> >> Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> >> Cc: Ian Campbell <ian.campbell@citrix.com>
> >>
> > 
> > I know that we talked about this face to face already, but this troubles
> > me: is it really so uncommon for a device tree node corresponding to a
> > device to have a key-value pair that is critical for the initialization
> > of the device?
> 
> I remembered a chat with Christoffer (I think you were in CC) about
> specific device properties. But I can't find it in my mailbox.
> 
> I think the idea was Xen provides the generic properties (regs,
> interrupts) and we implement device specific properties in a
> configuration file that could be share with KVM (IIRC, KVM has the same
> needs).

What configuration file? Where would it live?
I would rather avoid forcing the user to specify these properties in the
VM config file.


> > The ACPI on ARM people are discussing how to introduce these key-value
> > pairs in ACPI too, so I wonder if we can really dismiss them so easily
> > for device assignment.
> > 
> > Could Xen discard everything that it knows cannot be passed to the guest
> > (information on clocks and phandles for example), but return to the
> > toolstack other harmless key-value pairs, such as device specific
> > configurations? Maybe we could introduce PHYSDEVOP_DTDEV_GET_KEYVALUE.
> 
> A blacklist won't work here because Xen may return properties that
> contain a list of phandle (for instance see the SMMU bindings). The name
> of those properties are not necessary generic.
> 
> IHMO, need to let the toolstack device whether we need to add specific
> properties. Those properties can be write down in a configuration file
> which will be parsed by the toolstack.

Could we simply remove anything that contains phandles? Is there a way
to detect if a value is a phandle?
Julien Grall June 19, 2014, 12:25 p.m. UTC | #4
On 06/19/2014 01:21 PM, Stefano Stabellini wrote:
>>> I know that we talked about this face to face already, but this troubles
>>> me: is it really so uncommon for a device tree node corresponding to a
>>> device to have a key-value pair that is critical for the initialization
>>> of the device?
>>
>> I remembered a chat with Christoffer (I think you were in CC) about
>> specific device properties. But I can't find it in my mailbox.
>>
>> I think the idea was Xen provides the generic properties (regs,
>> interrupts) and we implement device specific properties in a
>> configuration file that could be share with KVM (IIRC, KVM has the same
>> needs).
> 
> What configuration file? Where would it live?
> I would rather avoid forcing the user to specify these properties in the
> VM config file.

I meant an host config file.

>>> The ACPI on ARM people are discussing how to introduce these key-value
>>> pairs in ACPI too, so I wonder if we can really dismiss them so easily
>>> for device assignment.
>>>
>>> Could Xen discard everything that it knows cannot be passed to the guest
>>> (information on clocks and phandles for example), but return to the
>>> toolstack other harmless key-value pairs, such as device specific
>>> configurations? Maybe we could introduce PHYSDEVOP_DTDEV_GET_KEYVALUE.
>>
>> A blacklist won't work here because Xen may return properties that
>> contain a list of phandle (for instance see the SMMU bindings). The name
>> of those properties are not necessary generic.
>>
>> IHMO, need to let the toolstack device whether we need to add specific
>> properties. Those properties can be write down in a configuration file
>> which will be parsed by the toolstack.
> 
> Could we simply remove anything that contains phandles? Is there a way
> to detect if a value is a phandle?

A phandle is only a way to interpret a number. AFAIK, there is no way to
differentiate it.

Regards,
Christoffer Dall June 24, 2014, 8:46 a.m. UTC | #5
On 19 June 2014 13:58, Julien Grall <julien.grall@linaro.org> wrote:
> (Adding Christoffer)
>
> On 06/18/2014 08:38 PM, Stefano Stabellini wrote:
>> On Mon, 16 Jun 2014, Julien Grall wrote:
>>> DOM0 doesn't provide a generic way to get information about a device tree
>>> node. If we want to do it in userspace, we will have to duplicate the
>>> MMIO/IRQ translation from Xen. Therefore, we can let the hypervisor
>>> doing the job for us and get nearly all the informations.
>>>
>>> This new physdev operation will let the toolstack get the IRQ/MMIO regions
>>> and the compatible string. Most the device node can be described with only
>>> theses 3 items. If we need to add a specific properties, then we will have
>>> to implement it in userspace (some idea was to use a configuration file
>>> describing the additional properties).
>>>
>>> The hypercall is divided in 4 parts:
>>>     - GET_INFO: get the numbers of IRQ/MMIO and the size of the
>>>     compatible string;
>>>     - GET_IRQ: get the IRQ by index. If the IRQ is not routable (i.e not
>>>     an SPIs), the errno will be set to -EINVAL;
>>>     - GET_MMIO: get the MMIO range by index. If the base and the size of
>>>     is not page-aligned, the errno will be set to -EINVAL;
>>>     - GET_COMPAT: get the compatible string
>>>
>>> All the information will be accessible if the device is not used by Xen
>>> and protected by an IOMMU.
>>>
>>> Signed-off-by: Julien Grall <julien.grall@linaro.org>
>>> Cc: Ian Jackson <ian.jackson@eu.citrix.com>
>>> Cc: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
>>> Cc: Ian Campbell <ian.campbell@citrix.com>
>>>
>>
>> I know that we talked about this face to face already, but this troubles
>> me: is it really so uncommon for a device tree node corresponding to a
>> device to have a key-value pair that is critical for the initialization
>> of the device?
>
> I remembered a chat with Christoffer (I think you were in CC) about
> specific device properties. But I can't find it in my mailbox.
>
> I think the idea was Xen provides the generic properties (regs,
> interrupts) and we implement device specific properties in a
> configuration file that could be share with KVM (IIRC, KVM has the same
> needs).
>

Yeah, experience just shows us that when you start exposing the raw
hardware information to user space or through to VMs without have
semantic control over them, then you will very likely end up in a lot
of trouble.

It really should be able to limit the properties of devices that you
want to export to a reasonable set through a well-defined API.

If you have an extremely complicated device with interesting
inter-dependency, chances are you're going to need a device-specific
user space driver to couple devices, tie inter-dependent devices
together when you describe the machine to your VM, etc.  The API
suggested should take care of the common generic case.

The suggestion about a VM config file was more of a loose-thought if
we start having a bunch of networking devices that have special
properties and we wish to support passthrough of these on both Xen and
KVM, then keeping device-specific data in a config file may be a way
to accomplish that.  This is pretty much speculation and loose ideas
at this point.

Personally, I would prefer doing something along the lines of what
Julien suggest and add necessary properties as needed.  If it turns
out you need a lot more information about devices someone actually
tries to pass through to VMs, then revisit the issue.  This patch
doesn't seem to suggest an awfully complicated ABI that will cause a
lot of headache to maintain in the future or anything like that.

My 2 cents.

-Christoffer
Ian Campbell July 3, 2014, 11:33 a.m. UTC | #6
On Mon, 2014-06-16 at 17:17 +0100, Julien Grall wrote:

>  /*
>   * Local variables:
>   * mode: C

> +        struct {
> +            uint64_t mfn;
> +            uint64_t nr_mfn;

xen_pfn_t for both of these I think.

> +        } mmio;
> +        struct {
> +            uint32_t clen;          /* IN: Size of buffer. OUT: Size copied */

clen?
Ian Campbell July 3, 2014, 11:34 a.m. UTC | #7
On Thu, 2014-06-19 at 12:58 +0100, Julien Grall wrote:
> I think the idea was Xen provides the generic properties (regs,
> interrupts) and we implement device specific properties in a
> configuration file that could be share with KVM (IIRC, KVM has the same
> needs).

For this is the retrieval of the compatible string really needed?

Making this interface DT specific make me uncomfortable. I'd much rather
that it only contained hardware stuff (MMIO regions, irqs, etc).

Ian.
Ian Campbell July 3, 2014, 11:40 a.m. UTC | #8
On Thu, 2014-06-19 at 13:25 +0100, Julien Grall wrote:
> On 06/19/2014 01:21 PM, Stefano Stabellini wrote:
> >>> I know that we talked about this face to face already, but this troubles
> >>> me: is it really so uncommon for a device tree node corresponding to a
> >>> device to have a key-value pair that is critical for the initialization
> >>> of the device?
> >>
> >> I remembered a chat with Christoffer (I think you were in CC) about
> >> specific device properties. But I can't find it in my mailbox.
> >>
> >> I think the idea was Xen provides the generic properties (regs,
> >> interrupts) and we implement device specific properties in a
> >> configuration file that could be share with KVM (IIRC, KVM has the same
> >> needs).
> > 
> > What configuration file? Where would it live?
> > I would rather avoid forcing the user to specify these properties in the
> > VM config file.
> 
> I meant an host config file.

I think this is basically unavoidable. There is simply no sane way to
expose the necessary stuff from the actual dtb.

My opinion is that we should aim to get something which has the
underlying moving parts (mmio and irq mapping etc) working and in tree
sooner rather than later and leave the question of the sharp edges on
the UI until later.

Regardless of what syntactic sugar we add in the future we should always
have the lowlevel "inject a snippet of dts" interface as an option, and
that is all we really need to implement on the first pass.

A host config file mapping some useful string to such snippets is a nice
simple enhancement to that (and if it's already implemented, great, but
it's not mandatory on this pass IMHO).

> >>> The ACPI on ARM people are discussing how to introduce these key-value
> >>> pairs in ACPI too, so I wonder if we can really dismiss them so easily
> >>> for device assignment.
> >>>
> >>> Could Xen discard everything that it knows cannot be passed to the guest
> >>> (information on clocks and phandles for example), but return to the
> >>> toolstack other harmless key-value pairs, such as device specific
> >>> configurations? Maybe we could introduce PHYSDEVOP_DTDEV_GET_KEYVALUE.
> >>
> >> A blacklist won't work here because Xen may return properties that
> >> contain a list of phandle (for instance see the SMMU bindings). The name
> >> of those properties are not necessary generic.
> >>
> >> IHMO, need to let the toolstack device whether we need to add specific
> >> properties. Those properties can be write down in a configuration file
> >> which will be parsed by the toolstack.
> > 
> > Could we simply remove anything that contains phandles? Is there a way
> > to detect if a value is a phandle?
> 
> A phandle is only a way to interpret a number. AFAIK, there is no way to
> differentiate it.

Correct, it's just a number which the driver knows (by virtue of the
name etc) happens to be a phandle.

Ian.
Julien Grall July 3, 2014, 11:51 a.m. UTC | #9
Hi Ian,

On 07/03/2014 12:33 PM, Ian Campbell wrote:
> On Mon, 2014-06-16 at 17:17 +0100, Julien Grall wrote:
> 
>>  /*
>>   * Local variables:
>>   * mode: C
> 
>> +        struct {
>> +            uint64_t mfn;
>> +            uint64_t nr_mfn;
> 
> xen_pfn_t for both of these I think.

Ok. I will change it in the next version.

>> +        } mmio;
>> +        struct {
>> +            uint32_t clen;          /* IN: Size of buffer. OUT: Size copied */
> 
> clen?

compatible length.

Regards,
Ian Campbell July 3, 2014, 12:13 p.m. UTC | #10
On Thu, 2014-07-03 at 12:51 +0100, Julien Grall wrote:
> Hi Ian,
> 
> On 07/03/2014 12:33 PM, Ian Campbell wrote:
> > On Mon, 2014-06-16 at 17:17 +0100, Julien Grall wrote:
> > 
> >>  /*
> >>   * Local variables:
> >>   * mode: C
> > 
> >> +        struct {
> >> +            uint64_t mfn;
> >> +            uint64_t nr_mfn;
> > 
> > xen_pfn_t for both of these I think.
> 
> Ok. I will change it in the next version.
> 
> >> +        } mmio;
> >> +        struct {
> >> +            uint32_t clen;          /* IN: Size of buffer. OUT: Size copied */
> > 
> > clen?
> 
> compatible length.

I thought you had typo'd clean and didn't understand.

This is in a member called compat isn't it? In that case len would be
fine I think.

Ian.
diff mbox

Patch

diff --git a/tools/libxc/xc_physdev.c b/tools/libxc/xc_physdev.c
index cf02d85..405fe78 100644
--- a/tools/libxc/xc_physdev.c
+++ b/tools/libxc/xc_physdev.c
@@ -108,3 +108,132 @@  int xc_physdev_unmap_pirq(xc_interface *xch,
     return rc;
 }
 
+int xc_physdev_dtdev_getinfo(xc_interface *xch,
+                             char *path,
+                             xc_dtdev_info_t *info)
+{
+    int rc;
+    size_t size = strlen(path);
+    struct physdev_dtdev_op op;
+    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
+
+    if ( xc_hypercall_bounce_pre(xch, path) )
+        return -1;
+
+    op.op = PHYSDEVOP_DTDEV_GET_INFO;
+    op.plen = size;
+    set_xen_guest_handle(op.path, path);
+
+    rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op));
+
+    xc_hypercall_bounce_post(xch, path);
+
+    if ( !rc )
+    {
+        info->num_irqs = op.u.info.num_irqs;
+        info->num_mmios = op.u.info.num_mmios;
+        info->compat_len = op.u.info.compat_len;
+    }
+
+    return rc;
+}
+
+int xc_physdev_dtdev_getirq(xc_interface *xch,
+                            char *path,
+                            uint32_t index,
+                            xc_dtdev_irq_t *irq)
+{
+    int rc;
+    size_t size = strlen(path);
+    struct physdev_dtdev_op op;
+    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
+
+    if ( xc_hypercall_bounce_pre(xch, path) )
+        return -1;
+
+    op.op = PHYSDEVOP_DTDEV_GET_IRQ;
+    op.plen = size;
+    op.index = index;
+    set_xen_guest_handle(op.path, path);
+
+    rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op));
+
+    xc_hypercall_bounce_post(xch, path);
+
+    if ( !rc )
+    {
+        irq->irq = op.u.irq.irq;
+        irq->type = op.u.irq.type;
+    }
+
+    return rc;
+}
+
+int xc_physdev_dtdev_getmmio(xc_interface *xch,
+                             char *path,
+                             uint32_t index,
+                             xc_dtdev_mmio_t *mmio)
+{
+    int rc;
+    size_t size = strlen(path);
+    struct physdev_dtdev_op op;
+    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
+
+    if ( xc_hypercall_bounce_pre(xch, path) )
+        return -1;
+
+    op.op = PHYSDEVOP_DTDEV_GET_MMIO;
+    op.plen = size;
+    op.index = index;
+    set_xen_guest_handle(op.path, path);
+
+    rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op));
+
+    xc_hypercall_bounce_post(xch, path);
+
+    if ( !rc )
+    {
+        mmio->mfn = op.u.mmio.mfn;
+        mmio->nr_mfn = op.u.mmio.nr_mfn;
+    }
+
+    return rc;
+}
+
+int xc_physdev_dtdev_getcompat(xc_interface *xch,
+                               char *path,
+                               char *compat,
+                               uint32_t *clen)
+{
+    int rc;
+    size_t size = strlen(path);
+    struct physdev_dtdev_op op;
+    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
+    DECLARE_HYPERCALL_BOUNCE(compat, *clen, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
+
+    if ( xc_hypercall_bounce_pre(xch, path) )
+        return -1;
+
+    rc = -1;
+    if ( xc_hypercall_bounce_pre(xch, compat) )
+        goto out;
+
+    op.op = PHYSDEVOP_DTDEV_GET_COMPAT;
+    op.plen = size;
+    set_xen_guest_handle(op.path, path);
+
+    op.u.compat.clen = *clen;
+    set_xen_guest_handle(op.u.compat.compat, compat);
+
+    rc = do_physdev_op(xch, PHYSDEVOP_dtdev_op, &op, sizeof(op));
+
+    if ( !rc )
+        *clen = op.u.compat.clen;
+
+    xc_hypercall_bounce_post(xch, compat);
+
+out:
+    xc_hypercall_bounce_post(xch, path);
+
+    return rc;
+}
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index b55d857..5ad2d65 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -1143,6 +1143,42 @@  int xc_physdev_pci_access_modify(xc_interface *xch,
                                  int func,
                                  int enable);
 
+typedef struct xc_dtdev_info {
+    uint32_t num_irqs;
+    uint32_t num_mmios;
+    uint32_t compat_len;
+} xc_dtdev_info_t;
+
+int xc_physdev_dtdev_getinfo(xc_interface *xch,
+                             char *path,
+                             xc_dtdev_info_t *info);
+
+typedef struct xc_dtdev_irq {
+    uint32_t irq;
+    /* TODO: Maybe an enum here? */
+    uint32_t type;
+} xc_dtdev_irq_t;
+
+int xc_physdev_dtdev_getirq(xc_interface *xch,
+                            char *path,
+                            uint32_t index,
+                            xc_dtdev_irq_t *irq);
+
+typedef struct xc_dtdev_mmio {
+    uint64_t mfn;
+    uint64_t nr_mfn;
+} xc_dtdev_mmio_t;
+
+int xc_physdev_dtdev_getmmio(xc_interface *xch,
+                             char *path,
+                             uint32_t index,
+                             xc_dtdev_mmio_t *mmio);
+
+int xc_physdev_dtdev_getcompat(xc_interface *xch,
+                               char *path,
+                               char *compat,
+                               uint32_t *clen);
+
 int xc_readconsolering(xc_interface *xch,
                        char *buffer,
                        unsigned int *pnr_chars,
diff --git a/xen/arch/arm/physdev.c b/xen/arch/arm/physdev.c
index d17589c..11c5b59 100644
--- a/xen/arch/arm/physdev.c
+++ b/xen/arch/arm/physdev.c
@@ -82,6 +82,22 @@  int do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
                 ret = -EFAULT;
         }
         break;
+
+    case PHYSDEVOP_dtdev_op:
+        {
+            physdev_dtdev_op_t info;
+
+            ret = -EFAULT;
+            if ( copy_from_guest(&info, arg, 1) != 0 )
+                break;
+
+            /* TODO: Add xsm */
+            ret = dt_do_physdev_op(&info);
+
+            if ( __copy_to_guest(arg, &info, 1) )
+                ret = -EFAULT;
+        }
+        break;
     default:
         ret = -ENOSYS;
         break;
diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
index fd95307..482ff8f 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -24,6 +24,7 @@ 
 #include <xen/cpumask.h>
 #include <xen/ctype.h>
 #include <xen/lib.h>
+#include <xen/irq.h>
 
 struct dt_early_info __initdata early_info;
 const void *device_tree_flattened;
@@ -2021,6 +2022,117 @@  void __init dt_unflatten_host_device_tree(void)
     dt_alias_scan();
 }
 
+
+/* TODO: I think we need a bit of caching in each device node to get the
+ * information in constant time.
+ * For now we need to translate IRQs/MMIOs every time
+ */
+int dt_do_physdev_op(physdev_dtdev_op_t *info)
+{
+    struct dt_device_node *dev;
+    int ret;
+
+    ret = dt_find_node_by_gpath(info->path, info->plen, &dev);
+    if ( ret )
+        return ret;
+
+    /* Only allow access to protected device and not used by Xen */
+    if ( !dt_device_is_protected(dev) || dt_device_used_by(dev) == DOMID_XEN )
+        return -EACCES;
+
+    switch ( info->op )
+    {
+    case PHYSDEVOP_DTDEV_GET_INFO:
+        {
+            const struct dt_property *compat;
+
+            compat = dt_find_property(dev, "compatible", NULL);
+            /* Hopefully, this case should never happen, print error
+             * if it occurs
+             */
+            if ( !compat )
+            {
+                dprintk(XENLOG_G_ERR, "Unable to find compatible node for %s\n",
+                        dt_node_full_name(dev));
+                return -EBADFD;
+            }
+
+            info->u.info.num_irqs = dt_number_of_irq(dev);
+            info->u.info.num_mmios = dt_number_of_address(dev);
+            info->u.info.compat_len = compat->length;
+        }
+        break;
+
+    case PHYSDEVOP_DTDEV_GET_IRQ:
+        {
+            struct dt_irq irq;
+
+            ret = dt_device_get_irq(dev, info->index, &irq);
+            if ( ret )
+                return ret;
+
+            /* Check if Xen is able to route the IRQ to the guest */
+            if ( !is_routable_irq(irq.irq) )
+                return -EINVAL;
+
+            info->u.irq.irq = irq.irq;
+            /* TODO: Translate the type into an exportable value */
+            info->u.irq.type = irq.type;
+        }
+        break;
+
+    case PHYSDEVOP_DTDEV_GET_MMIO:
+        {
+            uint64_t addr, size;
+
+            ret = dt_device_get_address(dev, info->index, &addr, &size);
+            if ( ret )
+                return ret;
+
+            /* Make sure the address and the size are page aligned.
+             * If not, we may passthrough MMIO regions which may belong
+             * to another device. Deny it!
+             */
+            if ( (addr & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
+            {
+                dprintk(XENLOG_ERR, "%s: contain non-page aligned range:"
+                        " addr = 0x%"PRIx64" size = 0x%"PRIx64"\n",
+                        dt_node_full_name(dev), addr, size);
+                return -EINVAL;
+            }
+
+            info->u.mmio.mfn = paddr_to_pfn(addr);
+            info->u.mmio.nr_mfn = paddr_to_pfn(size);
+        }
+        break;
+
+    case PHYSDEVOP_DTDEV_GET_COMPAT:
+        {
+            const struct dt_property *compat;
+
+            compat = dt_find_property(dev, "compatible", NULL);
+            if ( !compat || !compat->length )
+                return -ENOENT;
+
+            if ( info->u.compat.clen < compat->length )
+                return -ENOSPC;
+
+            if ( copy_to_guest(info->u.compat.compat, compat->value,
+                               compat->length) != 0 )
+                return -EFAULT;
+
+            info->u.compat.clen = compat->length;
+        }
+        break;
+
+    default:
+        return -ENOSYS;
+    }
+
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h
index d547928..23cf673 100644
--- a/xen/include/public/physdev.h
+++ b/xen/include/public/physdev.h
@@ -337,6 +337,46 @@  struct physdev_dbgp_op {
 typedef struct physdev_dbgp_op physdev_dbgp_op_t;
 DEFINE_XEN_GUEST_HANDLE(physdev_dbgp_op_t);
 
+/* Retrieve informations about a device node */
+#define PHYSDEVOP_dtdev_op        32
+
+struct physdev_dtdev_op {
+    /* IN */
+    uint32_t plen;                  /* Length of the path */
+    XEN_GUEST_HANDLE(char) path;    /* Path to the device tree node */
+#define PHYSDEVOP_DTDEV_GET_INFO        0
+#define PHYSDEVOP_DTDEV_GET_IRQ         1
+#define PHYSDEVOP_DTDEV_GET_MMIO        2
+#define PHYSDEVOP_DTDEV_GET_COMPAT      3
+    uint8_t op;
+    uint32_t pad0:24;
+    uint32_t index;                 /* Index for the IRQ/MMIO to retrieve */
+    /* OUT */
+    union {
+        struct {
+            uint32_t num_irqs;      /* Number of IRQs */
+            uint32_t num_mmios;     /* Number of MMIOs */
+            uint32_t compat_len;    /* Length of the compatible string */
+        } info;
+        struct {
+            /* TODO: Do we need to handle MSI-X? */
+            uint32_t irq;           /* IRQ number */
+            /* TODO: Describe with defines the IRQ type */
+            uint32_t type;          /* IRQ type (i.e edge, level...) */
+        } irq;
+        struct {
+            uint64_t mfn;
+            uint64_t nr_mfn;
+        } mmio;
+        struct {
+            uint32_t clen;          /* IN: Size of buffer. OUT: Size copied */
+            XEN_GUEST_HANDLE_64(char) compat;
+        } compat;
+    } u;
+};
+typedef struct physdev_dtdev_op physdev_dtdev_op_t;
+DEFINE_XEN_GUEST_HANDLE(physdev_dtdev_op_t);
+
 /*
  * Notify that some PIRQ-bound event channels have been unmasked.
  * ** This command is obsolete since interface version 0x00030202 and is **
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
index bb33e54..3d5101c 100644
--- a/xen/include/xen/device_tree.h
+++ b/xen/include/xen/device_tree.h
@@ -12,6 +12,7 @@ 
 
 #include <asm/byteorder.h>
 #include <public/xen.h>
+#include <public/physdev.h>
 #include <xen/init.h>
 #include <xen/string.h>
 #include <xen/types.h>
@@ -711,6 +712,8 @@  int dt_parse_phandle_with_args(const struct dt_device_node *np,
                                const char *cells_name, int index,
                                struct dt_phandle_args *out_args);
 
+int dt_do_physdev_op(physdev_dtdev_op_t *info);
+
 #endif /* __XEN_DEVICE_TREE_H */
 
 /*