1b30d05adSPekka Enberg #include "kvm/blk-virtio.h" 2b30d05adSPekka Enberg 3984b7ae0SPekka Enberg #include "kvm/virtio_pci.h" 45a24a9f2SPekka Enberg #include "kvm/disk-image.h" 5b30d05adSPekka Enberg #include "kvm/ioport.h" 6fe99fd4eSPekka Enberg #include "kvm/util.h" 78b1ff07eSPekka Enberg #include "kvm/kvm.h" 8b30d05adSPekka Enberg #include "kvm/pci.h" 9b30d05adSPekka Enberg 10*20c64ecaSPekka Enberg #include <linux/virtio_ring.h> 11*20c64ecaSPekka Enberg #include <linux/virtio_blk.h> 124155ba8cSPekka Enberg #include <inttypes.h> 134155ba8cSPekka Enberg #include <assert.h> 144155ba8cSPekka 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 */ 63a267e01bSPekka Enberg .host_features = 0, 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 82d1888318SCyrill Gorcunov offset = port - IOPORT_VIRTIO_BLK; 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 116a267e01bSPekka Enberg static bool blk_virtio_read(struct kvm *self, struct virt_queue *queue) 1174155ba8cSPekka Enberg { 1184155ba8cSPekka Enberg struct vring_used_elem *used_elem; 1194155ba8cSPekka Enberg struct virtio_blk_outhdr *req; 1204155ba8cSPekka Enberg struct vring_desc *desc; 121a267e01bSPekka Enberg uint16_t desc_ndx; 122258dd093SPekka Enberg uint32_t block_len; 1234155ba8cSPekka Enberg uint8_t *status; 124258dd093SPekka Enberg void *block; 1254155ba8cSPekka Enberg 126a267e01bSPekka Enberg desc_ndx = queue->vring.avail->ring[queue->last_avail_idx++ % queue->vring.num]; 1274155ba8cSPekka Enberg 128a267e01bSPekka Enberg if (desc_ndx >= queue->vring.num) { 1294155ba8cSPekka Enberg warning("fatal I/O error"); 1304155ba8cSPekka Enberg return false; 1314155ba8cSPekka Enberg } 1324155ba8cSPekka Enberg 133a267e01bSPekka Enberg /* header */ 134a267e01bSPekka Enberg desc = &queue->vring.desc[desc_ndx]; 1354155ba8cSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 1364155ba8cSPekka Enberg 1374155ba8cSPekka Enberg req = guest_flat_to_host(self, desc->addr); 1384155ba8cSPekka Enberg 1394155ba8cSPekka Enberg /* block */ 140a267e01bSPekka Enberg desc = &queue->vring.desc[desc->next]; 1414155ba8cSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 1424155ba8cSPekka Enberg 143258dd093SPekka Enberg block = guest_flat_to_host(self, desc->addr); 144258dd093SPekka Enberg block_len = desc->len; 1454155ba8cSPekka Enberg 146a267e01bSPekka Enberg /* status */ 147a267e01bSPekka Enberg desc = &queue->vring.desc[desc->next]; 148a267e01bSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 149a267e01bSPekka Enberg 150a267e01bSPekka Enberg status = guest_flat_to_host(self, desc->addr); 151a267e01bSPekka Enberg 152258dd093SPekka Enberg switch (req->type) { 153a267e01bSPekka Enberg case VIRTIO_BLK_T_IN: { 154a267e01bSPekka Enberg int err; 155a267e01bSPekka Enberg 156258dd093SPekka Enberg err = disk_image__read_sector(self->disk_image, req->sector, block, block_len); 157a267e01bSPekka Enberg if (err) 158a267e01bSPekka Enberg *status = VIRTIO_BLK_S_IOERR; 159a267e01bSPekka Enberg else 160a267e01bSPekka Enberg *status = VIRTIO_BLK_S_OK; 161258dd093SPekka Enberg break; 162a267e01bSPekka Enberg } 163a267e01bSPekka Enberg case VIRTIO_BLK_T_OUT: { 164a267e01bSPekka Enberg int err; 165a267e01bSPekka Enberg 166258dd093SPekka Enberg err = disk_image__write_sector(self->disk_image, req->sector, block, block_len); 167a267e01bSPekka Enberg if (err) 168a267e01bSPekka Enberg *status = VIRTIO_BLK_S_IOERR; 169a267e01bSPekka Enberg else 170a267e01bSPekka Enberg *status = VIRTIO_BLK_S_OK; 171258dd093SPekka Enberg break; 172a267e01bSPekka Enberg } 173258dd093SPekka Enberg default: 1744155ba8cSPekka Enberg warning("request type %d", req->type); 175a267e01bSPekka Enberg *status = VIRTIO_BLK_S_IOERR; 176a2c8c696SAsias He break; 177a2c8c696SAsias He } 178a2c8c696SAsias He 179a2c8c696SAsias He used_elem = &queue->vring.used->ring[queue->vring.used->idx++ % queue->vring.num]; 180a267e01bSPekka Enberg 181a267e01bSPekka Enberg used_elem->id = desc_ndx; 182a267e01bSPekka Enberg used_elem->len = 3; 1834155ba8cSPekka Enberg 1844155ba8cSPekka Enberg return true; 1854155ba8cSPekka Enberg } 1864155ba8cSPekka Enberg 187fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 188fbc2fbf9SPekka Enberg { 189fbc2fbf9SPekka Enberg unsigned long offset; 190fbc2fbf9SPekka Enberg 191d1888318SCyrill Gorcunov offset = port - IOPORT_VIRTIO_BLK; 192fbc2fbf9SPekka Enberg 193fbc2fbf9SPekka Enberg switch (offset) { 194fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 195fbc2fbf9SPekka Enberg device.guest_features = ioport__read32(data); 196fbc2fbf9SPekka Enberg break; 19710eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_PFN: { 19810eca11dSPekka Enberg struct virt_queue *queue; 19910eca11dSPekka Enberg void *p; 20010eca11dSPekka Enberg 20110eca11dSPekka Enberg queue = &device.virt_queues[device.queue_selector]; 20210eca11dSPekka Enberg 20310eca11dSPekka Enberg queue->pfn = ioport__read32(data); 20410eca11dSPekka Enberg 20510eca11dSPekka Enberg p = guest_flat_to_host(self, queue->pfn << 12); 20610eca11dSPekka Enberg 20710eca11dSPekka Enberg vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, 4096); 20810eca11dSPekka Enberg 2097e61688eSPekka Enberg break; 21010eca11dSPekka Enberg } 211fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 21247bf1d0fSPekka Enberg device.queue_selector = ioport__read16(data); 2137e61688eSPekka Enberg break; 21410eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: { 21510eca11dSPekka Enberg struct virt_queue *queue; 21610eca11dSPekka Enberg uint16_t queue_index; 21710eca11dSPekka Enberg 21810eca11dSPekka Enberg queue_index = ioport__read16(data); 21910eca11dSPekka Enberg 22010eca11dSPekka Enberg queue = &device.virt_queues[queue_index]; 22110eca11dSPekka Enberg 2224155ba8cSPekka Enberg while (queue->vring.avail->idx != queue->last_avail_idx) { 223a267e01bSPekka Enberg if (!blk_virtio_read(self, queue)) 2244155ba8cSPekka Enberg return false; 22593d18b72SPekka Enberg } 2268b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); 2275a24a9f2SPekka Enberg 2287e61688eSPekka Enberg break; 22910eca11dSPekka Enberg } 230fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 231fbc2fbf9SPekka Enberg device.status = ioport__read8(data); 232fbc2fbf9SPekka Enberg break; 233fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 23440ce993fSPekka Enberg device.config_vector = VIRTIO_MSI_NO_VECTOR; 23540ce993fSPekka Enberg break; 236fbc2fbf9SPekka Enberg case VIRTIO_MSI_QUEUE_VECTOR: 23740ce993fSPekka Enberg break; 238fbc2fbf9SPekka Enberg default: 239fbc2fbf9SPekka Enberg return false; 240fbc2fbf9SPekka Enberg }; 241fbc2fbf9SPekka Enberg 242fbc2fbf9SPekka Enberg return true; 243fbc2fbf9SPekka Enberg } 244fbc2fbf9SPekka Enberg 245fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = { 246fbc2fbf9SPekka Enberg .io_in = blk_virtio_in, 247fbc2fbf9SPekka Enberg .io_out = blk_virtio_out, 248fbc2fbf9SPekka Enberg }; 249fbc2fbf9SPekka Enberg 250b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 251b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 252b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 253b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 254b30d05adSPekka Enberg 255fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = { 256b30d05adSPekka Enberg .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 257b30d05adSPekka Enberg .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 258b30d05adSPekka Enberg .header_type = PCI_HEADER_TYPE_NORMAL, 259b30d05adSPekka Enberg .revision_id = 0, 260b30d05adSPekka Enberg .class = 0x010000, 261b30d05adSPekka Enberg .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 262b30d05adSPekka Enberg .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 263d1888318SCyrill Gorcunov .bar[0] = IOPORT_VIRTIO_BLK | PCI_BASE_ADDRESS_SPACE_IO, 264dc53a427SPekka Enberg .irq_pin = 1, 2658b1ff07eSPekka Enberg .irq_line = VIRTIO_BLK_IRQ, 266b30d05adSPekka Enberg }; 267b30d05adSPekka Enberg 268ca7c891bSCyrill Gorcunov void blk_virtio__init(struct kvm *self) 269b30d05adSPekka Enberg { 2701f848897SPekka Enberg if (!self->disk_image) 2711f848897SPekka Enberg return; 2721f848897SPekka Enberg 273a267e01bSPekka Enberg device.blk_config.capacity = self->disk_image->size / SECTOR_SIZE; 274ca7c891bSCyrill Gorcunov 275fbc2fbf9SPekka Enberg pci__register(&blk_virtio_pci_device, 1); 276b30d05adSPekka Enberg 277d1888318SCyrill Gorcunov ioport__register(IOPORT_VIRTIO_BLK, &blk_virtio_io_ops, 256); 278b30d05adSPekka Enberg } 279