Commit e57dd20bb7062b398a7af7c6d109eda765b5aae2

Authored by aliguori
1 parent d94f9486

xen: add console backend driver. (Gerd Hoffmann)

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@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7221 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -562,6 +562,7 @@ endif
562 562  
563 563 # xen backend driver support
564 564 XEN_OBJS := xen_machine_pv.o xen_backend.o
  565 +XEN_OBJS += xen_console.o
565 566 ifeq ($(CONFIG_XEN), yes)
566 567 OBJS += $(XEN_OBJS)
567 568 LIBS += $(XEN_LIBS)
... ...
hw/xen_backend.h
... ... @@ -83,4 +83,7 @@ int xen_be_send_notify(struct XenDevice *xendev);
83 83 void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
84 84 __attribute__ ((format(printf, 3, 4)));
85 85  
  86 +/* actual backend drivers */
  87 +extern struct XenDevOps xen_console_ops; /* xen_console.c */
  88 +
86 89 #endif /* QEMU_HW_XEN_BACKEND_H */
... ...
hw/xen_console.c 0 → 100644
  1 +/*
  2 + * Copyright (C) International Business Machines Corp., 2005
  3 + * Author(s): Anthony Liguori <aliguori@us.ibm.com>
  4 + *
  5 + * Copyright (C) Red Hat 2007
  6 + *
  7 + * Xen Console
  8 + *
  9 + * This program is free software; you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License as published by
  11 + * the Free Software Foundation; under version 2 of the License.
  12 + *
  13 + * This program is distributed in the hope that it will be useful,
  14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + * GNU General Public License for more details.
  17 + *
  18 + * You should have received a copy of the GNU General Public License along
  19 + * with this program; if not, write to the Free Software Foundation, Inc.,
  20 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21 + */
  22 +
  23 +#include <stdlib.h>
  24 +#include <errno.h>
  25 +#include <string.h>
  26 +#include <sys/select.h>
  27 +#include <fcntl.h>
  28 +#include <unistd.h>
  29 +#include <termios.h>
  30 +#include <stdarg.h>
  31 +#include <sys/mman.h>
  32 +#include <xs.h>
  33 +#include <xen/io/console.h>
  34 +#include <xenctrl.h>
  35 +
  36 +#include "hw.h"
  37 +#include "sysemu.h"
  38 +#include "qemu-char.h"
  39 +#include "xen_backend.h"
  40 +
  41 +struct buffer {
  42 + uint8_t *data;
  43 + size_t consumed;
  44 + size_t size;
  45 + size_t capacity;
  46 + size_t max_capacity;
  47 +};
  48 +
  49 +struct XenConsole {
  50 + struct XenDevice xendev; /* must be first */
  51 + struct buffer buffer;
  52 + char console[XEN_BUFSIZE];
  53 + int ring_ref;
  54 + void *sring;
  55 + CharDriverState *chr;
  56 + int backlog;
  57 +};
  58 +
  59 +static void buffer_append(struct XenConsole *con)
  60 +{
  61 + struct buffer *buffer = &con->buffer;
  62 + XENCONS_RING_IDX cons, prod, size;
  63 + struct xencons_interface *intf = con->sring;
  64 +
  65 + cons = intf->out_cons;
  66 + prod = intf->out_prod;
  67 + xen_mb();
  68 +
  69 + size = prod - cons;
  70 + if ((size == 0) || (size > sizeof(intf->out)))
  71 + return;
  72 +
  73 + if ((buffer->capacity - buffer->size) < size) {
  74 + buffer->capacity += (size + 1024);
  75 + buffer->data = qemu_realloc(buffer->data, buffer->capacity);
  76 + }
  77 +
  78 + while (cons != prod)
  79 + buffer->data[buffer->size++] = intf->out[
  80 + MASK_XENCONS_IDX(cons++, intf->out)];
  81 +
  82 + xen_mb();
  83 + intf->out_cons = cons;
  84 + xen_be_send_notify(&con->xendev);
  85 +
  86 + if (buffer->max_capacity &&
  87 + buffer->size > buffer->max_capacity) {
  88 + /* Discard the middle of the data. */
  89 +
  90 + size_t over = buffer->size - buffer->max_capacity;
  91 + uint8_t *maxpos = buffer->data + buffer->max_capacity;
  92 +
  93 + memmove(maxpos - over, maxpos, over);
  94 + buffer->data = qemu_realloc(buffer->data, buffer->max_capacity);
  95 + buffer->size = buffer->capacity = buffer->max_capacity;
  96 +
  97 + if (buffer->consumed > buffer->max_capacity - over)
  98 + buffer->consumed = buffer->max_capacity - over;
  99 + }
  100 +}
  101 +
  102 +static void buffer_advance(struct buffer *buffer, size_t len)
  103 +{
  104 + buffer->consumed += len;
  105 + if (buffer->consumed == buffer->size) {
  106 + buffer->consumed = 0;
  107 + buffer->size = 0;
  108 + }
  109 +}
  110 +
  111 +static int ring_free_bytes(struct XenConsole *con)
  112 +{
  113 + struct xencons_interface *intf = con->sring;
  114 + XENCONS_RING_IDX cons, prod, space;
  115 +
  116 + cons = intf->in_cons;
  117 + prod = intf->in_prod;
  118 + xen_mb();
  119 +
  120 + space = prod - cons;
  121 + if (space > sizeof(intf->in))
  122 + return 0; /* ring is screwed: ignore it */
  123 +
  124 + return (sizeof(intf->in) - space);
  125 +}
  126 +
  127 +static int xencons_can_receive(void *opaque)
  128 +{
  129 + struct XenConsole *con = opaque;
  130 + return ring_free_bytes(con);
  131 +}
  132 +
  133 +static void xencons_receive(void *opaque, const uint8_t *buf, int len)
  134 +{
  135 + struct XenConsole *con = opaque;
  136 + struct xencons_interface *intf = con->sring;
  137 + XENCONS_RING_IDX prod;
  138 + int i, max;
  139 +
  140 + max = ring_free_bytes(con);
  141 + /* The can_receive() func limits this, but check again anyway */
  142 + if (max < len)
  143 + len = max;
  144 +
  145 + prod = intf->in_prod;
  146 + for (i = 0; i < len; i++) {
  147 + intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
  148 + buf[i];
  149 + }
  150 + xen_wmb();
  151 + intf->in_prod = prod;
  152 + xen_be_send_notify(&con->xendev);
  153 +}
  154 +
  155 +static void xencons_send(struct XenConsole *con)
  156 +{
  157 + ssize_t len, size;
  158 +
  159 + size = con->buffer.size - con->buffer.consumed;
  160 + if (con->chr)
  161 + len = qemu_chr_write(con->chr, con->buffer.data + con->buffer.consumed,
  162 + size);
  163 + else
  164 + len = size;
  165 + if (len < 1) {
  166 + if (!con->backlog) {
  167 + con->backlog = 1;
  168 + xen_be_printf(&con->xendev, 1, "backlog piling up, nobody listening?\n");
  169 + }
  170 + } else {
  171 + buffer_advance(&con->buffer, len);
  172 + if (con->backlog && len == size) {
  173 + con->backlog = 0;
  174 + xen_be_printf(&con->xendev, 1, "backlog is gone\n");
  175 + }
  176 + }
  177 +}
  178 +
  179 +/* -------------------------------------------------------------------- */
  180 +
  181 +static int con_init(struct XenDevice *xendev)
  182 +{
  183 + struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
  184 + char *type, *dom;
  185 +
  186 + /* setup */
  187 + dom = xs_get_domain_path(xenstore, con->xendev.dom);
  188 + snprintf(con->console, sizeof(con->console), "%s/console", dom);
  189 + free(dom);
  190 +
  191 + type = xenstore_read_str(con->console, "type");
  192 + if (!type || 0 != strcmp(type, "ioemu")) {
  193 + xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
  194 + return -1;
  195 + }
  196 +
  197 + if (!serial_hds[con->xendev.dev])
  198 + xen_be_printf(xendev, 1, "WARNING: serial line %d not configured\n",
  199 + con->xendev.dev);
  200 + else
  201 + con->chr = serial_hds[con->xendev.dev];
  202 +
  203 + return 0;
  204 +}
  205 +
  206 +static int con_connect(struct XenDevice *xendev)
  207 +{
  208 + struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
  209 + int limit;
  210 +
  211 + if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1)
  212 + return -1;
  213 + if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1)
  214 + return -1;
  215 + if (xenstore_read_int(con->console, "limit", &limit) == 0)
  216 + con->buffer.max_capacity = limit;
  217 +
  218 + con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom,
  219 + XC_PAGE_SIZE,
  220 + PROT_READ|PROT_WRITE,
  221 + con->ring_ref);
  222 + if (!con->sring)
  223 + return -1;
  224 +
  225 + xen_be_bind_evtchn(&con->xendev);
  226 + if (con->chr)
  227 + qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive,
  228 + NULL, con);
  229 +
  230 + xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
  231 + con->ring_ref,
  232 + con->xendev.remote_port,
  233 + con->xendev.local_port,
  234 + con->buffer.max_capacity);
  235 + return 0;
  236 +}
  237 +
  238 +static void con_disconnect(struct XenDevice *xendev)
  239 +{
  240 + struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
  241 +
  242 + if (con->chr)
  243 + qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
  244 + xen_be_unbind_evtchn(&con->xendev);
  245 +
  246 + if (con->sring) {
  247 + munmap(con->sring, XC_PAGE_SIZE);
  248 + con->sring = NULL;
  249 + }
  250 +}
  251 +
  252 +static void con_event(struct XenDevice *xendev)
  253 +{
  254 + struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
  255 +
  256 + buffer_append(con);
  257 + if (con->buffer.size - con->buffer.consumed)
  258 + xencons_send(con);
  259 +}
  260 +
  261 +/* -------------------------------------------------------------------- */
  262 +
  263 +struct XenDevOps xen_console_ops = {
  264 + .size = sizeof(struct XenConsole),
  265 + .flags = DEVOPS_FLAG_IGNORE_STATE,
  266 + .init = con_init,
  267 + .connect = con_connect,
  268 + .event = con_event,
  269 + .disconnect = con_disconnect,
  270 +};
... ...
hw/xen_machine_pv.c
... ... @@ -56,6 +56,7 @@ static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
56 56 fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
57 57 exit(1);
58 58 }
  59 + xen_be_register("console", &xen_console_ops);
59 60 }
60 61  
61 62 QEMUMachine xenpv_machine = {
... ...