diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c
index 7e6a886..8ea1c13 100644
--- a/tools/console/daemon/io.c
+++ b/tools/console/daemon/io.c
@@ -68,6 +68,8 @@ extern int log_time_hv;
 extern int log_time_guest;
 extern char *log_dir;
 extern int discard_overflowed_data;
+extern int debug_fd;
+extern bool vpl011_console;
 
 static int log_time_hv_needts = 1;
 static int log_time_guest_needts = 1;
@@ -101,11 +103,15 @@ struct domain {
 	struct domain *next;
 	char *conspath;
 	int ring_ref;
+	int vpl011_ring_ref;
 	xenevtchn_port_or_error_t local_port;
 	xenevtchn_port_or_error_t remote_port;
+	xenevtchn_port_or_error_t vpl011_local_port;
+	xenevtchn_port_or_error_t vpl011_remote_port;
 	xenevtchn_handle *xce_handle;
 	int xce_pollfd_idx;
 	struct xencons_interface *interface;
+	struct xencons_interface *vpl011_interface;
 	int event_count;
 	long long next_period;
 };
@@ -158,11 +164,11 @@ static int write_with_timestamp(int fd, const char *data, size_t sz,
 	return 0;
 }
 
-static void buffer_append(struct domain *dom)
+static void buffer_append(struct domain *dom, struct xencons_interface *intf, int port)
 {
 	struct buffer *buffer = &dom->buffer;
 	XENCONS_RING_IDX cons, prod, size;
-	struct xencons_interface *intf = dom->interface;
+    char debug_buf[80];
 
 	cons = intf->out_cons;
 	prod = intf->out_prod;
@@ -187,7 +193,10 @@ static void buffer_append(struct domain *dom)
 
 	xen_mb();
 	intf->out_cons = cons;
-	xenevtchn_notify(dom->xce_handle, dom->local_port);
+    snprintf(debug_buf, 79, "cons=%d, prod=%d\n", cons, prod);
+    write (debug_fd, debug_buf, strlen(debug_buf));
+
+	xenevtchn_notify(dom->xce_handle, port);
 
 	/* Get the data to the logfile as early as possible because if
 	 * no one is listening on the console pty then it will fill up
@@ -529,14 +538,65 @@ static void domain_unmap_interface(struct domain *dom)
 	dom->ring_ref = -1;
 }
  
+static void domain_unmap_vpl011_interface(struct domain *dom)
+{
+	if ( dom->vpl011_interface == NULL )
+		return;
+	if ( xgt_handle && dom->vpl011_ring_ref == -1 )
+		xengnttab_unmap(xgt_handle, dom->vpl011_interface, 1);
+	else
+		munmap(dom->vpl011_interface, XC_PAGE_SIZE);
+	dom->vpl011_interface = NULL;
+	dom->vpl011_ring_ref = -1;
+}
+
+int bind_event_channel(struct domain *dom, int new_rport, int *lport, int *rport)
+{
+    int err = 0, rc;
+
+	/* Go no further if port has not changed and we are still bound. */
+	if ( new_rport == *rport ) {
+		xc_evtchn_status_t status = {
+			.dom = DOMID_SELF,
+			.port = *lport };
+		if ((xc_evtchn_status(xc, &status) == 0) &&
+		    (status.status == EVTCHNSTAT_interdomain))
+            goto out;
+	}
+
+    /* initialize the ports */
+	*lport = -1;
+	*rport = -1;
+ 
+    /* bind to new remote port */
+	rc = xenevtchn_bind_interdomain(dom->xce_handle,
+		dom->domid, new_rport);
+
+	if ( rc == -1 ) {
+		err = errno;
+		xenevtchn_close(dom->xce_handle);
+		dom->xce_handle = NULL;
+		goto out;
+	}
+
+    /* store new local and remote event channel ports */
+	*lport = rc;
+	*rport = new_rport;
+
+out:
+    return err;
+}
+
 static int domain_create_ring(struct domain *dom)
 {
-	int err, remote_port, ring_ref, rc;
+	int err, remote_port, ring_ref, vpl011_remote_port, vpl011_ring_ref;
 	char *type, path[PATH_MAX];
 
 	err = xs_gather(xs, dom->conspath,
 			"ring-ref", "%u", &ring_ref,
 			"port", "%i", &remote_port,
+			"vpl011-ring-ref", "%u", &vpl011_ring_ref,
+            "vpl011-port", "%i", &vpl011_remote_port,
 			NULL);
 	if (err)
 		goto out;
@@ -553,6 +613,10 @@ static int domain_create_ring(struct domain *dom)
 	if (ring_ref != dom->ring_ref && dom->ring_ref != -1)
 		domain_unmap_interface(dom);
 
+	/* If using vpl011 ring_ref and it has changed, remap */
+	if ( vpl011_ring_ref != dom->vpl011_ring_ref && dom->vpl011_ring_ref != -1 )
+		domain_unmap_vpl011_interface(dom);
+
 	if (!dom->interface && xgt_handle) {
 		/* Prefer using grant table */
 		dom->interface = xengnttab_map_grant_ref(xgt_handle,
@@ -560,6 +624,8 @@ static int domain_create_ring(struct domain *dom)
 			PROT_READ|PROT_WRITE);
 		dom->ring_ref = -1;
 	}
+
+    /* map PV console ring buffer */
 	if (!dom->interface) {
 		/* Fall back to xc_map_foreign_range */
 		dom->interface = xc_map_foreign_range(
@@ -573,18 +639,20 @@ static int domain_create_ring(struct domain *dom)
 		dom->ring_ref = ring_ref;
 	}
 
-	/* Go no further if port has not changed and we are still bound. */
-	if (remote_port == dom->remote_port) {
-		xc_evtchn_status_t status = {
-			.dom = DOMID_SELF,
-			.port = dom->local_port };
-		if ((xc_evtchn_status(xc, &status) == 0) &&
-		    (status.status == EVTCHNSTAT_interdomain))
+    /* map vpl011 console ring buffer */
+	if ( !dom->vpl011_interface ) {
+		/* Fall back to xc_map_foreign_range */
+		dom->vpl011_interface = xc_map_foreign_range(
+			xc, dom->domid, XC_PAGE_SIZE,
+			PROT_READ|PROT_WRITE,
+			(unsigned long)vpl011_ring_ref);
+		if ( dom->vpl011_interface == NULL ) {
+			err = EINVAL;
 			goto out;
+		}
+		dom->vpl011_ring_ref = vpl011_ring_ref;
 	}
 
-	dom->local_port = -1;
-	dom->remote_port = -1;
 	if (dom->xce_handle != NULL)
 		xenevtchn_close(dom->xce_handle);
 
@@ -595,18 +663,22 @@ static int domain_create_ring(struct domain *dom)
 		err = errno;
 		goto out;
 	}
- 
-	rc = xenevtchn_bind_interdomain(dom->xce_handle,
-		dom->domid, remote_port);
 
-	if (rc == -1) {
-		err = errno;
+    /* bind PV console channel */
+    err = bind_event_channel(dom, remote_port, &dom->local_port, &dom->remote_port);
+    if (err)
+    {
 		xenevtchn_close(dom->xce_handle);
-		dom->xce_handle = NULL;
-		goto out;
-	}
-	dom->local_port = rc;
-	dom->remote_port = remote_port;
+        goto out;
+    }
+
+    /* bind vpl011 console channel */
+    err = bind_event_channel(dom, vpl011_remote_port, &dom->vpl011_local_port, &dom->vpl011_remote_port);
+    if (err)
+    {
+		xenevtchn_close(dom->xce_handle);
+        goto out;
+    }
 
 	if (dom->master_fd == -1) {
 		if (!domain_create_tty(dom)) {
@@ -615,6 +687,8 @@ static int domain_create_ring(struct domain *dom)
 			dom->xce_handle = NULL;
 			dom->local_port = -1;
 			dom->remote_port = -1;
+			dom->vpl011_local_port = -1;
+			dom->vpl011_remote_port = -1;
 			goto out;
 		}
 	}
@@ -812,8 +886,9 @@ static void handle_tty_read(struct domain *dom)
 	ssize_t len = 0;
 	char msg[80];
 	int i;
-	struct xencons_interface *intf = dom->interface;
+	struct xencons_interface *intf;
 	XENCONS_RING_IDX prod;
+    xenevtchn_port_or_error_t port;
 
 	if (dom->is_dead)
 		return;
@@ -826,6 +901,21 @@ static void handle_tty_read(struct domain *dom)
 		len = sizeof(msg);
 
 	len = read(dom->master_fd, msg, len);
+
+    /* select the interface based on whether vpl011 console is 
+     * enabled or not
+     */
+    if ( vpl011_console )
+    {
+        intf = dom->vpl011_interface;
+        port = dom->vpl011_local_port;
+    }
+    else
+    {
+        intf = dom->interface;
+        port = dom->local_port;
+    }
+
 	/*
 	 * Note: on Solaris, len == 0 means the slave closed, and this
 	 * is no problem, but Linux can't handle this usefully, so we
@@ -835,13 +925,14 @@ static void handle_tty_read(struct domain *dom)
 		domain_handle_broken_tty(dom, domain_is_valid(dom->domid));
 	} else if (domain_is_valid(dom->domid)) {
 		prod = intf->in_prod;
+
 		for (i = 0; i < len; i++) {
 			intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
 				msg[i];
 		}
 		xen_wmb();
 		intf->in_prod = prod;
-		xenevtchn_notify(dom->xce_handle, dom->local_port);
+		xenevtchn_notify(dom->xce_handle, port);
 	} else {
 		domain_close_tty(dom);
 		shutdown_domain(dom);
@@ -869,6 +960,8 @@ static void handle_tty_write(struct domain *dom)
 static void handle_ring_read(struct domain *dom)
 {
 	xenevtchn_port_or_error_t port;
+    char debug_buf[80];
+    struct xencons_interface *intf;
 
 	if (dom->is_dead)
 		return;
@@ -876,12 +969,28 @@ static void handle_ring_read(struct domain *dom)
 	if ((port = xenevtchn_pending(dom->xce_handle)) == -1)
 		return;
 
-	dom->event_count++;
 
-	buffer_append(dom);
+    dom->event_count++;
+
+    /*
+     * select the interface based on the port which the event received
+     */
+    if ( port == dom->vpl011_local_port )
+    {
+        intf = dom->vpl011_interface;
+    }
+    else
+    {
+        intf = dom->interface;
+    }
+
+    snprintf (debug_buf, 79, "port=%d\n", port);
+    write (debug_fd, debug_buf, strlen(debug_buf));
+
+    buffer_append(dom, intf, port);
 
-	if (dom->event_count < RATE_LIMIT_ALLOWANCE)
-		(void)xenevtchn_unmask(dom->xce_handle, port);
+    if (dom->event_count < RATE_LIMIT_ALLOWANCE)
+        (void)xenevtchn_unmask(dom->xce_handle, port);
 }
 
 static void handle_xs(void)
@@ -1068,7 +1177,8 @@ void handle_io(void)
 			if ((now+5) > d->next_period) {
 				d->next_period = now + RATE_LIMIT_PERIOD;
 				if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
-					(void)xenevtchn_unmask(d->xce_handle, d->local_port);
+					    (void)xenevtchn_unmask(d->xce_handle, d->local_port);
+					    (void)xenevtchn_unmask(d->xce_handle, d->vpl011_local_port);
 				}
 				d->event_count = 0;
 			}
diff --git a/tools/console/daemon/main.c b/tools/console/daemon/main.c
index 806d2fd..3d3e061 100644
--- a/tools/console/daemon/main.c
+++ b/tools/console/daemon/main.c
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
 #include <signal.h>
@@ -41,6 +42,13 @@ int log_time_guest = 0;
 char *log_dir = NULL;
 int discard_overflowed_data = 1;
 
+int debug_fd;
+/*
+ * For now pl011 console is enabled by default.
+ * Later it would be exported out as a user configurable option
+ */
+bool vpl011_console=true;
+
 static void handle_hup(int sig)
 {
         log_reload = 1;
@@ -190,6 +198,8 @@ int main(int argc, char **argv)
 	openlog("xenconsoled", syslog_option, LOG_DAEMON);
 	setlogmask(syslog_mask);
 
+	debug_fd = open("/var/log/xen/debug.log", O_WRONLY|O_CREAT|O_APPEND, 0644);
+
 	increase_fd_limit();
 
 	if (!is_interactive) {
diff --git a/tools/libxc/include/xc_dom.h b/tools/libxc/include/xc_dom.h
index 608cbc2..7454ba9 100644
--- a/tools/libxc/include/xc_dom.h
+++ b/tools/libxc/include/xc_dom.h
@@ -218,6 +218,9 @@ struct xc_dom_image {
 
     /* Extra SMBIOS structures passed to HVMLOADER */
     struct xc_hvm_firmware_module smbios_module;
+
+    xen_pfn_t vpl011_console_pfn;
+    unsigned int vpl011_console_evtchn;
 };
 
 /* --- pluggable kernel loader ------------------------------------- */
diff --git a/tools/libxc/xc_dom_arm.c b/tools/libxc/xc_dom_arm.c
index a7e839e..7060a22 100644
--- a/tools/libxc/xc_dom_arm.c
+++ b/tools/libxc/xc_dom_arm.c
@@ -26,10 +26,11 @@
 #include "xg_private.h"
 #include "xc_dom.h"
 
-#define NR_MAGIC_PAGES 3
+#define NR_MAGIC_PAGES 4
 #define CONSOLE_PFN_OFFSET 0
 #define XENSTORE_PFN_OFFSET 1
 #define MEMACCESS_PFN_OFFSET 2
+#define VPL011_CONSOLE_PFN_OFFSET 3
 
 #define LPAE_SHIFT 9
 
@@ -85,6 +86,7 @@ static int alloc_magic_pages(struct xc_dom_image *dom)
 
     dom->console_pfn = base + CONSOLE_PFN_OFFSET;
     dom->xenstore_pfn = base + XENSTORE_PFN_OFFSET;
+    dom->vpl011_console_pfn = base + VPL011_CONSOLE_PFN_OFFSET;
 
     xc_clear_domain_page(dom->xch, dom->guest_domid, dom->console_pfn);
     xc_clear_domain_page(dom->xch, dom->guest_domid, dom->xenstore_pfn);
@@ -95,6 +97,9 @@ static int alloc_magic_pages(struct xc_dom_image *dom)
             dom->xenstore_pfn);
     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_MONITOR_RING_PFN,
             base + MEMACCESS_PFN_OFFSET);
+    xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_VPL011_CONSOLE_PFN,
+            base + VPL011_CONSOLE_PFN_OFFSET);
+
     /* allocated by toolstack */
     xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_CONSOLE_EVTCHN,
             dom->console_evtchn);
diff --git a/tools/libxc/xc_dom_boot.c b/tools/libxc/xc_dom_boot.c
index 791041b..3420a08 100644
--- a/tools/libxc/xc_dom_boot.c
+++ b/tools/libxc/xc_dom_boot.c
@@ -227,6 +227,9 @@ int xc_dom_boot_image(struct xc_dom_image *dom)
     if ( (rc = clear_page(dom, dom->xenstore_pfn)) != 0 )
         return rc;
 
+    if ( (rc = clear_page(dom, dom->vpl011_console_pfn)) != 0 )
+        return rc;
+
     /* start info page */
     if ( dom->arch_hooks->start_info )
         dom->arch_hooks->start_info(dom);
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index fa1daeb..e330738 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -1337,9 +1337,6 @@ static inline int xc_hvm_param_deprecated_check(uint32_t param)
 {
     switch ( param )
     {
-        case HVM_PARAM_MEMORY_EVENT_CR0:
-        case HVM_PARAM_MEMORY_EVENT_CR3:
-        case HVM_PARAM_MEMORY_EVENT_CR4:
         case HVM_PARAM_MEMORY_EVENT_INT3:
         case HVM_PARAM_MEMORY_EVENT_SINGLE_STEP:
         case HVM_PARAM_MEMORY_EVENT_MSR:
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index d400fa2..4acd8c5 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -3159,6 +3159,10 @@ int libxl__device_console_add(libxl__gc *gc, uint32_t domid,
         flexarray_append(ro_front, GCSPRINTF("%"PRIu32, state->console_port));
         flexarray_append(ro_front, "ring-ref");
         flexarray_append(ro_front, GCSPRINTF("%lu", state->console_mfn));
+        flexarray_append(ro_front, "vpl011-port");
+        flexarray_append(ro_front, GCSPRINTF("%"PRIu32, state->vpl011_console_port));
+        flexarray_append(ro_front, "vpl011-ring-ref");
+        flexarray_append(ro_front, GCSPRINTF("%lu", state->vpl011_console_mfn));
     } else {
         flexarray_append(front, "state");
         flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c
index d842d88..12eb2b2 100644
--- a/tools/libxl/libxl_arm.c
+++ b/tools/libxl/libxl_arm.c
@@ -130,9 +130,10 @@ static struct arch_info {
     const char *guest_type;
     const char *timer_compat;
     const char *cpu_compat;
+    const char *uart_compat;
 } arch_info[] = {
-    {"xen-3.0-armv7l",  "arm,armv7-timer", "arm,cortex-a15" },
-    {"xen-3.0-aarch64", "arm,armv8-timer", "arm,armv8" },
+    {"xen-3.0-armv7l",  "arm,armv7-timer", "arm,cortex-a15", "arm,sbsa-uart" },
+    {"xen-3.0-aarch64", "arm,armv8-timer", "arm,armv8", "arm,sbsa-uart" },
 };
 
 /*
@@ -590,6 +591,48 @@ static int make_hypervisor_node(libxl__gc *gc, void *fdt,
     return 0;
 }
 
+static int make_vpl011_uart_node(libxl__gc *gc, void *fdt,
+                           const struct arch_info *ainfo,
+                           struct xc_dom_image *dom)
+{
+    int res;
+    gic_interrupt intr;
+    uint64_t    vpl011_irq;
+
+    res = fdt_begin_node(fdt, "sbsa-pl011");
+    if (res) return res;
+
+    res = fdt_property_compat(gc, fdt, 1, ainfo->uart_compat);
+    if (res) return res;
+
+    res = fdt_property_regs(gc, fdt, ROOT_ADDRESS_CELLS, ROOT_SIZE_CELLS,
+                            1,
+                            GUEST_PL011_BASE, GUEST_PL011_SIZE);
+    if (res) 
+        return res;
+
+    /*
+     * Get the SPI VIRQ assigned to vpl011.
+     * The SPI VIRQ is assigned by Xen
+     */
+    res = xc_hvm_param_get(dom->xch, dom->guest_domid, HVM_PARAM_VPL011_VIRQ, 
+                                                                    &vpl011_irq);
+    if (res)
+        return res;
+
+    set_interrupt(intr, vpl011_irq, 0xf, DT_IRQ_TYPE_LEVEL_HIGH);
+
+    res = fdt_property_interrupts(gc, fdt, &intr, 1);
+    if (res) return res;
+
+    fdt_property_u32(fdt, "current-speed", 115200);
+
+    res = fdt_end_node(fdt);
+    if (res) return res;
+
+    return 0;
+}
+
 static const struct arch_info *get_arch_info(libxl__gc *gc,
                                              const struct xc_dom_image *dom)
 {
@@ -888,6 +931,7 @@ next_resize:
 
         FDT( make_timer_node(gc, fdt, ainfo, xc_config->clock_frequency) );
         FDT( make_hypervisor_node(gc, fdt, vers) );
+        FDT( make_vpl011_uart_node(gc, fdt, ainfo, dom) );
 
         if (pfdt)
             FDT( copy_partial_fdt(gc, fdt, pfdt) );
@@ -933,9 +977,11 @@ int libxl__arch_domain_init_hw_description(libxl__gc *gc,
     val |= GUEST_EVTCHN_PPI;
     rc = xc_hvm_param_set(dom->xch, dom->guest_domid, HVM_PARAM_CALLBACK_IRQ,
                           val);
+
     if (rc)
         return rc;
 
+
     rc = libxl__prepare_dtb(gc, info, state, dom);
     if (rc) goto out;
 
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index d519c8d..45f99c2 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -302,7 +302,7 @@ int libxl__build_pre(libxl__gc *gc, uint32_t domid,
     libxl_ctx *ctx = libxl__gc_owner(gc);
     char *xs_domid, *con_domid;
     int rc;
-    uint64_t size;
+    uint64_t size, val;
 
     if (xc_domain_max_vcpus(ctx->xch, domid, info->max_vcpus) != 0) {
         LOG(ERROR, "Couldn't set max vcpu count");
@@ -432,6 +432,11 @@ int libxl__build_pre(libxl__gc *gc, uint32_t domid,
     state->store_port = xc_evtchn_alloc_unbound(ctx->xch, domid, state->store_domid);
     state->console_port = xc_evtchn_alloc_unbound(ctx->xch, domid, state->console_domid);
 
+    /* get the vpl011 event channel from Xen */
+    xc_hvm_param_get(ctx->xch, domid, HVM_PARAM_VPL011_CONSOLE_EVTCHN,
+            &val);
+    state->vpl011_console_port = (int)val;
+
     if (info->type == LIBXL_DOMAIN_TYPE_HVM) {
         hvm_set_conf_params(ctx->xch, domid, info);
 #if defined(__i386__) || defined(__x86_64__)
@@ -727,6 +732,7 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid,
 
     dom->flags = flags;
     dom->console_evtchn = state->console_port;
+    dom->vpl011_console_evtchn = state->vpl011_console_port;
     dom->console_domid = state->console_domid;
     dom->xenstore_evtchn = state->store_port;
     dom->xenstore_domid = state->store_domid;
@@ -771,6 +777,7 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid,
     if (xc_dom_feature_translated(dom)) {
         state->console_mfn = dom->console_pfn;
         state->store_mfn = dom->xenstore_pfn;
+        state->vpl011_console_mfn = dom->vpl011_console_pfn;
     } else {
         state->console_mfn = xc_dom_p2m(dom, dom->console_pfn);
         state->store_mfn = xc_dom_p2m(dom, dom->xenstore_pfn);
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 5f46578..6103036 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1128,6 +1128,8 @@ typedef struct {
     uint32_t num_vmemranges;
 
     xc_domain_configuration_t config;
+    unsigned long vpl011_console_mfn;
+    uint32_t    vpl011_console_port;
 } libxl__domain_build_state;
 
 _hidden int libxl__build_pre(libxl__gc *gc, uint32_t domid,
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 7afb8a3..ba94852 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -49,6 +49,7 @@ obj-y += vm_event.o
 obj-y += vtimer.o
 obj-y += vpsci.o
 obj-y += vuart.o
+obj-y += vpl011.o
 
 #obj-bin-y += ....o
 
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 7e43691..a0d96b9 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -20,6 +20,7 @@
 #include <xen/errno.h>
 #include <xen/bitops.h>
 #include <xen/grant_table.h>
+#include <xen/vpl011.h>
 
 #include <asm/current.h>
 #include <asm/event.h>
@@ -626,6 +627,12 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags,
     if ( (rc = domain_vtimer_init(d, config)) != 0 )
         goto fail;
 
+    /*
+     * call vpl011 init only for guest domains
+     */
+    if ( d->domain_id && ((rc = domain_vpl011_init(d)) != 0) )
+        goto fail;
+
     update_domain_wallclock_time(d);
 
     /*
diff --git a/xen/arch/arm/hvm.c b/xen/arch/arm/hvm.c
index d999bde..a484ea1 100644
--- a/xen/arch/arm/hvm.c
+++ b/xen/arch/arm/hvm.c
@@ -23,8 +23,11 @@
 #include <xen/guest_access.h>
 #include <xen/sched.h>
 #include <xen/monitor.h>
+#include <xen/event.h>
+#include <xen/vmap.h>
 
 #include <xsm/xsm.h>
+#include <xen/vpl011.h>
 
 #include <public/xen.h>
 #include <public/hvm/params.h>
@@ -61,10 +64,27 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
         if ( op == HVMOP_set_param )
         {
             d->arch.hvm_domain.params[a.index] = a.value;
+
+            if ( a.index == HVM_PARAM_VPL011_CONSOLE_PFN )
+            {
+                vpl011_map_guest_page(d);
+                printk("HVM_PARAM_VPL011_CONSOLE_PFN param set val=0x%lx\n", a.value);
+            }
+            else if ( a.index == HVM_PARAM_VPL011_MMIO_ADDR )
+            {
+                printk("HVM_PARAM_VPL011_MMIO_ADDR param set val=0x%lx\n", a.value);
+            }
         }
         else
         {
-            a.value = d->arch.hvm_domain.params[a.index];
+            if ( a.index == HVM_PARAM_VPL011_MMIO_ADDR )
+            {
+                a.value = d->arch.hvm_domain.params[a.index];
+                printk("HVM_PARAM_PL011_MMIO_ADDR param get val=0x%lx\n", a.value);
+            }
+            else
+                a.value = d->arch.hvm_domain.params[a.index];
+
             rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0;
         }
 
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 049e449..e347ca0 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -37,6 +37,7 @@
 #include <xen/virtual_region.h>
 #include <xen/vmap.h>
 #include <xen/libfdt/libfdt.h>
+#include <xen/vpl011.h>
 #include <xen/acpi.h>
 #include <asm/alternative.h>
 #include <asm/page.h>
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 364d5f0..f6ae7e2 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -118,6 +118,12 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis)
 
     d->arch.vgic.ctlr = 0;
 
+    /*
+     * Allocate atleast 1 for vpl011 SPI to guest 
+     */
+    if ( !nr_spis )
+        nr_spis = 1;
+
     /* Limit the number of virtual SPIs supported to (1020 - 32) = 988  */
     if ( nr_spis > (1020 - NR_LOCAL_IRQS) )
         return -EINVAL;
@@ -586,6 +592,7 @@ int vgic_allocate_virq(struct domain *d, bool spi)
      */
     do
     {
+        printk("searching virq in < %d, %d >\n", first, end);
         virq = find_next_zero_bit(d->arch.vgic.allocated_irqs, end, first);
         if ( virq >= end )
             return -1;
diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c
new file mode 100644
index 0000000..5c4507e
--- /dev/null
+++ b/xen/arch/arm/vpl011.c
@@ -0,0 +1,391 @@
+/*
+ * arch/arm/vpl011.c
+ *
+ * Virtual PL011 UART 
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/errno.h>
+#include <xen/guest_access.h>
+#include <xen/sched.h>
+#include <xen/monitor.h>
+#include <xen/event.h>
+#include <xen/vmap.h>
+
+#include <xsm/xsm.h>
+#include <xen/vpl011.h>
+
+#include <public/xen.h>
+#include <public/hvm/params.h>
+#include <public/hvm/hvm_op.h>
+
+#include <asm/hypercall.h>
+
+static int vpl011_mmio_read(struct vcpu *v, mmio_info_t *info, register_t *r, void *priv)
+{
+    unsigned char ch;
+
+    switch (info->gpa - GUEST_PL011_BASE)
+    {
+        case VPL011_UARTCR_OFFSET:
+            *r = v->domain->arch.vpl011.control;
+            break;
+        case VPL011_UARTDR_OFFSET:
+            vpl011_read_data(v->domain, &ch);
+            *r = ch;
+            break;
+        case VPL011_UARTFR_OFFSET:
+            *r = v->domain->arch.vpl011.flag;
+            if ( *r & (1<<VPL011_UARTFR_TXFF_BIT) )
+                printk ("TXFF in FR\n");
+            break;
+        case VPL011_UARTIMSC_OFFSET:
+            *r = v->domain->arch.vpl011.intr_mask;
+            break;
+        case VPL011_UARTICR_OFFSET: 
+            *r = 0;
+            break;
+        case VPL011_UARTRIS_OFFSET:
+            *r = v->domain->arch.vpl011.raw_intr_status;
+            break;
+        case VPL011_UARTMIS_OFFSET:
+            *r = v->domain->arch.vpl011.raw_intr_status &
+                                v->domain->arch.vpl011.intr_mask;
+            break;
+        case VPL011_UARTDMACR_OFFSET:
+            *r = 0; /* uart DMA is not supported. Here it always returns 0 */
+            break;
+        case VPL011_UARTRSR_OFFSET: 
+            *r = 0; /* it always returns 0 as there are no physical errors */
+            break;
+        default:
+            printk ("vpl011_mmio_read: invalid switch case %d\n", (int)(info->gpa - GUEST_PL011_BASE));
+            break;
+    }
+
+    return 1;
+}
+
+static int vpl011_mmio_write(struct vcpu *v, mmio_info_t *info, register_t r, void *priv)
+{
+    unsigned char ch = r;
+
+    switch (info->gpa - GUEST_PL011_BASE)
+    {
+        case VPL011_UARTCR_OFFSET:
+            v->domain->arch.vpl011.control = r;
+            break;
+        case VPL011_UARTDR_OFFSET:
+            vpl011_write_data(v->domain, ch);
+            break;
+        case VPL011_UARTIMSC_OFFSET:
+            v->domain->arch.vpl011.intr_mask = r;
+            printk ("set intr mask=0x%x\n", v->domain->arch.vpl011.intr_mask);
+            break;
+        case VPL011_UARTICR_OFFSET: 
+            /*
+             * clear all bits which are set in the input
+             */
+            v->domain->arch.vpl011.raw_intr_status &= ~r;
+            break;
+        case VPL011_UARTRSR_OFFSET: // nothing to clear
+            break;
+        case VPL011_UARTFR_OFFSET: // these are all RO registers
+        case VPL011_UARTRIS_OFFSET:
+        case VPL011_UARTMIS_OFFSET:
+        case VPL011_UARTDMACR_OFFSET:
+            break;
+        default:
+            printk ("vpl011_mmio_write: switch case not handled %d\n", (int)(info->gpa - GUEST_PL011_BASE));
+            break;
+    }
+
+    return 1;
+}
+
+static const struct mmio_handler_ops vpl011_mmio_handler = {
+    .read = vpl011_mmio_read,
+    .write = vpl011_mmio_write,
+};
+
+
+
+int vpl011_map_guest_page(struct domain *d)
+{
+    int rc=0;
+
+    printk ("HVM_PARAM_VPL011_CONSOLE_PFN = 0x%lx\n", d->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_PFN]);
+
+    /*
+     * map the guest PFN to Xen address space
+     */
+    rc = prepare_ring_for_helper(d, d->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_PFN],
+                                        &d->arch.vpl011.ring_page, (void **)&d->arch.vpl011.vpl011_cons_intf);
+    if ( rc < 0 )
+    {
+        printk("Failed to map vpl011 guest PFN\n");
+    }
+
+    return rc;
+}
+
+static int vpl011_data_avail(struct domain *d)
+{
+    int rc=0;
+    unsigned long flags;
+
+    struct vpl011_cons_intf_s *intf = d->arch.vpl011.vpl011_cons_intf;
+
+    VPL011_LOCK(d, flags);
+
+    /*`
+     * check IN ring buffer
+     */
+    if ( !VPL011_IN_RING_EMPTY(intf) )
+    {
+        /*
+         * clear the RX FIFO empty flag as the ring is not empty
+         */
+        d->arch.vpl011.flag &= ~(1<<VPL011_UARTFR_RXFE_BIT);
+
+        /*
+         * if the buffer is full then set the RX FIFO FULL flag
+         */
+        if ( VPL011_IN_RING_FULL(intf) )
+            d->arch.vpl011.flag |= (1<<VPL011_UARTFR_RXFF_BIT);
+
+        /*
+         * set the RX interrupt status
+         */
+        d->arch.vpl011.raw_intr_status |= (1<<VPL011_UARTRIS_RXRIS_BIT);
+    }
+
+    /*
+     * check OUT ring buffer
+     */
+    if ( !VPL011_OUT_RING_FULL(intf) )
+    {
+        /*
+         * if the buffer is not full then clear the TX FIFO full flag
+         */
+        d->arch.vpl011.flag &= ~(1<<VPL011_UARTFR_TXFF_BIT);
+
+        /*
+         * set the TX interrupt status
+         */
+        d->arch.vpl011.raw_intr_status |= (1<<VPL011_UARTRIS_TXRIS_BIT);
+
+        if ( VPL011_OUT_RING_EMPTY(intf) )
+        {
+            /*
+             * clear the uart busy flag and set the TX FIFO empty flag
+             */
+            d->arch.vpl011.flag &= ~(1<<VPL011_UARTFR_BUSY_BIT);
+            d->arch.vpl011.flag |= (1<<VPL011_UARTFR_TXFE_BIT);
+        }
+    }
+    else
+        printk("OUT ring buffer FULL\n");
+
+    VPL011_UNLOCK(d, flags);
+
+#if 0
+    printk ("flags=0x%x, intr=0x%x, mask=0x%x, in_cons=%d, in_prod=%d, out_cons=%d, out_prod=%d\n", 
+                                d->arch.vpl011.flag, 
+                                d->arch.vpl011.raw_intr_status,
+                                d->arch.vpl011.intr_mask,
+                                intf->in_cons, 
+                                intf->in_prod, 
+                                intf->out_cons, 
+                                intf->out_prod);
+#endif
+
+    /*
+     * send an interrupt if it is not masked
+     */
+    if ( d->arch.vpl011.raw_intr_status & d->arch.vpl011.intr_mask )
+    {
+#if 0
+        printk("SENding guest pl011 intr %d with mask=0x%x, flag=0x%x, out_cons=%d, out_prod=%d, in_cons=%d, in_prod=%d...\n", 
+                (int)d->arch.hvm_domain.params[HVM_PARAM_VPL011_VIRQ],
+                d->arch.vpl011.raw_intr_status,
+                d->arch.vpl011.flag,
+                intf->out_cons,
+                intf->out_prod,
+                intf->in_cons,
+                intf->in_prod);
+#endif
+
+        vgic_vcpu_inject_spi(d, (int)d->arch.hvm_domain.params[HVM_PARAM_VPL011_VIRQ]);
+    }
+
+    if ( !VPL011_OUT_RING_EMPTY(intf) )
+    {
+        /*
+         * raise an interrupt to dom0
+         */
+        //printk("sending Dom0 event 0x%lx\n", d->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_EVTCHN]);
+        rc = evtchn_send(d, d->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_EVTCHN]); 
+
+        if ( rc < 0 )
+            printk("Failed to send vpl011 interrupt to dom0\n");
+    }
+
+    return rc;
+}
+
+int vpl011_read_data(struct domain *d, unsigned char *data)
+{
+    int rc=0;
+    unsigned long flags;
+    struct vpl011_cons_intf_s *intf = d->arch.vpl011.vpl011_cons_intf;
+
+    *data = 0;
+
+    VPL011_LOCK(d, flags);
+
+    /*
+     * if there is data in the ring buffer then copy it to the output buffer
+     */
+    if ( !VPL011_IN_RING_EMPTY(intf) )
+    {
+        *data = intf->in[MASK_VPL011CONS_IDX(intf->in_cons++, intf->in)];
+    }
+
+    /*
+     * if the ring buffer is empty then set the RX FIFO empty flag
+     */
+    if ( VPL011_IN_RING_EMPTY(intf) )
+    {
+        d->arch.vpl011.flag |= (1<<VPL011_UARTFR_RXFE_BIT);
+        d->arch.vpl011.raw_intr_status &= ~(1<<VPL011_UARTRIS_RXRIS_BIT);
+    }
+
+    /*
+     * clear the RX FIFO full flag
+     */
+    d->arch.vpl011.flag &= ~(1<<VPL011_UARTFR_RXFF_BIT);
+
+    VPL011_UNLOCK(d, flags);
+
+    return rc;
+}
+
+int vpl011_write_data(struct domain *d, unsigned char data)
+{
+    int rc=0;
+    unsigned long flags;
+    struct vpl011_cons_intf_s *intf = d->arch.vpl011.vpl011_cons_intf;
+
+    //printk ("vpl011_write_data[%d][%d]=%c, full=%d...\n", intf->out_cons, intf->out_prod, data, VPL011_OUT_RING_FULL(intf));
+
+    VPL011_LOCK(d, flags);
+
+    /*
+     * if there is space in the ring buffer then write the data
+     */
+    if ( !VPL011_OUT_RING_FULL(intf) )
+    {
+        intf->out[MASK_VPL011CONS_IDX(intf->out_prod++, intf->out)] = data;
+        smp_wmb();
+    }
+
+    /*
+     * if there is no space in the ring buffer then set the 
+     * TX FIFO FULL flag
+     */
+    if ( VPL011_OUT_RING_FULL(intf) )
+    {
+        d->arch.vpl011.flag |= (1<<VPL011_UARTFR_TXFF_BIT);
+    }
+
+    /*
+     * set the uart busy status
+     */
+    d->arch.vpl011.flag |= (1<<VPL011_UARTFR_BUSY_BIT);
+
+    /*
+     * clear the TX FIFO empty flag
+     */
+    d->arch.vpl011.flag &= ~(1<<VPL011_UARTFR_TXFE_BIT);
+
+    VPL011_UNLOCK(d, flags);
+
+    /*
+     * raise an event to dom0 only if it is the first character in the buffer
+     */
+    if ( VPL011_RING_DEPTH(intf, out) == 1 )
+    {
+        //printk("sending dom0 event 0x%lx\n", d->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_EVTCHN]);
+
+        rc = evtchn_send(d, d->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_EVTCHN]); 
+
+        if ( rc < 0 )
+            printk("Failed to send vpl011 interrupt to dom0\n");
+    }
+
+    return rc;
+}
+
+static void vpl011_notification(struct vcpu *v, unsigned int port)
+{
+    vpl011_data_avail(v->domain);
+}
+
+int domain_vpl011_init(struct domain *d)
+{
+    int rc=0;
+
+    /*
+     * register xen event channel
+     */
+    rc = alloc_unbound_xen_event_channel(d, 0, current->domain->domain_id, 
+                                                        vpl011_notification);
+    if (rc < 0)
+    {
+        printk ("Failed to allocate vpl011 event channel\n");
+        return rc;
+    }
+    d->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_EVTCHN] = rc;
+    
+    /*
+     * allocate an SPI VIRQ for the guest
+     */
+    d->arch.hvm_domain.params[HVM_PARAM_VPL011_VIRQ] = vgic_allocate_spi(d);
+
+    /*
+     * register mmio handler 
+     */
+    register_mmio_handler (d, &vpl011_mmio_handler, GUEST_PL011_BASE, GUEST_PL011_SIZE, NULL);
+
+    /* 
+     * initialize the lock
+     */
+    spin_lock_init(&d->arch.vpl011.lock);
+
+    /* 
+     * clear the flag, control and interrupts registers
+     */
+    d->arch.vpl011.control = 0;
+    d->arch.vpl011.flag = 0;
+    d->arch.vpl011.intr_mask = 0;
+    d->arch.vpl011.intr_clear = 0;
+    d->arch.vpl011.raw_intr_status = 0;
+    d->arch.vpl011.masked_intr_status = 0;
+
+    return 0;
+}
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index 638dc5e..07a09c2 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -27,6 +27,7 @@
 #include <xen/keyhandler.h>
 #include <xen/event_fifo.h>
 #include <asm/current.h>
+#include <xen/domain_page.h>
 
 #include <public/xen.h>
 #include <public/event_channel.h>
@@ -663,9 +664,11 @@ int evtchn_send(struct domain *ld, unsigned int lport)
 
     spin_lock(&lchn->lock);
 
-    /* Guest cannot send via a Xen-attached event channel. */
-    if ( unlikely(consumer_is_xen(lchn)) )
+    /* Guest cannot send via a Xen-attached event channel unless it is vpl011 channel */
+    if ( unlikely(consumer_is_xen(lchn) && 
+                (lport != ld->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_EVTCHN])) )
     {
+        printk("evtchn_send failed to send via xen event channel\n");
         ret = -EINVAL;
         goto out;
     }
@@ -681,7 +684,9 @@ int evtchn_send(struct domain *ld, unsigned int lport)
         rport = lchn->u.interdomain.remote_port;
         rchn  = evtchn_from_port(rd, rport);
         if ( consumer_is_xen(rchn) )
+        {
             xen_notification_fn(rchn)(rd->vcpu[rchn->notify_vcpu_id], rport);
+        }
         else
             evtchn_port_set_pending(rd, rchn->notify_vcpu_id, rchn);
         break;
@@ -1202,6 +1207,7 @@ int alloc_unbound_xen_event_channel(
 
     chn->state = ECS_UNBOUND;
     chn->xen_consumer = get_xen_consumer(notification_fn);
+    printk ("allocated xen_consumer = %d for port = %d, remote dom=%d\n", chn->xen_consumer, port, remote_domid);
     chn->notify_vcpu_id = lvcpu;
     chn->u.unbound.remote_domid = remote_domid;
 
@@ -1217,6 +1223,7 @@ void free_xen_event_channel(struct domain *d, int port)
 {
     BUG_ON(!port_is_valid(d, port));
 
+    printk ("event channel freed for dom=%d, port=%d\n", d->domain_id, port); 
     evtchn_close(d, port, 0);
 }
 
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 2d6fbb1..f49606e 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -11,6 +11,7 @@
 #include <asm/gic.h>
 #include <public/hvm/params.h>
 #include <xen/serial.h>
+#include <xen/vpl011.h>
 
 struct hvm_domain
 {
@@ -40,6 +41,7 @@ struct vtimer {
         uint64_t cval;
 };
 
+
 struct arch_domain
 {
 #ifdef CONFIG_ARM_64
@@ -131,6 +133,18 @@ struct arch_domain
     struct {
         uint8_t privileged_call_enabled : 1;
     } monitor;
+
+    struct vpl011 {
+        struct vpl011_cons_intf_s *vpl011_cons_intf;
+        struct page_info *ring_page;
+        uint32_t    flag;               /* flag register */
+        uint32_t    control;            /* control register */
+        uint32_t    intr_mask;          /* interrupt mask register*/
+        uint32_t    intr_clear;         /* interrupt clear register */
+        uint32_t    raw_intr_status;    /* raw interrupt status register */
+        uint32_t    masked_intr_status; /* masked interrupt register */
+        spinlock_t  lock;
+    } vpl011;
 }  __cacheline_aligned;
 
 struct arch_vcpu
diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
index bd974fb..d1d031b 100644
--- a/xen/include/public/arch-arm.h
+++ b/xen/include/public/arch-arm.h
@@ -406,6 +406,10 @@ typedef uint64_t xen_callback_t;
 #define GUEST_GICV3_GICR0_BASE     xen_mk_ullong(0x03020000) /* vCPU0..127 */
 #define GUEST_GICV3_GICR0_SIZE     xen_mk_ullong(0x01000000)
 
+/* PL011 mappings */
+#define GUEST_PL011_BASE  xen_mk_ullong(0x04020000)
+#define GUEST_PL011_SIZE  xen_mk_ullong(0x00001000)
+
 /* ACPI tables physical address */
 #define GUEST_ACPI_BASE 0x20000000ULL
 #define GUEST_ACPI_SIZE 0x02000000ULL
@@ -420,6 +424,7 @@ typedef uint64_t xen_callback_t;
 #define GUEST_MAGIC_BASE  xen_mk_ullong(0x39000000)
 #define GUEST_MAGIC_SIZE  xen_mk_ullong(0x01000000)
 
+
 #define GUEST_RAM_BANKS   2
 
 #define GUEST_RAM0_BASE   xen_mk_ullong(0x40000000) /* 3GB of low RAM @ 1GB */
diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h
index 3f54a49..a9aa1d9 100644
--- a/xen/include/public/hvm/params.h
+++ b/xen/include/public/hvm/params.h
@@ -202,11 +202,12 @@
  * You can find these address definitions in <hvm/ioreq.h>
  */
 #define HVM_PARAM_ACPI_IOPORTS_LOCATION 19
+#define HVM_PARAM_VPL011_CONSOLE_PFN 19
+#define HVM_PARAM_VPL011_CONSOLE_EVTCHN 20
+#define HVM_PARAM_VPL011_VIRQ           21
+#define HVM_PARAM_VPL011_MMIO_ADDR 22
 
 /* Deprecated */
-#define HVM_PARAM_MEMORY_EVENT_CR0          20
-#define HVM_PARAM_MEMORY_EVENT_CR3          21
-#define HVM_PARAM_MEMORY_EVENT_CR4          22
 #define HVM_PARAM_MEMORY_EVENT_INT3         23
 #define HVM_PARAM_MEMORY_EVENT_SINGLE_STEP  25
 #define HVM_PARAM_MEMORY_EVENT_MSR          30
@@ -253,6 +254,7 @@
  */
 #define HVM_PARAM_X87_FIP_WIDTH 36
 
-#define HVM_NR_PARAMS 37
+
+#define HVM_NR_PARAMS 38
 
 #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
diff --git a/xen/include/xen/vpl011.h b/xen/include/xen/vpl011.h
new file mode 100644
index 0000000..dd09d41
--- /dev/null
+++ b/xen/include/xen/vpl011.h
@@ -0,0 +1,146 @@
+/*
+ * include/xen/vpl011.h
+ *
+ * Virtual PL011 UART 
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _VPL011_H_
+
+#define _VPL011_H_
+
+/*
+ * register offsets
+ */
+#define VPL011_UARTDR_OFFSET    0x0 // data register (RW)
+#define VPL011_UARTRSR_OFFSET   0x4 // receive status and error clear register (RW)
+#define VPL011_UARTFR_OFFSET    0x18 // flag register (RO)
+#define VPL011_UARTRIS_OFFSET   0x3c // raw interrupt status register (RO)
+#define VPL011_UARTMIS_OFFSET   0x40 // masked interrupt status register (RO)
+#define VPL011_UARTIMSC_OFFSET  0x38 // interrupt mask set/clear register (RW)
+#define VPL011_UARTICR_OFFSET   0x44 // interrupt clear register (WO)
+#define VPL011_UARTCR_OFFSET    0x30 // uart control register
+#define VPL011_UARTDMACR_OFFSET 0x48 // uart dma control register
+
+/*
+ * control register bits - RW
+ */
+#define VPL011_UARTCR_UARTEN_BIT 0
+#define VPL011_UARTCR_TXE_BIT    8
+#define VPL011_UARTCR_RXE_BIT    9
+
+/*
+ * Flag register bits - RO
+ */
+#define VPL011_UARTFR_CTS_BIT   0   // clear to send
+#define VPL011_UARTFR_DSR_BIT   1   // data set ready
+#define VPL011_UARTFR_DCD_BIT   2   // data carrier detect
+#define VPL011_UARTFR_BUSY_BIT  3   // uart busy
+#define VPL011_UARTFR_RXFE_BIT  4   // receive fifo empty
+#define VPL011_UARTFR_TXFF_BIT  5   // transmit fifo full
+#define VPL011_UARTFR_RXFF_BIT  6   // receive fifo full
+#define VPL011_UARTFR_TXFE_BIT  7   // transmit fifo empty
+#define VPL011_UARTFR_RI_BIT    8   // ring indicator
+
+/*
+ * UART raw interrupt status bits - RO
+ */
+#define VPL011_UARTRIS_RIRMIS_BIT  0
+#define VPL011_UARTRIS_CTSRMIS_BIT 1
+#define VPL011_UARTRIS_DCDRMIS_BIT 2
+#define VPL011_UARTRIS_DSRRMIS_BIT 3
+#define VPL011_UARTRIS_RXRIS_BIT   4
+#define VPL011_UARTRIS_TXRIS_BIT   5
+#define VPL011_UARTRIS_RTRIS_BIT   6
+#define VPL011_UARTRIS_FERIS_BIT   7
+#define VPL011_UARTRIS_PERIS_BIT   8
+#define VPL011_UARTRIS_BERIS_BIT   9
+#define VPL011_UARTRIS_OERIS_BIT   10
+
+/*
+ * UART masked interrupt status bits - RO
+ */
+#define VPL011_UARTMIS_RIMMIS_BIT  0
+#define VPL011_UARTMIS_CTSMMIS_BIT 1
+#define VPL011_UARTMIS_DCDMMIS_BIT 2
+#define VPL011_UARTMIS_DSRMMIS_BIT 3
+#define VPL011_UARTMIS_RXMIS_BIT   4
+#define VPL011_UARTMIS_TXMIS_BIT   5
+#define VPL011_UARTMIS_RTMIS_BIT   6
+#define VPL011_UARTMIS_FEMIS_BIT   7
+#define VPL011_UARTMIS_PEMIS_BIT   8
+#define VPL011_UARTMIS_BEMIS_BIT   9
+#define VPL011_UARTMIS_OEMIS_BIT   10
+
+/*
+ * UART  interrupt clear bits - WO
+ */
+#define VPL011_UARTICR_RIMIC_BIT   0
+#define VPL011_UARTICR_CTSMIC_BIT   1
+#define VPL011_UARTICR_DCDMIC_BIT   2
+#define VPL011_UARTICR_DSRMIC_BIT   3
+#define VPL011_UARTICR_RXIC_BIT   4
+#define VPL011_UARTICR_TXIC_BIT   5
+#define VPL011_UARTICR_RTIC_BIT   6
+#define VPL011_UARTICR_FEIC_BIT   7
+#define VPL011_UARTICR_PEIC_BIT   8
+#define VPL011_UARTICR_BEIC_BIT   9
+#define VPL011_UARTICR_OEIC_BIT   10
+
+/*
+ * UART interrupt mask set/clear bits - RW
+ */
+#define VPL011_UARTIMSC_RIMIM_BIT   0
+#define VPL011_UARTIMSC_CTSMIM_BIT   1
+#define VPL011_UARTIMSC_DCDMIM_BIT   2
+#define VPL011_UARTIMSC_DSRMIM_BIT   3
+#define VPL011_UARTIMSC_RXIM_BIT   4
+#define VPL011_UARTIMSC_TXIM_BIT   5
+#define VPL011_UARTIMSC_RTIM_BIT   6
+#define VPL011_UARTIMSC_FEIM_BIT   7
+#define VPL011_UARTIMSC_PEIM_BIT   8
+#define VPL011_UARTIMSC_BEIM_BIT   9
+#define VPL011_UARTIMSC_OEIM_BIT   10
+
+
+/*
+ * helper macros
+ */
+#define VPL011_RING_DEPTH(intf,dir) (((intf)->dir ## _prod - (intf)->dir ## _cons))
+#define VPL011_RING_MAX_DEPTH(intf,dir) (sizeof((intf)->dir)-1)
+
+#define VPL011_IN_RING_EMPTY(intf) (VPL011_RING_DEPTH(intf, in) == 0)
+
+#define VPL011_OUT_RING_EMPTY(intf) (VPL011_RING_DEPTH(intf, out) == 0)
+
+#define VPL011_IN_RING_FULL(intf) (VPL011_RING_DEPTH(intf, in) == VPL011_RING_MAX_DEPTH(intf, in))
+
+#define VPL011_OUT_RING_FULL(intf) (VPL011_RING_DEPTH(intf, out) == VPL011_RING_MAX_DEPTH(intf,out))
+
+#define VPL011_LOCK(d,flags) spin_lock_irqsave(&(d)->arch.vpl011.lock, flags)
+#define VPL011_UNLOCK(d,flags) spin_unlock_irqrestore(&(d)->arch.vpl011.lock, flags)
+
+int domain_vpl011_init(struct domain *d);
+int vpl011_map_guest_page(struct domain *d);
+int vpl011_read_data(struct domain *d, unsigned char *data);
+int vpl011_write_data(struct domain *d, unsigned char data);
+
+#define MASK_VPL011CONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1)) 
+struct vpl011_cons_intf_s {
+    char in[1024];
+    char out[2048];
+    uint32_t in_cons, in_prod;
+    uint32_t out_cons, out_prod;
+};
+#endif
