From patchwork Mon Feb 6 18:09:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bhupinder Thakur X-Patchwork-Id: 93471 Delivered-To: patch@linaro.org Received: by 10.140.20.99 with SMTP id 90csp1818465qgi; Mon, 6 Feb 2017 10:11:40 -0800 (PST) X-Received: by 10.36.211.213 with SMTP id n204mr7960877itg.49.1486404700524; Mon, 06 Feb 2017 10:11:40 -0800 (PST) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org. [192.237.175.120]) by mx.google.com with ESMTPS id g83si9719015iof.70.2017.02.06.10.11.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Feb 2017 10:11:40 -0800 (PST) Received-SPF: neutral (google.com: 192.237.175.120 is neither permitted nor denied by best guess record for domain of xen-devel-bounces@lists.xen.org) client-ip=192.237.175.120; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=neutral (google.com: 192.237.175.120 is neither permitted nor denied by best guess record for domain of xen-devel-bounces@lists.xen.org) smtp.mailfrom=xen-devel-bounces@lists.xen.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1canjF-0007gD-IA; Mon, 06 Feb 2017 18:09:29 +0000 Received: from mail6.bemta6.messagelabs.com ([193.109.254.103]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1canjD-0007fs-My for xen-devel@lists.xenproject.org; Mon, 06 Feb 2017 18:09:27 +0000 Received: from [193.109.254.147] by server-9.bemta-6.messagelabs.com id 66/FF-27165-7DBB8985; Mon, 06 Feb 2017 18:09:27 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrOIsWRWlGSWpSXmKPExsXiVRusr3t194w IgyU3VCy+b5nM5MDocfjDFZYAxijWzLyk/IoE1ow7T1awFhx+zFRxrP09cwPj06lMXYxcHEIC 0xkl9sz/B+RwcrAIzGOWWN/qBpKQEOhnlbh//hwLSEJCIEbiw/srbBB2pUT3nI2sILaQgJbE0 VOzWSEmtTBJfNi0Dsjh4GATMJGY1SEBUiMioCRxb9VksAXMAqES/561sYPYwgK+Eu17/rBBLF aVeDT5NjtIK6+At8TORTEQq+Qkbp7rZAaxOQV8JN6+vcUGsdZb4uX3BUwTGAUWMDKsYlQvTi0 qSy3SNddLKspMzyjJTczM0TU0MNPLTS0uTkxPzUlMKtZLzs/dxAgMLAYg2ME487L/IUZJDiYl UV6RtTMihPiS8lMqMxKLM+KLSnNSiw8xynBwKEnwbtsFlBMsSk1PrUjLzAGGOExagoNHSYRXD STNW1yQmFucmQ6ROsXoynHr16mXTBynbpwGkvu2nwGSX3aCyF27Lr9kEmLJy89LlRLnzQZpFg BpzijNgxsNi89LjLJSwryMQMcK8RSkFuVmlqDKv2IU52BUEublBpnCk5lXAnfBK6DjmICO23Z lGshxJYkIKakGxvyqLXtFONXPnVc3Ka2N3/u6iJm1jDsw9b9m+Z75+jyHwp9/35PUnz15r7Xb zkLmh1Ncrk2UdlR6+3nRDlXWOTvK15k/NKqe72EgHTbRoejt/+vVv1VDFjzvt+DeOPeCjZ96j 1aEe+KZL2tvPBMynpn8SXO5/o7/W47kf9oQaeip0bT1aDPvQiWW4oxEQy3mouJEAJO0uJfKAg AA X-Env-Sender: bhupinder.thakur@linaro.org X-Msg-Ref: server-12.tower-27.messagelabs.com!1486404563!84177916!1 X-Originating-IP: [74.125.83.47] X-SpamReason: No, hits=0.0 required=7.0 tests= X-StarScan-Received: X-StarScan-Version: 9.1.1; banners=-,-,- X-VirusChecked: Checked Received: (qmail 9848 invoked from network); 6 Feb 2017 18:09:25 -0000 Received: from mail-pg0-f47.google.com (HELO mail-pg0-f47.google.com) (74.125.83.47) by server-12.tower-27.messagelabs.com with AES128-GCM-SHA256 encrypted SMTP; 6 Feb 2017 18:09:25 -0000 Received: by mail-pg0-f47.google.com with SMTP id 14so30453622pgg.1 for ; Mon, 06 Feb 2017 10:09:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=L3KSv1ahA62gIpQdqrOC3SjOJIVtLpaGLG/qa2ZuFGU=; b=U4cL+iEFY7zB0kbiJvlnAoM6E8lQNqx9PnNgTctmElU8jSASnl9/Ml/MmxHuJM6lS2 mMxpuyrZlxsZpHuBnFfqpV5A8d1Xj7Lk5kutYVCInnB/U36YpbEuYtBpF3yYW3yNp2Jr 3OzZyyqXdYkJCFXPu2gLzoYJ1DB9VzwlsbORQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=L3KSv1ahA62gIpQdqrOC3SjOJIVtLpaGLG/qa2ZuFGU=; b=XUpHQuUV40b+GhJuI9p8bvpZmVMcYnGqlr9j9Vzb6vChKA9UG+By4L3Jvy4nOZqCwq uJFQV+fRIvf7/9+M/LlZTHUqg6oEO9H7OmF5mb5npMrJzCG7SwxT1EfqRFlbTo30Ck/g 5Bwl64iDYU87yBpxkAUr7bp8wvPIl9DisYkMXYjKLAoSMCWreH+TiEtJowbIan6BhEHJ Va6JiNq9+NqYPyTmYTh3ktnMXUVzJ1Iq6Fi+1BN2yFQfZTyGt+V4ni9qzFLBjXDchFzl r0ZZ+T91uBcsUwo0rKT+fkc2mAUpFbm5YUBsLnpdd/3ECYnvgOqliFx3o1KS2tVRRCN1 y0CA== X-Gm-Message-State: AIkVDXLvrX4RobFtSRXTTa74PobWrDxEtQ2jf77YrQ4SsLqYrDYUFuYLAhQKs5GPls6nqbod X-Received: by 10.84.248.10 with SMTP id p10mr18947388pll.87.1486404562881; Mon, 06 Feb 2017 10:09:22 -0800 (PST) Received: from blr-ubuntu-linaro.wlan.qualcomm.com ([103.5.19.18]) by smtp.gmail.com with ESMTPSA id r78sm4334508pfl.63.2017.02.06.10.09.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 06 Feb 2017 10:09:22 -0800 (PST) From: Bhupinder Thakur To: xen-devel@lists.xenproject.org Date: Mon, 6 Feb 2017 23:39:08 +0530 Message-Id: <1486404548-15062-2-git-send-email-bhupinder.thakur@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1486404548-15062-1-git-send-email-bhupinder.thakur@linaro.org> References: <1486404548-15062-1-git-send-email-bhupinder.thakur@linaro.org> Cc: Julien Grall , Stefano Stabellini Subject: [Xen-devel] [PATCH 1/1] xen/arm: Add pl011 uart support in Xen for guest domains X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" 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 --- 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 #include #include +#include #include #include #include @@ -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 #include #include +#include #include #include @@ -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 #include #include +#include +#include #include +#include #include #include @@ -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 #include #include +#include #include #include #include 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +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<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<arch.vpl011.flag |= (1<arch.vpl011.raw_intr_status |= (1<arch.vpl011.flag &= ~(1<arch.vpl011.raw_intr_status |= (1<arch.vpl011.flag &= ~(1<arch.vpl011.flag |= (1<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<arch.vpl011.raw_intr_status &= ~(1<arch.vpl011.flag &= ~(1<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<arch.vpl011.flag |= (1<arch.vpl011.flag &= ~(1<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 #include #include +#include #include #include @@ -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 #include #include +#include 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 */ #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 . + */ + +#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