+pci_probe_msi_info(struct pci_device* device)
+{
+ // Note that Virtualbox have to use ICH9 chipset for MSI support.
+ // Qemu seems ok with default PIIX3, Bochs is pending to test...
+ // See https://www.virtualbox.org/manual/ch03.html (section 3.5.1)
+ pci_reg_t status =
+ pci_read_cspace(device->cspace_base, PCI_REG_STATUS_CMD) >> 16;
+
+ if (!(status & 0x10)) {
+ device->msi_loc = 0;
+ return;
+ }
+
+ pci_reg_t cap_ptr = pci_read_cspace(device->cspace_base, 0x34) & 0xff;
+ uint32_t cap_hdr;
+
+ while (cap_ptr) {
+ cap_hdr = pci_read_cspace(device->cspace_base, cap_ptr);
+ if ((cap_hdr & 0xff) == 0x5) {
+ // MSI
+ device->msi_loc = cap_ptr;
+ return;
+ }
+ cap_ptr = (cap_hdr >> 8) & 0xff;
+ }
+}
+
+#define PCI_PRINT_BAR_LISTING
+
+int
+__pci_read_cspace(struct v_inode* inode, void* buffer, size_t len, size_t fpos)
+{
+ if (len < 256) {
+ return ERANGE;
+ }
+
+ struct twifs_node* node = (struct twifs_node*)(inode->data);
+ struct pci_device* pcidev = (struct pci_device*)(node->data);
+
+ for (size_t i = 0; i < 256; i += sizeof(pci_reg_t)) {
+ *(pci_reg_t*)(buffer + i) = pci_read_cspace(pcidev->cspace_base, i);
+ }
+
+ return 256;
+}
+
+void
+pci_build_fsmapping()
+{
+ struct twifs_node *pci_class = twifs_dir_node(NULL, "pci"), *pci_dev;
+ struct pci_device *pos, *n;
+ llist_for_each(pos, n, &pci_devices, dev_chain)
+ {
+ pci_dev = twifs_dir_node(pci_class,
+ "B%d:D%d:F%d.%x:%x",
+ PCI_BUS_NUM(pos->cspace_base),
+ PCI_SLOT_NUM(pos->cspace_base),
+ PCI_FUNCT_NUM(pos->cspace_base),
+ PCI_DEV_VENDOR(pos->device_info),
+ PCI_DEV_DEVID(pos->device_info));
+ struct twifs_node* fnode = twifs_file_node(pci_dev, "cspace");
+ fnode->data = pos;
+ fnode->ops.read = __pci_read_cspace;
+ }
+}
+
+size_t
+pci_bar_sizing(struct pci_device* dev, uint32_t* bar_out, uint32_t bar_num)
+{
+ pci_reg_t bar = pci_read_cspace(dev->cspace_base, PCI_REG_BAR(bar_num));
+ if (!bar) {
+ *bar_out = 0;
+ return 0;
+ }
+
+ pci_write_cspace(dev->cspace_base, PCI_REG_BAR(bar_num), 0xffffffff);
+ pci_reg_t sized =
+ pci_read_cspace(dev->cspace_base, PCI_REG_BAR(bar_num)) & ~0x1;
+ if (PCI_BAR_MMIO(bar)) {
+ sized = PCI_BAR_ADDR_MM(sized);
+ }
+ *bar_out = bar;
+ pci_write_cspace(dev->cspace_base, PCI_REG_BAR(bar_num), bar);
+ return ~sized + 1;
+}
+
+void
+pci_setup_msi(struct pci_device* device, int vector)