Annotation of qemu/hw/xen_console.c, revision 1.1.1.1

1.1       root        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, see <http://www.gnu.org/licenses/>.
                     20:  */
                     21: 
                     22: #include <stdlib.h>
                     23: #include <errno.h>
                     24: #include <string.h>
                     25: #include <sys/select.h>
                     26: #include <fcntl.h>
                     27: #include <unistd.h>
                     28: #include <termios.h>
                     29: #include <stdarg.h>
                     30: #include <sys/mman.h>
                     31: #include <xs.h>
                     32: #include <xen/io/console.h>
                     33: #include <xenctrl.h>
                     34: 
                     35: #include "hw.h"
                     36: #include "sysemu.h"
                     37: #include "qemu-char.h"
                     38: #include "xen_backend.h"
                     39: 
                     40: struct buffer {
                     41:     uint8_t *data;
                     42:     size_t consumed;
                     43:     size_t size;
                     44:     size_t capacity;
                     45:     size_t max_capacity;
                     46: };
                     47: 
                     48: struct XenConsole {
                     49:     struct XenDevice  xendev;  /* must be first */
                     50:     struct buffer     buffer;
                     51:     char              console[XEN_BUFSIZE];
                     52:     int               ring_ref;
                     53:     void              *sring;
                     54:     CharDriverState   *chr;
                     55:     int               backlog;
                     56: };
                     57: 
                     58: static void buffer_append(struct XenConsole *con)
                     59: {
                     60:     struct buffer *buffer = &con->buffer;
                     61:     XENCONS_RING_IDX cons, prod, size;
                     62:     struct xencons_interface *intf = con->sring;
                     63: 
                     64:     cons = intf->out_cons;
                     65:     prod = intf->out_prod;
                     66:     xen_mb();
                     67: 
                     68:     size = prod - cons;
                     69:     if ((size == 0) || (size > sizeof(intf->out)))
                     70:        return;
                     71: 
                     72:     if ((buffer->capacity - buffer->size) < size) {
                     73:        buffer->capacity += (size + 1024);
                     74:        buffer->data = qemu_realloc(buffer->data, buffer->capacity);
                     75:     }
                     76: 
                     77:     while (cons != prod)
                     78:        buffer->data[buffer->size++] = intf->out[
                     79:            MASK_XENCONS_IDX(cons++, intf->out)];
                     80: 
                     81:     xen_mb();
                     82:     intf->out_cons = cons;
                     83:     xen_be_send_notify(&con->xendev);
                     84: 
                     85:     if (buffer->max_capacity &&
                     86:        buffer->size > buffer->max_capacity) {
                     87:        /* Discard the middle of the data. */
                     88: 
                     89:        size_t over = buffer->size - buffer->max_capacity;
                     90:        uint8_t *maxpos = buffer->data + buffer->max_capacity;
                     91: 
                     92:        memmove(maxpos - over, maxpos, over);
                     93:        buffer->data = qemu_realloc(buffer->data, buffer->max_capacity);
                     94:        buffer->size = buffer->capacity = buffer->max_capacity;
                     95: 
                     96:        if (buffer->consumed > buffer->max_capacity - over)
                     97:            buffer->consumed = buffer->max_capacity - over;
                     98:     }
                     99: }
                    100: 
                    101: static void buffer_advance(struct buffer *buffer, size_t len)
                    102: {
                    103:     buffer->consumed += len;
                    104:     if (buffer->consumed == buffer->size) {
                    105:        buffer->consumed = 0;
                    106:        buffer->size = 0;
                    107:     }
                    108: }
                    109: 
                    110: static int ring_free_bytes(struct XenConsole *con)
                    111: {
                    112:     struct xencons_interface *intf = con->sring;
                    113:     XENCONS_RING_IDX cons, prod, space;
                    114: 
                    115:     cons = intf->in_cons;
                    116:     prod = intf->in_prod;
                    117:     xen_mb();
                    118: 
                    119:     space = prod - cons;
                    120:     if (space > sizeof(intf->in))
                    121:        return 0; /* ring is screwed: ignore it */
                    122: 
                    123:     return (sizeof(intf->in) - space);
                    124: }
                    125: 
                    126: static int xencons_can_receive(void *opaque)
                    127: {
                    128:     struct XenConsole *con = opaque;
                    129:     return ring_free_bytes(con);
                    130: }
                    131: 
                    132: static void xencons_receive(void *opaque, const uint8_t *buf, int len)
                    133: {
                    134:     struct XenConsole *con = opaque;
                    135:     struct xencons_interface *intf = con->sring;
                    136:     XENCONS_RING_IDX prod;
                    137:     int i, max;
                    138: 
                    139:     max = ring_free_bytes(con);
                    140:     /* The can_receive() func limits this, but check again anyway */
                    141:     if (max < len)
                    142:        len = max;
                    143: 
                    144:     prod = intf->in_prod;
                    145:     for (i = 0; i < len; i++) {
                    146:        intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
                    147:            buf[i];
                    148:     }
                    149:     xen_wmb();
                    150:     intf->in_prod = prod;
                    151:     xen_be_send_notify(&con->xendev);
                    152: }
                    153: 
                    154: static void xencons_send(struct XenConsole *con)
                    155: {
                    156:     ssize_t len, size;
                    157: 
                    158:     size = con->buffer.size - con->buffer.consumed;
                    159:     if (con->chr)
                    160:         len = qemu_chr_write(con->chr, con->buffer.data + con->buffer.consumed,
                    161:                              size);
                    162:     else
                    163:         len = size;
                    164:     if (len < 1) {
                    165:        if (!con->backlog) {
                    166:            con->backlog = 1;
                    167:            xen_be_printf(&con->xendev, 1, "backlog piling up, nobody listening?\n");
                    168:        }
                    169:     } else {
                    170:        buffer_advance(&con->buffer, len);
                    171:        if (con->backlog && len == size) {
                    172:            con->backlog = 0;
                    173:            xen_be_printf(&con->xendev, 1, "backlog is gone\n");
                    174:        }
                    175:     }
                    176: }
                    177: 
                    178: /* -------------------------------------------------------------------- */
                    179: 
                    180: static int con_init(struct XenDevice *xendev)
                    181: {
                    182:     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
                    183:     char *type, *dom;
                    184: 
                    185:     /* setup */
                    186:     dom = xs_get_domain_path(xenstore, con->xendev.dom);
                    187:     snprintf(con->console, sizeof(con->console), "%s/console", dom);
                    188:     free(dom);
                    189: 
                    190:     type = xenstore_read_str(con->console, "type");
                    191:     if (!type || strcmp(type, "ioemu") != 0) {
                    192:        xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
                    193:        return -1;
                    194:     }
                    195: 
                    196:     if (!serial_hds[con->xendev.dev])
                    197:        xen_be_printf(xendev, 1, "WARNING: serial line %d not configured\n",
                    198:                       con->xendev.dev);
                    199:     else
                    200:         con->chr = serial_hds[con->xendev.dev];
                    201: 
                    202:     return 0;
                    203: }
                    204: 
                    205: static int con_connect(struct XenDevice *xendev)
                    206: {
                    207:     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
                    208:     int limit;
                    209: 
                    210:     if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1)
                    211:        return -1;
                    212:     if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1)
                    213:        return -1;
                    214:     if (xenstore_read_int(con->console, "limit", &limit) == 0)
                    215:        con->buffer.max_capacity = limit;
                    216: 
                    217:     con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom,
                    218:                                      XC_PAGE_SIZE,
                    219:                                      PROT_READ|PROT_WRITE,
                    220:                                      con->ring_ref);
                    221:     if (!con->sring)
                    222:        return -1;
                    223: 
                    224:     xen_be_bind_evtchn(&con->xendev);
                    225:     if (con->chr)
                    226:         qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive,
                    227:                               NULL, con);
                    228: 
                    229:     xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
                    230:                  con->ring_ref,
                    231:                  con->xendev.remote_port,
                    232:                  con->xendev.local_port,
                    233:                  con->buffer.max_capacity);
                    234:     return 0;
                    235: }
                    236: 
                    237: static void con_disconnect(struct XenDevice *xendev)
                    238: {
                    239:     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
                    240: 
                    241:     if (con->chr)
                    242:         qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
                    243:     xen_be_unbind_evtchn(&con->xendev);
                    244: 
                    245:     if (con->sring) {
                    246:        munmap(con->sring, XC_PAGE_SIZE);
                    247:        con->sring = NULL;
                    248:     }
                    249: }
                    250: 
                    251: static void con_event(struct XenDevice *xendev)
                    252: {
                    253:     struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
                    254: 
                    255:     buffer_append(con);
                    256:     if (con->buffer.size - con->buffer.consumed)
                    257:        xencons_send(con);
                    258: }
                    259: 
                    260: /* -------------------------------------------------------------------- */
                    261: 
                    262: struct XenDevOps xen_console_ops = {
                    263:     .size       = sizeof(struct XenConsole),
                    264:     .flags      = DEVOPS_FLAG_IGNORE_STATE,
                    265:     .init       = con_init,
                    266:     .connect    = con_connect,
                    267:     .event      = con_event,
                    268:     .disconnect = con_disconnect,
                    269: };

unix.superglobalmegacorp.com