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] [PATCH 3/7] xen: add console backend driver.

To: qemu-devel@xxxxxxxxxx, xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 3/7] xen: add console backend driver.
From: Gerd Hoffmann <kraxel@xxxxxxxxxx>
Date: Tue, 28 Oct 2008 13:23:38 +0100
Cc: Gerd Hoffmann <kraxel@xxxxxxxxxx>
Delivery-date: Tue, 28 Oct 2008 05:25:38 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <1225196622-14164-1-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: <1225196622-14164-1-git-send-email-kraxel@xxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
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    |  276 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xen_machine_pv.c |    3 +
 4 files changed, 283 insertions(+), 0 deletions(-)
 create mode 100644 hw/xen_console.c

diff --git a/Makefile.target b/Makefile.target
index c18cbc6..50f1dca 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -631,6 +631,7 @@ endif
 
 # xen backend driver support
 XEN_OBJS := xen_machine_pv.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 a1243f6..4744713 100644
--- a/hw/xen_backend.h
+++ b/hw/xen_backend.h
@@ -83,4 +83,7 @@ int xen_be_send_notify(struct XenDevice *xendev);
 void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, 
...)
     __attribute__ ((format(printf, 3, 4)));
 
+/* actual backend drivers */
+extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
+
 #endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_console.c b/hw/xen_console.c
new file mode 100644
index 0000000..c172cf2
--- /dev/null
+++ b/hw/xen_console.c
@@ -0,0 +1,276 @@
+/*
+ *  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 <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 XenConsole {
+    struct XenDevice  xendev;  /* must be first */
+    struct buffer     buffer;
+    char              console[XEN_BUFSIZE];
+    int               ring_ref;
+    void              *sring;
+    CharDriverState   *chr;
+    int               backlog;
+};
+
+static void buffer_append(struct XenConsole *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 = qemu_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 = qemu_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 XenConsole *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 XenConsole *con = opaque;
+    return ring_free_bytes(con);
+}
+
+static void xencons_receive(void *opaque, const uint8_t *buf, int len)
+{
+    struct XenConsole *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 XenConsole *con)
+{
+    ssize_t len, size;
+
+    size = con->buffer.size - con->buffer.consumed;
+    if (con->chr)
+        len = qemu_chr_write(con->chr, con->buffer.data + con->buffer.consumed,
+                             size);
+    else
+        len = 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 XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+    char *type, *dom;
+
+    /* setup */
+    dom = xs_get_domain_path(xenstore, con->xendev.dom);
+    snprintf(con->console, sizeof(con->console), "%s/console", dom);
+    free(dom);
+
+    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;
+    }
+
+    if (!serial_hds[con->xendev.dev])
+       xen_be_printf(xendev, 1, "WARNING: serial line %d not configured\n",
+                      con->xendev.dev);
+    else
+        con->chr = serial_hds[con->xendev.dev];
+
+    return 0;
+}
+
+static int con_connect(struct XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, 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);
+    if (con->chr)
+        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 XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+    if (con->chr)
+        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 XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+    buffer_append(con);
+    if (con->buffer.size - con->buffer.consumed)
+       xencons_send(con);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct XenDevOps xen_console_ops = {
+    .size       = sizeof(struct XenConsole),
+    .flags      = DEVOPS_FLAG_IGNORE_STATE,
+    .init       = con_init,
+    .connect    = con_connect,
+    .event      = con_event,
+    .disconnect = con_disconnect,
+};
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
index 67f997f..fca2e09 100644
--- a/hw/xen_machine_pv.c
+++ b/hw/xen_machine_pv.c
@@ -63,6 +63,9 @@ static int xen_init_pv(DisplayState *ds)
     if (rc < 0)
         return rc;
 
+    /* xenbus backend drivers */
+    xen_be_register("console", &xen_console_ops);
+
     return 0;
 }
 
-- 
1.5.6.5


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