160742802SPekka Enberg #include "kvm/pci.h" 260742802SPekka Enberg #include "kvm/ioport.h" 376f9c841SCyrill Gorcunov #include "kvm/util.h" 460742802SPekka Enberg 560742802SPekka Enberg #include <stdint.h> 660742802SPekka Enberg 74402a581SPekka Enberg static struct pci_config_address pci_config_address; 860742802SPekka Enberg 9*ba824677SPekka Enberg static void *pci_config_address_ptr(uint16_t port) 10*ba824677SPekka Enberg { 11*ba824677SPekka Enberg unsigned long offset; 12*ba824677SPekka Enberg void *base; 13*ba824677SPekka Enberg 14*ba824677SPekka Enberg offset = port - PCI_CONFIG_ADDRESS; 15*ba824677SPekka Enberg base = &pci_config_address; 16*ba824677SPekka Enberg 17*ba824677SPekka Enberg return base + offset; 18*ba824677SPekka Enberg } 19*ba824677SPekka Enberg 20305b72ceSCyrill Gorcunov static bool pci_config_address_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 2160742802SPekka Enberg { 22*ba824677SPekka Enberg void *p = pci_config_address_ptr(port); 2360742802SPekka Enberg 24*ba824677SPekka Enberg memcpy(p, data, size); 2560742802SPekka Enberg 2660742802SPekka Enberg return true; 2760742802SPekka Enberg } 2860742802SPekka Enberg 29305b72ceSCyrill Gorcunov static bool pci_config_address_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 3060742802SPekka Enberg { 31*ba824677SPekka Enberg void *p = pci_config_address_ptr(port); 3260742802SPekka Enberg 33*ba824677SPekka Enberg memcpy(data, p, size); 3460742802SPekka Enberg 3560742802SPekka Enberg return true; 3660742802SPekka Enberg } 3760742802SPekka Enberg 38305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_address_ops = { 39305b72ceSCyrill Gorcunov .io_in = pci_config_address_in, 40305b72ceSCyrill Gorcunov .io_out = pci_config_address_out, 4160742802SPekka Enberg }; 4260742802SPekka Enberg 43305b72ceSCyrill Gorcunov static bool pci_config_data_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 4460742802SPekka Enberg { 4560742802SPekka Enberg return true; 4660742802SPekka Enberg } 4760742802SPekka Enberg 4876f9c841SCyrill Gorcunov #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 4976f9c841SCyrill Gorcunov #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 5078732ce2SAsias He #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 5178732ce2SAsias He #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 5276f9c841SCyrill Gorcunov 5376f9c841SCyrill Gorcunov static struct pci_device_header virtio_device = { 5476f9c841SCyrill Gorcunov .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 5576f9c841SCyrill Gorcunov .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 5676f9c841SCyrill Gorcunov .header_type = PCI_HEADER_TYPE_NORMAL, 5778732ce2SAsias He .revision_id = 0, 5878732ce2SAsias He .class = 0x010000, 5978732ce2SAsias He .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 6078732ce2SAsias He .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 6178732ce2SAsias He .bar[0] = IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO, 6276f9c841SCyrill Gorcunov }; 6376f9c841SCyrill Gorcunov 6476f9c841SCyrill Gorcunov static bool pci_device_matches(uint8_t bus_number, uint8_t device_number, uint8_t function_number) 6576f9c841SCyrill Gorcunov { 6676f9c841SCyrill Gorcunov if (pci_config_address.bus_number != bus_number) 6776f9c841SCyrill Gorcunov return false; 6876f9c841SCyrill Gorcunov 6976f9c841SCyrill Gorcunov if (pci_config_address.device_number != device_number) 7076f9c841SCyrill Gorcunov return false; 7176f9c841SCyrill Gorcunov 7276f9c841SCyrill Gorcunov return pci_config_address.function_number == function_number; 7376f9c841SCyrill Gorcunov } 7476f9c841SCyrill Gorcunov 75305b72ceSCyrill Gorcunov static bool pci_config_data_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 7660742802SPekka Enberg { 77e4d2cea2SPekka Enberg unsigned long start; 78e4d2cea2SPekka Enberg 79e4d2cea2SPekka Enberg /* 80e4d2cea2SPekka Enberg * If someone accesses PCI configuration space offsets that are not 8170d08766SCyrill Gorcunov * aligned to 4 bytes, it uses ioports to signify that. 82e4d2cea2SPekka Enberg */ 8370d08766SCyrill Gorcunov start = port - PCI_CONFIG_DATA; 84e4d2cea2SPekka Enberg 85e498ea08SPekka Enberg if (pci_device_matches(0, 1, 0)) { 86598419d5SPekka Enberg unsigned long offset; 87598419d5SPekka Enberg 88e4d2cea2SPekka Enberg offset = start + (pci_config_address.register_number << 2); 89598419d5SPekka Enberg if (offset < sizeof(struct pci_device_header)) { 90e498ea08SPekka Enberg void *p = &virtio_device; 9118ae021aSPekka Enberg memcpy(data, p + offset, size); 92598419d5SPekka Enberg } else 93598419d5SPekka Enberg memset(data, 0x00, size); 94e498ea08SPekka Enberg } else 95e498ea08SPekka Enberg memset(data, 0xff, size); 964c797ebcSCyrill Gorcunov 9760742802SPekka Enberg return true; 9860742802SPekka Enberg } 9960742802SPekka Enberg 100305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_data_ops = { 101305b72ceSCyrill Gorcunov .io_in = pci_config_data_in, 102305b72ceSCyrill Gorcunov .io_out = pci_config_data_out, 10360742802SPekka Enberg }; 10460742802SPekka Enberg 105beb095ebSCyrill Gorcunov static bool virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 106beb095ebSCyrill Gorcunov { 107beb095ebSCyrill Gorcunov return true; 108beb095ebSCyrill Gorcunov } 109beb095ebSCyrill Gorcunov 110beb095ebSCyrill Gorcunov static bool virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 111beb095ebSCyrill Gorcunov { 112beb095ebSCyrill Gorcunov return true; 113beb095ebSCyrill Gorcunov } 114beb095ebSCyrill Gorcunov 115beb095ebSCyrill Gorcunov static struct ioport_operations virtio_io_ops = { 116beb095ebSCyrill Gorcunov .io_in = virtio_in, 117beb095ebSCyrill Gorcunov .io_out = virtio_out, 118beb095ebSCyrill Gorcunov }; 119beb095ebSCyrill Gorcunov 12060742802SPekka Enberg void pci__init(void) 12160742802SPekka Enberg { 122beb095ebSCyrill Gorcunov ioport__register(IOPORT_VIRTIO, &virtio_io_ops); 123beb095ebSCyrill Gorcunov 12470d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops); 12570d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 1, &pci_config_data_ops); 12670d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 2, &pci_config_data_ops); 12770d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 3, &pci_config_data_ops); 12870d08766SCyrill Gorcunov 129*ba824677SPekka Enberg ioport__register(PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops); 130*ba824677SPekka Enberg ioport__register(PCI_CONFIG_ADDRESS + 1, &pci_config_address_ops); 131*ba824677SPekka Enberg ioport__register(PCI_CONFIG_ADDRESS + 2, &pci_config_address_ops); 132*ba824677SPekka Enberg ioport__register(PCI_CONFIG_ADDRESS + 3, &pci_config_address_ops); 13360742802SPekka Enberg } 134