virtio-console.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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. #include "hw.h"
  14. #include "qemu-char.h"
  15. #include "virtio.h"
  16. #include "virtio-console.h"
  17. typedef struct VirtIOConsole
  18. {
  19. VirtIODevice vdev;
  20. VirtQueue *ivq, *dvq;
  21. CharDriverState *chr;
  22. } VirtIOConsole;
  23. static VirtIOConsole *to_virtio_console(VirtIODevice *vdev)
  24. {
  25. return (VirtIOConsole *)vdev;
  26. }
  27. static void virtio_console_handle_output(VirtIODevice *vdev, VirtQueue *vq)
  28. {
  29. VirtIOConsole *s = to_virtio_console(vdev);
  30. VirtQueueElement elem;
  31. while (virtqueue_pop(vq, &elem)) {
  32. ssize_t len = 0;
  33. int d;
  34. for (d=0; d < elem.out_num; d++)
  35. len += qemu_chr_write(s->chr, elem.out_sg[d].iov_base,elem.out_sg[d].iov_len);
  36. virtqueue_push(vq, &elem, len);
  37. virtio_notify(vdev, vq);
  38. }
  39. }
  40. static void virtio_console_handle_input(VirtIODevice *vdev, VirtQueue *vq)
  41. {
  42. }
  43. static uint32_t virtio_console_get_features(VirtIODevice *vdev)
  44. {
  45. return 0;
  46. }
  47. static int vcon_can_read(void *opaque)
  48. {
  49. VirtIOConsole *s = (VirtIOConsole *) opaque;
  50. if (!virtio_queue_ready(s->ivq) ||
  51. !(s->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
  52. virtio_queue_empty(s->ivq))
  53. return 0;
  54. /* current implementations have a page sized buffer.
  55. * We fall back to a one byte per read if there is not enough room.
  56. * It would be cool to have a function that returns the available byte
  57. * instead of checking for a limit */
  58. if (virtqueue_avail_bytes(s->ivq, TARGET_PAGE_SIZE, 0))
  59. return TARGET_PAGE_SIZE;
  60. if (virtqueue_avail_bytes(s->ivq, 1, 0))
  61. return 1;
  62. return 0;
  63. }
  64. static void vcon_read(void *opaque, const uint8_t *buf, int size)
  65. {
  66. VirtIOConsole *s = (VirtIOConsole *) opaque;
  67. VirtQueueElement elem;
  68. int offset = 0;
  69. /* The current kernel implementation has only one outstanding input
  70. * buffer of PAGE_SIZE. Nevertheless, this function is prepared to
  71. * handle multiple buffers with multiple sg element for input */
  72. while (offset < size) {
  73. int i = 0;
  74. if (!virtqueue_pop(s->ivq, &elem))
  75. break;
  76. while (offset < size && i < elem.in_num) {
  77. int len = MIN(elem.in_sg[i].iov_len, size - offset);
  78. memcpy(elem.in_sg[i].iov_base, buf + offset, len);
  79. offset += len;
  80. i++;
  81. }
  82. virtqueue_push(s->ivq, &elem, size);
  83. }
  84. virtio_notify(&s->vdev, s->ivq);
  85. }
  86. static void vcon_event(void *opaque, int event)
  87. {
  88. /* we will ignore any event for the time being */
  89. }
  90. static void virtio_console_save(QEMUFile *f, void *opaque)
  91. {
  92. VirtIOConsole *s = opaque;
  93. virtio_save(&s->vdev, f);
  94. }
  95. static int virtio_console_load(QEMUFile *f, void *opaque, int version_id)
  96. {
  97. VirtIOConsole *s = opaque;
  98. if (version_id != 1)
  99. return -EINVAL;
  100. virtio_load(&s->vdev, f);
  101. return 0;
  102. }
  103. void *virtio_console_init(PCIBus *bus, CharDriverState *chr)
  104. {
  105. VirtIOConsole *s;
  106. s = (VirtIOConsole *)virtio_init_pci(bus, "virtio-console",
  107. PCI_VENDOR_ID_REDHAT_QUMRANET,
  108. PCI_DEVICE_ID_VIRTIO_CONSOLE,
  109. PCI_VENDOR_ID_REDHAT_QUMRANET,
  110. VIRTIO_ID_CONSOLE,
  111. PCI_CLASS_DISPLAY_OTHER, 0x00,
  112. 0, sizeof(VirtIOConsole));
  113. if (s == NULL)
  114. return NULL;
  115. s->vdev.get_features = virtio_console_get_features;
  116. s->ivq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_input);
  117. s->dvq = virtio_add_queue(&s->vdev, 128, virtio_console_handle_output);
  118. s->chr = chr;
  119. qemu_chr_add_handlers(chr, vcon_can_read, vcon_read, vcon_event, s);
  120. register_savevm("virtio-console", -1, 1, virtio_console_save, virtio_console_load, s);
  121. return &s->vdev;
  122. }