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