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

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

unix.superglobalmegacorp.com