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 128b1ff07eSPekka Enberg #define VIRTIO_BLK_IRQ 14 13984b7ae0SPekka Enberg 1410eca11dSPekka Enberg #define NUM_VIRT_QUEUES 1 1510eca11dSPekka Enberg 1610eca11dSPekka Enberg #define VIRTIO_BLK_QUEUE_SIZE 16 1710eca11dSPekka Enberg 1810eca11dSPekka Enberg struct virt_queue { 1910eca11dSPekka Enberg struct vring vring; 20fe99fd4eSPekka Enberg uint32_t pfn; 21*93d18b72SPekka Enberg /* The last_avail_idx field is an index to ->ring of struct vring_avail. 22fe99fd4eSPekka Enberg It's where we assume the next request index is at. */ 23*93d18b72SPekka Enberg uint16_t last_avail_idx; 2410eca11dSPekka Enberg }; 2510eca11dSPekka Enberg 26fbc2fbf9SPekka Enberg struct device { 2740ce993fSPekka Enberg struct virtio_blk_config blk_config; 28c435b91dSPekka Enberg uint32_t host_features; 29fbc2fbf9SPekka Enberg uint32_t guest_features; 3040ce993fSPekka Enberg uint16_t config_vector; 31fbc2fbf9SPekka Enberg uint8_t status; 3247bf1d0fSPekka Enberg 3347bf1d0fSPekka Enberg /* virtio queue */ 3447bf1d0fSPekka Enberg uint16_t queue_selector; 3510eca11dSPekka Enberg 3610eca11dSPekka Enberg struct virt_queue virt_queues[NUM_VIRT_QUEUES]; 37fbc2fbf9SPekka Enberg }; 38fbc2fbf9SPekka Enberg 3940ce993fSPekka Enberg #define DISK_CYLINDERS 1024 4040ce993fSPekka Enberg #define DISK_HEADS 64 4140ce993fSPekka Enberg #define DISK_SECTORS 32 4240ce993fSPekka Enberg 43c435b91dSPekka Enberg static struct device device = { 4440ce993fSPekka Enberg .blk_config = (struct virtio_blk_config) { 4540ce993fSPekka Enberg .capacity = DISK_CYLINDERS * DISK_HEADS * DISK_SECTORS, 4640ce993fSPekka Enberg /* VIRTIO_BLK_F_GEOMETRY */ 4740ce993fSPekka Enberg .geometry = { 4840ce993fSPekka Enberg .cylinders = DISK_CYLINDERS, 4940ce993fSPekka Enberg .heads = DISK_HEADS, 5040ce993fSPekka Enberg .sectors = DISK_SECTORS, 5140ce993fSPekka Enberg }, 5240ce993fSPekka Enberg /* VIRTIO_BLK_SIZE */ 5340ce993fSPekka Enberg .blk_size = 4096, 5440ce993fSPekka Enberg }, 551ef2738dSCyrill Gorcunov /* 561ef2738dSCyrill Gorcunov * Note we don't set VIRTIO_BLK_F_GEOMETRY here so the 571ef2738dSCyrill Gorcunov * node kernel will compute disk geometry by own, the 581ef2738dSCyrill Gorcunov * same applies to VIRTIO_BLK_F_BLK_SIZE 591ef2738dSCyrill Gorcunov */ 601ef2738dSCyrill Gorcunov .host_features = (1UL << VIRTIO_BLK_F_RO), 61c435b91dSPekka Enberg }; 62fbc2fbf9SPekka Enberg 6340ce993fSPekka Enberg static bool virtio_blk_config_in(void *data, unsigned long offset, int size, uint32_t count) 6440ce993fSPekka Enberg { 6540ce993fSPekka Enberg uint8_t *config_space = (uint8_t *) &device.blk_config; 6640ce993fSPekka Enberg 6740ce993fSPekka Enberg if (size != 1 || count != 1) 6840ce993fSPekka Enberg return false; 6940ce993fSPekka Enberg 7040ce993fSPekka Enberg ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]); 7140ce993fSPekka Enberg 7240ce993fSPekka Enberg return true; 7340ce993fSPekka Enberg } 7440ce993fSPekka Enberg 75fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 76fbc2fbf9SPekka Enberg { 77fbc2fbf9SPekka Enberg unsigned long offset; 78fbc2fbf9SPekka Enberg 79fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 80fbc2fbf9SPekka Enberg 81fbc2fbf9SPekka Enberg switch (offset) { 82fbc2fbf9SPekka Enberg case VIRTIO_PCI_HOST_FEATURES: 83c435b91dSPekka Enberg ioport__write32(data, device.host_features); 84fbc2fbf9SPekka Enberg break; 85fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 868b1ff07eSPekka Enberg return false; 87fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 8810eca11dSPekka Enberg ioport__write32(data, device.virt_queues[device.queue_selector].pfn); 898b1ff07eSPekka Enberg break; 90fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NUM: 9110eca11dSPekka Enberg ioport__write16(data, VIRTIO_BLK_QUEUE_SIZE); 928b1ff07eSPekka Enberg break; 93fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 94fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: 95fbc2fbf9SPekka Enberg return false; 96fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 97fbc2fbf9SPekka Enberg ioport__write8(data, device.status); 98fbc2fbf9SPekka Enberg break; 99fbc2fbf9SPekka Enberg case VIRTIO_PCI_ISR: 1008b1ff07eSPekka Enberg ioport__write8(data, 0x1); 1018b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 0); 1027e61688eSPekka Enberg break; 103fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 10440ce993fSPekka Enberg ioport__write16(data, device.config_vector); 10540ce993fSPekka Enberg break; 106fbc2fbf9SPekka Enberg default: 10740ce993fSPekka Enberg return virtio_blk_config_in(data, offset, size, count); 108fbc2fbf9SPekka Enberg }; 109fbc2fbf9SPekka Enberg 110fbc2fbf9SPekka Enberg return true; 111fbc2fbf9SPekka Enberg } 112fbc2fbf9SPekka Enberg 113fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 114fbc2fbf9SPekka Enberg { 115fbc2fbf9SPekka Enberg unsigned long offset; 116fbc2fbf9SPekka Enberg 117fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 118fbc2fbf9SPekka Enberg 119fbc2fbf9SPekka Enberg switch (offset) { 120fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 121fbc2fbf9SPekka Enberg device.guest_features = ioport__read32(data); 122fbc2fbf9SPekka Enberg break; 12310eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_PFN: { 12410eca11dSPekka Enberg struct virt_queue *queue; 12510eca11dSPekka Enberg void *p; 12610eca11dSPekka Enberg 12710eca11dSPekka Enberg queue = &device.virt_queues[device.queue_selector]; 12810eca11dSPekka Enberg 12910eca11dSPekka Enberg queue->pfn = ioport__read32(data); 13010eca11dSPekka Enberg 13110eca11dSPekka Enberg p = guest_flat_to_host(self, queue->pfn << 12); 13210eca11dSPekka Enberg 13310eca11dSPekka Enberg vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, 4096); 13410eca11dSPekka Enberg 1357e61688eSPekka Enberg break; 13610eca11dSPekka Enberg } 137fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 13847bf1d0fSPekka Enberg device.queue_selector = ioport__read16(data); 1397e61688eSPekka Enberg break; 14010eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: { 141fe99fd4eSPekka Enberg struct virtio_blk_outhdr *req; 14210eca11dSPekka Enberg struct virt_queue *queue; 143fe99fd4eSPekka Enberg struct vring_desc *desc; 14410eca11dSPekka Enberg uint16_t queue_index; 145fe99fd4eSPekka Enberg uint16_t desc_ndx; 1465a24a9f2SPekka Enberg uint32_t dst_len; 1475a24a9f2SPekka Enberg uint8_t *status; 1485a24a9f2SPekka Enberg void *dst; 1491f848897SPekka Enberg int err; 15010eca11dSPekka Enberg 15110eca11dSPekka Enberg queue_index = ioport__read16(data); 15210eca11dSPekka Enberg 15310eca11dSPekka Enberg queue = &device.virt_queues[queue_index]; 15410eca11dSPekka Enberg 155*93d18b72SPekka Enberg if (queue->vring.avail->idx == queue->last_avail_idx) { 156*93d18b72SPekka Enberg warning("vring is empty"); 157*93d18b72SPekka Enberg break; 158*93d18b72SPekka Enberg } 159fe99fd4eSPekka Enberg 160*93d18b72SPekka Enberg desc_ndx = queue->vring.avail->ring[queue->last_avail_idx++ % queue->vring.num]; 161*93d18b72SPekka Enberg 162*93d18b72SPekka Enberg if (desc_ndx >= queue->vring.num) { 163*93d18b72SPekka Enberg warning("fatal I/O error"); 164fe99fd4eSPekka Enberg break; 165fe99fd4eSPekka Enberg } 166fe99fd4eSPekka Enberg 1675a24a9f2SPekka Enberg /* header */ 168fe99fd4eSPekka Enberg desc = &queue->vring.desc[desc_ndx]; 169fe99fd4eSPekka Enberg 170fe99fd4eSPekka Enberg req = guest_flat_to_host(self, desc->addr); 171fe99fd4eSPekka Enberg 1725a24a9f2SPekka Enberg /* block */ 1735a24a9f2SPekka Enberg desc = &queue->vring.desc[desc->next]; 1745a24a9f2SPekka Enberg 1755a24a9f2SPekka Enberg dst = guest_flat_to_host(self, desc->addr); 1765a24a9f2SPekka Enberg dst_len = desc->len; 1775a24a9f2SPekka Enberg 1785a24a9f2SPekka Enberg /* status */ 1795a24a9f2SPekka Enberg desc = &queue->vring.desc[desc->next]; 1805a24a9f2SPekka Enberg 1815a24a9f2SPekka Enberg status = guest_flat_to_host(self, desc->addr); 1825a24a9f2SPekka Enberg 1835a24a9f2SPekka Enberg err = disk_image__read_sector(self->disk_image, req->sector, dst, dst_len); 1845a24a9f2SPekka Enberg 1855a24a9f2SPekka Enberg if (err) 1865a24a9f2SPekka Enberg *status = VIRTIO_BLK_S_IOERR; 1875a24a9f2SPekka Enberg else 1885a24a9f2SPekka Enberg *status = VIRTIO_BLK_S_OK; 1895a24a9f2SPekka Enberg 1905a24a9f2SPekka Enberg queue->vring.used->idx++; 1915a24a9f2SPekka Enberg 1928b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); 1935a24a9f2SPekka Enberg 1947e61688eSPekka Enberg break; 19510eca11dSPekka Enberg } 196fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 197fbc2fbf9SPekka Enberg device.status = ioport__read8(data); 198fbc2fbf9SPekka Enberg break; 199fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 20040ce993fSPekka Enberg device.config_vector = VIRTIO_MSI_NO_VECTOR; 20140ce993fSPekka Enberg break; 202fbc2fbf9SPekka Enberg case VIRTIO_MSI_QUEUE_VECTOR: 20340ce993fSPekka Enberg break; 204fbc2fbf9SPekka Enberg default: 205fbc2fbf9SPekka Enberg return false; 206fbc2fbf9SPekka Enberg }; 207fbc2fbf9SPekka Enberg 208fbc2fbf9SPekka Enberg return true; 209fbc2fbf9SPekka Enberg } 210fbc2fbf9SPekka Enberg 211fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = { 212fbc2fbf9SPekka Enberg .io_in = blk_virtio_in, 213fbc2fbf9SPekka Enberg .io_out = blk_virtio_out, 214fbc2fbf9SPekka Enberg }; 215fbc2fbf9SPekka Enberg 216b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 217b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 218b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 219b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 220b30d05adSPekka Enberg 221fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = { 222b30d05adSPekka Enberg .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 223b30d05adSPekka Enberg .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 224b30d05adSPekka Enberg .header_type = PCI_HEADER_TYPE_NORMAL, 225b30d05adSPekka Enberg .revision_id = 0, 226b30d05adSPekka Enberg .class = 0x010000, 227b30d05adSPekka Enberg .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 228b30d05adSPekka Enberg .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 229b30d05adSPekka Enberg .bar[0] = IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO, 230dc53a427SPekka Enberg .irq_pin = 1, 2318b1ff07eSPekka Enberg .irq_line = VIRTIO_BLK_IRQ, 232b30d05adSPekka Enberg }; 233b30d05adSPekka Enberg 234ca7c891bSCyrill Gorcunov void blk_virtio__init(struct kvm *self) 235b30d05adSPekka Enberg { 2361f848897SPekka Enberg if (!self->disk_image) 2371f848897SPekka Enberg return; 2381f848897SPekka Enberg 2396160ab9dSAsias He device.blk_config.capacity = self->disk_image->size / 512; 240ca7c891bSCyrill Gorcunov 241fbc2fbf9SPekka Enberg pci__register(&blk_virtio_pci_device, 1); 242b30d05adSPekka Enberg 2438b1ff07eSPekka Enberg ioport__register(IOPORT_VIRTIO, &blk_virtio_io_ops, 256); 244b30d05adSPekka Enberg } 245