#include #include #include "pci/pci.h" #include "pci/reg.h" #include "io/io.h" #include "std/string.h" #include "util/util.h" #include "pci/ide.h" #include "kprintf.h" uint8_t pci_read8(uint32_t id, uint32_t reg) { uint32_t addr = 0x80000000 | id | (reg & 0xFC); io_out32(PCI_CONFIG_ADDR, addr); return io_in8(PCI_CONFIG_DATA + (reg & 0x03)); } uint16_t pci_read16(uint32_t id, uint32_t reg) { uint32_t addr = 0x80000000 | id | (reg & 0xFC); io_out32(PCI_CONFIG_ADDR, addr); return io_in16(PCI_CONFIG_DATA + (reg & 0x02)); } uint32_t pci_read32(uint32_t id, uint32_t reg) { uint32_t addr = 0x80000000 | id | (reg & 0xFC); io_out32(PCI_CONFIG_ADDR, addr); return io_in32(PCI_CONFIG_DATA + reg); } void pci_write8(uint32_t id, uint32_t reg, uint8_t v) { uint32_t addr = 0x80000000 | id | (reg & 0xFC); io_out32(PCI_CONFIG_ADDR, addr); io_out8(PCI_CONFIG_DATA + (reg & 0x03), v); } void pci_write16(uint32_t id, uint32_t reg, uint16_t v) { uint32_t addr = 0x80000000 | id | (reg & 0xFC); io_out32(PCI_CONFIG_ADDR, addr); io_out16(PCI_CONFIG_DATA + (reg & 0x02), v); } void pci_write32(uint32_t id, uint32_t reg, uint32_t v) { uint32_t addr = 0x80000000 | id | (reg & 0xFC); io_out32(PCI_CONFIG_ADDR, addr); io_out32(PCI_CONFIG_DATA + reg, v); } void pci_readbar(uint32_t id, uint32_t idx, uint32_t *addr, uint32_t *mask) { uint32_t reg = PCI_BAR0 + idx * sizeof(uint32_t); *addr = pci_read32(id, reg); pci_write32(id, reg, 0xffffffff); *mask = pci_read32(id, reg); pci_write32(id, reg, *addr); } void pci_getbar(PciBar *bar, uint32_t id, uint32_t idx) { uint32_t addrlo; uint32_t masklo; pci_readbar(id, idx, &addrlo, &masklo); if (addrlo & PCI_BAR_MEM32) { bar->u.addr = (void *)((uint64_t)(addrlo & ~0x3)); bar->size = ~(masklo & ~0xF) + 1; bar->flags = addrlo & 0xF; } else if (addrlo & PCI_BAR_MEM64) { uint32_t addrhi; uint32_t maskhi; pci_readbar(id, idx+1, &addrhi, &maskhi); bar->u.addr = (void *)(((uint64_t)addrhi << 32) | ((uint64_t)addrlo & ~0xF)); bar->size = ~(((uint64_t)maskhi << 32) | ((uint64_t)masklo & ~0xF)) + 1; bar->flags = addrlo & 0xF; } else if (addrlo & PCI_BAR_IO) { bar->u.port = (uint16_t)(addrlo & ~0x3); bar->size = (uint16_t)(~(masklo & ~0x3) + 1); bar->flags = addrlo & 0x3; } } static PciMatch PCI_MATCHES[] = { { 0x8086, 0x7010, &pci_ide_init }, }; void pci_visit(uint32_t bus, uint32_t dev, uint32_t fn) { uint32_t id = PCI_MAKE_ID(bus, dev, fn); PciDevInfo devinfo; memset(&devinfo, 0, sizeof(devinfo)); devinfo.vendorid = pci_read16(id, PCI_VENDORID); if (devinfo.vendorid == 0xffff) { return; } devinfo.deviceid = pci_read16(id, PCI_DEVICEID); devinfo.progintf = pci_read8(id, PCI_PROGINTF); devinfo.subclass = pci_read8(id, PCI_SUBCLASS); devinfo.classcode = pci_read8(id, PCI_CLASSCODE); devinfo.bus = bus; devinfo.dev = dev; devinfo.fn = fn; LOG("pci", "%02X:%02X:%u 0x%04X/0x%04X: %s\n", bus, dev, fn, devinfo.vendorid, devinfo.deviceid, pci_classname(devinfo.classcode, devinfo.subclass, devinfo.progintf)); for (size_t i = 0; i < LEN(PCI_MATCHES); i++) { if (PCI_MATCHES[i].k1 == devinfo.vendorid && PCI_MATCHES[i].k2 == devinfo.deviceid) { PCI_MATCHES[i].initfn(&devinfo); } } } void pci_init(void) { for (uint32_t bus = 0; bus < 0x100; bus++) { for (uint32_t dev = 0; dev < 32; dev++) { uint32_t baseid = PCI_MAKE_ID(bus, dev, 0); uint8_t hdrtype = pci_read8(baseid, PCI_HDRTYPE); uint32_t fncount = hdrtype & PCI_MULTIFN ? 8 : 1; for (uint32_t fn = 0; fn < fncount; fn++) { pci_visit(bus, dev, fn); } } } }