1b30d05adSPekka Enberg #include "kvm/blk-virtio.h" 2b30d05adSPekka Enberg 3c435b91dSPekka Enberg #include "kvm/virtio_blk.h" 4984b7ae0SPekka Enberg #include "kvm/virtio_pci.h" 5b30d05adSPekka Enberg #include "kvm/ioport.h" 68b1ff07eSPekka Enberg #include "kvm/kvm.h" 7b30d05adSPekka Enberg #include "kvm/pci.h" 8b30d05adSPekka Enberg 98b1ff07eSPekka Enberg #define VIRTIO_BLK_IRQ 14 10984b7ae0SPekka Enberg 11fbc2fbf9SPekka Enberg struct device { 1240ce993fSPekka Enberg struct virtio_blk_config blk_config; 13c435b91dSPekka Enberg uint32_t host_features; 14fbc2fbf9SPekka Enberg uint32_t guest_features; 1540ce993fSPekka Enberg uint16_t config_vector; 16fbc2fbf9SPekka Enberg uint8_t status; 17*47bf1d0fSPekka Enberg 18*47bf1d0fSPekka Enberg /* virtio queue */ 19*47bf1d0fSPekka Enberg uint32_t queue_pfn; 20*47bf1d0fSPekka Enberg uint16_t queue_selector; 21fbc2fbf9SPekka Enberg }; 22fbc2fbf9SPekka Enberg 2340ce993fSPekka Enberg #define DISK_CYLINDERS 1024 2440ce993fSPekka Enberg #define DISK_HEADS 64 2540ce993fSPekka Enberg #define DISK_SECTORS 32 2640ce993fSPekka Enberg 27c435b91dSPekka Enberg static struct device device = { 2840ce993fSPekka Enberg .blk_config = (struct virtio_blk_config) { 2940ce993fSPekka Enberg .capacity = DISK_CYLINDERS * DISK_HEADS * DISK_SECTORS, 3040ce993fSPekka Enberg /* VIRTIO_BLK_F_GEOMETRY */ 3140ce993fSPekka Enberg .geometry = { 3240ce993fSPekka Enberg .cylinders = DISK_CYLINDERS, 3340ce993fSPekka Enberg .heads = DISK_HEADS, 3440ce993fSPekka Enberg .sectors = DISK_SECTORS, 3540ce993fSPekka Enberg }, 3640ce993fSPekka Enberg /* VIRTIO_BLK_SIZE */ 3740ce993fSPekka Enberg .blk_size = 4096, 3840ce993fSPekka Enberg }, 3998790f28SPekka Enberg .host_features = (1UL << VIRTIO_BLK_F_GEOMETRY) 40cb938db9SPekka Enberg | (1UL << VIRTIO_BLK_F_RO) 41c435b91dSPekka Enberg | (1UL << VIRTIO_BLK_F_BLK_SIZE), 42c435b91dSPekka Enberg }; 43fbc2fbf9SPekka Enberg 4440ce993fSPekka Enberg static bool virtio_blk_config_in(void *data, unsigned long offset, int size, uint32_t count) 4540ce993fSPekka Enberg { 4640ce993fSPekka Enberg uint8_t *config_space = (uint8_t *) &device.blk_config; 4740ce993fSPekka Enberg 4840ce993fSPekka Enberg if (size != 1 || count != 1) 4940ce993fSPekka Enberg return false; 5040ce993fSPekka Enberg 5140ce993fSPekka Enberg ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]); 5240ce993fSPekka Enberg 5340ce993fSPekka Enberg return true; 5440ce993fSPekka Enberg } 5540ce993fSPekka Enberg 56fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 57fbc2fbf9SPekka Enberg { 58fbc2fbf9SPekka Enberg unsigned long offset; 59fbc2fbf9SPekka Enberg 60fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 61fbc2fbf9SPekka Enberg 62fbc2fbf9SPekka Enberg switch (offset) { 63fbc2fbf9SPekka Enberg case VIRTIO_PCI_HOST_FEATURES: 64c435b91dSPekka Enberg ioport__write32(data, device.host_features); 65fbc2fbf9SPekka Enberg break; 66fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 678b1ff07eSPekka Enberg return false; 68fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 698b1ff07eSPekka Enberg ioport__write32(data, 0x00); 708b1ff07eSPekka Enberg break; 71fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NUM: 728b1ff07eSPekka Enberg ioport__write16(data, 0x10); 738b1ff07eSPekka Enberg break; 74fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 75fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: 76fbc2fbf9SPekka Enberg return false; 77fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 78fbc2fbf9SPekka Enberg ioport__write8(data, device.status); 79fbc2fbf9SPekka Enberg break; 80fbc2fbf9SPekka Enberg case VIRTIO_PCI_ISR: 818b1ff07eSPekka Enberg ioport__write8(data, 0x1); 828b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 0); 837e61688eSPekka Enberg break; 84fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 8540ce993fSPekka Enberg ioport__write16(data, device.config_vector); 8640ce993fSPekka Enberg break; 87fbc2fbf9SPekka Enberg default: 8840ce993fSPekka Enberg return virtio_blk_config_in(data, offset, size, count); 89fbc2fbf9SPekka Enberg }; 90fbc2fbf9SPekka Enberg 91fbc2fbf9SPekka Enberg return true; 92fbc2fbf9SPekka Enberg } 93fbc2fbf9SPekka Enberg 94fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 95fbc2fbf9SPekka Enberg { 96fbc2fbf9SPekka Enberg unsigned long offset; 97fbc2fbf9SPekka Enberg 98fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 99fbc2fbf9SPekka Enberg 100fbc2fbf9SPekka Enberg switch (offset) { 101fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 102fbc2fbf9SPekka Enberg device.guest_features = ioport__read32(data); 103fbc2fbf9SPekka Enberg break; 104fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 105*47bf1d0fSPekka Enberg device.queue_pfn = ioport__read32(data); 1067e61688eSPekka Enberg break; 107fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 108*47bf1d0fSPekka Enberg device.queue_selector = ioport__read16(data); 1097e61688eSPekka Enberg break; 1107e61688eSPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: 1118b1ff07eSPekka Enberg kvm__irq_line(self, VIRTIO_BLK_IRQ, 1); 1127e61688eSPekka Enberg break; 113fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 114fbc2fbf9SPekka Enberg device.status = ioport__read8(data); 115fbc2fbf9SPekka Enberg break; 116fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 11740ce993fSPekka Enberg device.config_vector = VIRTIO_MSI_NO_VECTOR; 11840ce993fSPekka Enberg break; 119fbc2fbf9SPekka Enberg case VIRTIO_MSI_QUEUE_VECTOR: 12040ce993fSPekka Enberg break; 121fbc2fbf9SPekka Enberg default: 122fbc2fbf9SPekka Enberg return false; 123fbc2fbf9SPekka Enberg }; 124fbc2fbf9SPekka Enberg 125fbc2fbf9SPekka Enberg return true; 126fbc2fbf9SPekka Enberg } 127fbc2fbf9SPekka Enberg 128fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = { 129fbc2fbf9SPekka Enberg .io_in = blk_virtio_in, 130fbc2fbf9SPekka Enberg .io_out = blk_virtio_out, 131fbc2fbf9SPekka Enberg }; 132fbc2fbf9SPekka Enberg 133b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 134b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 135b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 136b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 137b30d05adSPekka Enberg 138fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = { 139b30d05adSPekka Enberg .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 140b30d05adSPekka Enberg .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 141b30d05adSPekka Enberg .header_type = PCI_HEADER_TYPE_NORMAL, 142b30d05adSPekka Enberg .revision_id = 0, 143b30d05adSPekka Enberg .class = 0x010000, 144b30d05adSPekka Enberg .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 145b30d05adSPekka Enberg .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 146b30d05adSPekka Enberg .bar[0] = IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO, 147dc53a427SPekka Enberg /* XXX: Is this IRQ setup OK? */ 148dc53a427SPekka Enberg .irq_pin = 1, 1498b1ff07eSPekka Enberg .irq_line = VIRTIO_BLK_IRQ, 150b30d05adSPekka Enberg }; 151b30d05adSPekka Enberg 152b30d05adSPekka Enberg void blk_virtio__init(void) 153b30d05adSPekka Enberg { 154fbc2fbf9SPekka Enberg pci__register(&blk_virtio_pci_device, 1); 155b30d05adSPekka Enberg 1568b1ff07eSPekka Enberg ioport__register(IOPORT_VIRTIO, &blk_virtio_io_ops, 256); 157b30d05adSPekka Enberg } 158