160742802SPekka Enberg #include "kvm/pci.h" 260742802SPekka Enberg #include "kvm/ioport.h" 3*76f9c841SCyrill 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 37*76f9c841SCyrill Gorcunov static struct pci_device_header no_device = { 38*76f9c841SCyrill Gorcunov .vendor_id = 0xffff, 39*76f9c841SCyrill Gorcunov .device_id = 0xffff, 40*76f9c841SCyrill Gorcunov .revision_id = 0xff, 41*76f9c841SCyrill Gorcunov .class = 0xffffff, 42*76f9c841SCyrill Gorcunov }; 43*76f9c841SCyrill Gorcunov 44*76f9c841SCyrill Gorcunov #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 45*76f9c841SCyrill Gorcunov #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 46*76f9c841SCyrill Gorcunov 47*76f9c841SCyrill Gorcunov static struct pci_device_header virtio_device = { 48*76f9c841SCyrill Gorcunov .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 49*76f9c841SCyrill Gorcunov .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 50*76f9c841SCyrill Gorcunov .header_type = PCI_HEADER_TYPE_NORMAL, 51*76f9c841SCyrill Gorcunov }; 52*76f9c841SCyrill Gorcunov 53*76f9c841SCyrill Gorcunov static bool pci_device_matches(uint8_t bus_number, uint8_t device_number, uint8_t function_number) 54*76f9c841SCyrill Gorcunov { 55*76f9c841SCyrill Gorcunov if (pci_config_address.bus_number != bus_number) 56*76f9c841SCyrill Gorcunov return false; 57*76f9c841SCyrill Gorcunov 58*76f9c841SCyrill Gorcunov if (pci_config_address.device_number != device_number) 59*76f9c841SCyrill Gorcunov return false; 60*76f9c841SCyrill Gorcunov 61*76f9c841SCyrill Gorcunov return pci_config_address.function_number == function_number; 62*76f9c841SCyrill Gorcunov } 63*76f9c841SCyrill Gorcunov 64305b72ceSCyrill Gorcunov static bool pci_config_data_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 6560742802SPekka Enberg { 66*76f9c841SCyrill Gorcunov void *p; 674c797ebcSCyrill Gorcunov 68*76f9c841SCyrill Gorcunov if (pci_device_matches(0, 1, 0)) 69*76f9c841SCyrill Gorcunov p = &virtio_device; 70*76f9c841SCyrill Gorcunov else 71*76f9c841SCyrill Gorcunov p = &no_device; 72*76f9c841SCyrill Gorcunov 73*76f9c841SCyrill Gorcunov memcpy(data, p + (pci_config_address.register_number * 4), size); 744c797ebcSCyrill Gorcunov 7560742802SPekka Enberg return true; 7660742802SPekka Enberg } 7760742802SPekka Enberg 78305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_data_ops = { 79305b72ceSCyrill Gorcunov .io_in = pci_config_data_in, 80305b72ceSCyrill Gorcunov .io_out = pci_config_data_out, 8160742802SPekka Enberg }; 8260742802SPekka Enberg 8360742802SPekka Enberg void pci__init(void) 8460742802SPekka Enberg { 85305b72ceSCyrill Gorcunov ioport__register(PCI_CONFIG_DATA, &pci_config_data_ops); 86305b72ceSCyrill Gorcunov ioport__register(PCI_CONFIG_ADDRESS, &pci_config_address_ops); 8760742802SPekka Enberg } 88