#include <palacios/vmm.h>
#include <palacios/vmm_dev_mgr.h>
#include <devices/lnx_virtio_pci.h>
-#include <devices/lnx_virtio_blk.h>
-#include <devices/block_dev.h>
#include <palacios/vm_guest_mem.h>
#include <devices/pci.h>
#endif
+#define SECTOR_SIZE 512
+
#define BLK_CAPACITY_PORT 20
#define BLK_MAX_SIZE_PORT 28
#define BLK_MAX_SEG_PORT 32
struct virtio_dev_state {
struct vm_device * pci_bus;
struct list_head dev_list;
- struct guest_info * vm;
};
struct virtio_blk_state {
struct virtio_queue queue;
- union {
- struct v3_cd_ops * cd_ops;
- struct v3_hd_ops * hd_ops;
- };
+ struct v3_dev_blk_ops * ops;
- v3_block_type_t block_type;
void * backend_data;
int io_range_size;
};
-static int virtio_free(struct vm_device * dev) {
- return -1;
-}
+
static int blk_reset(struct virtio_blk_state * virtio) {
}
-static int virtio_reset(struct vm_device * dev) {
- struct virtio_dev_state * dev_state = (struct virtio_dev_state *)(dev->private_data);
- struct virtio_blk_state * blk_state = NULL;
-
- list_for_each_entry(blk_state, &(dev_state->dev_list), dev_link) {
- blk_reset(blk_state);
- }
- return 0;
-}
-static int handle_read_op(struct virtio_blk_state * blk_state, uint8_t * buf, uint64_t * sector, uint32_t len) {
+static int handle_read_op(struct virtio_blk_state * blk_state, uint8_t * buf, uint64_t * sector, uint64_t len) {
int ret = -1;
- if (blk_state->block_type == BLOCK_DISK) {
- if (len % HD_SECTOR_SIZE) {
- PrintError("Write of something that is not a sector len %d, mod=%d\n", len, len % HD_SECTOR_SIZE);
- return -1;
- }
-
-
- PrintDebug("Reading Disk\n");
-
- ret = blk_state->hd_ops->read(buf, len / HD_SECTOR_SIZE, *sector, blk_state->backend_data);
-
- *sector += len / HD_SECTOR_SIZE;
-
- } else if (blk_state->block_type == BLOCK_CDROM) {
- if (len % ATAPI_BLOCK_SIZE) {
- PrintError("Write of something that is not an ATAPI block len %d, mod=%d\n", len, len % ATAPI_BLOCK_SIZE);
- return -1;
- }
-
- ret = blk_state->cd_ops->read(buf, len / ATAPI_BLOCK_SIZE, *sector , blk_state->backend_data);
-
- *sector += len / ATAPI_BLOCK_SIZE;
- }
+ PrintDebug("Reading Disk\n");
+ ret = blk_state->ops->read(buf, (*sector) * SECTOR_SIZE, len, (void *)(blk_state->backend_data));
+ *sector += (len / SECTOR_SIZE);
return ret;
}
-static int handle_write_op(struct virtio_blk_state * blk_state, uint8_t * buf, uint64_t * sector, uint32_t len) {
+static int handle_write_op(struct virtio_blk_state * blk_state, uint8_t * buf, uint64_t * sector, uint64_t len) {
int ret = -1;
- if (blk_state->block_type == BLOCK_DISK) {
- if (len % HD_SECTOR_SIZE) {
- PrintError("Write of something that is not a sector len %d, mod=%d\n", len, len % HD_SECTOR_SIZE);
- return -1;
- }
-
- PrintDebug("Writing Disk\n");
-
- ret = blk_state->hd_ops->write(buf, len / HD_SECTOR_SIZE, *sector, blk_state->backend_data);
-
- *sector += len / HD_SECTOR_SIZE;
- }
+ PrintDebug("Writing Disk\n");
+ ret = blk_state->ops->write(buf, (*sector) * SECTOR_SIZE, len, (void *)(blk_state->backend_data));
+ *sector += (len / SECTOR_SIZE);
return ret;
}
// multiple block operations need to increment the sector
-static int handle_block_op(struct virtio_blk_state * blk_state, struct blk_op_hdr * hdr,
+static int handle_block_op(struct guest_info * core, struct virtio_blk_state * blk_state, struct blk_op_hdr * hdr,
struct vring_desc * buf_desc, uint8_t * status) {
uint8_t * buf = NULL;
PrintDebug("Handling Block op\n");
-
-
-
- if (guest_pa_to_host_va(blk_state->virtio_dev->vm, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
+ if (v3_gpa_to_hva(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
PrintError("Could not translate buffer address\n");
return -1;
}
-
PrintDebug("Sector=%p Length=%d\n", (void *)(addr_t)(hdr->sector), buf_desc->length);
if (hdr->type == BLK_IN_REQ) {
- if (blk_state->block_type != BLOCK_NONE) {
- if (handle_read_op(blk_state, buf, &(hdr->sector), buf_desc->length) == -1) {
- *status = BLK_STATUS_ERR;
- return -1;
- } else {
- *status = BLK_STATUS_OK;
- }
+ if (handle_read_op(blk_state, buf, &(hdr->sector), buf_desc->length) == -1) {
+ *status = BLK_STATUS_ERR;
+ return -1;
} else {
- *status = BLK_STATUS_NOT_SUPPORTED;
+ *status = BLK_STATUS_OK;
}
-
} else if (hdr->type == BLK_OUT_REQ) {
- if (blk_state->block_type == BLOCK_DISK) {
- if (handle_write_op(blk_state, buf, &(hdr->sector), buf_desc->length) == -1) {
- *status = BLK_STATUS_ERR;
- return -1;
- } else {
- *status = BLK_STATUS_OK;
- }
-
+ if (handle_write_op(blk_state, buf, &(hdr->sector), buf_desc->length) == -1) {
+ *status = BLK_STATUS_ERR;
+ return -1;
} else {
- *status = BLK_STATUS_NOT_SUPPORTED;
+ *status = BLK_STATUS_OK;
}
-
} else if (hdr->type == BLK_SCSI_CMD) {
PrintError("VIRTIO: SCSI Command Not supported!!!\n");
*status = BLK_STATUS_NOT_SUPPORTED;
return -1;
}
-
-
PrintDebug("Returning Status: %d\n", *status);
return 0;
-static int handle_kick(struct virtio_blk_state * blk_state) {
+static int handle_kick(struct guest_info * core, struct virtio_blk_state * blk_state) {
struct virtio_queue * q = &(blk_state->queue);
PrintDebug("VIRTIO KICK: cur_index=%d (mod=%d), avail_index=%d\n",
q->cur_avail_idx, q->cur_avail_idx % QUEUE_SIZE, q->avail->index);
- while (q->cur_avail_idx < q->avail->index) {
+ while (q->cur_avail_idx != q->avail->index) {
struct vring_desc * hdr_desc = NULL;
struct vring_desc * buf_desc = NULL;
struct vring_desc * status_desc = NULL;
PrintDebug("Header Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", hdr_desc,
(void *)(hdr_desc->addr_gpa), hdr_desc->length, hdr_desc->flags, hdr_desc->next);
- if (guest_pa_to_host_va(blk_state->virtio_dev->vm, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
+ if (v3_gpa_to_hva(core, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
PrintError("Could not translate block header address\n");
return -1;
}
PrintDebug("Buffer Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", buf_desc,
(void *)(buf_desc->addr_gpa), buf_desc->length, buf_desc->flags, buf_desc->next);
- if (handle_block_op(blk_state, &hdr, buf_desc, &tmp_status) == -1) {
+ if (handle_block_op(core, blk_state, &hdr, buf_desc, &tmp_status) == -1) {
PrintError("Error handling block operation\n");
return -1;
}
PrintDebug("Status Descriptor (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n", status_desc,
(void *)(status_desc->addr_gpa), status_desc->length, status_desc->flags, status_desc->next);
- if (guest_pa_to_host_va(blk_state->virtio_dev->vm, status_desc->addr_gpa, (addr_t *)&(status_ptr)) == -1) {
+ if (v3_gpa_to_hva(core, status_desc->addr_gpa, (addr_t *)&(status_ptr)) == -1) {
PrintError("Could not translate status address\n");
return -1;
}
return 0;
}
-static int virtio_io_write(uint16_t port, void * src, uint_t length, void * private_data) {
+static int virtio_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * private_data) {
struct virtio_blk_state * blk_state = (struct virtio_blk_state *)private_data;
int port_idx = port % blk_state->io_range_size;
// round up to next page boundary.
blk_state->queue.ring_used_addr = (blk_state->queue.ring_used_addr + 0xfff) & ~0xfff;
- if (guest_pa_to_host_va(blk_state->virtio_dev->vm, blk_state->queue.ring_desc_addr, (addr_t *)&(blk_state->queue.desc)) == -1) {
+ if (v3_gpa_to_hva(core, blk_state->queue.ring_desc_addr, (addr_t *)&(blk_state->queue.desc)) == -1) {
PrintError("Could not translate ring descriptor address\n");
return -1;
}
- if (guest_pa_to_host_va(blk_state->virtio_dev->vm, blk_state->queue.ring_avail_addr, (addr_t *)&(blk_state->queue.avail)) == -1) {
+ if (v3_gpa_to_hva(core, blk_state->queue.ring_avail_addr, (addr_t *)&(blk_state->queue.avail)) == -1) {
PrintError("Could not translate ring available address\n");
return -1;
}
- if (guest_pa_to_host_va(blk_state->virtio_dev->vm, blk_state->queue.ring_used_addr, (addr_t *)&(blk_state->queue.used)) == -1) {
+ if (v3_gpa_to_hva(core, blk_state->queue.ring_used_addr, (addr_t *)&(blk_state->queue.used)) == -1) {
PrintError("Could not translate ring used address\n");
return -1;
}
break;
case VRING_Q_NOTIFY_PORT:
PrintDebug("Handling Kick\n");
- if (handle_kick(blk_state) == -1) {
+ if (handle_kick(core, blk_state) == -1) {
PrintError("Could not handle Block Notification\n");
return -1;
}
}
-static int virtio_io_read(uint16_t port, void * dst, uint_t length, void * private_data) {
+static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) {
struct virtio_blk_state * blk_state = (struct virtio_blk_state *)private_data;
int port_idx = port % blk_state->io_range_size;
}
+static int virtio_free(struct virtio_dev_state * virtio) {
+ struct virtio_blk_state * blk_state = NULL;
+ struct virtio_blk_state * tmp = NULL;
+
+ list_for_each_entry_safe(blk_state, tmp, &(virtio->dev_list), dev_link) {
+
+ // unregister from PCI
+
+ list_del(&(blk_state->dev_link));
+ V3_Free(blk_state);
+ }
+
+
+ V3_Free(virtio);
+
+ return 0;
+}
+
static struct v3_device_ops dev_ops = {
- .free = virtio_free,
- .reset = virtio_reset,
- .start = NULL,
- .stop = NULL,
+ .free = (int (*)(void *))virtio_free,
+
};
blk_state->pci_dev = pci_dev;
+
+
+ /* Add backend to list of devices */
+ list_add(&(blk_state->dev_link), &(virtio->dev_list));
/* Block configuration */
blk_state->virtio_cfg.host_features = VIRTIO_SEG_MAX;
}
-int v3_virtio_register_cdrom(struct vm_device * dev, struct v3_cd_ops * ops, void * private_data) {
- struct virtio_dev_state * virtio = (struct virtio_dev_state *)dev->private_data;
- struct virtio_blk_state * blk_state = (struct virtio_blk_state *)V3_Malloc(sizeof(struct virtio_blk_state));
- memset(blk_state, 0, sizeof(struct virtio_blk_state));
-
- register_dev(virtio, blk_state);
-
- blk_state->block_type = BLOCK_CDROM;
- blk_state->cd_ops = ops;
- blk_state->backend_data = private_data;
-
- blk_state->block_cfg.capacity = ops->get_capacity(private_data);
-
- return 0;
-}
+static int connect_fn(struct v3_vm_info * vm,
+ void * frontend_data,
+ struct v3_dev_blk_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * private_data) {
+ struct virtio_dev_state * virtio = (struct virtio_dev_state *)frontend_data;
-int v3_virtio_register_harddisk(struct vm_device * dev, struct v3_hd_ops * ops, void * private_data) {
- struct virtio_dev_state * virtio = (struct virtio_dev_state *)dev->private_data;
struct virtio_blk_state * blk_state = (struct virtio_blk_state *)V3_Malloc(sizeof(struct virtio_blk_state));
memset(blk_state, 0, sizeof(struct virtio_blk_state));
register_dev(virtio, blk_state);
- blk_state->block_type = BLOCK_DISK;
- blk_state->hd_ops = ops;
+ blk_state->ops = ops;
blk_state->backend_data = private_data;
- blk_state->block_cfg.capacity = ops->get_capacity(private_data);
+ blk_state->block_cfg.capacity = ops->get_capacity(private_data) / SECTOR_SIZE;
- PrintDebug("Virtio Capacity = %d -- 0x%p\n", (int)(virtio->block_cfg.capacity),
- (void *)(addr_t)(virtio->block_cfg.capacity));
+ PrintDebug("Virtio Capacity = %d -- 0x%p\n", (int)(blk_state->block_cfg.capacity),
+ (void *)(addr_t)(blk_state->block_cfg.capacity));
return 0;
}
-
-
-static int virtio_init(struct guest_info * vm, void * cfg_data) {
- struct vm_device * pci_bus = v3_find_dev(vm, (char *)cfg_data);
+static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
+ struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
struct virtio_dev_state * virtio_state = NULL;
-
+ char * dev_id = v3_cfg_val(cfg, "ID");
PrintDebug("Initializing VIRTIO Block device\n");
INIT_LIST_HEAD(&(virtio_state->dev_list));
virtio_state->pci_bus = pci_bus;
- virtio_state->vm = vm;
- 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");
+
+ struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, virtio_state);
+
+ if (dev == NULL) {
+ PrintError("Could not attach device %s\n", dev_id);
+ V3_Free(virtio_state);
+ return -1;
+ }
+
+ if (v3_dev_add_blk_frontend(vm, dev_id, connect_fn, (void *)virtio_state) == -1) {
+ PrintError("Could not register %s as block frontend\n", dev_id);
+ v3_remove_device(dev);
return -1;
}
return 0;
}
-
-
device_register("LNX_VIRTIO_BLK", virtio_init)