156 lines
5.2 KiB
C
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; }
|