156 lines
5.2 KiB
C

#include <lcrash/pci/pci.h>
#include <lcrash/mm/virt.h>
#include <lcrash/acpi/acpi.h>
#include <lcrash/debug/debug.h>
#include <lcrash/driver/sysbus.h>
#include <lcrash/mm/kmalloc.h>
#include <lcrash/driver/vga.h>
#include <lcrash/util.h>
#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; }