1 #include "kvm/pci.h" 2 #include "kvm/ioport.h" 3 #include "kvm/util.h" 4 5 #include <stdint.h> 6 7 static struct pci_config_address pci_config_address; 8 9 static bool pci_config_address_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 10 { 11 struct pci_config_address *addr = data; 12 13 pci_config_address = *addr; 14 15 return true; 16 } 17 18 static bool pci_config_address_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 19 { 20 struct pci_config_address *addr = data; 21 22 *addr = pci_config_address; 23 24 return true; 25 } 26 27 static struct ioport_operations pci_config_address_ops = { 28 .io_in = pci_config_address_in, 29 .io_out = pci_config_address_out, 30 }; 31 32 static bool pci_config_data_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 33 { 34 return true; 35 } 36 37 #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 38 #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 39 40 static struct pci_device_header virtio_device = { 41 .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 42 .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 43 .header_type = PCI_HEADER_TYPE_NORMAL, 44 }; 45 46 static bool pci_device_matches(uint8_t bus_number, uint8_t device_number, uint8_t function_number) 47 { 48 if (pci_config_address.bus_number != bus_number) 49 return false; 50 51 if (pci_config_address.device_number != device_number) 52 return false; 53 54 return pci_config_address.function_number == function_number; 55 } 56 57 static bool pci_config_data_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 58 { 59 unsigned long start; 60 61 /* 62 * If someone accesses PCI configuration space offsets that are not 63 * aligned to 4 bytes, it uses ioports to signify that. 64 */ 65 start = port - PCI_CONFIG_DATA; 66 67 if (pci_device_matches(0, 1, 0)) { 68 unsigned long offset; 69 70 offset = start + (pci_config_address.register_number << 2); 71 if (offset < sizeof(struct pci_device_header)) { 72 void *p = &virtio_device; 73 memcpy(data, p + offset, size); 74 } else 75 memset(data, 0x00, size); 76 } else 77 memset(data, 0xff, size); 78 79 return true; 80 } 81 82 static struct ioport_operations pci_config_data_ops = { 83 .io_in = pci_config_data_in, 84 .io_out = pci_config_data_out, 85 }; 86 87 void pci__init(void) 88 { 89 ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops); 90 ioport__register(PCI_CONFIG_DATA + 1, &pci_config_data_ops); 91 ioport__register(PCI_CONFIG_DATA + 2, &pci_config_data_ops); 92 ioport__register(PCI_CONFIG_DATA + 3, &pci_config_data_ops); 93 94 ioport__register(PCI_CONFIG_ADDRESS, &pci_config_address_ops); 95 } 96