@@ -13,8 +13,8 @@ CSCOPE = cscope
TAGS = ctags
OBJS += 8250-serial.o
-OBJS += blk-virtio.o
-OBJS += console-virtio.o
+OBJS += virtio-blk.o
+OBJS += virtio-console.o
OBJS += cpuid.o
OBJS += read-write.o
OBJS += disk-image.o
deleted file mode 100644
@@ -1,293 +0,0 @@
-#include "kvm/blk-virtio.h"
-
-#include "kvm/virtio_pci.h"
-
-#include "kvm/disk-image.h"
-#include "kvm/virtio.h"
-#include "kvm/ioport.h"
-#include "kvm/util.h"
-#include "kvm/kvm.h"
-#include "kvm/pci.h"
-
-#include <linux/virtio_ring.h>
-#include <linux/virtio_blk.h>
-#include <inttypes.h>
-#include <assert.h>
-
-#define VIRTIO_BLK_IRQ 14
-
-#define NUM_VIRT_QUEUES 1
-
-#define VIRTIO_BLK_QUEUE_SIZE 128
-
-struct blk_device {
- struct virtio_blk_config blk_config;
- uint32_t host_features;
- uint32_t guest_features;
- uint16_t config_vector;
- uint8_t status;
-
- /* virtio queue */
- uint16_t queue_selector;
-
- struct virt_queue virt_queues[NUM_VIRT_QUEUES];
-};
-
-#define DISK_SEG_MAX 126
-
-static struct blk_device blk_device = {
- .blk_config = (struct virtio_blk_config) {
- /* VIRTIO_BLK_F_SEG_MAX */
- .seg_max = DISK_SEG_MAX,
- },
- /*
- * Note we don't set VIRTIO_BLK_F_GEOMETRY here so the
- * node kernel will compute disk geometry by own, the
- * same applies to VIRTIO_BLK_F_BLK_SIZE
- */
- .host_features = (1UL << VIRTIO_BLK_F_SEG_MAX),
-};
-
-static bool virtio_blk_config_in(void *data, unsigned long offset, int size, uint32_t count)
-{
- uint8_t *config_space = (uint8_t *) &blk_device.blk_config;
-
- if (size != 1 || count != 1)
- return false;
-
- ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]);
-
- return true;
-}
-
-static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
-{
- unsigned long offset;
-
- offset = port - IOPORT_VIRTIO_BLK;
-
- switch (offset) {
- case VIRTIO_PCI_HOST_FEATURES:
- ioport__write32(data, blk_device.host_features);
- break;
- case VIRTIO_PCI_GUEST_FEATURES:
- return false;
- case VIRTIO_PCI_QUEUE_PFN:
- ioport__write32(data, blk_device.virt_queues[blk_device.queue_selector].pfn);
- break;
- case VIRTIO_PCI_QUEUE_NUM:
- ioport__write16(data, VIRTIO_BLK_QUEUE_SIZE);
- break;
- case VIRTIO_PCI_QUEUE_SEL:
- case VIRTIO_PCI_QUEUE_NOTIFY:
- return false;
- case VIRTIO_PCI_STATUS:
- ioport__write8(data, blk_device.status);
- break;
- case VIRTIO_PCI_ISR:
- ioport__write8(data, 0x1);
- kvm__irq_line(self, VIRTIO_BLK_IRQ, 0);
- break;
- case VIRTIO_MSI_CONFIG_VECTOR:
- ioport__write16(data, blk_device.config_vector);
- break;
- default:
- return virtio_blk_config_in(data, offset, size, count);
- };
-
- return true;
-}
-
-static bool blk_virtio_request(struct kvm *self, struct virt_queue *queue)
-{
- struct vring_used_elem *used_elem;
- struct virtio_blk_outhdr *req;
- uint16_t desc_block_last;
- struct vring_desc *desc;
- uint16_t desc_status;
- uint16_t desc_block;
- uint32_t block_len;
- uint32_t block_cnt;
- uint16_t desc_hdr;
- uint8_t *status;
- void *block;
- int err;
- int err_cnt;
-
- /* header */
- desc_hdr = virt_queue__pop(queue);
-
- if (desc_hdr >= queue->vring.num) {
- warning("fatal I/O error");
- return false;
- }
-
- desc = virt_queue__get_desc(queue, desc_hdr);
- assert(!(desc->flags & VRING_DESC_F_INDIRECT));
-
- req = guest_flat_to_host(self, desc->addr);
-
- /* status */
- desc_status = desc_hdr;
-
- do {
- desc_block_last = desc_status;
- desc_status = virt_queue__get_desc(queue, desc_status)->next;
-
- if (desc_status >= queue->vring.num) {
- warning("fatal I/O error");
- return false;
- }
-
- desc = virt_queue__get_desc(queue, desc_status);
- assert(!(desc->flags & VRING_DESC_F_INDIRECT));
-
- } while (desc->flags & VRING_DESC_F_NEXT);
-
- status = guest_flat_to_host(self, desc->addr);
-
- /* block */
- desc_block = desc_hdr;
- block_cnt = 0;
- err_cnt = 0;
-
- do {
- desc_block = virt_queue__get_desc(queue, desc_block)->next;
-
- desc = virt_queue__get_desc(queue, desc_block);
- assert(!(desc->flags & VRING_DESC_F_INDIRECT));
-
- block = guest_flat_to_host(self, desc->addr);
- block_len = desc->len;
-
- switch (req->type) {
- case VIRTIO_BLK_T_IN:
- err = disk_image__read_sector(self->disk_image, req->sector, block, block_len);
- break;
- case VIRTIO_BLK_T_OUT:
- err = disk_image__write_sector(self->disk_image, req->sector, block, block_len);
- break;
- default:
- warning("request type %d", req->type);
- err = -1;
- }
-
- if (err)
- err_cnt++;
-
- req->sector += block_len >> SECTOR_SHIFT;
- block_cnt += block_len;
-
- if (desc_block == desc_block_last)
- break;
-
- if (desc_block >= queue->vring.num) {
- warning("fatal I/O error");
- return false;
- }
-
- } while (true);
-
- *status = err_cnt ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
-
- used_elem = virt_queue__get_used_elem(queue);
- used_elem->id = desc_hdr;
- used_elem->len = block_cnt;
-
- return true;
-}
-
-static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
-{
- unsigned long offset;
-
- offset = port - IOPORT_VIRTIO_BLK;
-
- switch (offset) {
- case VIRTIO_PCI_GUEST_FEATURES:
- blk_device.guest_features = ioport__read32(data);
- break;
- case VIRTIO_PCI_QUEUE_PFN: {
- struct virt_queue *queue;
- void *p;
-
- queue = &blk_device.virt_queues[blk_device.queue_selector];
-
- queue->pfn = ioport__read32(data);
-
- p = guest_flat_to_host(self, queue->pfn << 12);
-
- vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, 4096);
-
- break;
- }
- case VIRTIO_PCI_QUEUE_SEL:
- blk_device.queue_selector = ioport__read16(data);
- break;
- case VIRTIO_PCI_QUEUE_NOTIFY: {
- struct virt_queue *queue;
- uint16_t queue_index;
-
- queue_index = ioport__read16(data);
-
- queue = &blk_device.virt_queues[queue_index];
-
- while (queue->vring.avail->idx != queue->last_avail_idx) {
- if (!blk_virtio_request(self, queue))
- return false;
- }
- kvm__irq_line(self, VIRTIO_BLK_IRQ, 1);
-
- break;
- }
- case VIRTIO_PCI_STATUS:
- blk_device.status = ioport__read8(data);
- break;
- case VIRTIO_MSI_CONFIG_VECTOR:
- blk_device.config_vector = VIRTIO_MSI_NO_VECTOR;
- break;
- case VIRTIO_MSI_QUEUE_VECTOR:
- break;
- default:
- return false;
- };
-
- return true;
-}
-
-static struct ioport_operations blk_virtio_io_ops = {
- .io_in = blk_virtio_in,
- .io_out = blk_virtio_out,
-};
-
-#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
-#define PCI_DEVICE_ID_VIRTIO_BLK 0x1001
-#define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4
-#define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002
-
-static struct pci_device_header blk_virtio_pci_device = {
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = PCI_DEVICE_ID_VIRTIO_BLK,
- .header_type = PCI_HEADER_TYPE_NORMAL,
- .revision_id = 0,
- .class = 0x010000,
- .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
- .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK,
- .bar[0] = IOPORT_VIRTIO_BLK | PCI_BASE_ADDRESS_SPACE_IO,
- .irq_pin = 1,
- .irq_line = VIRTIO_BLK_IRQ,
-};
-
-#define PCI_VIRTIO_BLK_DEVNUM 1
-
-void blk_virtio__init(struct kvm *self)
-{
- if (!self->disk_image)
- return;
-
- blk_device.blk_config.capacity = self->disk_image->size / SECTOR_SIZE;
-
- pci__register(&blk_virtio_pci_device, PCI_VIRTIO_BLK_DEVNUM);
-
- ioport__register(IOPORT_VIRTIO_BLK, &blk_virtio_io_ops, IOPORT_VIRTIO_BLK_SIZE);
-}
deleted file mode 100644
@@ -1,218 +0,0 @@
-#include "kvm/console-virtio.h"
-#include "kvm/virtio_pci.h"
-#include "kvm/disk-image.h"
-#include "kvm/virtio.h"
-#include "kvm/ioport.h"
-#include "kvm/util.h"
-#include "kvm/term.h"
-#include "kvm/kvm.h"
-#include "kvm/pci.h"
-
-#include <linux/virtio_console.h>
-#include <linux/virtio_ring.h>
-#include <linux/virtio_blk.h>
-
-#include <sys/uio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <inttypes.h>
-#include <termios.h>
-#include <assert.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#define VIRTIO_CONSOLE_IRQ 14
-#define VIRTIO_CONSOLE_QUEUE_SIZE 128
-#define VIRTIO_CONSOLE_NUM_QUEUES 2
-#define VIRTIO_CONSOLE_RX_QUEUE 0
-#define VIRTIO_CONSOLE_TX_QUEUE 1
-#define PCI_VIRTIO_CONSOLE_DEVNUM 2
-
-struct console_device {
- struct virt_queue vqs[VIRTIO_CONSOLE_NUM_QUEUES];
- struct virtio_console_config console_config;
- uint32_t host_features;
- uint32_t guest_features;
- uint16_t config_vector;
- uint8_t status;
- uint16_t queue_selector;
-};
-
-static struct console_device console_device = {
- .console_config = {
- .cols = 80,
- .rows = 24,
- .max_nr_ports = 1,
- },
-
- .host_features = 0,
-};
-
-/*
- * Interrupts are injected for hvc0 only.
- */
-void virtio_console__inject_interrupt(struct kvm *self)
-{
- struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
- struct virt_queue *vq;
- uint16_t out, in;
- uint16_t head;
- int len;
-
- vq = &console_device.vqs[VIRTIO_CONSOLE_RX_QUEUE];
-
- if (term_readable(CONSOLE_VIRTIO) && virt_queue__available(vq)) {
- head = virt_queue__get_iov(vq, iov, &out, &in, self);
- len = term_getc_iov(CONSOLE_VIRTIO, iov, in);
- virt_queue__set_used_elem(vq, head, len);
- kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 1);
- }
-}
-
-static bool virtio_console_pci_io_device_specific_in(void *data, unsigned long offset, int size, uint32_t count)
-{
- uint8_t *config_space = (uint8_t *) &console_device.console_config;
-
- if (size != 1 || count != 1)
- return false;
-
- if ((offset - VIRTIO_PCI_CONFIG_NOMSI) > sizeof(struct virtio_console_config))
- error("config offset is too big: %li", offset - VIRTIO_PCI_CONFIG_NOMSI);
-
- ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]);
-
- return true;
-}
-
-static bool virtio_console_pci_io_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
-{
- unsigned long offset = port - IOPORT_VIRTIO_CONSOLE;
-
- switch (offset) {
- case VIRTIO_PCI_HOST_FEATURES:
- ioport__write32(data, console_device.host_features);
- break;
- case VIRTIO_PCI_GUEST_FEATURES:
- return false;
- case VIRTIO_PCI_QUEUE_PFN:
- ioport__write32(data, console_device.vqs[console_device.queue_selector].pfn);
- break;
- case VIRTIO_PCI_QUEUE_NUM:
- ioport__write16(data, VIRTIO_CONSOLE_QUEUE_SIZE);
- break;
- case VIRTIO_PCI_QUEUE_SEL:
- case VIRTIO_PCI_QUEUE_NOTIFY:
- return false;
- case VIRTIO_PCI_STATUS:
- ioport__write8(data, console_device.status);
- break;
- case VIRTIO_PCI_ISR:
- ioport__write8(data, 0x1);
- kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 0);
- break;
- case VIRTIO_MSI_CONFIG_VECTOR:
- ioport__write16(data, console_device.config_vector);
- break;
- default:
- return virtio_console_pci_io_device_specific_in(data, offset, size, count);
- };
-
- return true;
-}
-
-static void virtio_console_handle_callback(struct kvm *self, uint16_t queue_index)
-{
- struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
- struct virt_queue *vq;
- uint16_t out, in;
- uint16_t head;
- uint32_t len;
-
- vq = &console_device.vqs[queue_index];
-
- if (queue_index == VIRTIO_CONSOLE_TX_QUEUE) {
-
- while (virt_queue__available(vq)) {
- head = virt_queue__get_iov(vq, iov, &out, &in, self);
- len = term_putc_iov(CONSOLE_VIRTIO, iov, out);
- virt_queue__set_used_elem(vq, head, len);
- }
-
- kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 1);
- }
-}
-
-static bool virtio_console_pci_io_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
-{
- unsigned long offset = port - IOPORT_VIRTIO_CONSOLE;
-
- switch (offset) {
- case VIRTIO_PCI_GUEST_FEATURES:
- console_device.guest_features = ioport__read32(data);
- break;
- case VIRTIO_PCI_QUEUE_PFN: {
- struct virt_queue *queue;
- void *p;
-
- assert(console_device.queue_selector < VIRTIO_CONSOLE_NUM_QUEUES);
-
- queue = &console_device.vqs[console_device.queue_selector];
- queue->pfn = ioport__read32(data);
- p = guest_flat_to_host(self, queue->pfn << 12);
-
- vring_init(&queue->vring, VIRTIO_CONSOLE_QUEUE_SIZE, p, 4096);
-
- break;
- }
- case VIRTIO_PCI_QUEUE_SEL:
- console_device.queue_selector = ioport__read16(data);
- break;
- case VIRTIO_PCI_QUEUE_NOTIFY: {
- uint16_t queue_index;
- queue_index = ioport__read16(data);
- virtio_console_handle_callback(self, queue_index);
- break;
- }
- case VIRTIO_PCI_STATUS:
- console_device.status = ioport__read8(data);
- break;
- case VIRTIO_MSI_CONFIG_VECTOR:
- console_device.config_vector = VIRTIO_MSI_NO_VECTOR;
- break;
- case VIRTIO_MSI_QUEUE_VECTOR:
- break;
- default:
- return false;
- };
-
- return true;
-}
-
-static struct ioport_operations virtio_console_io_ops = {
- .io_in = virtio_console_pci_io_in,
- .io_out = virtio_console_pci_io_out,
-};
-
-#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
-#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1002
-#define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4
-#define PCI_SUBSYSTEM_ID_VIRTIO_CONSOLE 0x0003
-
-static struct pci_device_header virtio_console_pci_device = {
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE,
- .header_type = PCI_HEADER_TYPE_NORMAL,
- .revision_id = 0,
- .class = (0x07 << 8) | (0x80 << 4) | (0x0 << 0),
- .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
- .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_CONSOLE,
- .bar[0] = IOPORT_VIRTIO_CONSOLE | PCI_BASE_ADDRESS_SPACE_IO,
- .irq_pin = 3,
- .irq_line = VIRTIO_CONSOLE_IRQ,
-};
-
-void virtio_console__init(struct kvm *self)
-{
- pci__register(&virtio_console_pci_device, PCI_VIRTIO_CONSOLE_DEVNUM);
- ioport__register(IOPORT_VIRTIO_CONSOLE, &virtio_console_io_ops, IOPORT_VIRTIO_CONSOLE_SIZE);
-}
deleted file mode 100644
@@ -1,8 +0,0 @@
-#ifndef KVM__BLK_VIRTIO_H
-#define KVM__BLK_VIRTIO_H
-
-struct kvm;
-
-void blk_virtio__init(struct kvm *self);
-
-#endif /* KVM__BLK_VIRTIO_H */
deleted file mode 100644
@@ -1,9 +0,0 @@
-#ifndef KVM__CONSOLE_VIRTIO_H
-#define KVM__CONSOLE_VIRTIO_H
-
-struct kvm;
-
-void virtio_console__init(struct kvm *self);
-void virtio_console__inject_interrupt(struct kvm *self);
-
-#endif /* KVM__CONSOLE_VIRTIO_H */
new file mode 100644
@@ -0,0 +1,8 @@
+#ifndef KVM__BLK_VIRTIO_H
+#define KVM__BLK_VIRTIO_H
+
+struct kvm;
+
+void virtio_blk__init(struct kvm *self);
+
+#endif /* KVM__BLK_VIRTIO_H */
new file mode 100644
@@ -0,0 +1,9 @@
+#ifndef KVM__CONSOLE_VIRTIO_H
+#define KVM__CONSOLE_VIRTIO_H
+
+struct kvm;
+
+void virtio_console__init(struct kvm *self);
+void virtio_console__inject_interrupt(struct kvm *self);
+
+#endif /* KVM__CONSOLE_VIRTIO_H */
new file mode 100644
@@ -0,0 +1,59 @@
+/*
+ * Virtio PCI driver
+ *
+ * This module allows virtio devices to be used over a virtual PCI device.
+ * This can be used with QEMU based VMMs like KVM or Xen.
+ *
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ */
+
+#ifndef _LINUX_VIRTIO_PCI_H
+#define _LINUX_VIRTIO_PCI_H
+
+/* A 32-bit r/o bitmask of the features supported by the host */
+#define VIRTIO_PCI_HOST_FEATURES 0
+
+/* A 32-bit r/w bitmask of features activated by the guest */
+#define VIRTIO_PCI_GUEST_FEATURES 4
+
+/* A 32-bit r/w PFN for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_PFN 8
+
+/* A 16-bit r/o queue size for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_NUM 12
+
+/* A 16-bit r/w queue selector */
+#define VIRTIO_PCI_QUEUE_SEL 14
+
+/* A 16-bit r/w queue notifier */
+#define VIRTIO_PCI_QUEUE_NOTIFY 16
+
+/* An 8-bit device status register. */
+#define VIRTIO_PCI_STATUS 18
+
+/* An 8-bit r/o interrupt status register. Reading the value will return the
+ * current contents of the ISR and will also clear it. This is effectively
+ * a read-and-acknowledge. */
+#define VIRTIO_PCI_ISR 19
+
+/* MSI-X registers: only enabled if MSI-X is enabled. */
+/* A 16-bit vector for configuration changes. */
+#define VIRTIO_MSI_CONFIG_VECTOR 20
+
+/* A 16-bit vector for selected queue notifications. */
+#define VIRTIO_MSI_QUEUE_VECTOR 22
+
+/* Vector value used to disable MSI for queue */
+#define VIRTIO_MSI_NO_VECTOR 0xffff
+
+/* Config space size */
+#define VIRTIO_PCI_CONFIG_NOMSI 20
+#define VIRTIO_PCI_CONFIG_MSI 24
+
+#endif /* _LINUX_VIRTIO_PCI_H */
deleted file mode 100644
@@ -1,59 +0,0 @@
-/*
- * Virtio PCI driver
- *
- * This module allows virtio devices to be used over a virtual PCI device.
- * This can be used with QEMU based VMMs like KVM or Xen.
- *
- * Copyright IBM Corp. 2007
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This header is BSD licensed so anyone can use the definitions to implement
- * compatible drivers/servers.
- */
-
-#ifndef _LINUX_VIRTIO_PCI_H
-#define _LINUX_VIRTIO_PCI_H
-
-/* A 32-bit r/o bitmask of the features supported by the host */
-#define VIRTIO_PCI_HOST_FEATURES 0
-
-/* A 32-bit r/w bitmask of features activated by the guest */
-#define VIRTIO_PCI_GUEST_FEATURES 4
-
-/* A 32-bit r/w PFN for the currently selected queue */
-#define VIRTIO_PCI_QUEUE_PFN 8
-
-/* A 16-bit r/o queue size for the currently selected queue */
-#define VIRTIO_PCI_QUEUE_NUM 12
-
-/* A 16-bit r/w queue selector */
-#define VIRTIO_PCI_QUEUE_SEL 14
-
-/* A 16-bit r/w queue notifier */
-#define VIRTIO_PCI_QUEUE_NOTIFY 16
-
-/* An 8-bit device status register. */
-#define VIRTIO_PCI_STATUS 18
-
-/* An 8-bit r/o interrupt status register. Reading the value will return the
- * current contents of the ISR and will also clear it. This is effectively
- * a read-and-acknowledge. */
-#define VIRTIO_PCI_ISR 19
-
-/* MSI-X registers: only enabled if MSI-X is enabled. */
-/* A 16-bit vector for configuration changes. */
-#define VIRTIO_MSI_CONFIG_VECTOR 20
-
-/* A 16-bit vector for selected queue notifications. */
-#define VIRTIO_MSI_QUEUE_VECTOR 22
-
-/* Vector value used to disable MSI for queue */
-#define VIRTIO_MSI_NO_VECTOR 0xffff
-
-/* Config space size */
-#define VIRTIO_PCI_CONFIG_NOMSI 20
-#define VIRTIO_PCI_CONFIG_MSI 24
-
-#endif /* _LINUX_VIRTIO_PCI_H */
@@ -1,8 +1,8 @@
#include "kvm/kvm.h"
#include "kvm/8250-serial.h"
-#include "kvm/blk-virtio.h"
-#include "kvm/console-virtio.h"
+#include "kvm/virtio-blk.h"
+#include "kvm/virtio-console.h"
#include "kvm/disk-image.h"
#include "kvm/util.h"
#include "kvm/pci.h"
@@ -145,7 +145,7 @@ int main(int argc, char *argv[])
pci__init();
- blk_virtio__init(kvm);
+ virtio_blk__init(kvm);
virtio_console__init(kvm);
new file mode 100644
@@ -0,0 +1,293 @@
+#include "kvm/virtio-blk.h"
+
+#include "kvm/virtio-pci.h"
+
+#include "kvm/disk-image.h"
+#include "kvm/virtio.h"
+#include "kvm/ioport.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_blk.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#define VIRTIO_BLK_IRQ 14
+
+#define NUM_VIRT_QUEUES 1
+
+#define VIRTIO_BLK_QUEUE_SIZE 128
+
+struct blk_device {
+ struct virtio_blk_config blk_config;
+ uint32_t host_features;
+ uint32_t guest_features;
+ uint16_t config_vector;
+ uint8_t status;
+
+ /* virtio queue */
+ uint16_t queue_selector;
+
+ struct virt_queue virt_queues[NUM_VIRT_QUEUES];
+};
+
+#define DISK_SEG_MAX 126
+
+static struct blk_device blk_device = {
+ .blk_config = (struct virtio_blk_config) {
+ /* VIRTIO_BLK_F_SEG_MAX */
+ .seg_max = DISK_SEG_MAX,
+ },
+ /*
+ * Note we don't set VIRTIO_BLK_F_GEOMETRY here so the
+ * node kernel will compute disk geometry by own, the
+ * same applies to VIRTIO_BLK_F_BLK_SIZE
+ */
+ .host_features = (1UL << VIRTIO_BLK_F_SEG_MAX),
+};
+
+static bool virtio_blk_pci_io_device_specific_in(void *data, unsigned long offset, int size, uint32_t count)
+{
+ uint8_t *config_space = (uint8_t *) &blk_device.blk_config;
+
+ if (size != 1 || count != 1)
+ return false;
+
+ ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]);
+
+ return true;
+}
+
+static bool virtio_blk_pci_io_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
+{
+ unsigned long offset;
+
+ offset = port - IOPORT_VIRTIO_BLK;
+
+ switch (offset) {
+ case VIRTIO_PCI_HOST_FEATURES:
+ ioport__write32(data, blk_device.host_features);
+ break;
+ case VIRTIO_PCI_GUEST_FEATURES:
+ return false;
+ case VIRTIO_PCI_QUEUE_PFN:
+ ioport__write32(data, blk_device.virt_queues[blk_device.queue_selector].pfn);
+ break;
+ case VIRTIO_PCI_QUEUE_NUM:
+ ioport__write16(data, VIRTIO_BLK_QUEUE_SIZE);
+ break;
+ case VIRTIO_PCI_QUEUE_SEL:
+ case VIRTIO_PCI_QUEUE_NOTIFY:
+ return false;
+ case VIRTIO_PCI_STATUS:
+ ioport__write8(data, blk_device.status);
+ break;
+ case VIRTIO_PCI_ISR:
+ ioport__write8(data, 0x1);
+ kvm__irq_line(self, VIRTIO_BLK_IRQ, 0);
+ break;
+ case VIRTIO_MSI_CONFIG_VECTOR:
+ ioport__write16(data, blk_device.config_vector);
+ break;
+ default:
+ return virtio_blk_pci_io_device_specific_in(data, offset, size, count);
+ };
+
+ return true;
+}
+
+static bool virtio_blk_request(struct kvm *self, struct virt_queue *queue)
+{
+ struct vring_used_elem *used_elem;
+ struct virtio_blk_outhdr *req;
+ uint16_t desc_block_last;
+ struct vring_desc *desc;
+ uint16_t desc_status;
+ uint16_t desc_block;
+ uint32_t block_len;
+ uint32_t block_cnt;
+ uint16_t desc_hdr;
+ uint8_t *status;
+ void *block;
+ int err;
+ int err_cnt;
+
+ /* header */
+ desc_hdr = virt_queue__pop(queue);
+
+ if (desc_hdr >= queue->vring.num) {
+ warning("fatal I/O error");
+ return false;
+ }
+
+ desc = virt_queue__get_desc(queue, desc_hdr);
+ assert(!(desc->flags & VRING_DESC_F_INDIRECT));
+
+ req = guest_flat_to_host(self, desc->addr);
+
+ /* status */
+ desc_status = desc_hdr;
+
+ do {
+ desc_block_last = desc_status;
+ desc_status = virt_queue__get_desc(queue, desc_status)->next;
+
+ if (desc_status >= queue->vring.num) {
+ warning("fatal I/O error");
+ return false;
+ }
+
+ desc = virt_queue__get_desc(queue, desc_status);
+ assert(!(desc->flags & VRING_DESC_F_INDIRECT));
+
+ } while (desc->flags & VRING_DESC_F_NEXT);
+
+ status = guest_flat_to_host(self, desc->addr);
+
+ /* block */
+ desc_block = desc_hdr;
+ block_cnt = 0;
+ err_cnt = 0;
+
+ do {
+ desc_block = virt_queue__get_desc(queue, desc_block)->next;
+
+ desc = virt_queue__get_desc(queue, desc_block);
+ assert(!(desc->flags & VRING_DESC_F_INDIRECT));
+
+ block = guest_flat_to_host(self, desc->addr);
+ block_len = desc->len;
+
+ switch (req->type) {
+ case VIRTIO_BLK_T_IN:
+ err = disk_image__read_sector(self->disk_image, req->sector, block, block_len);
+ break;
+ case VIRTIO_BLK_T_OUT:
+ err = disk_image__write_sector(self->disk_image, req->sector, block, block_len);
+ break;
+ default:
+ warning("request type %d", req->type);
+ err = -1;
+ }
+
+ if (err)
+ err_cnt++;
+
+ req->sector += block_len >> SECTOR_SHIFT;
+ block_cnt += block_len;
+
+ if (desc_block == desc_block_last)
+ break;
+
+ if (desc_block >= queue->vring.num) {
+ warning("fatal I/O error");
+ return false;
+ }
+
+ } while (true);
+
+ *status = err_cnt ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
+
+ used_elem = virt_queue__get_used_elem(queue);
+ used_elem->id = desc_hdr;
+ used_elem->len = block_cnt;
+
+ return true;
+}
+
+static bool virtio_blk_pci_io_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
+{
+ unsigned long offset;
+
+ offset = port - IOPORT_VIRTIO_BLK;
+
+ switch (offset) {
+ case VIRTIO_PCI_GUEST_FEATURES:
+ blk_device.guest_features = ioport__read32(data);
+ break;
+ case VIRTIO_PCI_QUEUE_PFN: {
+ struct virt_queue *queue;
+ void *p;
+
+ queue = &blk_device.virt_queues[blk_device.queue_selector];
+
+ queue->pfn = ioport__read32(data);
+
+ p = guest_flat_to_host(self, queue->pfn << 12);
+
+ vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, 4096);
+
+ break;
+ }
+ case VIRTIO_PCI_QUEUE_SEL:
+ blk_device.queue_selector = ioport__read16(data);
+ break;
+ case VIRTIO_PCI_QUEUE_NOTIFY: {
+ struct virt_queue *queue;
+ uint16_t queue_index;
+
+ queue_index = ioport__read16(data);
+
+ queue = &blk_device.virt_queues[queue_index];
+
+ while (queue->vring.avail->idx != queue->last_avail_idx) {
+ if (!virtio_blk_request(self, queue))
+ return false;
+ }
+ kvm__irq_line(self, VIRTIO_BLK_IRQ, 1);
+
+ break;
+ }
+ case VIRTIO_PCI_STATUS:
+ blk_device.status = ioport__read8(data);
+ break;
+ case VIRTIO_MSI_CONFIG_VECTOR:
+ blk_device.config_vector = VIRTIO_MSI_NO_VECTOR;
+ break;
+ case VIRTIO_MSI_QUEUE_VECTOR:
+ break;
+ default:
+ return false;
+ };
+
+ return true;
+}
+
+static struct ioport_operations virtio_blk_io_ops = {
+ .io_in = virtio_blk_pci_io_in,
+ .io_out = virtio_blk_pci_io_out,
+};
+
+#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_DEVICE_ID_VIRTIO_BLK 0x1001
+#define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002
+
+static struct pci_device_header virtio_blk_pci_device = {
+ .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+ .device_id = PCI_DEVICE_ID_VIRTIO_BLK,
+ .header_type = PCI_HEADER_TYPE_NORMAL,
+ .revision_id = 0,
+ .class = 0x010000,
+ .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
+ .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK,
+ .bar[0] = IOPORT_VIRTIO_BLK | PCI_BASE_ADDRESS_SPACE_IO,
+ .irq_pin = 1,
+ .irq_line = VIRTIO_BLK_IRQ,
+};
+
+#define PCI_VIRTIO_BLK_DEVNUM 1
+
+void virtio_blk__init(struct kvm *self)
+{
+ if (!self->disk_image)
+ return;
+
+ blk_device.blk_config.capacity = self->disk_image->size / SECTOR_SIZE;
+
+ pci__register(&virtio_blk_pci_device, PCI_VIRTIO_BLK_DEVNUM);
+
+ ioport__register(IOPORT_VIRTIO_BLK, &virtio_blk_io_ops, IOPORT_VIRTIO_BLK_SIZE);
+}
new file mode 100644
@@ -0,0 +1,218 @@
+#include "kvm/virtio-console.h"
+#include "kvm/virtio-pci.h"
+#include "kvm/disk-image.h"
+#include "kvm/virtio.h"
+#include "kvm/ioport.h"
+#include "kvm/util.h"
+#include "kvm/term.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+
+#include <linux/virtio_console.h>
+#include <linux/virtio_ring.h>
+#include <linux/virtio_blk.h>
+
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+#include <termios.h>
+#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define VIRTIO_CONSOLE_IRQ 14
+#define VIRTIO_CONSOLE_QUEUE_SIZE 128
+#define VIRTIO_CONSOLE_NUM_QUEUES 2
+#define VIRTIO_CONSOLE_RX_QUEUE 0
+#define VIRTIO_CONSOLE_TX_QUEUE 1
+#define PCI_VIRTIO_CONSOLE_DEVNUM 2
+
+struct console_device {
+ struct virt_queue vqs[VIRTIO_CONSOLE_NUM_QUEUES];
+ struct virtio_console_config console_config;
+ uint32_t host_features;
+ uint32_t guest_features;
+ uint16_t config_vector;
+ uint8_t status;
+ uint16_t queue_selector;
+};
+
+static struct console_device console_device = {
+ .console_config = {
+ .cols = 80,
+ .rows = 24,
+ .max_nr_ports = 1,
+ },
+
+ .host_features = 0,
+};
+
+/*
+ * Interrupts are injected for hvc0 only.
+ */
+void virtio_console__inject_interrupt(struct kvm *self)
+{
+ struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
+ struct virt_queue *vq;
+ uint16_t out, in;
+ uint16_t head;
+ int len;
+
+ vq = &console_device.vqs[VIRTIO_CONSOLE_RX_QUEUE];
+
+ if (term_readable(CONSOLE_VIRTIO) && virt_queue__available(vq)) {
+ head = virt_queue__get_iov(vq, iov, &out, &in, self);
+ len = term_getc_iov(CONSOLE_VIRTIO, iov, in);
+ virt_queue__set_used_elem(vq, head, len);
+ kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 1);
+ }
+}
+
+static bool virtio_console_pci_io_device_specific_in(void *data, unsigned long offset, int size, uint32_t count)
+{
+ uint8_t *config_space = (uint8_t *) &console_device.console_config;
+
+ if (size != 1 || count != 1)
+ return false;
+
+ if ((offset - VIRTIO_PCI_CONFIG_NOMSI) > sizeof(struct virtio_console_config))
+ error("config offset is too big: %li", offset - VIRTIO_PCI_CONFIG_NOMSI);
+
+ ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]);
+
+ return true;
+}
+
+static bool virtio_console_pci_io_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
+{
+ unsigned long offset = port - IOPORT_VIRTIO_CONSOLE;
+
+ switch (offset) {
+ case VIRTIO_PCI_HOST_FEATURES:
+ ioport__write32(data, console_device.host_features);
+ break;
+ case VIRTIO_PCI_GUEST_FEATURES:
+ return false;
+ case VIRTIO_PCI_QUEUE_PFN:
+ ioport__write32(data, console_device.vqs[console_device.queue_selector].pfn);
+ break;
+ case VIRTIO_PCI_QUEUE_NUM:
+ ioport__write16(data, VIRTIO_CONSOLE_QUEUE_SIZE);
+ break;
+ case VIRTIO_PCI_QUEUE_SEL:
+ case VIRTIO_PCI_QUEUE_NOTIFY:
+ return false;
+ case VIRTIO_PCI_STATUS:
+ ioport__write8(data, console_device.status);
+ break;
+ case VIRTIO_PCI_ISR:
+ ioport__write8(data, 0x1);
+ kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 0);
+ break;
+ case VIRTIO_MSI_CONFIG_VECTOR:
+ ioport__write16(data, console_device.config_vector);
+ break;
+ default:
+ return virtio_console_pci_io_device_specific_in(data, offset, size, count);
+ };
+
+ return true;
+}
+
+static void virtio_console_handle_callback(struct kvm *self, uint16_t queue_index)
+{
+ struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
+ struct virt_queue *vq;
+ uint16_t out, in;
+ uint16_t head;
+ uint32_t len;
+
+ vq = &console_device.vqs[queue_index];
+
+ if (queue_index == VIRTIO_CONSOLE_TX_QUEUE) {
+
+ while (virt_queue__available(vq)) {
+ head = virt_queue__get_iov(vq, iov, &out, &in, self);
+ len = term_putc_iov(CONSOLE_VIRTIO, iov, out);
+ virt_queue__set_used_elem(vq, head, len);
+ }
+
+ kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 1);
+ }
+}
+
+static bool virtio_console_pci_io_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
+{
+ unsigned long offset = port - IOPORT_VIRTIO_CONSOLE;
+
+ switch (offset) {
+ case VIRTIO_PCI_GUEST_FEATURES:
+ console_device.guest_features = ioport__read32(data);
+ break;
+ case VIRTIO_PCI_QUEUE_PFN: {
+ struct virt_queue *queue;
+ void *p;
+
+ assert(console_device.queue_selector < VIRTIO_CONSOLE_NUM_QUEUES);
+
+ queue = &console_device.vqs[console_device.queue_selector];
+ queue->pfn = ioport__read32(data);
+ p = guest_flat_to_host(self, queue->pfn << 12);
+
+ vring_init(&queue->vring, VIRTIO_CONSOLE_QUEUE_SIZE, p, 4096);
+
+ break;
+ }
+ case VIRTIO_PCI_QUEUE_SEL:
+ console_device.queue_selector = ioport__read16(data);
+ break;
+ case VIRTIO_PCI_QUEUE_NOTIFY: {
+ uint16_t queue_index;
+ queue_index = ioport__read16(data);
+ virtio_console_handle_callback(self, queue_index);
+ break;
+ }
+ case VIRTIO_PCI_STATUS:
+ console_device.status = ioport__read8(data);
+ break;
+ case VIRTIO_MSI_CONFIG_VECTOR:
+ console_device.config_vector = VIRTIO_MSI_NO_VECTOR;
+ break;
+ case VIRTIO_MSI_QUEUE_VECTOR:
+ break;
+ default:
+ return false;
+ };
+
+ return true;
+}
+
+static struct ioport_operations virtio_console_io_ops = {
+ .io_in = virtio_console_pci_io_in,
+ .io_out = virtio_console_pci_io_out,
+};
+
+#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1002
+#define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_SUBSYSTEM_ID_VIRTIO_CONSOLE 0x0003
+
+static struct pci_device_header virtio_console_pci_device = {
+ .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
+ .device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE,
+ .header_type = PCI_HEADER_TYPE_NORMAL,
+ .revision_id = 0,
+ .class = (0x07 << 8) | (0x80 << 4) | (0x0 << 0),
+ .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
+ .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_CONSOLE,
+ .bar[0] = IOPORT_VIRTIO_CONSOLE | PCI_BASE_ADDRESS_SPACE_IO,
+ .irq_pin = 3,
+ .irq_line = VIRTIO_CONSOLE_IRQ,
+};
+
+void virtio_console__init(struct kvm *self)
+{
+ pci__register(&virtio_console_pci_device, PCI_VIRTIO_CONSOLE_DEVNUM);
+ ioport__register(IOPORT_VIRTIO_CONSOLE, &virtio_console_io_ops, IOPORT_VIRTIO_CONSOLE_SIZE);
+}
- rename {blk,console}-virtio.* to virtio-{blk,console}.* - change the virtio block device PCI io space operation callback names Signed-off-by: Asias He <asias.hejun@gmail.com> --- tools/kvm/Makefile | 4 +- tools/kvm/blk-virtio.c | 293 -------------------------------- tools/kvm/console-virtio.c | 218 ------------------------ tools/kvm/include/kvm/blk-virtio.h | 8 - tools/kvm/include/kvm/console-virtio.h | 9 - tools/kvm/include/kvm/virtio-blk.h | 8 + tools/kvm/include/kvm/virtio-console.h | 9 + tools/kvm/include/kvm/virtio-pci.h | 59 +++++++ tools/kvm/include/kvm/virtio_pci.h | 59 ------- tools/kvm/main.c | 6 +- tools/kvm/virtio-blk.c | 293 ++++++++++++++++++++++++++++++++ tools/kvm/virtio-console.c | 218 ++++++++++++++++++++++++ 12 files changed, 592 insertions(+), 592 deletions(-) delete mode 100644 tools/kvm/blk-virtio.c delete mode 100644 tools/kvm/console-virtio.c delete mode 100644 tools/kvm/include/kvm/blk-virtio.h delete mode 100644 tools/kvm/include/kvm/console-virtio.h create mode 100644 tools/kvm/include/kvm/virtio-blk.h create mode 100644 tools/kvm/include/kvm/virtio-console.h create mode 100644 tools/kvm/include/kvm/virtio-pci.h delete mode 100644 tools/kvm/include/kvm/virtio_pci.h create mode 100644 tools/kvm/virtio-blk.c create mode 100644 tools/kvm/virtio-console.c