Files
my-os-project2/kernel/pci/pci.c
2025-11-18 23:28:45 +01:00

127 lines
3.6 KiB
C

#include <stdint.h>
#include <stddef.h>
#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);
}
}
}
}