#include #include #include #include #include #include #include #include #define PSD_MISC_() PciCreateMiscDevice(Parent, Bus, Device, DeviceHeader->Class, DeviceHeader->Subclass, DeviceHeader->ProgIF) bool PciIsPresent = false; bool PciSupportsECM = false; void* PciBusses[256] = {}; struct SysbusDeviceDescription* PciSBHostControllerDevice = 0; struct SysbusDeviceDescription* PciSBMiscDevice = 0; void PciCreateMiscDevice(struct SysbusDevice* Parent, u8 Bus, u8 Device, u8 Class, u8 Subclass, u8 ProgInterface) { struct SysbusDevice* Dev = SysbusCreateDevice(PciSBMiscDevice, Parent, NULL); struct PciSBMiscDevice* DeviceData = KernelHeapAlloc(sizeof(PciSBMiscDevice), 1, 0); DeviceData->Bus = Bus; DeviceData->Device = Device; DeviceData->Class = Class; DeviceData->Subclass = Subclass; DeviceData->ProgInterface = ProgInterface; Dev->DeviceName = "PCI Misc Device"; Dev->DeviceData = DeviceData; } void PciScanDevice(u32 Bus, u32 Device, struct SysbusDevice* Parent) { struct PciConfigurationSpaceHeader* DeviceHeader = (struct PciConfigurationSpaceHeader*)(PciBusses[Bus] + Device * 0x8000); // Is a device connected here? if (DeviceHeader->VendorID != 0xFFFF) { if ((DeviceHeader->HeaderType & 3) == 0) { if (DeviceHeader->Class == 3) { if (DeviceHeader->Subclass == 0) { if (DeviceHeader->ProgIF == 0) { // It looks like theres something in the // VGA's BARs but i can't seem to find any // documentation on them, so we'll just use // legacy vga ports! // Get VGA drivers ready if (!VgaIsInitialized()) VgaInitialize(); // QEMU oh so kindly provides us with a builtin version of the VESA BIOS Extensions! // They break our code. Disable them. if (DeviceHeader->VendorID == 0x1234 && DeviceHeader->DeviceID == 0x1111) { PortWrite16(0x01CE, 0x04); // VBE_DISPI_IOPORT_INDEX <= 0x04 PortWrite16(0x01D0, 0x00); // [IDX:04] ENABLED <= FALSE } struct SysbusDevice* VgaDev = VgaCreateDevice(Parent); VgaDev->DeviceName = "VGA Device"; } else PSD_MISC_(); } else PSD_MISC_(); } else if (DeviceHeader->Class == 6) { if (DeviceHeader->Subclass == 0) { if (DeviceHeader->HeaderType & 0x80) { Panic("No support for multiple host controller busses"); } else { struct PciSBHostController_CreateArgs CreateArgs; CreateArgs.Bus = Bus; CreateArgs.Device = Device; CreateArgs.OwnedBusCount = 1; CreateArgs.OwnedBusses[0] = Bus; struct SysbusDevice* HostController = SysbusCreateDevice( PciSBHostControllerDevice, Parent, &CreateArgs ); HostController->DeviceName = "PCI Host Controller"; if (Device == 0) { for (int i = 1; i < 32; i++) PciScanDevice(Bus, i, HostController); } else Panic("Bus root inside bus"); } } else PSD_MISC_(); } else PSD_MISC_(); } else PSD_MISC_(); } } s32 PciSBHostControllerDevice_Create(struct SysbusDevice* Device, void* Data) { struct PciSBHostController_CreateArgs* CreateArgs = Data; struct PciSBHostController* DeviceData = KernelHeapAlloc(sizeof(struct PciSBHostController), 1, KHA_ZERO); // Copy parameters DeviceData->Bus = CreateArgs->Bus; DeviceData->Device = CreateArgs->Device; DeviceData->OwnedBusCount = CreateArgs->OwnedBusCount; for (int i = 0; i < DeviceData->OwnedBusCount; i++) DeviceData->OwnedBusses[i] = CreateArgs->OwnedBusses[i]; // Save device data Device->DeviceData = (void*)DeviceData; return 0; } s32 PciSBHostControllerDevice_Delete(struct SysbusDevice* Device) { struct PciSBHostController* DeviceData = Device->DeviceData; // Free device data KernelHeapFree(DeviceData); return 0; } void PciInitialize() { // Try to figure out if we have PCIe if (!AcpiPresent()) Panic("Failed to initialize PCI"); // Define our devices PciSBHostControllerDevice = SysbusCreateDeviceDescription(); PciSBHostControllerDevice->DeviceName = "PCI Host Controller"; PciSBHostControllerDevice->CreateDevice = PciSBHostControllerDevice_Create; PciSBHostControllerDevice->DeleteDevice = PciSBHostControllerDevice_Delete; PciSBMiscDevice = SysbusCreateDeviceDescription(); PciSBMiscDevice->DeviceName = "PCI Misc Device"; // Acpi struct AcpiMCFG* BridgeTable = AcpiGetTable("MCFG"); // Guess not if (BridgeTable == NULL) Panic("Failed to find PCI bridge table"); // Take our pcie bridges s32 Length = (BridgeTable->Header.Length - 44) / 16; for (int i = 0; i < Length; i++) { // Identity map our busses because linux doesn't do it for us VmemMapMemory( BridgeTable->Bridges[i].Address, BridgeTable->Bridges[i].Address, (BridgeTable->Bridges[i].EndBus - BridgeTable->Bridges[i].StartBus + 1) * 0x100000 ); for (int Bus = BridgeTable->Bridges[i].StartBus; Bus < BridgeTable->Bridges[i].EndBus; Bus++) { PciBusses[Bus] = BridgeTable->Bridges[i].Address + (Bus - BridgeTable->Bridges[i].StartBus) * 0x100000; } } // Scan the root bus PciScanDevice(0, 0, SysbusGetRootDevice()); return; } bool PciPresent() { return PciIsPresent; } bool PciePresent() { return PciSupportsECM; }