#include <palacios/vmm.h>
-#include <devices/lnx_virtio.h>
-#include <devices/pci.h>
+#include <devices/lnx_virtio_pci.h>
+
+#include <devices/pci.h>
struct blk_config {
uint8_t sectors;
} __attribute__((packed));
-struct blk_state {
- struct blk_config cfg;
+
+
+/* Host Feature flags */
+#define VIRTIO_BARRIER 0x01 /* Does host support barriers? */
+#define VIRTIO_SIZE_MAX 0x02 /* Indicates maximum segment size */
+#define VIRTIO_SEG_MAX 0x04 /* Indicates maximum # of segments */
+#define VIRTIO_LEGACY_GEOM 0x10 /* Indicates support of legacy geometry */
+
+
+
+struct virtio_blk_state {
+ struct blk_config block_cfg;
+ struct virtio_config virtio_cfg;
struct vm_device * pci_bus;
+ struct pci_device * pci_dev;
+
+ struct virtio_device * virtio_dev; // the virtio device struction for _this_ device
+
+
+ int io_range_size;
};
-static int virtio_pci_write(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
- return -1;
+
+static int virtio_io_write(uint16_t port, void * src, uint_t length, struct vm_device * dev) {
+ struct virtio_device * virtio_dev = find_virtio_dev(dev);
+ int port_idx = port % virtio->io_range_size;
+ uint8_t * cfg_ptr = (uint8_t *)cfg;
+
+ PrintDebug("VIRTIO BLOCK Write for port %d (index=%d) len=%d, value=%x\n",
+ port, port_idx, length, *(uint32_t *)src);
+
+
+
+ switch (port_index) {
+ case VRING_Q_NOTIFY_PORT:
+ // handle output
+ PrintError("Notification\n");
+ return -1;
+ break;
+ case VRING_STATUS_PORT:
+ if (cfg->status == 0) {
+ PrintDebug("Resetting device\n");
+ return -1;
+ //reset
+ }
+ break;
+ default:
+ return -1;
+ break;
+ }
+
+
+
+
+ return length;
}
-static int virtio_pci_read(uint16_t port, void * dst, uint_t length, struct vm_device * dev) {
+static int virtio_io_read(uint16_t port, void * dst, uint_t length, struct vm_device * dev) {
+ struct blk_state * virtio = (struct blk_state *)dev->private_data;
+ int port_idx = port % virtio->io_range_size;
+ uint8_t * cfg_ptr = (uint8_t *)cfg;
+
+ PrintDebug("VIRTIO BLOCK Read for port %d (index =%d), length=%d\n",
+ port, port_idx, length);
+
+ switch (port_idx) {
+ // search for device....
+ // call and return dev config read
+ default:
+ return -1;
+ }
+
+
+ return length;
+}
+
+struct v3_dev_ops = {
+ .free = virtio_free,
+ .reset = NULL,
+ .stop = NULL,
+ .start = NULL
+};
+
+
+static int virtio_free(struct vm_device * dev) {
return -1;
}
-static int virtio_init(struct vm_device * dev) {
- struct blk_state * virtio = (struct blk_state *)(dev->private_data);
+
+
+
+static struct v3_device_ops dev_ops = {
+ .free = virtio_free,
+ .reset = NULL,
+ .start = NULL,
+ .stop = NULL,
+};
+
+
+
+
+
+
+static int virtio_init(struct guest_info * vm, void * cfg_data) {
+ struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
+ struct virtio_blk_state * virtio_state = NULL;
+ struct pci_device * pci_dev = NULL;
PrintDebug("Initializing VIRTIO Block device\n");
- if (virtio->pci_bus != NULL) {
+ if (pci_bus == NULL) {
+ PrintError("VirtIO devices require a PCI Bus");
+ return -1;
+ }
+
+
+ virtio_state = (struct virtio_blk_state *)V3_Malloc(sizeof(struct virtio_blk_state));
+ memset(virtio_state, 0, sizeof(struct virtio_blk_state));
+
+
+ struct vm_device * dev = v3_allocate_device("LNX_VIRTIO_BLK", &dev_ops, virtio_state);
+ if (v3_attach_device(vm, dev) == -1) {
+ PrintError("Could not attach device %s\n", "LNX_VIRTIO_BLK");
+ return -1;
+ }
+
+
+ // PCI initialization
+ {
struct v3_pci_bar bars[6];
- struct pci_device * pci_dev = NULL;
- int i;
- int num_ports_pow2 = 1;
int num_ports = sizeof(struct virtio_config) + sizeof(struct blk_config);
-
+ int tmp_ports = num_ports;
+ int i;
+
+
// This gets the number of ports, rounded up to a power of 2
- while (num_ports > 0) {
- num_ports >>= 1;
- num_ports_pow2 <<= 1;
+ virtio_state->io_range_size = 1; // must be a power of 2
+
+ while (tmp_ports > 0) {
+ tmp_ports >>= 1;
+ virtio_state->io_range_size <<= 1;
}
- // reset num_ports
- num_ports = sizeof(struct virtio_config) + sizeof(struct blk_config);
-
- if (num_ports & ((num_ports_pow2 >> 1) - 1)) {
- num_ports_pow2 >>= 1;
+ // this is to account for any low order bits being set in num_ports
+ // if there are none, then num_ports was already a power of 2 so we shift right to reset it
+ if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
+ virtio_state->io_range_size >>= 1;
}
bars[0].type = PCI_BAR_IO;
bars[0].default_base_port = -1;
- bars[0].num_ports = num_ports_pow2;
+ bars[0].num_ports = virtio_state->io_range_size;
- bars[0].io_read = virtio_pci_read;
- bars[0].io_write = virtio_pci_write;
+ bars[0].io_read = virtio_io_read;
+ bars[0].io_write = virtio_io_write;
- pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE,
+ pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE,
0, PCI_AUTO_DEV_NUM, 0,
- "VIRTIO-BLK", bars,
+ "LNX_VIRTIO_BLK", bars,
NULL, NULL, NULL, dev);
if (!pci_dev) {
}
pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
+ pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
+
+
pci_dev->config_header.device_id = VIRTIO_BLOCK_DEV_ID;
pci_dev->config_header.class = PCI_CLASS_STORAGE;
pci_dev->config_header.subclass = PCI_STORAGE_SUBCLASS_OTHER;
-
- pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
+
pci_dev->config_header.subsystem_id = VIRTIO_BLOCK_SUBDEVICE_ID;
- pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
- }
-
-
-
- return -1;
-}
-
-static int virtio_deinit(struct vm_device * dev) {
- return -1;
-}
-
-
-
-static struct vm_device_ops dev_ops = {
- .init = virtio_init,
- .deinit = virtio_deinit,
- .reset = NULL,
- .start = NULL,
- .stop = NULL,
-};
+ pci_dev->config_header.intr_pin = 1;
+ pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
-struct vm_device * v3_create_virtio(struct vm_device * pci_bus) {
- struct blk_state * virtio = NULL;
- PrintDebug("Creating VirtIO Block device\n");
+ virtio_state->pci_dev = pci_dev;
+ virtio_state->pci_bus = pci_bus;
- if (pci_bus == NULL) {
- PrintError("VirtIO requires a PCI bus\n");
- return NULL;
+ /* Block configuration */
}
+
+ return 0;
+}
- virtio = (struct blk_state *)V3_Malloc(sizeof(struct blk_state));
-
- virtio->pci_bus = pci_bus;
-
- return v3_create_device("VIRTIO_BLK", &dev_ops, virtio);
-}
+device_register("LNX_VIRTIO_BLK", virtio_init)