[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 07/13] xen: add console backend driver.
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_pv.c | 3 + 4 files changed, 278 insertions(+), 0 deletions(-) create mode 100644 hw/xen_console.c diff --git a/Makefile.target b/Makefile.target index 78a6402..92ad109 100644 --- a/Makefile.target +++ b/Makefile.target @@ -517,6 +517,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 3a79ad0..10bd1a6 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 */ +struct XenDevOps xen_console_ops; /* xen_console.c */ + #endif /* QEMU_XEN_BACKEND_H */ diff --git a/hw/xen_console.c b/hw/xen_console.c new file mode 100644 index 0000000..2ea88f6 --- /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 <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; + 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 XenDevice *xendev) +{ + struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); + char *type, *dom; + + if (!serial_hds[con->xendev.dev]) { + xen_be_printf(xendev, 1, "serial line %d not configured\n", con->xendev.dev); + return -1; + } + + /* setup */ + dom = xs_get_domain_path(xenstore, con->xendev.dom); + snprintf(con->console, sizeof(con->console), "%s/console", dom); + free(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 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); + 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); + + 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 2eceb8e..93f66d0 100644 --- a/hw/xen_machine_pv.c +++ b/hw/xen_machine_pv.c @@ -97,6 +97,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.5.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |