1b30d05adSPekka Enberg #include "kvm/blk-virtio.h" 2b30d05adSPekka Enberg 3984b7ae0SPekka Enberg #include "kvm/virtio_pci.h" 4b30d05adSPekka Enberg #include "kvm/ioport.h" 58b1ff07eSPekka Enberg #include "kvm/kvm.h" 6b30d05adSPekka Enberg #include "kvm/pci.h" 7b30d05adSPekka Enberg 88b1ff07eSPekka Enberg #define VIRTIO_BLK_IRQ 14 9984b7ae0SPekka Enberg 10fbc2fbf9SPekka Enberg struct device { 11fbc2fbf9SPekka Enberg uint32_t guest_features; 12fbc2fbf9SPekka Enberg uint8_t status; 13fbc2fbf9SPekka Enberg }; 14fbc2fbf9SPekka Enberg 15fbc2fbf9SPekka Enberg static struct device device; 16fbc2fbf9SPekka Enberg 17fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 18fbc2fbf9SPekka Enberg { 19fbc2fbf9SPekka Enberg unsigned long offset; 20fbc2fbf9SPekka Enberg 21fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 22fbc2fbf9SPekka Enberg 238b1ff07eSPekka Enberg /* XXX: Let virtio block device handle this */ 248b1ff07eSPekka Enberg if (offset >= VIRTIO_PCI_CONFIG_NOMSI) 258b1ff07eSPekka Enberg return true; 268b1ff07eSPekka Enberg 27fbc2fbf9SPekka Enberg switch (offset) { 28fbc2fbf9SPekka Enberg case VIRTIO_PCI_HOST_FEATURES: 29fbc2fbf9SPekka Enberg ioport__write32(data, 0x00); 30fbc2fbf9SPekka Enberg break; 31fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 328b1ff07eSPekka Enberg return false; 33fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 348b1ff07eSPekka Enberg ioport__write32(data, 0x00); 358b1ff07eSPekka Enberg break; 36fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NUM: 378b1ff07eSPekka Enberg ioport__write16(data, 0x10); 388b1ff07eSPekka Enberg break; 39fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 40fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: 41fbc2fbf9SPekka Enberg return false; 42fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 43fbc2fbf9SPekka Enberg ioport__write8(data, device.status); 44fbc2fbf9SPekka Enberg break; 45fbc2fbf9SPekka Enberg case VIRTIO_PCI_ISR: 468b1ff07eSPekka Enberg ioport__write8(data, 0x1); 478b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 0); 488b1ff07eSPekka Enberg return true; 49fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 50fbc2fbf9SPekka Enberg default: 51fbc2fbf9SPekka Enberg return false; 52fbc2fbf9SPekka Enberg }; 53fbc2fbf9SPekka Enberg 54fbc2fbf9SPekka Enberg return true; 55fbc2fbf9SPekka Enberg } 56fbc2fbf9SPekka Enberg 57fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 58fbc2fbf9SPekka Enberg { 59fbc2fbf9SPekka Enberg unsigned long offset; 60fbc2fbf9SPekka Enberg 61fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 62fbc2fbf9SPekka Enberg 638b1ff07eSPekka Enberg /* XXX: Let virtio block device handle this */ 648b1ff07eSPekka Enberg if (offset >= VIRTIO_PCI_CONFIG_NOMSI) 658b1ff07eSPekka Enberg return true; 668b1ff07eSPekka Enberg 67fbc2fbf9SPekka Enberg switch (offset) { 68fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 69fbc2fbf9SPekka Enberg device.guest_features = ioport__read32(data); 70fbc2fbf9SPekka Enberg break; 71fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 728b1ff07eSPekka Enberg return true; 73fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 748b1ff07eSPekka Enberg return true; 758b1ff07eSPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: { 768b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); 778b1ff07eSPekka Enberg return true; 788b1ff07eSPekka Enberg } 79fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 80fbc2fbf9SPekka Enberg device.status = ioport__read8(data); 81fbc2fbf9SPekka Enberg break; 82fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 83fbc2fbf9SPekka Enberg case VIRTIO_MSI_QUEUE_VECTOR: 84fbc2fbf9SPekka Enberg default: 85fbc2fbf9SPekka Enberg return false; 86fbc2fbf9SPekka Enberg }; 87fbc2fbf9SPekka Enberg 88fbc2fbf9SPekka Enberg return true; 89fbc2fbf9SPekka Enberg } 90fbc2fbf9SPekka Enberg 91fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = { 92fbc2fbf9SPekka Enberg .io_in = blk_virtio_in, 93fbc2fbf9SPekka Enberg .io_out = blk_virtio_out, 94fbc2fbf9SPekka Enberg }; 95fbc2fbf9SPekka Enberg 96b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 97b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 98b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 99b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 100b30d05adSPekka Enberg 101fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = { 102b30d05adSPekka Enberg .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 103b30d05adSPekka Enberg .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 104b30d05adSPekka Enberg .header_type = PCI_HEADER_TYPE_NORMAL, 105b30d05adSPekka Enberg .revision_id = 0, 106b30d05adSPekka Enberg .class = 0x010000, 107b30d05adSPekka Enberg .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 108b30d05adSPekka Enberg .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 109b30d05adSPekka Enberg .bar[0] = IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO, 110*406f1a89SPekka Enberg .irq_pin = 0, 1118b1ff07eSPekka Enberg .irq_line = VIRTIO_BLK_IRQ, 112b30d05adSPekka Enberg }; 113b30d05adSPekka Enberg 114b30d05adSPekka Enberg void blk_virtio__init(void) 115b30d05adSPekka Enberg { 116fbc2fbf9SPekka Enberg pci__register(&blk_virtio_pci_device, 1); 117b30d05adSPekka Enberg 1188b1ff07eSPekka Enberg ioport__register(IOPORT_VIRTIO, &blk_virtio_io_ops, 256); 119b30d05adSPekka Enberg } 120