1b30d05adSPekka Enberg #include "kvm/blk-virtio.h" 2b30d05adSPekka Enberg 3*10eca11dSPekka Enberg #include "kvm/virtio_ring.h" 4c435b91dSPekka Enberg #include "kvm/virtio_blk.h" 5984b7ae0SPekka Enberg #include "kvm/virtio_pci.h" 6b30d05adSPekka Enberg #include "kvm/ioport.h" 78b1ff07eSPekka Enberg #include "kvm/kvm.h" 8b30d05adSPekka Enberg #include "kvm/pci.h" 9b30d05adSPekka Enberg 108b1ff07eSPekka Enberg #define VIRTIO_BLK_IRQ 14 11984b7ae0SPekka Enberg 12*10eca11dSPekka Enberg #define NUM_VIRT_QUEUES 1 13*10eca11dSPekka Enberg 14*10eca11dSPekka Enberg #define VIRTIO_BLK_QUEUE_SIZE 16 15*10eca11dSPekka Enberg 16*10eca11dSPekka Enberg struct virt_queue { 17*10eca11dSPekka Enberg uint32_t pfn; 18*10eca11dSPekka Enberg struct vring vring; 19*10eca11dSPekka Enberg }; 20*10eca11dSPekka Enberg 21fbc2fbf9SPekka Enberg struct device { 2240ce993fSPekka Enberg struct virtio_blk_config blk_config; 23c435b91dSPekka Enberg uint32_t host_features; 24fbc2fbf9SPekka Enberg uint32_t guest_features; 2540ce993fSPekka Enberg uint16_t config_vector; 26fbc2fbf9SPekka Enberg uint8_t status; 2747bf1d0fSPekka Enberg 2847bf1d0fSPekka Enberg /* virtio queue */ 2947bf1d0fSPekka Enberg uint16_t queue_selector; 30*10eca11dSPekka Enberg 31*10eca11dSPekka Enberg struct virt_queue virt_queues[NUM_VIRT_QUEUES]; 32fbc2fbf9SPekka Enberg }; 33fbc2fbf9SPekka Enberg 3440ce993fSPekka Enberg #define DISK_CYLINDERS 1024 3540ce993fSPekka Enberg #define DISK_HEADS 64 3640ce993fSPekka Enberg #define DISK_SECTORS 32 3740ce993fSPekka Enberg 38c435b91dSPekka Enberg static struct device device = { 3940ce993fSPekka Enberg .blk_config = (struct virtio_blk_config) { 4040ce993fSPekka Enberg .capacity = DISK_CYLINDERS * DISK_HEADS * DISK_SECTORS, 4140ce993fSPekka Enberg /* VIRTIO_BLK_F_GEOMETRY */ 4240ce993fSPekka Enberg .geometry = { 4340ce993fSPekka Enberg .cylinders = DISK_CYLINDERS, 4440ce993fSPekka Enberg .heads = DISK_HEADS, 4540ce993fSPekka Enberg .sectors = DISK_SECTORS, 4640ce993fSPekka Enberg }, 4740ce993fSPekka Enberg /* VIRTIO_BLK_SIZE */ 4840ce993fSPekka Enberg .blk_size = 4096, 4940ce993fSPekka Enberg }, 5098790f28SPekka Enberg .host_features = (1UL << VIRTIO_BLK_F_GEOMETRY) 51cb938db9SPekka Enberg | (1UL << VIRTIO_BLK_F_RO) 52c435b91dSPekka Enberg | (1UL << VIRTIO_BLK_F_BLK_SIZE), 53c435b91dSPekka Enberg }; 54fbc2fbf9SPekka Enberg 5540ce993fSPekka Enberg static bool virtio_blk_config_in(void *data, unsigned long offset, int size, uint32_t count) 5640ce993fSPekka Enberg { 5740ce993fSPekka Enberg uint8_t *config_space = (uint8_t *) &device.blk_config; 5840ce993fSPekka Enberg 5940ce993fSPekka Enberg if (size != 1 || count != 1) 6040ce993fSPekka Enberg return false; 6140ce993fSPekka Enberg 6240ce993fSPekka Enberg ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]); 6340ce993fSPekka Enberg 6440ce993fSPekka Enberg return true; 6540ce993fSPekka Enberg } 6640ce993fSPekka Enberg 67fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 68fbc2fbf9SPekka Enberg { 69fbc2fbf9SPekka Enberg unsigned long offset; 70fbc2fbf9SPekka Enberg 71fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 72fbc2fbf9SPekka Enberg 73fbc2fbf9SPekka Enberg switch (offset) { 74fbc2fbf9SPekka Enberg case VIRTIO_PCI_HOST_FEATURES: 75c435b91dSPekka Enberg ioport__write32(data, device.host_features); 76fbc2fbf9SPekka Enberg break; 77fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 788b1ff07eSPekka Enberg return false; 79fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 80*10eca11dSPekka Enberg ioport__write32(data, device.virt_queues[device.queue_selector].pfn); 818b1ff07eSPekka Enberg break; 82fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NUM: 83*10eca11dSPekka Enberg ioport__write16(data, VIRTIO_BLK_QUEUE_SIZE); 848b1ff07eSPekka Enberg break; 85fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 86fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: 87fbc2fbf9SPekka Enberg return false; 88fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 89fbc2fbf9SPekka Enberg ioport__write8(data, device.status); 90fbc2fbf9SPekka Enberg break; 91fbc2fbf9SPekka Enberg case VIRTIO_PCI_ISR: 928b1ff07eSPekka Enberg ioport__write8(data, 0x1); 938b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 0); 947e61688eSPekka Enberg break; 95fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 9640ce993fSPekka Enberg ioport__write16(data, device.config_vector); 9740ce993fSPekka Enberg break; 98fbc2fbf9SPekka Enberg default: 9940ce993fSPekka Enberg return virtio_blk_config_in(data, offset, size, count); 100fbc2fbf9SPekka Enberg }; 101fbc2fbf9SPekka Enberg 102fbc2fbf9SPekka Enberg return true; 103fbc2fbf9SPekka Enberg } 104fbc2fbf9SPekka Enberg 105fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 106fbc2fbf9SPekka Enberg { 107fbc2fbf9SPekka Enberg unsigned long offset; 108fbc2fbf9SPekka Enberg 109fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 110fbc2fbf9SPekka Enberg 111fbc2fbf9SPekka Enberg switch (offset) { 112fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 113fbc2fbf9SPekka Enberg device.guest_features = ioport__read32(data); 114fbc2fbf9SPekka Enberg break; 115*10eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_PFN: { 116*10eca11dSPekka Enberg struct virt_queue *queue; 117*10eca11dSPekka Enberg void *p; 118*10eca11dSPekka Enberg 119*10eca11dSPekka Enberg queue = &device.virt_queues[device.queue_selector]; 120*10eca11dSPekka Enberg 121*10eca11dSPekka Enberg queue->pfn = ioport__read32(data); 122*10eca11dSPekka Enberg 123*10eca11dSPekka Enberg p = guest_flat_to_host(self, queue->pfn << 12); 124*10eca11dSPekka Enberg 125*10eca11dSPekka Enberg vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, 4096); 126*10eca11dSPekka Enberg 1277e61688eSPekka Enberg break; 128*10eca11dSPekka Enberg } 129fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 13047bf1d0fSPekka Enberg device.queue_selector = ioport__read16(data); 1317e61688eSPekka Enberg break; 132*10eca11dSPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: { 133*10eca11dSPekka Enberg struct virt_queue *queue; 134*10eca11dSPekka Enberg uint16_t queue_index; 135*10eca11dSPekka Enberg 136*10eca11dSPekka Enberg queue_index = ioport__read16(data); 137*10eca11dSPekka Enberg 138*10eca11dSPekka Enberg queue = &device.virt_queues[queue_index]; 139*10eca11dSPekka Enberg 1408b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); 1417e61688eSPekka Enberg break; 142*10eca11dSPekka Enberg } 143fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 144fbc2fbf9SPekka Enberg device.status = ioport__read8(data); 145fbc2fbf9SPekka Enberg break; 146fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 14740ce993fSPekka Enberg device.config_vector = VIRTIO_MSI_NO_VECTOR; 14840ce993fSPekka Enberg break; 149fbc2fbf9SPekka Enberg case VIRTIO_MSI_QUEUE_VECTOR: 15040ce993fSPekka Enberg break; 151fbc2fbf9SPekka Enberg default: 152fbc2fbf9SPekka Enberg return false; 153fbc2fbf9SPekka Enberg }; 154fbc2fbf9SPekka Enberg 155fbc2fbf9SPekka Enberg return true; 156fbc2fbf9SPekka Enberg } 157fbc2fbf9SPekka Enberg 158fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = { 159fbc2fbf9SPekka Enberg .io_in = blk_virtio_in, 160fbc2fbf9SPekka Enberg .io_out = blk_virtio_out, 161fbc2fbf9SPekka Enberg }; 162fbc2fbf9SPekka Enberg 163b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 164b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 165b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 166b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 167b30d05adSPekka Enberg 168fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = { 169b30d05adSPekka Enberg .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 170b30d05adSPekka Enberg .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 171b30d05adSPekka Enberg .header_type = PCI_HEADER_TYPE_NORMAL, 172b30d05adSPekka Enberg .revision_id = 0, 173b30d05adSPekka Enberg .class = 0x010000, 174b30d05adSPekka Enberg .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 175b30d05adSPekka Enberg .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 176b30d05adSPekka Enberg .bar[0] = IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO, 177dc53a427SPekka Enberg /* XXX: Is this IRQ setup OK? */ 178dc53a427SPekka Enberg .irq_pin = 1, 1798b1ff07eSPekka Enberg .irq_line = VIRTIO_BLK_IRQ, 180b30d05adSPekka Enberg }; 181b30d05adSPekka Enberg 182b30d05adSPekka Enberg void blk_virtio__init(void) 183b30d05adSPekka Enberg { 184fbc2fbf9SPekka Enberg pci__register(&blk_virtio_pci_device, 1); 185b30d05adSPekka Enberg 1868b1ff07eSPekka Enberg ioport__register(IOPORT_VIRTIO, &blk_virtio_io_ops, 256); 187b30d05adSPekka Enberg } 188