1b30d05adSPekka Enberg #include "kvm/blk-virtio.h" 2b30d05adSPekka Enberg 3984b7ae0SPekka Enberg #include "kvm/virtio_pci.h" 476b6349fSPekka Enberg 55a24a9f2SPekka Enberg #include "kvm/disk-image.h" 6*39d6af07SAsias He #include "kvm/virtio.h" 7b30d05adSPekka Enberg #include "kvm/ioport.h" 8fe99fd4eSPekka Enberg #include "kvm/util.h" 98b1ff07eSPekka Enberg #include "kvm/kvm.h" 10b30d05adSPekka Enberg #include "kvm/pci.h" 11b30d05adSPekka Enberg 1220c64ecaSPekka Enberg #include <linux/virtio_ring.h> 1320c64ecaSPekka Enberg #include <linux/virtio_blk.h> 144155ba8cSPekka Enberg #include <inttypes.h> 154155ba8cSPekka Enberg #include <assert.h> 164155ba8cSPekka Enberg 178b1ff07eSPekka Enberg #define VIRTIO_BLK_IRQ 14 18984b7ae0SPekka Enberg 1910eca11dSPekka Enberg #define NUM_VIRT_QUEUES 1 2010eca11dSPekka Enberg 2103110ff3SAsias He #define VIRTIO_BLK_QUEUE_SIZE 128 2210eca11dSPekka Enberg 23802e07a0SAsias He struct blk_device { 2440ce993fSPekka Enberg struct virtio_blk_config blk_config; 25c435b91dSPekka Enberg uint32_t host_features; 26fbc2fbf9SPekka Enberg uint32_t guest_features; 2740ce993fSPekka Enberg uint16_t config_vector; 28fbc2fbf9SPekka Enberg uint8_t status; 2947bf1d0fSPekka Enberg 3047bf1d0fSPekka Enberg /* virtio queue */ 3147bf1d0fSPekka Enberg uint16_t queue_selector; 3210eca11dSPekka Enberg 3310eca11dSPekka Enberg struct virt_queue virt_queues[NUM_VIRT_QUEUES]; 34fbc2fbf9SPekka Enberg }; 35fbc2fbf9SPekka Enberg 3603110ff3SAsias He #define DISK_SEG_MAX 126 3740ce993fSPekka Enberg 38802e07a0SAsias He static struct blk_device blk_device = { 3940ce993fSPekka Enberg .blk_config = (struct virtio_blk_config) { 40e199f440SPekka Enberg /* VIRTIO_BLK_F_SEG_MAX */ 4103110ff3SAsias He .seg_max = DISK_SEG_MAX, 4240ce993fSPekka Enberg }, 431ef2738dSCyrill Gorcunov /* 441ef2738dSCyrill Gorcunov * Note we don't set VIRTIO_BLK_F_GEOMETRY here so the 451ef2738dSCyrill Gorcunov * node kernel will compute disk geometry by own, the 461ef2738dSCyrill Gorcunov * same applies to VIRTIO_BLK_F_BLK_SIZE 471ef2738dSCyrill Gorcunov */ 4803110ff3SAsias He .host_features = (1UL << VIRTIO_BLK_F_SEG_MAX), 49c435b91dSPekka Enberg }; 50fbc2fbf9SPekka Enberg 5140ce993fSPekka Enberg static bool virtio_blk_config_in(void *data, unsigned long offset, int size, uint32_t count) 5240ce993fSPekka Enberg { 53802e07a0SAsias He uint8_t *config_space = (uint8_t *) &blk_device.blk_config; 5440ce993fSPekka Enberg 5540ce993fSPekka Enberg if (size != 1 || count != 1) 5640ce993fSPekka Enberg return false; 5740ce993fSPekka Enberg 5840ce993fSPekka Enberg ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]); 5940ce993fSPekka Enberg 6040ce993fSPekka Enberg return true; 6140ce993fSPekka Enberg } 6240ce993fSPekka Enberg 63fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 64fbc2fbf9SPekka Enberg { 65fbc2fbf9SPekka Enberg unsigned long offset; 66fbc2fbf9SPekka Enberg 67d1888318SCyrill Gorcunov offset = port - IOPORT_VIRTIO_BLK; 68fbc2fbf9SPekka Enberg 69fbc2fbf9SPekka Enberg switch (offset) { 70fbc2fbf9SPekka Enberg case VIRTIO_PCI_HOST_FEATURES: 71802e07a0SAsias He ioport__write32(data, blk_device.host_features); 72fbc2fbf9SPekka Enberg break; 73fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 748b1ff07eSPekka Enberg return false; 75fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 76802e07a0SAsias He ioport__write32(data, blk_device.virt_queues[blk_device.queue_selector].pfn); 778b1ff07eSPekka Enberg break; 78fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NUM: 7910eca11dSPekka Enberg ioport__write16(data, VIRTIO_BLK_QUEUE_SIZE); 808b1ff07eSPekka Enberg break; 81fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 82fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: 83fbc2fbf9SPekka Enberg return false; 84fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 85802e07a0SAsias He ioport__write8(data, blk_device.status); 86fbc2fbf9SPekka Enberg break; 87fbc2fbf9SPekka Enberg case VIRTIO_PCI_ISR: 888b1ff07eSPekka Enberg ioport__write8(data, 0x1); 898b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 0); 907e61688eSPekka Enberg break; 91fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 92802e07a0SAsias He ioport__write16(data, blk_device.config_vector); 9340ce993fSPekka Enberg break; 94fbc2fbf9SPekka Enberg default: 9540ce993fSPekka Enberg return virtio_blk_config_in(data, offset, size, count); 96fbc2fbf9SPekka Enberg }; 97fbc2fbf9SPekka Enberg 98fbc2fbf9SPekka Enberg return true; 99fbc2fbf9SPekka Enberg } 100fbc2fbf9SPekka Enberg 10103110ff3SAsias He static bool blk_virtio_request(struct kvm *self, struct virt_queue *queue) 1024155ba8cSPekka Enberg { 1034155ba8cSPekka Enberg struct vring_used_elem *used_elem; 1044155ba8cSPekka Enberg struct virtio_blk_outhdr *req; 10503110ff3SAsias He uint16_t desc_block_last; 1064155ba8cSPekka Enberg struct vring_desc *desc; 10703110ff3SAsias He uint16_t desc_status; 10803110ff3SAsias He uint16_t desc_block; 109258dd093SPekka Enberg uint32_t block_len; 11003110ff3SAsias He uint32_t block_cnt; 11103110ff3SAsias He uint16_t desc_hdr; 1124155ba8cSPekka Enberg uint8_t *status; 113258dd093SPekka Enberg void *block; 11403110ff3SAsias He int err; 11503110ff3SAsias He int err_cnt; 1164155ba8cSPekka Enberg 11703110ff3SAsias He /* header */ 11803110ff3SAsias He desc_hdr = virt_queue__pop(queue); 1194155ba8cSPekka Enberg 12003110ff3SAsias He if (desc_hdr >= queue->vring.num) { 1214155ba8cSPekka Enberg warning("fatal I/O error"); 1224155ba8cSPekka Enberg return false; 1234155ba8cSPekka Enberg } 1244155ba8cSPekka Enberg 12503110ff3SAsias He desc = virt_queue__get_desc(queue, desc_hdr); 1264155ba8cSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 1274155ba8cSPekka Enberg 1284155ba8cSPekka Enberg req = guest_flat_to_host(self, desc->addr); 1294155ba8cSPekka Enberg 13003110ff3SAsias He /* status */ 13103110ff3SAsias He desc_status = desc_hdr; 13203110ff3SAsias He 13303110ff3SAsias He do { 13403110ff3SAsias He desc_block_last = desc_status; 13503110ff3SAsias He desc_status = virt_queue__get_desc(queue, desc_status)->next; 13603110ff3SAsias He 13703110ff3SAsias He if (desc_status >= queue->vring.num) { 13803110ff3SAsias He warning("fatal I/O error"); 13903110ff3SAsias He return false; 14003110ff3SAsias He } 14103110ff3SAsias He 14203110ff3SAsias He desc = virt_queue__get_desc(queue, desc_status); 14303110ff3SAsias He assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 14403110ff3SAsias He 14503110ff3SAsias He } while (desc->flags & VRING_DESC_F_NEXT); 14603110ff3SAsias He 14703110ff3SAsias He status = guest_flat_to_host(self, desc->addr); 14803110ff3SAsias He 1494155ba8cSPekka Enberg /* block */ 15003110ff3SAsias He desc_block = desc_hdr; 15103110ff3SAsias He block_cnt = 0; 15203110ff3SAsias He err_cnt = 0; 15303110ff3SAsias He 15403110ff3SAsias He do { 15503110ff3SAsias He desc_block = virt_queue__get_desc(queue, desc_block)->next; 15603110ff3SAsias He 15703110ff3SAsias He desc = virt_queue__get_desc(queue, desc_block); 1584155ba8cSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 1594155ba8cSPekka Enberg 160258dd093SPekka Enberg block = guest_flat_to_host(self, desc->addr); 161258dd093SPekka Enberg block_len = desc->len; 1624155ba8cSPekka Enberg 163258dd093SPekka Enberg switch (req->type) { 16403110ff3SAsias He case VIRTIO_BLK_T_IN: 165258dd093SPekka Enberg err = disk_image__read_sector(self->disk_image, req->sector, block, block_len); 166258dd093SPekka Enberg break; 16703110ff3SAsias He case VIRTIO_BLK_T_OUT: 168258dd093SPekka Enberg err = disk_image__write_sector(self->disk_image, req->sector, block, block_len); 169258dd093SPekka Enberg break; 170258dd093SPekka Enberg default: 1714155ba8cSPekka Enberg warning("request type %d", req->type); 17203110ff3SAsias He err = -1; 173a2c8c696SAsias He } 174a2c8c696SAsias He 17503110ff3SAsias He if (err) 17603110ff3SAsias He err_cnt++; 177a267e01bSPekka Enberg 17803110ff3SAsias He req->sector += block_len >> SECTOR_SHIFT; 17903110ff3SAsias He block_cnt += block_len; 18003110ff3SAsias He 18103110ff3SAsias He if (desc_block == desc_block_last) 18203110ff3SAsias He break; 18303110ff3SAsias He 18403110ff3SAsias He if (desc_block >= queue->vring.num) { 18503110ff3SAsias He warning("fatal I/O error"); 18603110ff3SAsias He return false; 18703110ff3SAsias He } 18803110ff3SAsias He 18903110ff3SAsias He } while (true); 19003110ff3SAsias He 19103110ff3SAsias He *status = err_cnt ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK; 19203110ff3SAsias He 19303110ff3SAsias He used_elem = virt_queue__get_used_elem(queue); 19403110ff3SAsias He used_elem->id = desc_hdr; 19503110ff3SAsias He used_elem->len = block_cnt; 1964155ba8cSPekka Enberg 1974155ba8cSPekka Enberg return true; 1984155ba8cSPekka Enberg } 1994155ba8cSPekka Enberg 200fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 201fbc2fbf9SPekka Enberg { 202fbc2fbf9SPekka Enberg unsigned long offset; 203fbc2fbf9SPekka Enberg 204d1888318SCyrill Gorcunov offset = port - IOPORT_VIRTIO_BLK; 205fbc2fbf9SPekka Enberg 206fbc2fbf9SPekka Enberg switch (offset) { 207fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 208802e07a0SAsias He blk_device.guest_features = ioport__read32(data); 209fbc2fbf9SPekka Enberg break; 21010eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_PFN: { 21110eca11dSPekka Enberg struct virt_queue *queue; 21210eca11dSPekka Enberg void *p; 21310eca11dSPekka Enberg 214802e07a0SAsias He queue = &blk_device.virt_queues[blk_device.queue_selector]; 21510eca11dSPekka Enberg 21610eca11dSPekka Enberg queue->pfn = ioport__read32(data); 21710eca11dSPekka Enberg 21810eca11dSPekka Enberg p = guest_flat_to_host(self, queue->pfn << 12); 21910eca11dSPekka Enberg 22010eca11dSPekka Enberg vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, 4096); 22110eca11dSPekka Enberg 2227e61688eSPekka Enberg break; 22310eca11dSPekka Enberg } 224fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 225802e07a0SAsias He blk_device.queue_selector = ioport__read16(data); 2267e61688eSPekka Enberg break; 22710eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: { 22810eca11dSPekka Enberg struct virt_queue *queue; 22910eca11dSPekka Enberg uint16_t queue_index; 23010eca11dSPekka Enberg 23110eca11dSPekka Enberg queue_index = ioport__read16(data); 23210eca11dSPekka Enberg 233802e07a0SAsias He queue = &blk_device.virt_queues[queue_index]; 23410eca11dSPekka Enberg 2354155ba8cSPekka Enberg while (queue->vring.avail->idx != queue->last_avail_idx) { 23603110ff3SAsias He if (!blk_virtio_request(self, queue)) 2374155ba8cSPekka Enberg return false; 23893d18b72SPekka Enberg } 2398b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); 2405a24a9f2SPekka Enberg 2417e61688eSPekka Enberg break; 24210eca11dSPekka Enberg } 243fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 244802e07a0SAsias He blk_device.status = ioport__read8(data); 245fbc2fbf9SPekka Enberg break; 246fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 247802e07a0SAsias He blk_device.config_vector = VIRTIO_MSI_NO_VECTOR; 24840ce993fSPekka Enberg break; 249fbc2fbf9SPekka Enberg case VIRTIO_MSI_QUEUE_VECTOR: 25040ce993fSPekka Enberg break; 251fbc2fbf9SPekka Enberg default: 252fbc2fbf9SPekka Enberg return false; 253fbc2fbf9SPekka Enberg }; 254fbc2fbf9SPekka Enberg 255fbc2fbf9SPekka Enberg return true; 256fbc2fbf9SPekka Enberg } 257fbc2fbf9SPekka Enberg 258fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = { 259fbc2fbf9SPekka Enberg .io_in = blk_virtio_in, 260fbc2fbf9SPekka Enberg .io_out = blk_virtio_out, 261fbc2fbf9SPekka Enberg }; 262fbc2fbf9SPekka Enberg 263b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 264b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 265b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 266b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 267b30d05adSPekka Enberg 268fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = { 269b30d05adSPekka Enberg .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 270b30d05adSPekka Enberg .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 271b30d05adSPekka Enberg .header_type = PCI_HEADER_TYPE_NORMAL, 272b30d05adSPekka Enberg .revision_id = 0, 273b30d05adSPekka Enberg .class = 0x010000, 274b30d05adSPekka Enberg .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 275b30d05adSPekka Enberg .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 276d1888318SCyrill Gorcunov .bar[0] = IOPORT_VIRTIO_BLK | PCI_BASE_ADDRESS_SPACE_IO, 277dc53a427SPekka Enberg .irq_pin = 1, 2788b1ff07eSPekka Enberg .irq_line = VIRTIO_BLK_IRQ, 279b30d05adSPekka Enberg }; 280b30d05adSPekka Enberg 281f05bbe8dSAsias He #define PCI_VIRTIO_BLK_DEVNUM 1 282f05bbe8dSAsias He 283ca7c891bSCyrill Gorcunov void blk_virtio__init(struct kvm *self) 284b30d05adSPekka Enberg { 2851f848897SPekka Enberg if (!self->disk_image) 2861f848897SPekka Enberg return; 2871f848897SPekka Enberg 288802e07a0SAsias He blk_device.blk_config.capacity = self->disk_image->size / SECTOR_SIZE; 289ca7c891bSCyrill Gorcunov 290f05bbe8dSAsias He pci__register(&blk_virtio_pci_device, PCI_VIRTIO_BLK_DEVNUM); 291b30d05adSPekka Enberg 292f05bbe8dSAsias He ioport__register(IOPORT_VIRTIO_BLK, &blk_virtio_io_ops, IOPORT_VIRTIO_BLK_SIZE); 293b30d05adSPekka Enberg } 294