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 9305b72ceSCyrill Gorcunov static bool pci_config_address_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 1060742802SPekka Enberg { 114402a581SPekka Enberg struct pci_config_address *addr = data; 1260742802SPekka Enberg 13dad5bc09SCyrill Gorcunov pci_config_address = *addr; 1460742802SPekka Enberg 1560742802SPekka Enberg return true; 1660742802SPekka Enberg } 1760742802SPekka Enberg 18305b72ceSCyrill Gorcunov static bool pci_config_address_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 1960742802SPekka Enberg { 204402a581SPekka Enberg struct pci_config_address *addr = data; 2160742802SPekka Enberg 22305b72ceSCyrill Gorcunov *addr = pci_config_address; 2360742802SPekka Enberg 2460742802SPekka Enberg return true; 2560742802SPekka Enberg } 2660742802SPekka Enberg 27305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_address_ops = { 28305b72ceSCyrill Gorcunov .io_in = pci_config_address_in, 29305b72ceSCyrill Gorcunov .io_out = pci_config_address_out, 3060742802SPekka Enberg }; 3160742802SPekka Enberg 32305b72ceSCyrill Gorcunov static bool pci_config_data_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 3360742802SPekka Enberg { 3460742802SPekka Enberg return true; 3560742802SPekka Enberg } 3660742802SPekka Enberg 3776f9c841SCyrill Gorcunov #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 3876f9c841SCyrill Gorcunov #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 39*78732ce2SAsias He #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 40*78732ce2SAsias He #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 4176f9c841SCyrill Gorcunov 4276f9c841SCyrill Gorcunov static struct pci_device_header virtio_device = { 4376f9c841SCyrill Gorcunov .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 4476f9c841SCyrill Gorcunov .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 4576f9c841SCyrill Gorcunov .header_type = PCI_HEADER_TYPE_NORMAL, 46*78732ce2SAsias He .revision_id = 0, 47*78732ce2SAsias He .class = 0x010000, 48*78732ce2SAsias He .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 49*78732ce2SAsias He .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 50*78732ce2SAsias He .bar[0] = IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO, 5176f9c841SCyrill Gorcunov }; 5276f9c841SCyrill Gorcunov 5376f9c841SCyrill Gorcunov static bool pci_device_matches(uint8_t bus_number, uint8_t device_number, uint8_t function_number) 5476f9c841SCyrill Gorcunov { 5576f9c841SCyrill Gorcunov if (pci_config_address.bus_number != bus_number) 5676f9c841SCyrill Gorcunov return false; 5776f9c841SCyrill Gorcunov 5876f9c841SCyrill Gorcunov if (pci_config_address.device_number != device_number) 5976f9c841SCyrill Gorcunov return false; 6076f9c841SCyrill Gorcunov 6176f9c841SCyrill Gorcunov return pci_config_address.function_number == function_number; 6276f9c841SCyrill Gorcunov } 6376f9c841SCyrill Gorcunov 64305b72ceSCyrill Gorcunov static bool pci_config_data_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 6560742802SPekka Enberg { 66e4d2cea2SPekka Enberg unsigned long start; 67e4d2cea2SPekka Enberg 68e4d2cea2SPekka Enberg /* 69e4d2cea2SPekka Enberg * If someone accesses PCI configuration space offsets that are not 7070d08766SCyrill Gorcunov * aligned to 4 bytes, it uses ioports to signify that. 71e4d2cea2SPekka Enberg */ 7270d08766SCyrill Gorcunov start = port - PCI_CONFIG_DATA; 73e4d2cea2SPekka Enberg 74e498ea08SPekka Enberg if (pci_device_matches(0, 1, 0)) { 75598419d5SPekka Enberg unsigned long offset; 76598419d5SPekka Enberg 77e4d2cea2SPekka Enberg offset = start + (pci_config_address.register_number << 2); 78598419d5SPekka Enberg if (offset < sizeof(struct pci_device_header)) { 79e498ea08SPekka Enberg void *p = &virtio_device; 8018ae021aSPekka Enberg memcpy(data, p + offset, size); 81598419d5SPekka Enberg } else 82598419d5SPekka Enberg memset(data, 0x00, size); 83e498ea08SPekka Enberg } else 84e498ea08SPekka Enberg memset(data, 0xff, size); 854c797ebcSCyrill Gorcunov 8660742802SPekka Enberg return true; 8760742802SPekka Enberg } 8860742802SPekka Enberg 89305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_data_ops = { 90305b72ceSCyrill Gorcunov .io_in = pci_config_data_in, 91305b72ceSCyrill Gorcunov .io_out = pci_config_data_out, 9260742802SPekka Enberg }; 9360742802SPekka Enberg 94beb095ebSCyrill Gorcunov static bool virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 95beb095ebSCyrill Gorcunov { 96beb095ebSCyrill Gorcunov info("virtio_in"); 97beb095ebSCyrill Gorcunov return true; 98beb095ebSCyrill Gorcunov } 99beb095ebSCyrill Gorcunov 100beb095ebSCyrill Gorcunov static bool virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 101beb095ebSCyrill Gorcunov { 102beb095ebSCyrill Gorcunov info("virtio_out"); 103beb095ebSCyrill Gorcunov return true; 104beb095ebSCyrill Gorcunov } 105beb095ebSCyrill Gorcunov 106beb095ebSCyrill Gorcunov static struct ioport_operations virtio_io_ops = { 107beb095ebSCyrill Gorcunov .io_in = virtio_in, 108beb095ebSCyrill Gorcunov .io_out = virtio_out, 109beb095ebSCyrill Gorcunov }; 110beb095ebSCyrill Gorcunov 11160742802SPekka Enberg void pci__init(void) 11260742802SPekka Enberg { 113beb095ebSCyrill Gorcunov 114beb095ebSCyrill Gorcunov ioport__register(IOPORT_VIRTIO, &virtio_io_ops); 115beb095ebSCyrill Gorcunov 11670d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops); 11770d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 1, &pci_config_data_ops); 11870d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 2, &pci_config_data_ops); 11970d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 3, &pci_config_data_ops); 12070d08766SCyrill Gorcunov 12170d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_ADDRESS, &pci_config_address_ops); 12260742802SPekka Enberg } 123