|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 1/1] xen/arm: Add pl011 uart support in Xen for guest domains
As per "VM System Specification for ARM Processors", there is a requirement
for Xen to support guest console
over pl011 UART, which is SBSA compliant. The changes in this patch implement
the pl011 emulation in Xen
and a new pl011 console support in xenconsoled.
Signed-off-by: Bhupinder Thakur <bhupinder.thakur@xxxxxxxxxx>
---
tools/console/daemon/io.c | 170 ++++++++++++++---
tools/console/daemon/main.c | 10 +
tools/libxc/include/xc_dom.h | 3 +
tools/libxc/xc_dom_arm.c | 7 +-
tools/libxc/xc_dom_boot.c | 3 +
tools/libxc/xc_domain.c | 3 -
tools/libxl/libxl.c | 4 +
tools/libxl/libxl_arm.c | 50 ++++-
tools/libxl/libxl_dom.c | 9 +-
tools/libxl/libxl_internal.h | 2 +
xen/arch/arm/Makefile | 1 +
xen/arch/arm/domain.c | 7 +
xen/arch/arm/hvm.c | 22 ++-
xen/arch/arm/setup.c | 1 +
xen/arch/arm/vgic.c | 7 +
xen/arch/arm/vpl011.c | 391 ++++++++++++++++++++++++++++++++++++++++
xen/common/event_channel.c | 11 +-
xen/include/asm-arm/domain.h | 14 ++
xen/include/public/arch-arm.h | 5 +
xen/include/public/hvm/params.h | 10 +-
xen/include/xen/vpl011.h | 146 +++++++++++++++
21 files changed, 832 insertions(+), 44 deletions(-)
create mode 100644 xen/arch/arm/vpl011.c
create mode 100644 xen/include/xen/vpl011.h
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
--
2.7.4
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |