1b30d05adSPekka Enberg #include "kvm/blk-virtio.h" 2b30d05adSPekka Enberg 3984b7ae0SPekka Enberg #include "kvm/virtio_pci.h" 476b6349fSPekka Enberg 55a24a9f2SPekka Enberg #include "kvm/disk-image.h" 676b6349fSPekka 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 21*03110ff3SAsias He #define VIRTIO_BLK_QUEUE_SIZE 128 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 39*03110ff3SAsias He #define DISK_SEG_MAX 126 4040ce993fSPekka Enberg 41c435b91dSPekka Enberg static struct device device = { 4240ce993fSPekka Enberg .blk_config = (struct virtio_blk_config) { 4340ce993fSPekka Enberg .capacity = DISK_CYLINDERS * DISK_HEADS * DISK_SECTORS, 44*03110ff3SAsias He .seg_max = DISK_SEG_MAX, 4540ce993fSPekka Enberg /* VIRTIO_BLK_F_GEOMETRY */ 4640ce993fSPekka Enberg .geometry = { 4740ce993fSPekka Enberg .cylinders = DISK_CYLINDERS, 4840ce993fSPekka Enberg .heads = DISK_HEADS, 4940ce993fSPekka Enberg .sectors = DISK_SECTORS, 5040ce993fSPekka Enberg }, 5140ce993fSPekka Enberg /* VIRTIO_BLK_SIZE */ 5240ce993fSPekka Enberg .blk_size = 4096, 5340ce993fSPekka Enberg }, 541ef2738dSCyrill Gorcunov /* 551ef2738dSCyrill Gorcunov * Note we don't set VIRTIO_BLK_F_GEOMETRY here so the 561ef2738dSCyrill Gorcunov * node kernel will compute disk geometry by own, the 571ef2738dSCyrill Gorcunov * same applies to VIRTIO_BLK_F_BLK_SIZE 581ef2738dSCyrill Gorcunov */ 59*03110ff3SAsias He .host_features = (1UL << VIRTIO_BLK_F_SEG_MAX), 60c435b91dSPekka Enberg }; 61fbc2fbf9SPekka Enberg 6240ce993fSPekka Enberg static bool virtio_blk_config_in(void *data, unsigned long offset, int size, uint32_t count) 6340ce993fSPekka Enberg { 6440ce993fSPekka Enberg uint8_t *config_space = (uint8_t *) &device.blk_config; 6540ce993fSPekka Enberg 6640ce993fSPekka Enberg if (size != 1 || count != 1) 6740ce993fSPekka Enberg return false; 6840ce993fSPekka Enberg 6940ce993fSPekka Enberg ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]); 7040ce993fSPekka Enberg 7140ce993fSPekka Enberg return true; 7240ce993fSPekka Enberg } 7340ce993fSPekka Enberg 74fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 75fbc2fbf9SPekka Enberg { 76fbc2fbf9SPekka Enberg unsigned long offset; 77fbc2fbf9SPekka Enberg 78d1888318SCyrill Gorcunov offset = port - IOPORT_VIRTIO_BLK; 79fbc2fbf9SPekka Enberg 80fbc2fbf9SPekka Enberg switch (offset) { 81fbc2fbf9SPekka Enberg case VIRTIO_PCI_HOST_FEATURES: 82c435b91dSPekka Enberg ioport__write32(data, device.host_features); 83fbc2fbf9SPekka Enberg break; 84fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 858b1ff07eSPekka Enberg return false; 86fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 8710eca11dSPekka Enberg ioport__write32(data, device.virt_queues[device.queue_selector].pfn); 888b1ff07eSPekka Enberg break; 89fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NUM: 9010eca11dSPekka Enberg ioport__write16(data, VIRTIO_BLK_QUEUE_SIZE); 918b1ff07eSPekka Enberg break; 92fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 93fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: 94fbc2fbf9SPekka Enberg return false; 95fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 96fbc2fbf9SPekka Enberg ioport__write8(data, device.status); 97fbc2fbf9SPekka Enberg break; 98fbc2fbf9SPekka Enberg case VIRTIO_PCI_ISR: 998b1ff07eSPekka Enberg ioport__write8(data, 0x1); 1008b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 0); 1017e61688eSPekka Enberg break; 102fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 10340ce993fSPekka Enberg ioport__write16(data, device.config_vector); 10440ce993fSPekka Enberg break; 105fbc2fbf9SPekka Enberg default: 10640ce993fSPekka Enberg return virtio_blk_config_in(data, offset, size, count); 107fbc2fbf9SPekka Enberg }; 108fbc2fbf9SPekka Enberg 109fbc2fbf9SPekka Enberg return true; 110fbc2fbf9SPekka Enberg } 111fbc2fbf9SPekka Enberg 112*03110ff3SAsias He static bool blk_virtio_request(struct kvm *self, struct virt_queue *queue) 1134155ba8cSPekka Enberg { 1144155ba8cSPekka Enberg struct vring_used_elem *used_elem; 1154155ba8cSPekka Enberg struct virtio_blk_outhdr *req; 116*03110ff3SAsias He uint16_t desc_block_last; 1174155ba8cSPekka Enberg struct vring_desc *desc; 118*03110ff3SAsias He uint16_t desc_status; 119*03110ff3SAsias He uint16_t desc_block; 120258dd093SPekka Enberg uint32_t block_len; 121*03110ff3SAsias He uint32_t block_cnt; 122*03110ff3SAsias He uint16_t desc_hdr; 1234155ba8cSPekka Enberg uint8_t *status; 124258dd093SPekka Enberg void *block; 125*03110ff3SAsias He int err; 126*03110ff3SAsias He int err_cnt; 1274155ba8cSPekka Enberg 128*03110ff3SAsias He /* header */ 129*03110ff3SAsias He desc_hdr = virt_queue__pop(queue); 1304155ba8cSPekka Enberg 131*03110ff3SAsias He if (desc_hdr >= queue->vring.num) { 1324155ba8cSPekka Enberg warning("fatal I/O error"); 1334155ba8cSPekka Enberg return false; 1344155ba8cSPekka Enberg } 1354155ba8cSPekka Enberg 136*03110ff3SAsias He desc = virt_queue__get_desc(queue, desc_hdr); 1374155ba8cSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 1384155ba8cSPekka Enberg 1394155ba8cSPekka Enberg req = guest_flat_to_host(self, desc->addr); 1404155ba8cSPekka Enberg 141*03110ff3SAsias He /* status */ 142*03110ff3SAsias He desc_status = desc_hdr; 143*03110ff3SAsias He 144*03110ff3SAsias He do { 145*03110ff3SAsias He desc_block_last = desc_status; 146*03110ff3SAsias He desc_status = virt_queue__get_desc(queue, desc_status)->next; 147*03110ff3SAsias He 148*03110ff3SAsias He if (desc_status >= queue->vring.num) { 149*03110ff3SAsias He warning("fatal I/O error"); 150*03110ff3SAsias He return false; 151*03110ff3SAsias He } 152*03110ff3SAsias He 153*03110ff3SAsias He desc = virt_queue__get_desc(queue, desc_status); 154*03110ff3SAsias He assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 155*03110ff3SAsias He 156*03110ff3SAsias He } while (desc->flags & VRING_DESC_F_NEXT); 157*03110ff3SAsias He 158*03110ff3SAsias He status = guest_flat_to_host(self, desc->addr); 159*03110ff3SAsias He 1604155ba8cSPekka Enberg /* block */ 161*03110ff3SAsias He desc_block = desc_hdr; 162*03110ff3SAsias He block_cnt = 0; 163*03110ff3SAsias He err_cnt = 0; 164*03110ff3SAsias He 165*03110ff3SAsias He do { 166*03110ff3SAsias He desc_block = virt_queue__get_desc(queue, desc_block)->next; 167*03110ff3SAsias He 168*03110ff3SAsias He desc = virt_queue__get_desc(queue, desc_block); 1694155ba8cSPekka Enberg assert(!(desc->flags & VRING_DESC_F_INDIRECT)); 1704155ba8cSPekka Enberg 171258dd093SPekka Enberg block = guest_flat_to_host(self, desc->addr); 172258dd093SPekka Enberg block_len = desc->len; 1734155ba8cSPekka Enberg 174258dd093SPekka Enberg switch (req->type) { 175*03110ff3SAsias He case VIRTIO_BLK_T_IN: 176258dd093SPekka Enberg err = disk_image__read_sector(self->disk_image, req->sector, block, block_len); 177258dd093SPekka Enberg break; 178*03110ff3SAsias He case VIRTIO_BLK_T_OUT: 179258dd093SPekka Enberg err = disk_image__write_sector(self->disk_image, req->sector, block, block_len); 180258dd093SPekka Enberg break; 181258dd093SPekka Enberg default: 1824155ba8cSPekka Enberg warning("request type %d", req->type); 183*03110ff3SAsias He err = -1; 184a2c8c696SAsias He } 185a2c8c696SAsias He 186*03110ff3SAsias He if (err) 187*03110ff3SAsias He err_cnt++; 188a267e01bSPekka Enberg 189*03110ff3SAsias He req->sector += block_len >> SECTOR_SHIFT; 190*03110ff3SAsias He block_cnt += block_len; 191*03110ff3SAsias He 192*03110ff3SAsias He if (desc_block == desc_block_last) 193*03110ff3SAsias He break; 194*03110ff3SAsias He 195*03110ff3SAsias He if (desc_block >= queue->vring.num) { 196*03110ff3SAsias He warning("fatal I/O error"); 197*03110ff3SAsias He return false; 198*03110ff3SAsias He } 199*03110ff3SAsias He 200*03110ff3SAsias He } while (true); 201*03110ff3SAsias He 202*03110ff3SAsias He *status = err_cnt ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK; 203*03110ff3SAsias He 204*03110ff3SAsias He used_elem = virt_queue__get_used_elem(queue); 205*03110ff3SAsias He used_elem->id = desc_hdr; 206*03110ff3SAsias He used_elem->len = block_cnt; 2074155ba8cSPekka Enberg 2084155ba8cSPekka Enberg return true; 2094155ba8cSPekka Enberg } 2104155ba8cSPekka Enberg 211fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 212fbc2fbf9SPekka Enberg { 213fbc2fbf9SPekka Enberg unsigned long offset; 214fbc2fbf9SPekka Enberg 215d1888318SCyrill Gorcunov offset = port - IOPORT_VIRTIO_BLK; 216fbc2fbf9SPekka Enberg 217fbc2fbf9SPekka Enberg switch (offset) { 218fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 219fbc2fbf9SPekka Enberg device.guest_features = ioport__read32(data); 220fbc2fbf9SPekka Enberg break; 22110eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_PFN: { 22210eca11dSPekka Enberg struct virt_queue *queue; 22310eca11dSPekka Enberg void *p; 22410eca11dSPekka Enberg 22510eca11dSPekka Enberg queue = &device.virt_queues[device.queue_selector]; 22610eca11dSPekka Enberg 22710eca11dSPekka Enberg queue->pfn = ioport__read32(data); 22810eca11dSPekka Enberg 22910eca11dSPekka Enberg p = guest_flat_to_host(self, queue->pfn << 12); 23010eca11dSPekka Enberg 23110eca11dSPekka Enberg vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, 4096); 23210eca11dSPekka Enberg 2337e61688eSPekka Enberg break; 23410eca11dSPekka Enberg } 235fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 23647bf1d0fSPekka Enberg device.queue_selector = ioport__read16(data); 2377e61688eSPekka Enberg break; 23810eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: { 23910eca11dSPekka Enberg struct virt_queue *queue; 24010eca11dSPekka Enberg uint16_t queue_index; 24110eca11dSPekka Enberg 24210eca11dSPekka Enberg queue_index = ioport__read16(data); 24310eca11dSPekka Enberg 24410eca11dSPekka Enberg queue = &device.virt_queues[queue_index]; 24510eca11dSPekka Enberg 2464155ba8cSPekka Enberg while (queue->vring.avail->idx != queue->last_avail_idx) { 247*03110ff3SAsias He if (!blk_virtio_request(self, queue)) 2484155ba8cSPekka Enberg return false; 24993d18b72SPekka Enberg } 2508b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); 2515a24a9f2SPekka Enberg 2527e61688eSPekka Enberg break; 25310eca11dSPekka Enberg } 254fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 255fbc2fbf9SPekka Enberg device.status = ioport__read8(data); 256fbc2fbf9SPekka Enberg break; 257fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 25840ce993fSPekka Enberg device.config_vector = VIRTIO_MSI_NO_VECTOR; 25940ce993fSPekka Enberg break; 260fbc2fbf9SPekka Enberg case VIRTIO_MSI_QUEUE_VECTOR: 26140ce993fSPekka Enberg break; 262fbc2fbf9SPekka Enberg default: 263fbc2fbf9SPekka Enberg return false; 264fbc2fbf9SPekka Enberg }; 265fbc2fbf9SPekka Enberg 266fbc2fbf9SPekka Enberg return true; 267fbc2fbf9SPekka Enberg } 268fbc2fbf9SPekka Enberg 269fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = { 270fbc2fbf9SPekka Enberg .io_in = blk_virtio_in, 271fbc2fbf9SPekka Enberg .io_out = blk_virtio_out, 272fbc2fbf9SPekka Enberg }; 273fbc2fbf9SPekka Enberg 274b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 275b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 276b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 277b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 278b30d05adSPekka Enberg 279fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = { 280b30d05adSPekka Enberg .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 281b30d05adSPekka Enberg .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 282b30d05adSPekka Enberg .header_type = PCI_HEADER_TYPE_NORMAL, 283b30d05adSPekka Enberg .revision_id = 0, 284b30d05adSPekka Enberg .class = 0x010000, 285b30d05adSPekka Enberg .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 286b30d05adSPekka Enberg .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 287d1888318SCyrill Gorcunov .bar[0] = IOPORT_VIRTIO_BLK | PCI_BASE_ADDRESS_SPACE_IO, 288dc53a427SPekka Enberg .irq_pin = 1, 2898b1ff07eSPekka Enberg .irq_line = VIRTIO_BLK_IRQ, 290b30d05adSPekka Enberg }; 291b30d05adSPekka Enberg 292ca7c891bSCyrill Gorcunov void blk_virtio__init(struct kvm *self) 293b30d05adSPekka Enberg { 2941f848897SPekka Enberg if (!self->disk_image) 2951f848897SPekka Enberg return; 2961f848897SPekka Enberg 297a267e01bSPekka Enberg device.blk_config.capacity = self->disk_image->size / SECTOR_SIZE; 298ca7c891bSCyrill Gorcunov 299fbc2fbf9SPekka Enberg pci__register(&blk_virtio_pci_device, 1); 300b30d05adSPekka Enberg 301d1888318SCyrill Gorcunov ioport__register(IOPORT_VIRTIO_BLK, &blk_virtio_io_ops, 256); 302b30d05adSPekka Enberg } 303