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; 21fe99fd4eSPekka Enberg /* The next_avail_ndx field is an index to ->ring of struct vring_avail. 22fe99fd4eSPekka Enberg It's where we assume the next request index is at. */ 23fe99fd4eSPekka Enberg uint16_t next_avail_ndx; 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 }, 55*1ef2738dSCyrill Gorcunov /* 56*1ef2738dSCyrill Gorcunov * Note we don't set VIRTIO_BLK_F_GEOMETRY here so the 57*1ef2738dSCyrill Gorcunov * node kernel will compute disk geometry by own, the 58*1ef2738dSCyrill Gorcunov * same applies to VIRTIO_BLK_F_BLK_SIZE 59*1ef2738dSCyrill Gorcunov */ 60*1ef2738dSCyrill 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; 14910eca11dSPekka Enberg 15010eca11dSPekka Enberg queue_index = ioport__read16(data); 15110eca11dSPekka Enberg 15210eca11dSPekka Enberg queue = &device.virt_queues[queue_index]; 15310eca11dSPekka Enberg 154fe99fd4eSPekka Enberg desc_ndx = queue->vring.avail->ring[queue->next_avail_ndx++ % queue->vring.num]; 155fe99fd4eSPekka Enberg 156fe99fd4eSPekka Enberg if (queue->vring.avail->idx != queue->next_avail_ndx) { 157fe99fd4eSPekka Enberg /* 158fe99fd4eSPekka Enberg * The hypervisor and the guest disagree on next index. 159fe99fd4eSPekka Enberg */ 160fe99fd4eSPekka Enberg warning("I/O error"); 161fe99fd4eSPekka Enberg break; 162fe99fd4eSPekka Enberg } 163fe99fd4eSPekka Enberg 1645a24a9f2SPekka Enberg /* header */ 165fe99fd4eSPekka Enberg desc = &queue->vring.desc[desc_ndx]; 166fe99fd4eSPekka Enberg 167fe99fd4eSPekka Enberg req = guest_flat_to_host(self, desc->addr); 168fe99fd4eSPekka Enberg 1695a24a9f2SPekka Enberg /* block */ 1705a24a9f2SPekka Enberg desc = &queue->vring.desc[desc->next]; 1715a24a9f2SPekka Enberg 1725a24a9f2SPekka Enberg dst = guest_flat_to_host(self, desc->addr); 1735a24a9f2SPekka Enberg dst_len = desc->len; 1745a24a9f2SPekka Enberg 1755a24a9f2SPekka Enberg /* status */ 1765a24a9f2SPekka Enberg desc = &queue->vring.desc[desc->next]; 1775a24a9f2SPekka Enberg 1785a24a9f2SPekka Enberg status = guest_flat_to_host(self, desc->addr); 1795a24a9f2SPekka Enberg 1805a24a9f2SPekka Enberg if (self->disk_image) { 1815a24a9f2SPekka Enberg int err; 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 } else 1905a24a9f2SPekka Enberg *status = VIRTIO_BLK_S_IOERR; 1915a24a9f2SPekka Enberg 1925a24a9f2SPekka Enberg queue->vring.used->idx++; 1935a24a9f2SPekka Enberg 1948b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); 1955a24a9f2SPekka Enberg 1967e61688eSPekka Enberg break; 19710eca11dSPekka Enberg } 198fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 199fbc2fbf9SPekka Enberg device.status = ioport__read8(data); 200fbc2fbf9SPekka Enberg break; 201fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 20240ce993fSPekka Enberg device.config_vector = VIRTIO_MSI_NO_VECTOR; 20340ce993fSPekka Enberg break; 204fbc2fbf9SPekka Enberg case VIRTIO_MSI_QUEUE_VECTOR: 20540ce993fSPekka Enberg break; 206fbc2fbf9SPekka Enberg default: 207fbc2fbf9SPekka Enberg return false; 208fbc2fbf9SPekka Enberg }; 209fbc2fbf9SPekka Enberg 210fbc2fbf9SPekka Enberg return true; 211fbc2fbf9SPekka Enberg } 212fbc2fbf9SPekka Enberg 213fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = { 214fbc2fbf9SPekka Enberg .io_in = blk_virtio_in, 215fbc2fbf9SPekka Enberg .io_out = blk_virtio_out, 216fbc2fbf9SPekka Enberg }; 217fbc2fbf9SPekka Enberg 218b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 219b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 220b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 221b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 222b30d05adSPekka Enberg 223fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = { 224b30d05adSPekka Enberg .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 225b30d05adSPekka Enberg .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 226b30d05adSPekka Enberg .header_type = PCI_HEADER_TYPE_NORMAL, 227b30d05adSPekka Enberg .revision_id = 0, 228b30d05adSPekka Enberg .class = 0x010000, 229b30d05adSPekka Enberg .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 230b30d05adSPekka Enberg .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 231b30d05adSPekka Enberg .bar[0] = IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO, 232dc53a427SPekka Enberg .irq_pin = 1, 2338b1ff07eSPekka Enberg .irq_line = VIRTIO_BLK_IRQ, 234b30d05adSPekka Enberg }; 235b30d05adSPekka Enberg 236ca7c891bSCyrill Gorcunov void blk_virtio__init(struct kvm *self) 237b30d05adSPekka Enberg { 238*1ef2738dSCyrill Gorcunov if (self->disk_image) 239*1ef2738dSCyrill Gorcunov device.blk_config.capacity = self->disk_image->size; 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