X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fdevices%2Flnx_virtio_blk.c;h=7e26b3081566e8d51d71a2cc4dedc4376d81f422;hb=1bd025c8e158b2b5f4c8e8ccf1bcf8d702dde037;hp=69187ccc499490730e1317e49a94159d4a1a4263;hpb=afb2a35b2e15ba0fa932c4e49a3678f958a4502a;p=palacios.git diff --git a/palacios/src/devices/lnx_virtio_blk.c b/palacios/src/devices/lnx_virtio_blk.c index 69187cc..7e26b30 100644 --- a/palacios/src/devices/lnx_virtio_blk.c +++ b/palacios/src/devices/lnx_virtio_blk.c @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include #include @@ -34,6 +32,8 @@ #endif +#define SECTOR_SIZE 512 + #define BLK_CAPACITY_PORT 20 #define BLK_MAX_SIZE_PORT 28 #define BLK_MAX_SEG_PORT 32 @@ -81,7 +81,6 @@ struct blk_op_hdr { struct virtio_dev_state { struct vm_device * pci_bus; struct list_head dev_list; - struct guest_info * vm; }; struct virtio_blk_state { @@ -93,12 +92,8 @@ 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; @@ -109,9 +104,7 @@ struct virtio_blk_state { }; -static int virtio_free(struct vm_device * dev) { - return -1; -} + static int blk_reset(struct virtio_blk_state * virtio) { @@ -127,63 +120,25 @@ 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; } @@ -192,55 +147,38 @@ static int handle_write_op(struct virtio_blk_state * blk_state, uint8_t * buf, u // 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; @@ -260,13 +198,13 @@ static int get_desc_count(struct virtio_queue * q, int index) { -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; @@ -292,7 +230,7 @@ static int handle_kick(struct virtio_blk_state * blk_state) { 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; } @@ -312,7 +250,7 @@ static int handle_kick(struct virtio_blk_state * blk_state) { 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; } @@ -330,7 +268,7 @@ static int handle_kick(struct virtio_blk_state * blk_state) { 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; } @@ -354,7 +292,7 @@ static int handle_kick(struct virtio_blk_state * blk_state) { 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; @@ -392,19 +330,19 @@ static int virtio_io_write(uint16_t port, void * src, uint_t length, void * priv // 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; } @@ -434,7 +372,7 @@ static int virtio_io_write(uint16_t port, void * src, uint_t length, void * priv 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; } @@ -461,7 +399,7 @@ static int virtio_io_write(uint16_t port, void * src, uint_t length, void * priv } -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; @@ -533,13 +471,29 @@ static int virtio_io_read(uint16_t port, void * dst, uint_t length, void * priva } +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, + }; @@ -612,6 +566,10 @@ static int register_dev(struct virtio_dev_state * virtio, struct virtio_blk_stat 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; @@ -629,49 +587,35 @@ static int register_dev(struct virtio_dev_state * virtio, struct virtio_blk_stat } -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"); @@ -686,18 +630,24 @@ static int virtio_init(struct guest_info * vm, void * cfg_data) { 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)