From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KNTYF-0001sJ-Qc for qemu-devel@nongnu.org; Mon, 28 Jul 2008 10:18:15 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KNTYB-0001r4-QG for qemu-devel@nongnu.org; Mon, 28 Jul 2008 10:18:15 -0400 Received: from [199.232.76.173] (port=54434 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KNTYB-0001qx-Jo for qemu-devel@nongnu.org; Mon, 28 Jul 2008 10:18:11 -0400 Received: from wr-out-0506.google.com ([64.233.184.230]:44508) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1KNTYA-0005QL-Bj for qemu-devel@nongnu.org; Mon, 28 Jul 2008 10:18:11 -0400 Received: by wr-out-0506.google.com with SMTP id c46so4017969wra.18 for ; Mon, 28 Jul 2008 07:18:08 -0700 (PDT) Message-ID: <488DD4FF.9030400@codemonkey.ws> Date: Mon, 28 Jul 2008 09:17:35 -0500 From: Anthony Liguori MIME-Version: 1.0 Subject: Re: [Qemu-devel] [PATCH 3/7] xen: add console backend driver. References: <1217251078-6591-1-git-send-email-kraxel@redhat.com> <1217251078-6591-4-git-send-email-kraxel@redhat.com> In-Reply-To: <1217251078-6591-4-git-send-email-kraxel@redhat.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: xen-devel@lists.xensource.com, Gerd Hoffmann 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 > --- > 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 > + * > + * 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 > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#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 = { >