File:  [Qemu by Fabrice Bellard] / qemu / hw / virtio-console.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:53:44 2018 UTC (2 years, 11 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0105, qemu0104, qemu0103, qemu0102, qemu0101, qemu0100, HEAD
qemu 0.10.0

    1: /*
    2:  * Virtio Console Device
    3:  *
    4:  * Copyright IBM, Corp. 2008
    5:  *
    6:  * Authors:
    7:  *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
    8:  *
    9:  * This work is licensed under the terms of the GNU GPL, version 2.  See
   10:  * the COPYING file in the top-level directory.
   11:  *
   12:  */
   13: 
   14: #include "hw.h"
   15: #include "qemu-char.h"
   16: #include "virtio.h"
   17: #include "virtio-console.h"
   18: 
   19: 
   20: typedef struct VirtIOConsole
   21: {
   22:     VirtIODevice vdev;
   23:     VirtQueue *ivq, *dvq;
   24:     CharDriverState *chr;
   25: } VirtIOConsole;
   26: 
   27: static VirtIOConsole *to_virtio_console(VirtIODevice *vdev)
   28: {
   29:     return (VirtIOConsole *)vdev;
   30: }
   31: 
   32: static void virtio_console_handle_output(VirtIODevice *vdev, VirtQueue *vq)
   33: {
   34:     VirtIOConsole *s = to_virtio_console(vdev);
   35:     VirtQueueElement elem;
   36: 
   37:     while (virtqueue_pop(vq, &elem)) {
   38:         ssize_t len = 0;
   39:         int d;
   40: 
   41:         for (d=0; d < elem.out_num; d++)
   42:             len += qemu_chr_write(s->chr, elem.out_sg[d].iov_base,elem.out_sg[d].iov_len);
   43:         virtqueue_push(vq, &elem, len);
   44:         virtio_notify(vdev, vq);
   45:     }
   46: }
   47: 
   48: static void virtio_console_handle_input(VirtIODevice *vdev, VirtQueue *vq)
   49: {
   50: }
   51: 
   52: static uint32_t virtio_console_get_features(VirtIODevice *vdev)
   53: {
   54:     return 0;
   55: }
   56: 
   57: static int vcon_can_read(void *opaque)
   58: {
   59:     VirtIOConsole *s = (VirtIOConsole *) opaque;
   60: 
   61:     if (!virtio_queue_ready(s->ivq) ||
   62:         !(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
   63:         virtio_queue_empty(s->ivq))
   64:         return 0;
   65: 
   66:     /* current implementations have a page sized buffer.
   67:      * We fall back to a one byte per read if there is not enough room.
   68:      * It would be cool to have a function that returns the available byte
   69:      * instead of checking for a limit */
   70:     if (virtqueue_avail_bytes(s->ivq, TARGET_PAGE_SIZE, 0))
   71:         return TARGET_PAGE_SIZE;
   72:     if (virtqueue_avail_bytes(s->ivq, 1, 0))
   73:         return 1;
   74:     return 0;
   75: }
   76: 
   77: static void vcon_read(void *opaque, const uint8_t *buf, int size)
   78: {
   79:     VirtIOConsole *s = (VirtIOConsole *) opaque;
   80:     VirtQueueElement elem;
   81:     int offset = 0;
   82: 
   83:     /* The current kernel implementation has only one outstanding input
   84:      * buffer of PAGE_SIZE. Nevertheless, this function is prepared to
   85:      * handle multiple buffers with multiple sg element for input */
   86:     while (offset < size) {
   87:         int i = 0;
   88:         if (!virtqueue_pop(s->ivq, &elem))
   89:                 break;
   90:         while (offset < size && i < elem.in_num) {
   91:             int len = MIN(elem.in_sg[i].iov_len, size - offset);
   92:             memcpy(elem.in_sg[i].iov_base, buf + offset, len);
   93:             offset += len;
   94:             i++;
   95:         }
   96:         virtqueue_push(s->ivq, &elem, size);
   97:     }
   98:     virtio_notify(&s->vdev, s->ivq);
   99: }
  100: 
  101: static void vcon_event(void *opaque, int event)
  102: {
  103:     /* we will ignore any event for the time being */
  104: }
  105: 
  106: static void virtio_console_save(QEMUFile *f, void *opaque)
  107: {
  108:     VirtIOConsole *s = opaque;
  109: 
  110:     virtio_save(&s->vdev, f);
  111: }
  112: 
  113: static int virtio_console_load(QEMUFile *f, void *opaque, int version_id)
  114: {
  115:     VirtIOConsole *s = opaque;
  116: 
  117:     if (version_id != 1)
  118:         return -EINVAL;
  119: 
  120:     virtio_load(&s->vdev, f);
  121:     return 0;
  122: }
  123: 
  124: void *virtio_console_init(PCIBus *bus, CharDriverState *chr)
  125: {
  126:     VirtIOConsole *s;
  127: 
  128:     s = (VirtIOConsole *)virtio_init_pci(bus, "virtio-console",
  129:                                          PCI_VENDOR_ID_REDHAT_QUMRANET,
  130:                                          PCI_DEVICE_ID_VIRTIO_CONSOLE,
  131:                                          PCI_VENDOR_ID_REDHAT_QUMRANET,
  132:                                          VIRTIO_ID_CONSOLE,
  133:                                          PCI_CLASS_DISPLAY_OTHER, 0x00,
  134:                                          0, sizeof(VirtIOConsole));
  135:     if (s == NULL)
  136:         return NULL;
  137: 
  138:     s->vdev.get_features = virtio_console_get_features;
  139: 
  140:     s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input);
  141:     s->dvq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_output);
  142: 
  143:     s->chr = chr;
  144:     qemu_chr_add_handlers(chr, vcon_can_read, vcon_read, vcon_event, s);
  145: 
  146:     register_savevm("virtio-console", -1, 1, virtio_console_save, virtio_console_load, s);
  147: 
  148:     return &s->vdev;
  149: }

unix.superglobalmegacorp.com