diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index c7710b8..35bbb3b 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -886,6 +886,26 @@ int xc_vcpu_getcontext(xc_interface *xch,
                        vcpu_guest_context_any_t *ctxt);
 
 /**
+ * This function initializes the vuart emulation and returns
+ * the event to be used by the backend for communicating with
+ * the emulation code.
+ *
+ * @parm xch a handle to an open hypervisor interface
+ * #parm type type of vuart
+ * @parm domid the domain to get information from
+ * @parm console_domid the domid of the backend console
+ * @parm gfn the guest pfn to be used as the ring buffer
+ * @parm evtchn the event channel to be used for events
+ * @return 0 on success, negative error on failure
+ */
+int xc_dom_vuart_init(xc_interface *xch,
+                      uint32_t type,
+                      domid_t domid,
+                      domid_t console_domid,
+                      xen_pfn_t gfn,
+                      evtchn_port_t *evtchn);
+
+/**
  * This function returns information about the XSAVE state of a particular
  * vcpu of a domain. If extstate->size and extstate->xfeature_mask are 0,
  * the call is considered a query to retrieve them and the buffer is not
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 3bab4e8..899bbd4 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -343,6 +343,31 @@ int xc_domain_get_guest_width(xc_interface *xch, uint32_t domid,
     return 0;
 }
 
+int xc_dom_vuart_init(xc_interface *xch,
+                      uint32_t type,
+                      domid_t domid,
+                      domid_t console_domid,
+                      xen_pfn_t gfn,
+                      evtchn_port_t *evtchn)
+{
+    DECLARE_DOMCTL;
+    int rc = 0;
+
+    domctl.cmd = XEN_DOMCTL_vuart_op;
+    domctl.domain = (domid_t)domid;
+    domctl.u.vuart_op.cmd = XEN_DOMCTL_VUART_OP_INIT;
+    domctl.u.vuart_op.type = type;
+    domctl.u.vuart_op.console_domid = console_domid;
+    domctl.u.vuart_op.gfn = gfn;
+
+    if ( (rc = do_domctl(xch, &domctl)) < 0 )
+        return rc;
+
+    *evtchn = domctl.u.vuart_op.evtchn;
+
+    return rc;
+}
+
 int xc_domain_getinfo(xc_interface *xch,
                       uint32_t first_domid,
                       unsigned int max_doms,
diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h
index 5e1fc60..784ec7f 100644
--- a/tools/libxl/libxl_arch.h
+++ b/tools/libxl/libxl_arch.h
@@ -44,6 +44,13 @@ int libxl__arch_domain_finalise_hw_description(libxl__gc *gc,
                                       libxl_domain_build_info *info,
                                       struct xc_dom_image *dom);
 
+/* perform any pending hardware initialization */
+_hidden
+int libxl__arch_build_dom_finish(libxl__gc *gc,
+                                 libxl_domain_build_info *info,
+                                 struct xc_dom_image *dom,
+                                 libxl__domain_build_state *state);
+
 /* build vNUMA vmemrange with arch specific information */
 _hidden
 int libxl__arch_vnuma_build_vmemrange(libxl__gc *gc,
diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c
index d842d88..a33d3c9 100644
--- a/tools/libxl/libxl_arm.c
+++ b/tools/libxl/libxl_arm.c
@@ -1038,6 +1038,27 @@ int libxl__arch_domain_finalise_hw_description(libxl__gc *gc,
     return 0;
 }
 
+int libxl__arch_build_dom_finish(libxl__gc *gc,
+                                 libxl_domain_build_info *info,
+                                 struct xc_dom_image *dom,
+                                 libxl__domain_build_state *state)
+{
+    int ret = 0;
+
+    if (info->arch_arm.vuart == LIBXL_VUART_TYPE_SBSA_UART) {
+        ret = xc_dom_vuart_init(CTX->xch,
+                                XEN_DOMCTL_VUART_TYPE_VPL011,
+                                dom->guest_domid,
+                                dom->console_domid,
+                                dom->vuart_gfn,
+                                &state->vuart_port);
+        if (ret < 0)
+            LOG(ERROR, "xc_dom_vuart_init failed\n");
+    }
+
+    return ret;
+}
+
 int libxl__arch_vnuma_build_vmemrange(libxl__gc *gc,
                                       uint32_t domid,
                                       libxl_domain_build_info *info,
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index e0f0d78..5f92023 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -702,6 +702,10 @@ static int libxl__build_dom(libxl__gc *gc, uint32_t domid,
         LOGE(ERROR, "xc_dom_gnttab_init failed");
         goto out;
     }
+    if ((ret = libxl__arch_build_dom_finish(gc, info, dom, state)) != 0) {
+        LOGE(ERROR, "libxl__arch_build_dom_finish failed");
+        goto out;
+    }
 
 out:
     return ret != 0 ? ERROR_FAIL : 0;
diff --git a/tools/libxl/libxl_x86.c b/tools/libxl/libxl_x86.c
index 455f6f0..0aaeded 100644
--- a/tools/libxl/libxl_x86.c
+++ b/tools/libxl/libxl_x86.c
@@ -391,6 +391,14 @@ int libxl__arch_domain_finalise_hw_description(libxl__gc *gc,
     return rc;
 }
 
+int libxl__arch_build_dom_finish(libxl__gc *gc,
+                                 libxl_domain_build_info *info,
+                                 struct xc_dom_image *dom,
+                                 libxl__domain_build_state *state)
+{
+    return 0;
+}
+
 /* Return 0 on success, ERROR_* on failure. */
 int libxl__arch_vnuma_build_vmemrange(libxl__gc *gc,
                                       uint32_t domid,
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 2dc8b0a..2ff8f43 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -862,6 +862,12 @@ int domain_relinquish_resources(struct domain *d)
         if ( ret )
             return ret;
 
+        /*
+         * Release the resources allocated for vpl011 which were
+         * allocated via a DOMCTL call XEN_DOMCTL_vuart_op.
+         */
+        domain_vpl011_deinit(d);
+
         d->arch.relmem = RELMEM_xen;
         /* Fallthrough */
 
diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c
index db6838d..c7f650e 100644
--- a/xen/arch/arm/domctl.c
+++ b/xen/arch/arm/domctl.c
@@ -5,9 +5,11 @@
  */
 
 #include <xen/errno.h>
+#include <xen/guest_access.h>
 #include <xen/hypercall.h>
 #include <xen/iocap.h>
 #include <xen/lib.h>
+#include <xen/mm.h>
 #include <xen/sched.h>
 #include <xen/types.h>
 #include <xsm/xsm.h>
@@ -119,6 +121,46 @@ long arch_do_domctl(struct xen_domctl *domctl, struct domain *d,
         d->disable_migrate = domctl->u.disable_migrate.disable;
         return 0;
 
+    case XEN_DOMCTL_vuart_op:
+    {
+        int rc;
+        struct xen_domctl_vuart_op *vuart_op = &domctl->u.vuart_op;
+
+        switch(vuart_op->cmd)
+        {
+        case XEN_DOMCTL_VUART_OP_INIT:
+
+            if ( !d->creation_finished )
+            {
+                if (vuart_op->type == XEN_DOMCTL_VUART_TYPE_VPL011)
+                {
+                        struct vpl011_init_info info;
+
+                        info.console_domid = vuart_op->console_domid;
+                        info.gfn = _gfn(vuart_op->gfn);
+
+                        rc = domain_vpl011_init(d, &info);
+                        if ( !rc )
+                        {
+                            vuart_op->evtchn = info.evtchn;
+                            rc = __copy_to_guest(u_domctl, domctl, 1);
+                        }
+                }
+                else
+                        rc = -EINVAL;
+            }
+            else
+                rc = - EPERM;
+
+            break;
+
+        default:
+            rc = -EINVAL;
+            break;
+        }
+
+        return rc;
+    }
     default:
     {
         int rc;
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 0669c31..be2d874 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -36,6 +36,7 @@
 #include "grant_table.h"
 #include "hvm/save.h"
 #include "memory.h"
+#include "event_channel.h"
 
 #define XEN_DOMCTL_INTERFACE_VERSION 0x0000000e
 
@@ -1148,6 +1149,24 @@ struct xen_domctl_psr_cat_op {
     uint32_t target;    /* IN */
     uint64_t data;      /* IN/OUT */
 };
+
+struct xen_domctl_vuart_op {
+#define XEN_DOMCTL_VUART_OP_INIT  0
+        uint32_t cmd;           /* XEN_DOMCTL_VUART_OP_* */
+        domid_t console_domid;  /* IN */
+#define XEN_DOMCTL_VUART_TYPE_VPL011 0
+        uint32_t type;          /* IN - type of vuart.
+                                 *      Currently only vpl011 supported.
+                                 */
+        xen_pfn_t gfn;          /* IN - guest gfn to be used as a
+                                 *      ring buffer.
+                                 */
+        evtchn_port_t evtchn;   /* OUT - remote port of the event
+                                 *       channel used for sending
+                                 *       ring buffer events.
+                                 */
+};
+
 typedef struct xen_domctl_psr_cat_op xen_domctl_psr_cat_op_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cat_op_t);
 
@@ -1228,6 +1247,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_monitor_op                    77
 #define XEN_DOMCTL_psr_cat_op                    78
 #define XEN_DOMCTL_soft_reset                    79
+#define XEN_DOMCTL_vuart_op                      80
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -1290,6 +1310,7 @@ struct xen_domctl {
         struct xen_domctl_psr_cmt_op        psr_cmt_op;
         struct xen_domctl_monitor_op        monitor_op;
         struct xen_domctl_psr_cat_op        psr_cat_op;
+        struct xen_domctl_vuart_op          vuart_op;
         uint8_t                             pad[128];
     } u;
 };
