WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] Re: [Qemu-devel] [PATCH 3/7] xen: add console backend driver

To: qemu-devel@xxxxxxxxxx
Subject: [Xen-devel] Re: [Qemu-devel] [PATCH 3/7] xen: add console backend driver.
From: Anthony Liguori <anthony@xxxxxxxxxxxxx>
Date: Mon, 28 Jul 2008 09:17:35 -0500
Cc: xen-devel@xxxxxxxxxxxxxxxxxxx, Gerd Hoffmann <kraxel@xxxxxxxxxx>
Delivery-date: Mon, 28 Jul 2008 07:18:38 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <1217251078-6591-4-git-send-email-kraxel@xxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <1217251078-6591-1-git-send-email-kraxel@xxxxxxxxxx> <1217251078-6591-4-git-send-email-kraxel@xxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Thunderbird 2.0.0.14 (X11/20080501)
Gerd Hoffmann wrote:
This patch adds a xenconsole backend driver.  It it based on current
xen-unstable code.  It has been changed to make use of the common
backend driver code.

Signed-off-by: Gerd Hoffmann <kraxel@xxxxxxxxxx>
---
 Makefile.target  |    1 +
 hw/xen-backend.h |    3 +
 hw/xen-console.c |  271 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen-machine.c |    2 +
 4 files changed, 277 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen-console.c

diff --git a/Makefile.target b/Makefile.target
index 0451048..05619fa 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -517,6 +517,7 @@ endif
# xen backend driver support
 XEN_OBJS := xen-machine.o xen-backend.o
+XEN_OBJS += xen-console.o
 ifeq ($(CONFIG_XEN), yes)
   OBJS += $(XEN_OBJS)
   LIBS += $(XEN_LIBS)
diff --git a/hw/xen-backend.h b/hw/xen-backend.h
index db36ae7..55ffd31 100644
--- a/hw/xen-backend.h
+++ b/hw/xen-backend.h
@@ -114,3 +114,6 @@ int xen_be_send_notify(struct xendev *xendev);
 void xen_be_printf(struct xendev *xendev, int msg_level, const char *fmt, ...)
     __attribute__ ((format(printf, 3, 4)));
+/* actual backend drivers */
+struct devops xen_console_ops;      /* xen_console.c     */
+
diff --git a/hw/xen-console.c b/hw/xen-console.c
new file mode 100644
index 0000000..9c67f1b
--- /dev/null
+++ b/hw/xen-console.c
@@ -0,0 +1,271 @@
+/*
+ *  Copyright (C) International Business Machines  Corp., 2005
+ *  Author(s): Anthony Liguori <aliguori@xxxxxxxxxx>
+ *
+ *  Copyright (C) Red Hat 2007
+ *
+ *  Xen Console
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; under version 2 of the License.
+ *
+ *  This program is distributed in the hope that 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <malloc.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <xs.h>
+#include <xen/io/console.h>
+#include <xenctrl.h>
+
+#include "hw.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "xen-backend.h"
+
+#define dolog(val, fmt, ...) fprintf(stderr, fmt "\n", ## __VA_ARGS__)
+
+struct buffer {
+    uint8_t *data;
+    size_t consumed;
+    size_t size;
+    size_t capacity;
+    size_t max_capacity;
+};
+
+struct xen_console {
+    struct xendev     xendev;  /* must be first */
+    struct buffer     buffer;
+    char              console[BUFSIZE];
+    int               ring_ref;
+    void              *sring;
+    CharDriverState   *chr;
+    int               backlog;
+};
+
+static void buffer_append(struct xen_console *con)
+{
+    struct buffer *buffer = &con->buffer;
+    XENCONS_RING_IDX cons, prod, size;
+    struct xencons_interface *intf = con->sring;
+
+    cons = intf->out_cons;
+    prod = intf->out_prod;
+    xen_mb();
+
+    size = prod - cons;
+    if ((size == 0) || (size > sizeof(intf->out)))
+       return;
+
+    if ((buffer->capacity - buffer->size) < size) {
+       buffer->capacity += (size + 1024);
+       buffer->data = realloc(buffer->data, buffer->capacity);
+       if (buffer->data == NULL) {
+           dolog(LOG_ERR, "Memory allocation failed");
+           exit(ENOMEM);
+       }
+    }
+
+    while (cons != prod)
+       buffer->data[buffer->size++] = intf->out[
+           MASK_XENCONS_IDX(cons++, intf->out)];
+
+    xen_mb();
+    intf->out_cons = cons;
+    xen_be_send_notify(&con->xendev);
+
+    if (buffer->max_capacity &&
+       buffer->size > buffer->max_capacity) {
+       /* Discard the middle of the data. */
+
+       size_t over = buffer->size - buffer->max_capacity;
+       uint8_t *maxpos = buffer->data + buffer->max_capacity;
+
+       memmove(maxpos - over, maxpos, over);
+       buffer->data = realloc(buffer->data, buffer->max_capacity);
+       buffer->size = buffer->capacity = buffer->max_capacity;
+
+       if (buffer->consumed > buffer->max_capacity - over)
+           buffer->consumed = buffer->max_capacity - over;
+    }
+}
+
+static void buffer_advance(struct buffer *buffer, size_t len)
+{
+    buffer->consumed += len;
+    if (buffer->consumed == buffer->size) {
+       buffer->consumed = 0;
+       buffer->size = 0;
+    }
+}
+
+static int ring_free_bytes(struct xen_console *con)
+{
+    struct xencons_interface *intf = con->sring;
+    XENCONS_RING_IDX cons, prod, space;
+
+    cons = intf->in_cons;
+    prod = intf->in_prod;
+    xen_mb();
+
+    space = prod - cons;
+    if (space > sizeof(intf->in))
+       return 0; /* ring is screwed: ignore it */
+
+    return (sizeof(intf->in) - space);
+}
+
+static int xencons_can_receive(void *opaque)
+{
+    struct xen_console *con = opaque;
+    return ring_free_bytes(con);
+}
+
+static void xencons_receive(void *opaque, const uint8_t *buf, int len)
+{
+    struct xen_console *con = opaque;
+    struct xencons_interface *intf = con->sring;
+    XENCONS_RING_IDX prod;
+    int i, max;
+
+    max = ring_free_bytes(con);
+    /* The can_receive() func limits this, but check again anyway */
+    if (max < len)
+       len = max;
+
+    prod = intf->in_prod;
+    for (i = 0; i < len; i++) {
+       intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
+           buf[i];
+    }
+    xen_wmb();
+    intf->in_prod = prod;
+    xen_be_send_notify(&con->xendev);
+}
+
+static void xencons_send(struct xen_console *con)
+{
+    ssize_t len, size;
+
+    size = con->buffer.size - con->buffer.consumed;
+    len = qemu_chr_write(con->chr, con->buffer.data + con->buffer.consumed,
+                        size);
+    if (len < 1) {
+       if (!con->backlog) {
+           con->backlog = 1;
+           xen_be_printf(&con->xendev, 1, "backlog piling up, nobody 
listening?\n");
+       }
+    } else {
+       buffer_advance(&con->buffer, len);
+       if (con->backlog && len == size) {
+           con->backlog = 0;
+           xen_be_printf(&con->xendev, 1, "backlog is gone\n");
+       }
+    }
+}
+
+/* -------------------------------------------------------------------- */
+
+static int con_init(struct xendev *xendev)
+{
+    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
+    char *type;
+
+    if (!serial_hds[con->xendev.dev]) {
+       xen_be_printf(xendev, 1, "serial line %d not configured\n", 
con->xendev.dev);
+       return -1;
+    }
+
+    /* setup */
+    snprintf(con->console, sizeof(con->console),
+            "/local/domain/%d/console", con->xendev.dom);
+    con->chr = serial_hds[con->xendev.dev];
+
+    type = xenstore_read_str(con->console, "type");
+    if (!type || 0 != strcmp(type, "ioemu")) {
+       xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
+       return -1;
+    }
+
+    return 0;
+}
+
+static int con_connect(struct xendev *xendev)
+{
+    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
+    int limit;
+
+    if (-1 == xenstore_read_int(con->console, "ring-ref", &con->ring_ref))
+       return -1;
+    if (-1 == xenstore_read_int(con->console, "port", 
&con->xendev.remote_port))
+       return -1;
+    if (0 == xenstore_read_int(con->console, "limit", &limit))
+       con->buffer.max_capacity = limit;
+
+    con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom,
+                                     XC_PAGE_SIZE,
+                                     PROT_READ|PROT_WRITE,
+                                     con->ring_ref);
+    if (!con->sring)
+       return -1;
+
+    xen_be_bind_evtchn(&con->xendev);
+    qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive,
+                         NULL, con);
+
+    xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit 
%zd\n",
+                 con->ring_ref,
+                 con->xendev.remote_port,
+                 con->xendev.local_port,
+                 con->buffer.max_capacity);
+    return 0;
+}
+
+static void con_disconnect(struct xendev *xendev)
+{
+    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
+
+    qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
+    xen_be_unbind_evtchn(&con->xendev);
+
+    if (con->sring) {
+       munmap(con->sring, XC_PAGE_SIZE);
+       con->sring = NULL;
+    }
+}
+
+static void con_event(struct xendev *xendev)
+{
+    struct xen_console *con = container_of(xendev, struct xen_console, xendev);
+
+    buffer_append(con);
+    if (con->buffer.size - con->buffer.consumed)
+       xencons_send(con);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct devops xen_console_ops = {

I missed it in the previous patchset, but it would be nice to QEMU-ify these things. For instance, 'struct xen_console' => 'XenConsole', 'struct devopts' => 'XenDevOpts', etc.

Regards,

Anthony Liguori

+    .size       = sizeof(struct xen_console),
+    .flags      = DEVOPS_FLAG_IGNORE_STATE,
+    .init       = con_init,
+    .connect    = con_connect,
+    .event      = con_event,
+    .disconnect = con_disconnect,
+};
diff --git a/hw/xen-machine.c b/hw/xen-machine.c
index 798c0a7..da10982 100644
--- a/hw/xen-machine.c
+++ b/hw/xen-machine.c
@@ -57,6 +57,8 @@ static void xenpv_init(ram_addr_t ram_size, int vga_ram_size,
/* setup xen backend handlers */
     xen_be_init();
+
+    xen_be_register("console", &xen_console_ops);
 }
QEMUMachine xenpv_machine = {


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

<Prev in Thread] Current Thread [Next in Thread>