1b30d05adSPekka Enberg #include "kvm/blk-virtio.h" 2b30d05adSPekka Enberg 310eca11dSPekka Enberg #include "kvm/virtio_ring.h" 4c435b91dSPekka Enberg #include "kvm/virtio_blk.h" 5984b7ae0SPekka Enberg #include "kvm/virtio_pci.h" 65a24a9f2SPekka Enberg #include "kvm/disk-image.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 12*4155ba8cSPekka Enberg #include <inttypes.h> 13*4155ba8cSPekka Enberg #include <assert.h> 14*4155ba8cSPekka Enberg 158b1ff07eSPekka Enberg #define VIRTIO_BLK_IRQ 14 16984b7ae0SPekka Enberg 1710eca11dSPekka Enberg #define NUM_VIRT_QUEUES 1 1810eca11dSPekka Enberg 1910eca11dSPekka Enberg #define VIRTIO_BLK_QUEUE_SIZE 16 2010eca11dSPekka Enberg 2110eca11dSPekka Enberg struct virt_queue { 2210eca11dSPekka Enberg struct vring vring; 23fe99fd4eSPekka Enberg uint32_t pfn; 2493d18b72SPekka Enberg /* The last_avail_idx field is an index to ->ring of struct vring_avail. 25fe99fd4eSPekka Enberg It's where we assume the next request index is at. */ 2693d18b72SPekka Enberg uint16_t last_avail_idx; 2710eca11dSPekka Enberg }; 2810eca11dSPekka Enberg 29fbc2fbf9SPekka Enberg struct device { 3040ce993fSPekka Enberg struct virtio_blk_config blk_config; 31c435b91dSPekka Enberg uint32_t host_features; 32fbc2fbf9SPekka Enberg uint32_t guest_features; 3340ce993fSPekka Enberg uint16_t config_vector; 34fbc2fbf9SPekka Enberg uint8_t status; 3547bf1d0fSPekka Enberg 3647bf1d0fSPekka Enberg /* virtio queue */ 3747bf1d0fSPekka Enberg uint16_t queue_selector; 3810eca11dSPekka Enberg 3910eca11dSPekka Enberg struct virt_queue virt_queues[NUM_VIRT_QUEUES]; 40fbc2fbf9SPekka Enberg }; 41fbc2fbf9SPekka Enberg 4240ce993fSPekka Enberg #define DISK_CYLINDERS 1024 4340ce993fSPekka Enberg #define DISK_HEADS 64 4440ce993fSPekka Enberg #define DISK_SECTORS 32 4540ce993fSPekka Enberg 46c435b91dSPekka Enberg static struct device device = { 4740ce993fSPekka Enberg .blk_config = (struct virtio_blk_config) { 4840ce993fSPekka Enberg .capacity = DISK_CYLINDERS * DISK_HEADS * DISK_SECTORS, 4940ce993fSPekka Enberg /* VIRTIO_BLK_F_GEOMETRY */ 5040ce993fSPekka Enberg .geometry = { 5140ce993fSPekka Enberg .cylinders = DISK_CYLINDERS, 5240ce993fSPekka Enberg .heads = DISK_HEADS, 5340ce993fSPekka Enberg .sectors = DISK_SECTORS, 5440ce993fSPekka Enberg }, 5540ce993fSPekka Enberg /* VIRTIO_BLK_SIZE */ 5640ce993fSPekka Enberg .blk_size = 4096, 5740ce993fSPekka Enberg }, 581ef2738dSCyrill Gorcunov /* 591ef2738dSCyrill Gorcunov * Note we don't set VIRTIO_BLK_F_GEOMETRY here so the 601ef2738dSCyrill Gorcunov * node kernel will compute disk geometry by own, the 611ef2738dSCyrill Gorcunov * same applies to VIRTIO_BLK_F_BLK_SIZE 621ef2738dSCyrill Gorcunov */ 631ef2738dSCyrill Gorcunov .host_features = (1UL << VIRTIO_BLK_F_RO), 64c435b91dSPekka Enberg }; 65fbc2fbf9SPekka Enberg 6640ce993fSPekka Enberg static bool virtio_blk_config_in(void *data, unsigned long offset, int size, uint32_t count) 6740ce993fSPekka Enberg { 6840ce993fSPekka Enberg uint8_t *config_space = (uint8_t *) &device.blk_config; 6940ce993fSPekka Enberg 7040ce993fSPekka Enberg if (size != 1 || count != 1) 7140ce993fSPekka Enberg return false; 7240ce993fSPekka Enberg 7340ce993fSPekka Enberg ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]); 7440ce993fSPekka Enberg 7540ce993fSPekka Enberg return true; 7640ce993fSPekka Enberg } 7740ce993fSPekka Enberg 78fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 79fbc2fbf9SPekka Enberg { 80fbc2fbf9SPekka Enberg unsigned long offset; 81fbc2fbf9SPekka Enberg 82fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 83fbc2fbf9SPekka Enberg 84fbc2fbf9SPekka Enberg switch (offset) { 85fbc2fbf9SPekka Enberg case VIRTIO_PCI_HOST_FEATURES: 86c435b91dSPekka Enberg ioport__write32(data, device.host_features); 87fbc2fbf9SPekka Enberg break; 88fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 898b1ff07eSPekka Enberg return false; 90fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 9110eca11dSPekka Enberg ioport__write32(data, device.virt_queues[device.queue_selector].pfn); 928b1ff07eSPekka Enberg break; 93fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NUM: 9410eca11dSPekka Enberg ioport__write16(data, VIRTIO_BLK_QUEUE_SIZE); 958b1ff07eSPekka Enberg break; 96fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 97fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: 98fbc2fbf9SPekka Enberg return false; 99fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 100fbc2fbf9SPekka Enberg ioport__write8(data, device.status); 101fbc2fbf9SPekka Enberg break; 102fbc2fbf9SPekka Enberg case VIRTIO_PCI_ISR: 1038b1ff07eSPekka Enberg ioport__write8(data, 0x1); 1048b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 0); 1057e61688eSPekka Enberg break; 106fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 10740ce993fSPekka Enberg ioport__write16(data, device.config_vector); 10840ce993fSPekka Enberg break; 109fbc2fbf9SPekka Enberg default: 11040ce993fSPekka Enberg return virtio_blk_config_in(data, offset, size, count); 111fbc2fbf9SPekka Enberg }; 112fbc2fbf9SPekka Enberg 113fbc2fbf9SPekka Enberg return true; 114fbc2fbf9SPekka Enberg } 115fbc2fbf9SPekka Enberg 116*4155ba8cSPekka Enberg static bool blk_virtio_read(struct kvm *self, struct virt_queue *queue) 117*4155ba8cSPekka Enberg { 118*4155ba8cSPekka Enberg struct vring_used_elem *used_elem; 119*4155ba8cSPekka Enberg struct virtio_blk_outhdr *req; 120*4155ba8cSPekka Enberg struct vring_desc *desc; 121*4155ba8cSPekka Enberg uint16_t desc_ndx; 122*4155ba8cSPekka Enberg uint32_t dst_len; 123*4155ba8cSPekka Enberg uint8_t *status; 124*4155ba8cSPekka Enberg void *dst; 125*4155ba8cSPekka Enberg int err; 126*4155ba8cSPekka Enberg 127*4155ba8cSPekka Enberg desc_ndx = queue->vring.avail->ring[queue->last_avail_idx++ % queue->vring.num]; 128*4155ba8cSPekka Enberg 129*4155ba8cSPekka Enberg if (desc_ndx >= queue->vring.num) { 130*4155ba8cSPekka Enberg warning("fatal I/O error"); 131*4155ba8cSPekka Enberg return false; 132*4155ba8cSPekka Enberg } 133*4155ba8cSPekka Enberg 134*4155ba8cSPekka Enberg /* header */ 135*4155ba8cSPekka Enberg desc = &queue->vring.desc[desc_ndx]; 136*4155ba8cSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 137*4155ba8cSPekka Enberg 138*4155ba8cSPekka Enberg req = guest_flat_to_host(self, desc->addr); 139*4155ba8cSPekka Enberg 140*4155ba8cSPekka Enberg /* block */ 141*4155ba8cSPekka Enberg desc = &queue->vring.desc[desc->next]; 142*4155ba8cSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 143*4155ba8cSPekka Enberg 144*4155ba8cSPekka Enberg dst = guest_flat_to_host(self, desc->addr); 145*4155ba8cSPekka Enberg dst_len = desc->len; 146*4155ba8cSPekka Enberg 147*4155ba8cSPekka Enberg /* status */ 148*4155ba8cSPekka Enberg desc = &queue->vring.desc[desc->next]; 149*4155ba8cSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 150*4155ba8cSPekka Enberg 151*4155ba8cSPekka Enberg status = guest_flat_to_host(self, desc->addr); 152*4155ba8cSPekka Enberg 153*4155ba8cSPekka Enberg info("reading sector %" PRIu64 " (%d bytes)", req->sector, dst_len); 154*4155ba8cSPekka Enberg 155*4155ba8cSPekka Enberg if (req->type == VIRTIO_BLK_T_IN) { 156*4155ba8cSPekka Enberg err = disk_image__read_sector(self->disk_image, req->sector, dst, dst_len); 157*4155ba8cSPekka Enberg 158*4155ba8cSPekka Enberg if (err) 159*4155ba8cSPekka Enberg *status = VIRTIO_BLK_S_IOERR; 160*4155ba8cSPekka Enberg else 161*4155ba8cSPekka Enberg *status = VIRTIO_BLK_S_OK; 162*4155ba8cSPekka Enberg } else { 163*4155ba8cSPekka Enberg warning("request type %d", req->type); 164*4155ba8cSPekka Enberg *status = VIRTIO_BLK_S_IOERR; 165*4155ba8cSPekka Enberg } 166*4155ba8cSPekka Enberg 167*4155ba8cSPekka Enberg used_elem = &queue->vring.used->ring[queue->vring.used->idx++ % queue->vring.num]; 168*4155ba8cSPekka Enberg 169*4155ba8cSPekka Enberg used_elem->id = desc_ndx; 170*4155ba8cSPekka Enberg used_elem->len = 3; 171*4155ba8cSPekka Enberg 172*4155ba8cSPekka Enberg return true; 173*4155ba8cSPekka Enberg } 174*4155ba8cSPekka Enberg 175fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 176fbc2fbf9SPekka Enberg { 177fbc2fbf9SPekka Enberg unsigned long offset; 178fbc2fbf9SPekka Enberg 179fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 180fbc2fbf9SPekka Enberg 181fbc2fbf9SPekka Enberg switch (offset) { 182fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 183fbc2fbf9SPekka Enberg device.guest_features = ioport__read32(data); 184fbc2fbf9SPekka Enberg break; 18510eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_PFN: { 18610eca11dSPekka Enberg struct virt_queue *queue; 18710eca11dSPekka Enberg void *p; 18810eca11dSPekka Enberg 18910eca11dSPekka Enberg queue = &device.virt_queues[device.queue_selector]; 19010eca11dSPekka Enberg 19110eca11dSPekka Enberg queue->pfn = ioport__read32(data); 19210eca11dSPekka Enberg 19310eca11dSPekka Enberg p = guest_flat_to_host(self, queue->pfn << 12); 19410eca11dSPekka Enberg 19510eca11dSPekka Enberg vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, 4096); 19610eca11dSPekka Enberg 1977e61688eSPekka Enberg break; 19810eca11dSPekka Enberg } 199fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 20047bf1d0fSPekka Enberg device.queue_selector = ioport__read16(data); 2017e61688eSPekka Enberg break; 20210eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: { 20310eca11dSPekka Enberg struct virt_queue *queue; 20410eca11dSPekka Enberg uint16_t queue_index; 20510eca11dSPekka Enberg 20610eca11dSPekka Enberg queue_index = ioport__read16(data); 20710eca11dSPekka Enberg 20810eca11dSPekka Enberg queue = &device.virt_queues[queue_index]; 20910eca11dSPekka Enberg 210*4155ba8cSPekka Enberg while (queue->vring.avail->idx != queue->last_avail_idx) { 211*4155ba8cSPekka Enberg if (!blk_virtio_read(self, queue)) 212*4155ba8cSPekka Enberg return false; 21393d18b72SPekka Enberg } 2148b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); 2155a24a9f2SPekka Enberg 2167e61688eSPekka Enberg break; 21710eca11dSPekka Enberg } 218fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 219fbc2fbf9SPekka Enberg device.status = ioport__read8(data); 220fbc2fbf9SPekka Enberg break; 221fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 22240ce993fSPekka Enberg device.config_vector = VIRTIO_MSI_NO_VECTOR; 22340ce993fSPekka Enberg break; 224fbc2fbf9SPekka Enberg case VIRTIO_MSI_QUEUE_VECTOR: 22540ce993fSPekka Enberg break; 226fbc2fbf9SPekka Enberg default: 227fbc2fbf9SPekka Enberg return false; 228fbc2fbf9SPekka Enberg }; 229fbc2fbf9SPekka Enberg 230fbc2fbf9SPekka Enberg return true; 231fbc2fbf9SPekka Enberg } 232fbc2fbf9SPekka Enberg 233fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = { 234fbc2fbf9SPekka Enberg .io_in = blk_virtio_in, 235fbc2fbf9SPekka Enberg .io_out = blk_virtio_out, 236fbc2fbf9SPekka Enberg }; 237fbc2fbf9SPekka Enberg 238b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 239b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 240b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 241b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 242b30d05adSPekka Enberg 243fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = { 244b30d05adSPekka Enberg .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 245b30d05adSPekka Enberg .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 246b30d05adSPekka Enberg .header_type = PCI_HEADER_TYPE_NORMAL, 247b30d05adSPekka Enberg .revision_id = 0, 248b30d05adSPekka Enberg .class = 0x010000, 249b30d05adSPekka Enberg .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 250b30d05adSPekka Enberg .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 251b30d05adSPekka Enberg .bar[0] = IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO, 252dc53a427SPekka Enberg .irq_pin = 1, 2538b1ff07eSPekka Enberg .irq_line = VIRTIO_BLK_IRQ, 254b30d05adSPekka Enberg }; 255b30d05adSPekka Enberg 256ca7c891bSCyrill Gorcunov void blk_virtio__init(struct kvm *self) 257b30d05adSPekka Enberg { 2581f848897SPekka Enberg if (!self->disk_image) 2591f848897SPekka Enberg return; 2601f848897SPekka Enberg 2616160ab9dSAsias He device.blk_config.capacity = self->disk_image->size / 512; 262ca7c891bSCyrill Gorcunov 263fbc2fbf9SPekka Enberg pci__register(&blk_virtio_pci_device, 1); 264b30d05adSPekka Enberg 2658b1ff07eSPekka Enberg ioport__register(IOPORT_VIRTIO, &blk_virtio_io_ops, 256); 266b30d05adSPekka Enberg } 267