1b30d05adSPekka Enberg #include "kvm/blk-virtio.h" 2b30d05adSPekka Enberg 3984b7ae0SPekka Enberg #include "kvm/virtio_pci.h" 4b30d05adSPekka Enberg #include "kvm/ioport.h" 5b30d05adSPekka Enberg #include "kvm/pci.h" 6b30d05adSPekka Enberg 7984b7ae0SPekka Enberg #define VIRTIO_PCI_IOPORT_SIZE 24 8984b7ae0SPekka Enberg 9*fbc2fbf9SPekka Enberg struct device { 10*fbc2fbf9SPekka Enberg uint32_t guest_features; 11*fbc2fbf9SPekka Enberg uint8_t status; 12*fbc2fbf9SPekka Enberg }; 13*fbc2fbf9SPekka Enberg 14*fbc2fbf9SPekka Enberg static struct device device; 15*fbc2fbf9SPekka Enberg 16*fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 17*fbc2fbf9SPekka Enberg { 18*fbc2fbf9SPekka Enberg unsigned long offset; 19*fbc2fbf9SPekka Enberg 20*fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 21*fbc2fbf9SPekka Enberg 22*fbc2fbf9SPekka Enberg switch (offset) { 23*fbc2fbf9SPekka Enberg case VIRTIO_PCI_HOST_FEATURES: 24*fbc2fbf9SPekka Enberg ioport__write32(data, 0x00); 25*fbc2fbf9SPekka Enberg break; 26*fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 27*fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 28*fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NUM: 29*fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 30*fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: 31*fbc2fbf9SPekka Enberg return false; 32*fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 33*fbc2fbf9SPekka Enberg ioport__write8(data, device.status); 34*fbc2fbf9SPekka Enberg break; 35*fbc2fbf9SPekka Enberg case VIRTIO_PCI_ISR: 36*fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 37*fbc2fbf9SPekka Enberg default: 38*fbc2fbf9SPekka Enberg return false; 39*fbc2fbf9SPekka Enberg }; 40*fbc2fbf9SPekka Enberg 41*fbc2fbf9SPekka Enberg return true; 42*fbc2fbf9SPekka Enberg } 43*fbc2fbf9SPekka Enberg 44*fbc2fbf9SPekka Enberg #include <stdio.h> 45*fbc2fbf9SPekka Enberg 46*fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 47*fbc2fbf9SPekka Enberg { 48*fbc2fbf9SPekka Enberg unsigned long offset; 49*fbc2fbf9SPekka Enberg 50*fbc2fbf9SPekka Enberg offset = port - IOPORT_VIRTIO; 51*fbc2fbf9SPekka Enberg 52*fbc2fbf9SPekka Enberg switch (offset) { 53*fbc2fbf9SPekka Enberg case VIRTIO_PCI_GUEST_FEATURES: 54*fbc2fbf9SPekka Enberg device.guest_features = ioport__read32(data); 55*fbc2fbf9SPekka Enberg break; 56*fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_PFN: 57*fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_SEL: 58*fbc2fbf9SPekka Enberg case VIRTIO_PCI_QUEUE_NOTIFY: 59*fbc2fbf9SPekka Enberg return false; 60*fbc2fbf9SPekka Enberg case VIRTIO_PCI_STATUS: 61*fbc2fbf9SPekka Enberg device.status = ioport__read8(data); 62*fbc2fbf9SPekka Enberg break; 63*fbc2fbf9SPekka Enberg case VIRTIO_MSI_CONFIG_VECTOR: 64*fbc2fbf9SPekka Enberg case VIRTIO_MSI_QUEUE_VECTOR: 65*fbc2fbf9SPekka Enberg default: 66*fbc2fbf9SPekka Enberg return false; 67*fbc2fbf9SPekka Enberg }; 68*fbc2fbf9SPekka Enberg 69*fbc2fbf9SPekka Enberg return true; 70*fbc2fbf9SPekka Enberg } 71*fbc2fbf9SPekka Enberg 72*fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = { 73*fbc2fbf9SPekka Enberg .io_in = blk_virtio_in, 74*fbc2fbf9SPekka Enberg .io_out = blk_virtio_out, 75*fbc2fbf9SPekka Enberg }; 76*fbc2fbf9SPekka Enberg 77b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 78b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 79b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 80b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 81b30d05adSPekka Enberg 82*fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = { 83b30d05adSPekka Enberg .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 84b30d05adSPekka Enberg .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 85b30d05adSPekka Enberg .header_type = PCI_HEADER_TYPE_NORMAL, 86b30d05adSPekka Enberg .revision_id = 0, 87b30d05adSPekka Enberg .class = 0x010000, 88b30d05adSPekka Enberg .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 89b30d05adSPekka Enberg .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 90b30d05adSPekka Enberg .bar[0] = IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO, 91b30d05adSPekka Enberg }; 92b30d05adSPekka Enberg 93b30d05adSPekka Enberg void blk_virtio__init(void) 94b30d05adSPekka Enberg { 95*fbc2fbf9SPekka Enberg pci__register(&blk_virtio_pci_device, 1); 96b30d05adSPekka Enberg 97984b7ae0SPekka Enberg ioport__register(IOPORT_VIRTIO, &blk_virtio_io_ops, VIRTIO_PCI_IOPORT_SIZE); 98b30d05adSPekka Enberg } 99