#include "hwcomm/PCI.hpp" #include <cstdint> #include "drv/amd_am79c973.hpp" #include "drv/drivers.hpp" #include "drv/rtl8139.hpp" #include "print.hpp" using namespace hwcomm; PCIFunctionAddr::PCIFunctionAddr(std::uint8_t bus, std::uint8_t device, std::uint8_t function) : bus(bus), device(device), function(function) { } PCIFunctionAddr::PCIFunctionAddr(PCIDeviceAddr deviceAddr, std::uint8_t function) : bus(deviceAddr.bus), device(deviceAddr.device), function(function) { } std::uint32_t PCIFunctionAddr::address(std::uint32_t offset) const { return 0x1 << 31 | ((bus & 0xff) << 16) | ((device & 0x1f) << 11) | ((function & 0x07) << 8) | (offset & 0xfc); } PCIController::PCIController() : cmdPort(0xcf8), dataPort(0xcfc) { } std::uint32_t PCIController::read(PCIFunctionAddr functionAddr, std::uint32_t offset) { cmdPort.write(functionAddr.address(offset)); std::uint32_t result = dataPort.read(); return result >> (8*(offset % 4)); } void PCIController::write(PCIFunctionAddr functionAddr, std::uint32_t offset, std::uint32_t value) { cmdPort.write(functionAddr.address(offset)); dataPort.write(value); } void PCIController::selectDrivers(drv::DriverManager &drvManager, InterruptManager &interrupts) { for (std::uint8_t bus = 0; bus < 8; ++bus) { for (std::uint8_t dev = 0; dev < 32; ++dev) { const int numFunctions = (deviceHasFunctions({ bus, dev }) ? 8 : 1); for (std::uint8_t func = 0; func < numFunctions; ++func) { PCIFunctionAddr addr = { bus, dev, func }; PCIDeviceDescr descr(*this, addr); if (descr.vendorId == 0x0000 || descr.vendorId == 0xffff) { continue; } for (int barNum = 0; barNum < 6; ++barNum) { BAR bar = readBAR(addr, barNum); if (bar.type == BARType::InputOutput) { descr.portBase = bar.portBase; } } if (drv::Driver *driver = getDriver(descr, interrupts)) { drvManager.addDriver(*driver); } kprint("PCI BUS ", bus, ", DEVICE ", dev, ", FUNCTION ", func, " = VENDOR ", descr.vendorId, ", DEVICE ", descr.deviceId, "\n"); } } } } bool PCIController::deviceHasFunctions(PCIDeviceAddr deviceAddr) { return read({ deviceAddr, 0 }, 0x0e) & 0x80; } BAR PCIController::readBAR(PCIFunctionAddr functionAddr, std::uint16_t barNum) { const std::uint32_t hdrType = read(functionAddr, 0x0e) & 0x7f; const int maxBARs = 6 - (4*hdrType); if (barNum >= maxBARs) { return {}; } BAR bar = {}; const std::uint32_t barValue = read(functionAddr, 0x10 + 4*barNum); bar.type = (barValue & 0x1 ? BARType::InputOutput : BARType::MemoryMapping); if (bar.type == BARType::MemoryMapping) { switch ((barValue >> 1) & 0x3) { case 0: // 32-bit Mode case 1: // 20-bit Mode case 2: // 64-bit Mode break; } return {}; } else { bar.portBase = (barValue & ~0x3); bar.prefetchable = false; } return bar; } drv::Driver * PCIController::getDriver(PCIDeviceDescr &dev, InterruptManager &interrupts) { drv::Driver *driver = nullptr; switch (dev.vendorId) { case 0x1022: // AMD switch (dev.deviceId) { case 0x2000: // am79c973 kprint("AMD am79c973\n"); driver = new drv::amd_am79c973(dev, interrupts); break; } break; case 0x10ec: // Realtek switch (dev.deviceId) { case 0x8139: // rtl8139 kprint("rtl8139\n"); driver = new drv::rtl8139(dev, interrupts); break; } case 0x8086: // Intel break; } switch (dev.classId) { case 0x03: // graphics switch (dev.subclassId) { case 0x00: // VGA kprint("VGA\n"); break; } break; } return driver; } PCIDeviceDescr::PCIDeviceDescr(PCIController &pciController, PCIFunctionAddr functionAddr) : functionAddr(functionAddr), pciController(pciController) { vendorId = pciController.read(functionAddr, 0x00); deviceId = pciController.read(functionAddr, 0x02); classId = pciController.read(functionAddr, 0x0b); subclassId = pciController.read(functionAddr, 0x0a); interfaceId = pciController.read(functionAddr, 0x09); revision = pciController.read(functionAddr, 0x08); interrupt = pciController.read(functionAddr, 0x3c); } void PCIDeviceDescr::enableBusMaster() { const std::uint32_t command = pciController.read(functionAddr, 0x04); pciController.write(functionAddr, 0x04, command | 0x4); }