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 */
 
 /*
