160742802SPekka Enberg #include "kvm/pci.h" 260742802SPekka Enberg #include "kvm/ioport.h" 376f9c841SCyrill Gorcunov #include "kvm/util.h" 460742802SPekka Enberg 5*b30d05adSPekka Enberg #include <assert.h> 660742802SPekka Enberg #include <stdint.h> 760742802SPekka Enberg 8*b30d05adSPekka Enberg #define PCI_MAX_DEVICES 256 9*b30d05adSPekka Enberg 10*b30d05adSPekka Enberg static struct pci_device_header *pci_devices[PCI_MAX_DEVICES]; 11*b30d05adSPekka Enberg 124402a581SPekka Enberg static struct pci_config_address pci_config_address; 1360742802SPekka Enberg 14ba824677SPekka Enberg static void *pci_config_address_ptr(uint16_t port) 15ba824677SPekka Enberg { 16ba824677SPekka Enberg unsigned long offset; 17ba824677SPekka Enberg void *base; 18ba824677SPekka Enberg 19ba824677SPekka Enberg offset = port - PCI_CONFIG_ADDRESS; 20ba824677SPekka Enberg base = &pci_config_address; 21ba824677SPekka Enberg 22ba824677SPekka Enberg return base + offset; 23ba824677SPekka Enberg } 24ba824677SPekka Enberg 25305b72ceSCyrill Gorcunov static bool pci_config_address_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 2660742802SPekka Enberg { 27ba824677SPekka Enberg void *p = pci_config_address_ptr(port); 2860742802SPekka Enberg 29ba824677SPekka Enberg memcpy(p, data, size); 3060742802SPekka Enberg 3160742802SPekka Enberg return true; 3260742802SPekka Enberg } 3360742802SPekka Enberg 34305b72ceSCyrill Gorcunov static bool pci_config_address_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 3560742802SPekka Enberg { 36ba824677SPekka Enberg void *p = pci_config_address_ptr(port); 3760742802SPekka Enberg 38ba824677SPekka Enberg memcpy(data, p, size); 3960742802SPekka Enberg 4060742802SPekka Enberg return true; 4160742802SPekka Enberg } 4260742802SPekka Enberg 43305b72ceSCyrill Gorcunov static struct ioport_operations pci_config_address_ops = { 44305b72ceSCyrill Gorcunov .io_in = pci_config_address_in, 45305b72ceSCyrill Gorcunov .io_out = pci_config_address_out, 4660742802SPekka Enberg }; 4760742802SPekka Enberg 48305b72ceSCyrill Gorcunov static bool pci_config_data_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 4960742802SPekka Enberg { 5060742802SPekka Enberg return true; 5160742802SPekka Enberg } 5260742802SPekka Enberg 53*b30d05adSPekka Enberg static bool pci_device_exists(uint8_t bus_number, uint8_t device_number, uint8_t function_number) 5476f9c841SCyrill Gorcunov { 55*b30d05adSPekka Enberg struct pci_device_header *dev; 56*b30d05adSPekka Enberg 5776f9c841SCyrill Gorcunov if (pci_config_address.bus_number != bus_number) 5876f9c841SCyrill Gorcunov return false; 5976f9c841SCyrill Gorcunov 60*b30d05adSPekka Enberg if (pci_config_address.function_number != function_number) 6176f9c841SCyrill Gorcunov return false; 6276f9c841SCyrill Gorcunov 63*b30d05adSPekka Enberg if (device_number >= PCI_MAX_DEVICES) 64*b30d05adSPekka Enberg return false; 65*b30d05adSPekka Enberg 66*b30d05adSPekka Enberg dev = pci_devices[device_number]; 67*b30d05adSPekka Enberg 68*b30d05adSPekka Enberg return dev != NULL; 6976f9c841SCyrill Gorcunov } 7076f9c841SCyrill Gorcunov 71305b72ceSCyrill Gorcunov static bool pci_config_data_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 7260742802SPekka Enberg { 73e4d2cea2SPekka Enberg unsigned long start; 74*b30d05adSPekka Enberg uint8_t dev_num; 75e4d2cea2SPekka Enberg 76e4d2cea2SPekka Enberg /* 77e4d2cea2SPekka Enberg * If someone accesses PCI configuration space offsets that are not 7870d08766SCyrill Gorcunov * aligned to 4 bytes, it uses ioports to signify that. 79e4d2cea2SPekka Enberg */ 8070d08766SCyrill Gorcunov start = port - PCI_CONFIG_DATA; 81e4d2cea2SPekka Enberg 82*b30d05adSPekka Enberg dev_num = pci_config_address.device_number; 83*b30d05adSPekka Enberg 84*b30d05adSPekka Enberg if (pci_device_exists(0, dev_num, 0)) { 85598419d5SPekka Enberg unsigned long offset; 86598419d5SPekka Enberg 87e4d2cea2SPekka Enberg offset = start + (pci_config_address.register_number << 2); 88598419d5SPekka Enberg if (offset < sizeof(struct pci_device_header)) { 89*b30d05adSPekka Enberg void *p = pci_devices[dev_num]; 90*b30d05adSPekka Enberg 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 105*b30d05adSPekka Enberg void pci__register(struct pci_device_header *dev, uint8_t dev_num) 106beb095ebSCyrill Gorcunov { 107*b30d05adSPekka Enberg assert(dev_num < PCI_MAX_DEVICES); 108beb095ebSCyrill Gorcunov 109*b30d05adSPekka Enberg pci_devices[dev_num] = dev; 110beb095ebSCyrill Gorcunov } 111beb095ebSCyrill Gorcunov 11260742802SPekka Enberg void pci__init(void) 11360742802SPekka Enberg { 11470d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops); 11570d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 1, &pci_config_data_ops); 11670d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 2, &pci_config_data_ops); 11770d08766SCyrill Gorcunov ioport__register(PCI_CONFIG_DATA + 3, &pci_config_data_ops); 11870d08766SCyrill Gorcunov 119ba824677SPekka Enberg ioport__register(PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops); 120ba824677SPekka Enberg ioport__register(PCI_CONFIG_ADDRESS + 1, &pci_config_address_ops); 121ba824677SPekka Enberg ioport__register(PCI_CONFIG_ADDRESS + 2, &pci_config_address_ops); 122ba824677SPekka Enberg ioport__register(PCI_CONFIG_ADDRESS + 3, &pci_config_address_ops); 12360742802SPekka Enberg } 124