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