diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 1348905..4cc0474 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -2145,6 +2145,142 @@ int xc_domain_set_max_evtchn(xc_interface *xch, uint32_t domid,
     return do_domctl(xch, &domctl);
 }
 
+int xc_dtdev_getinfo(xc_interface *xch,
+                     char *path,
+                     xc_dtdev_info_t *info)
+{
+    int rc;
+    size_t size = strlen(path);
+    DECLARE_DOMCTL;
+    struct xen_domctl_dtdev_op *op = &domctl.u.dtdev_op;
+    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
+
+    if ( xc_hypercall_bounce_pre(xch, path) )
+        return -1;
+
+    domctl.cmd = XEN_DOMCTL_dtdev_op;
+    op->op = DOMCTL_DTDEV_GET_INFO;
+    op->plen = size;
+    set_xen_guest_handle(op->path, path);
+
+    rc = do_domctl(xch, &domctl);
+
+    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_dtdev_getirq(xc_interface *xch,
+                    char *path,
+                    uint32_t index,
+                    xc_dtdev_irq_t *irq)
+{
+    int rc;
+    size_t size = strlen(path);
+    DECLARE_DOMCTL;
+    struct xen_domctl_dtdev_op *op = &domctl.u.dtdev_op;
+    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
+
+    if ( xc_hypercall_bounce_pre(xch, path) )
+        return -1;
+
+    domctl.cmd = XEN_DOMCTL_dtdev_op;
+    op->op = DOMCTL_DTDEV_GET_IRQ;
+    op->plen = size;
+    op->index = index;
+    set_xen_guest_handle(op->path, path);
+
+    rc = do_domctl(xch, &domctl);
+
+    xc_hypercall_bounce_post(xch, path);
+
+    if ( !rc )
+    {
+        irq->irq = op->u.irq.irq;
+        irq->type = op->u.irq.type;
+    }
+
+    return rc;
+}
+
+int xc_dtdev_getmmio(xc_interface *xch,
+                     char *path,
+                     uint32_t index,
+                     xc_dtdev_mmio_t *mmio)
+{
+    int rc;
+    size_t size = strlen(path);
+    DECLARE_DOMCTL;
+    struct xen_domctl_dtdev_op *op = &domctl.u.dtdev_op;
+    DECLARE_HYPERCALL_BOUNCE(path, size, XC_HYPERCALL_BUFFER_BOUNCE_IN);
+
+    if ( xc_hypercall_bounce_pre(xch, path) )
+        return -1;
+
+    op->op = DOMCTL_DTDEV_GET_MMIO;
+    op->plen = size;
+    op->index = index;
+    set_xen_guest_handle(op->path, path);
+
+    rc = do_domctl(xch, &domctl);
+
+    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_dtdev_getcompat(xc_interface *xch,
+                       char *path,
+                       char *compat,
+                       uint32_t *clen)
+{
+    int rc;
+    size_t size = strlen(path);
+    DECLARE_DOMCTL;
+    struct xen_domctl_dtdev_op *op = &domctl.u.dtdev_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 = DOMCTL_DTDEV_GET_COMPAT;
+    op->plen = size;
+    set_xen_guest_handle(op->path, path);
+
+    op->u.compat.len = *clen;
+    set_xen_guest_handle(op->u.compat.compat, compat);
+
+    rc = do_domctl(xch, &domctl);
+
+    if ( !rc )
+        *clen = op->u.compat.len;
+
+    xc_hypercall_bounce_post(xch, compat);
+
+out:
+    xc_hypercall_bounce_post(xch, path);
+
+    return rc;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index cdda4e5..c549753 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -1208,6 +1208,44 @@ 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;
+
+/* Retrieve device tree information */
+
+int xc_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_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_dtdev_getmmio(xc_interface *xch,
+                     char *path,
+                     uint32_t index,
+                     xc_dtdev_mmio_t *mmio);
+
+int xc_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/common/device_tree.c b/xen/common/device_tree.c
index 071109e..2f6c154 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -24,6 +24,8 @@
 #include <xen/cpumask.h>
 #include <xen/ctype.h>
 #include <asm/setup.h>
+#include <xen/lib.h>
+#include <xen/irq.h>
 
 const void *device_tree_flattened;
 dt_irq_xlate_func dt_irq_xlate;
@@ -1642,6 +1644,117 @@ void __init dt_unflatten_host_device_tree(void)
     dt_alias_scan();
 }
 
+/* TODO: I think Xen needs a bit of caching in each device node to get the
+ * information in constant time.
+ * For now, Xen has to translate IRQs/MMIOs every time
+ */
+int dt_do_domctl(struct xen_domctl *domctl)
+{
+    struct xen_domctl_dtdev_op *info = &domctl->u.dtdev_op;
+    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 DOMCTL_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 DOMCTL_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 assign the IRQ to the guest */
+            if ( !is_assignable_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 DOMCTL_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 DOMCTL_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.len < compat->length )
+                return -ENOSPC;
+
+            if ( copy_to_guest(info->u.compat.compat, compat->value,
+                               compat->length) != 0 )
+                return -EFAULT;
+
+            info->u.compat.len = compat->length;
+        }
+        break;
+
+    default:
+        return -ENOSYS;
+    }
+
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index 04ecd53..0c9926a 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -315,6 +315,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
     case XEN_DOMCTL_createdomain:
     case XEN_DOMCTL_getdomaininfo:
     case XEN_DOMCTL_test_assign_device:
+    case XEN_DOMCTL_dtdev_op:
         d = NULL;
         break;
     default:
@@ -1017,6 +1018,15 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
     }
     break;
 
+#ifdef HAS_DEVICE_TREE
+    case XEN_DOMCTL_dtdev_op:
+    {
+        ret = dt_do_domctl(op);
+        copyback = 1;
+    }
+    break;
+#endif
+
     default:
         ret = arch_do_domctl(op, d, u_domctl);
         break;
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index b5f2ed7..f7bad9b 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -946,6 +946,44 @@ typedef struct xen_domctl_vcpu_msrs xen_domctl_vcpu_msrs_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpu_msrs_t);
 #endif
 
+/* Device Tree: Retrieve informations about a device node */
+struct xen_domctl_dtdev_op {
+    /* IN */
+    uint32_t plen;                  /* Length of the path */
+    XEN_GUEST_HANDLE(char) path;    /* Path to the device tree node */
+#define DOMCTL_DTDEV_GET_INFO        0
+#define DOMCTL_DTDEV_GET_IRQ         1
+#define DOMCTL_DTDEV_GET_MMIO        2
+#define DOMCTL_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 {
+            xen_pfn_t mfn;
+            xen_pfn_t nr_mfn;
+        } mmio;
+        struct {
+            uint32_t len;           /* IN: Size of buffer. OUT: Size copied */
+            XEN_GUEST_HANDLE_64(char) compat;
+        } compat;
+    } u;
+};
+typedef struct xen_domctl_dtdev_op xen_domctl_dtdev_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_dtdev_op_t);
+
 struct xen_domctl {
     uint32_t cmd;
 #define XEN_DOMCTL_createdomain                   1
@@ -1019,6 +1057,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_get_vcpu_msrs                 72
 #define XEN_DOMCTL_set_vcpu_msrs                 73
 #define XEN_DOMCTL_configure_domain              74
+#define XEN_DOMCTL_dtdev_op                      75
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -1080,6 +1119,7 @@ struct xen_domctl {
         struct xen_domctl_gdbsx_memio       gdbsx_guest_memio;
         struct xen_domctl_set_broken_page_p2m set_broken_page_p2m;
         struct xen_domctl_cacheflush        cacheflush;
+        struct xen_domctl_dtdev_op          dtdev_op;
         struct xen_domctl_gdbsx_pauseunp_vcpu gdbsx_pauseunp_vcpu;
         struct xen_domctl_gdbsx_domstatus   gdbsx_domstatus;
         uint8_t                             pad[128];
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
index 6dc34df..8481939 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/domctl.h>
 #include <xen/init.h>
 #include <xen/string.h>
 #include <xen/types.h>
@@ -669,6 +670,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_domctl(struct xen_domctl *domctl);
+
 #endif /* __XEN_DEVICE_TREE_H */
 
 /*
