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 void *pci_config_address_ptr(uint16_t port) 10 { 11 unsigned long offset; 12 void *base; 13 14 offset = port - PCI_CONFIG_ADDRESS; 15 base = &pci_config_address; 16 17 return base + offset; 18 } 19 20 static bool pci_config_address_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 21 { 22 void *p = pci_config_address_ptr(port); 23 24 memcpy(p, data, size); 25 26 return true; 27 } 28 29 static bool pci_config_address_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 30 { 31 void *p = pci_config_address_ptr(port); 32 33 memcpy(data, p, size); 34 35 return true; 36 } 37 38 static struct ioport_operations pci_config_address_ops = { 39 .io_in = pci_config_address_in, 40 .io_out = pci_config_address_out, 41 }; 42 43 static bool pci_config_data_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 44 { 45 return true; 46 } 47 48 #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 49 #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 50 #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET 0x1af4 51 #define PCI_SUBSYSTEM_ID_VIRTIO_BLK 0x0002 52 53 static struct pci_device_header virtio_device = { 54 .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 55 .device_id = PCI_DEVICE_ID_VIRTIO_BLK, 56 .header_type = PCI_HEADER_TYPE_NORMAL, 57 .revision_id = 0, 58 .class = 0x010000, 59 .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 60 .subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK, 61 .bar[0] = IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO, 62 }; 63 64 static bool pci_device_matches(uint8_t bus_number, uint8_t device_number, uint8_t function_number) 65 { 66 if (pci_config_address.bus_number != bus_number) 67 return false; 68 69 if (pci_config_address.device_number != device_number) 70 return false; 71 72 return pci_config_address.function_number == function_number; 73 } 74 75 static bool pci_config_data_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 76 { 77 unsigned long start; 78 79 /* 80 * If someone accesses PCI configuration space offsets that are not 81 * aligned to 4 bytes, it uses ioports to signify that. 82 */ 83 start = port - PCI_CONFIG_DATA; 84 85 if (pci_device_matches(0, 1, 0)) { 86 unsigned long offset; 87 88 offset = start + (pci_config_address.register_number << 2); 89 if (offset < sizeof(struct pci_device_header)) { 90 void *p = &virtio_device; 91 memcpy(data, p + offset, size); 92 } else 93 memset(data, 0x00, size); 94 } else 95 memset(data, 0xff, size); 96 97 return true; 98 } 99 100 static struct ioport_operations pci_config_data_ops = { 101 .io_in = pci_config_data_in, 102 .io_out = pci_config_data_out, 103 }; 104 105 static bool virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 106 { 107 return true; 108 } 109 110 static bool virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 111 { 112 return true; 113 } 114 115 static struct ioport_operations virtio_io_ops = { 116 .io_in = virtio_in, 117 .io_out = virtio_out, 118 }; 119 120 void pci__init(void) 121 { 122 ioport__register(IOPORT_VIRTIO, &virtio_io_ops); 123 124 ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops); 125 ioport__register(PCI_CONFIG_DATA + 1, &pci_config_data_ops); 126 ioport__register(PCI_CONFIG_DATA + 2, &pci_config_data_ops); 127 ioport__register(PCI_CONFIG_DATA + 3, &pci_config_data_ops); 128 129 ioport__register(PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops); 130 ioport__register(PCI_CONFIG_ADDRESS + 1, &pci_config_address_ops); 131 ioport__register(PCI_CONFIG_ADDRESS + 2, &pci_config_address_ops); 132 ioport__register(PCI_CONFIG_ADDRESS + 3, &pci_config_address_ops); 133 } 134