1b30d05adSPekka Enberg #include "kvm/blk-virtio.h" 2b30d05adSPekka Enberg 3984b7ae0SPekka Enberg #include "kvm/virtio_pci.h" 4*76b6349fSPekka Enberg 55a24a9f2SPekka Enberg #include "kvm/disk-image.h" 6*76b6349fSPekka Enberg #include "kvm/virtqueue.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 2110eca11dSPekka Enberg #define VIRTIO_BLK_QUEUE_SIZE 16 2210eca11dSPekka Enberg 23fbc2fbf9SPekka Enberg struct 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 3640ce993fSPekka Enberg #define DISK_CYLINDERS 1024 3740ce993fSPekka Enberg #define DISK_HEADS 64 3840ce993fSPekka Enberg #define DISK_SECTORS 32 3940ce993fSPekka Enberg 40c435b91dSPekka Enberg static struct device device = { 4140ce993fSPekka Enberg .blk_config = (struct virtio_blk_config) { 4240ce993fSPekka Enberg .capacity = DISK_CYLINDERS * DISK_HEADS * DISK_SECTORS, 4340ce993fSPekka Enberg /* VIRTIO_BLK_F_GEOMETRY */ 4440ce993fSPekka Enberg .geometry = { 4540ce993fSPekka Enberg .cylinders = DISK_CYLINDERS, 4640ce993fSPekka Enberg .heads = DISK_HEADS, 4740ce993fSPekka Enberg .sectors = DISK_SECTORS, 4840ce993fSPekka Enberg }, 4940ce993fSPekka Enberg /* VIRTIO_BLK_SIZE */ 5040ce993fSPekka Enberg .blk_size = 4096, 5140ce993fSPekka Enberg }, 521ef2738dSCyrill Gorcunov /* 531ef2738dSCyrill Gorcunov * Note we don't set VIRTIO_BLK_F_GEOMETRY here so the 541ef2738dSCyrill Gorcunov * node kernel will compute disk geometry by own, the 551ef2738dSCyrill Gorcunov * same applies to VIRTIO_BLK_F_BLK_SIZE 561ef2738dSCyrill Gorcunov */ 57a267e01bSPekka Enberg .host_features = 0, 58c435b91dSPekka Enberg }; 59fbc2fbf9SPekka Enberg 6040ce993fSPekka Enberg static bool virtio_blk_config_in(void *data, unsigned long offset, int size, uint32_t count) 6140ce993fSPekka Enberg { 6240ce993fSPekka Enberg uint8_t *config_space = (uint8_t *) &device.blk_config; 6340ce993fSPekka Enberg 6440ce993fSPekka Enberg if (size != 1 || count != 1) 6540ce993fSPekka Enberg return false; 6640ce993fSPekka Enberg 6740ce993fSPekka Enberg ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]); 6840ce993fSPekka Enberg 6940ce993fSPekka Enberg return true; 7040ce993fSPekka Enberg } 7140ce993fSPekka Enberg 72fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 73fbc2fbf9SPekka Enberg { 74fbc2fbf9SPekka Enberg unsigned long offset; 75fbc2fbf9SPekka Enberg 76d1888318SCyrill Gorcunov offset = port - IOPORT_VIRTIO_BLK; 77fbc2fbf9SPekka Enberg 78fbc2fbf9SPekka Enberg switch (offset) { 79fbc2fbf9SPekka Enberg case VIRTIO_PCI_HOST_FEATURES: 80c435b91dSPekka Enberg ioport__write32(data, device.host_features); 81fbc2fbf9SPekka Enberg break; 82fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 838b1ff07eSPekka Enberg return false; 84fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 8510eca11dSPekka Enberg ioport__write32(data, device.virt_queues[device.queue_selector].pfn); 868b1ff07eSPekka Enberg break; 87fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NUM: 8810eca11dSPekka Enberg ioport__write16(data, VIRTIO_BLK_QUEUE_SIZE); 898b1ff07eSPekka Enberg break; 90fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 91fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: 92fbc2fbf9SPekka Enberg return false; 93fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 94fbc2fbf9SPekka Enberg ioport__write8(data, device.status); 95fbc2fbf9SPekka Enberg break; 96fbc2fbf9SPekka Enberg case VIRTIO_PCI_ISR: 978b1ff07eSPekka Enberg ioport__write8(data, 0x1); 988b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 0); 997e61688eSPekka Enberg break; 100fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 10140ce993fSPekka Enberg ioport__write16(data, device.config_vector); 10240ce993fSPekka Enberg break; 103fbc2fbf9SPekka Enberg default: 10440ce993fSPekka Enberg return virtio_blk_config_in(data, offset, size, count); 105fbc2fbf9SPekka Enberg }; 106fbc2fbf9SPekka Enberg 107fbc2fbf9SPekka Enberg return true; 108fbc2fbf9SPekka Enberg } 109fbc2fbf9SPekka Enberg 110a267e01bSPekka Enberg static bool blk_virtio_read(struct kvm *self, struct virt_queue *queue) 1114155ba8cSPekka Enberg { 1124155ba8cSPekka Enberg struct vring_used_elem *used_elem; 1134155ba8cSPekka Enberg struct virtio_blk_outhdr *req; 1144155ba8cSPekka Enberg struct vring_desc *desc; 115258dd093SPekka Enberg uint32_t block_len; 116*76b6349fSPekka Enberg uint16_t desc_ndx; 1174155ba8cSPekka Enberg uint8_t *status; 118258dd093SPekka Enberg void *block; 1194155ba8cSPekka Enberg 120*76b6349fSPekka Enberg desc_ndx = virt_queue__pop(queue); 1214155ba8cSPekka Enberg 122a267e01bSPekka Enberg if (desc_ndx >= queue->vring.num) { 1234155ba8cSPekka Enberg warning("fatal I/O error"); 1244155ba8cSPekka Enberg return false; 1254155ba8cSPekka Enberg } 1264155ba8cSPekka Enberg 127a267e01bSPekka Enberg /* header */ 128*76b6349fSPekka Enberg desc = virt_queue__get_desc(queue, desc_ndx); 1294155ba8cSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 1304155ba8cSPekka Enberg 1314155ba8cSPekka Enberg req = guest_flat_to_host(self, desc->addr); 1324155ba8cSPekka Enberg 1334155ba8cSPekka Enberg /* block */ 134*76b6349fSPekka Enberg desc = virt_queue__get_desc(queue, desc->next); 1354155ba8cSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 1364155ba8cSPekka Enberg 137258dd093SPekka Enberg block = guest_flat_to_host(self, desc->addr); 138258dd093SPekka Enberg block_len = desc->len; 1394155ba8cSPekka Enberg 140a267e01bSPekka Enberg /* status */ 141*76b6349fSPekka Enberg desc = virt_queue__get_desc(queue, desc->next); 142a267e01bSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 143a267e01bSPekka Enberg 144a267e01bSPekka Enberg status = guest_flat_to_host(self, desc->addr); 145a267e01bSPekka Enberg 146258dd093SPekka Enberg switch (req->type) { 147a267e01bSPekka Enberg case VIRTIO_BLK_T_IN: { 148a267e01bSPekka Enberg int err; 149a267e01bSPekka Enberg 150258dd093SPekka Enberg err = disk_image__read_sector(self->disk_image, req->sector, block, block_len); 151a267e01bSPekka Enberg if (err) 152a267e01bSPekka Enberg *status = VIRTIO_BLK_S_IOERR; 153a267e01bSPekka Enberg else 154a267e01bSPekka Enberg *status = VIRTIO_BLK_S_OK; 155258dd093SPekka Enberg break; 156a267e01bSPekka Enberg } 157a267e01bSPekka Enberg case VIRTIO_BLK_T_OUT: { 158a267e01bSPekka Enberg int err; 159a267e01bSPekka Enberg 160258dd093SPekka Enberg err = disk_image__write_sector(self->disk_image, req->sector, block, block_len); 161a267e01bSPekka Enberg if (err) 162a267e01bSPekka Enberg *status = VIRTIO_BLK_S_IOERR; 163a267e01bSPekka Enberg else 164a267e01bSPekka Enberg *status = VIRTIO_BLK_S_OK; 165258dd093SPekka Enberg break; 166a267e01bSPekka Enberg } 167258dd093SPekka Enberg default: 1684155ba8cSPekka Enberg warning("request type %d", req->type); 169a267e01bSPekka Enberg *status = VIRTIO_BLK_S_IOERR; 170a2c8c696SAsias He break; 171a2c8c696SAsias He } 172a2c8c696SAsias He 173*76b6349fSPekka Enberg used_elem = virt_queue__get_used_elem(queue); 174a267e01bSPekka Enberg 175a267e01bSPekka Enberg used_elem->id = desc_ndx; 176a267e01bSPekka Enberg used_elem->len = 3; 1774155ba8cSPekka Enberg 1784155ba8cSPekka Enberg return true; 1794155ba8cSPekka Enberg } 1804155ba8cSPekka Enberg 181fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 182fbc2fbf9SPekka Enberg { 183fbc2fbf9SPekka Enberg unsigned long offset; 184fbc2fbf9SPekka Enberg 185d1888318SCyrill Gorcunov offset = port - IOPORT_VIRTIO_BLK; 186fbc2fbf9SPekka Enberg 187fbc2fbf9SPekka Enberg switch (offset) { 188fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 189fbc2fbf9SPekka Enberg device.guest_features = ioport__read32(data); 190fbc2fbf9SPekka Enberg break; 19110eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_PFN: { 19210eca11dSPekka Enberg struct virt_queue *queue; 19310eca11dSPekka Enberg void *p; 19410eca11dSPekka Enberg 19510eca11dSPekka Enberg queue = &device.virt_queues[device.queue_selector]; 19610eca11dSPekka Enberg 19710eca11dSPekka Enberg queue->pfn = ioport__read32(data); 19810eca11dSPekka Enberg 19910eca11dSPekka Enberg p = guest_flat_to_host(self, queue->pfn << 12); 20010eca11dSPekka Enberg 20110eca11dSPekka Enberg vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, 4096); 20210eca11dSPekka Enberg 2037e61688eSPekka Enberg break; 20410eca11dSPekka Enberg } 205fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 20647bf1d0fSPekka Enberg device.queue_selector = ioport__read16(data); 2077e61688eSPekka Enberg break; 20810eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: { 20910eca11dSPekka Enberg struct virt_queue *queue; 21010eca11dSPekka Enberg uint16_t queue_index; 21110eca11dSPekka Enberg 21210eca11dSPekka Enberg queue_index = ioport__read16(data); 21310eca11dSPekka Enberg 21410eca11dSPekka Enberg queue = &device.virt_queues[queue_index]; 21510eca11dSPekka Enberg 2164155ba8cSPekka Enberg while (queue->vring.avail->idx != queue->last_avail_idx) { 217a267e01bSPekka Enberg if (!blk_virtio_read(self, queue)) 2184155ba8cSPekka Enberg return false; 21993d18b72SPekka Enberg } 2208b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); 2215a24a9f2SPekka Enberg 2227e61688eSPekka Enberg break; 22310eca11dSPekka Enberg } 224fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 225fbc2fbf9SPekka Enberg device.status = ioport__read8(data); 226fbc2fbf9SPekka Enberg break; 227fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 22840ce993fSPekka Enberg device.config_vector = VIRTIO_MSI_NO_VECTOR; 22940ce993fSPekka Enberg break; 230fbc2fbf9SPekka Enberg case VIRTIO_MSI_QUEUE_VECTOR: 23140ce993fSPekka Enberg break; 232fbc2fbf9SPekka Enberg default: 233fbc2fbf9SPekka Enberg return false; 234fbc2fbf9SPekka Enberg }; 235fbc2fbf9SPekka Enberg 236fbc2fbf9SPekka Enberg return true; 237fbc2fbf9SPekka Enberg } 238fbc2fbf9SPekka Enberg 239fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = { 240fbc2fbf9SPekka Enberg .io_in = blk_virtio_in, 241fbc2fbf9SPekka Enberg .io_out = blk_virtio_out, 242fbc2fbf9SPekka Enberg }; 243fbc2fbf9SPekka Enberg 244b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 245b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 246b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 247b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 248b30d05adSPekka Enberg 249fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = { 250b30d05adSPekka Enberg .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 251b30d05adSPekka Enberg .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 252b30d05adSPekka Enberg .header_type = PCI_HEADER_TYPE_NORMAL, 253b30d05adSPekka Enberg .revision_id = 0, 254b30d05adSPekka Enberg .class = 0x010000, 255b30d05adSPekka Enberg .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 256b30d05adSPekka Enberg .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 257d1888318SCyrill Gorcunov .bar[0] = IOPORT_VIRTIO_BLK | PCI_BASE_ADDRESS_SPACE_IO, 258dc53a427SPekka Enberg .irq_pin = 1, 2598b1ff07eSPekka Enberg .irq_line = VIRTIO_BLK_IRQ, 260b30d05adSPekka Enberg }; 261b30d05adSPekka Enberg 262ca7c891bSCyrill Gorcunov void blk_virtio__init(struct kvm *self) 263b30d05adSPekka Enberg { 2641f848897SPekka Enberg if (!self->disk_image) 2651f848897SPekka Enberg return; 2661f848897SPekka Enberg 267a267e01bSPekka Enberg device.blk_config.capacity = self->disk_image->size / SECTOR_SIZE; 268ca7c891bSCyrill Gorcunov 269fbc2fbf9SPekka Enberg pci__register(&blk_virtio_pci_device, 1); 270b30d05adSPekka Enberg 271d1888318SCyrill Gorcunov ioport__register(IOPORT_VIRTIO_BLK, &blk_virtio_io_ops, 256); 272b30d05adSPekka Enberg } 273