diff --git a/lcrash/CMakeLists.txt b/lcrash/CMakeLists.txt index 2c7d495..55c5ffb 100644 --- a/lcrash/CMakeLists.txt +++ b/lcrash/CMakeLists.txt @@ -8,7 +8,7 @@ lw_project(lcrash enable_language(ASM) lw_add_executable(lcrashkern - SOURCES main.c cmdline.c util.c lnxboot.c math.c debug/debug.c acpi/acpi.c efi/efi.c efi/guid.c efi/memmap.c gdb/gdb.c pci/pci.c mm/phys.c mm/kmalloc.c driver/sysbus.c + SOURCES main.c cmdline.c util.c lnxboot.c math.c debug/debug.c acpi/acpi.c efi/efi.c efi/guid.c efi/memmap.c gdb/gdb.c pci/pci.c mm/phys.c mm/kmalloc.c mm/virt.c driver/sysbus.c ) add_executable(lcrashkernld IMPORTED) set_property(TARGET lcrashkernld PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lcrash.ld) diff --git a/lcrash/debug/debug.c b/lcrash/debug/debug.c index 93802b6..4c8aea3 100644 --- a/lcrash/debug/debug.c +++ b/lcrash/debug/debug.c @@ -15,7 +15,7 @@ struct DebugExtendedDebugInformationBlock* DebugEDIB = 0; struct GdbDataBlock* DebugGDB = (struct GdbDataBlock*)0x100000; int DebugInitialize() { - DebugEDIB = KernelHeapAlloc(sizeof(struct DebugExtendedDebugInformationBlock), 0); + DebugEDIB = KernelHeapAlloc(sizeof(struct DebugExtendedDebugInformationBlock), 1, 0); if (DebugEDIB == 0) return -1; DebugGDB->EDIB = DebugEDIB; diff --git a/lcrash/driver/sysbus.c b/lcrash/driver/sysbus.c index 7b610f7..de68d0f 100644 --- a/lcrash/driver/sysbus.c +++ b/lcrash/driver/sysbus.c @@ -10,10 +10,10 @@ struct SysbusDevice* SysbusRootDevice = 0; * Create a new device description */ struct SysbusDeviceDescription* SysbusCreateDeviceDescriptionInternal() { - struct SysbusDeviceDescription* Description = KernelHeapAlloc(sizeof(struct SysbusDeviceDescription), 0); + struct SysbusDeviceDescription* Description = KernelHeapAlloc(sizeof(struct SysbusDeviceDescription), 1, 0); Description->DeviceName = 0; - Description->Instances = KernelHeapAlloc(sizeof(struct SysbusDevice*) * 4, 0); + Description->Instances = KernelHeapAlloc(sizeof(struct SysbusDevice*) * 4, 1, 0); Description->InstanceCount = 0; Description->InstanceSlots = 4; Description->CreateDevice = 0; @@ -29,7 +29,7 @@ struct SysbusDeviceDescription* SysbusCreateDeviceDescriptionInternal() { void SysbusAttachChildDeviceInternal(struct SysbusDevice* Parent, struct SysbusDevice* Child) { // See if we need to grow the list if (Parent->ChildCount >= Parent->ChildSlots) { - struct SysbusDevice** NewList = KernelHeapAlloc(sizeof(struct SysbusDevice*) * Parent->ChildSlots * 2, 0); + struct SysbusDevice** NewList = KernelHeapAlloc(sizeof(struct SysbusDevice*) * Parent->ChildSlots * 2, 1, 0); for (int i = 0; i < Parent->ChildCount; i++) { NewList[i] = Parent->Children[i]; } @@ -59,12 +59,12 @@ struct SysbusDevice* SysbusCreateDeviceInternal( void* DeviceData, bool IsRootDevice ) { - struct SysbusDevice* Device = KernelHeapAlloc(sizeof(struct SysbusDevice), 0); + struct SysbusDevice* Device = KernelHeapAlloc(sizeof(struct SysbusDevice), 1, 0); Device->DeviceDescription = Description; Device->DeviceName = 0; Device->DeviceData = 0; Device->Parent = Parent; - Device->Children = KernelHeapAlloc(sizeof(struct SysbusDevice*) * 4, 0); + Device->Children = KernelHeapAlloc(sizeof(struct SysbusDevice*) * 4, 1, 0); Device->ChildCount = 0; Device->ChildSlots = 4; @@ -73,7 +73,7 @@ struct SysbusDevice* SysbusCreateDeviceInternal( // See if we need to grow the instance list if (Description->InstanceCount >= Description->InstanceSlots) { - struct SysbusDevice** NewList = KernelHeapAlloc(sizeof(struct SysbusDevice*) * Description->InstanceSlots * 2, 0); + struct SysbusDevice** NewList = KernelHeapAlloc(sizeof(struct SysbusDevice*) * Description->InstanceSlots * 2, 1, 0); for (int i = 0; i < Description->InstanceCount; i++) { NewList[i] = Description->Instances[i]; } @@ -122,7 +122,5 @@ void SysbusInitialize() { ); SysbusRootDevice->DeviceName = "Lcrash System Bus"; - Panic("Failed to initialize system bus"); - return; } diff --git a/lcrash/main.c b/lcrash/main.c index 235b582..d487498 100644 --- a/lcrash/main.c +++ b/lcrash/main.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "types.h" #include "lnxboot.h" @@ -38,6 +39,9 @@ void entry64(struct boot_params* BootParams) { // Initialize the extended debugging information block if (DebugInitialize()) while (1) {} + // Initialize the virtual memory manager + VmemInitialize(); + // Initialize the system bus SysbusInitialize(); diff --git a/lcrash/mm/kmalloc.c b/lcrash/mm/kmalloc.c index 43cd5b8..7961c83 100644 --- a/lcrash/mm/kmalloc.c +++ b/lcrash/mm/kmalloc.c @@ -136,11 +136,99 @@ int KernelHeapInitialize() { return 0; } -void* KernelHeapAlloc(u32 Size, u32 Flags) { +/// Shamelessly copy pasted from function above +int KernelHeapGrow(struct KernelHeapZone* Zone, u32 Level, u32 Flags) { + // Allocate + struct PmemAllocation Block; + if (PmemAllocateBlock(1 << Level, &Block)) return -1; + + // Make the frame block + struct KernelHeapBlock* FrameBlock = Block.Address; + FrameBlock->Prev = Zone->Last; + FrameBlock->PrevFree = Zone->LastFree; + FrameBlock->Size = sizeof(struct KernelHeapFrame); + FrameBlock->Free = false; + + // Make the frame structure + struct KernelHeapFrame* Frame = Block.Address + + sizeof(struct KernelHeapBlock); + Frame->Block = Block; + Frame->Size = 1 << Level; + Frame->NextFrame = 0; + Frame->PrevFrame = Zone->LastFrame; + + // Make the root block + struct KernelHeapBlock* RootBlock = (struct KernelHeapBlock*)((void*)Frame + sizeof(struct KernelHeapFrame)); + RootBlock->Prev = FrameBlock; + FrameBlock->Next = RootBlock; + FrameBlock->NextFree = RootBlock; + RootBlock->Next = 0; + RootBlock->PrevFree = Zone->LastFree; + RootBlock->NextFree = 0; + RootBlock->Free = true; + RootBlock->Size = (1 << Level) + - sizeof(struct KernelHeapBlock) + - sizeof(struct KernelHeapFrame) + - sizeof(struct KernelHeapBlock); + + // Fill out the rest of the zone + Zone->LastFrame->NextFrame = Frame; + Zone->LastFrame = Frame; + Zone->Last->Next = FrameBlock; + for (struct KernelHeapBlock* Block = Zone->Last; Block != 0 && Block->NextFree == 0; Block = Block->Prev) Block->NextFree = RootBlock; + Zone->Last = RootBlock; + + return 0; +} + +void* KernelHeapAllocInternal(u32 Size, u32 Align, u32 Flags, u32 Iteration) { + u64 AlignMask = 0; + for (u32 i = 1; i < Align; i <<= 1) AlignMask |= i; + AlignMask = ~AlignMask; + // Find a free block for (struct KernelHeapZone* Zone = KernelHeapFirst; Zone != 0; Zone = Zone->Next) { for (struct KernelHeapBlock* Block = Zone->FirstFree; Block != 0; Block = Block->NextFree) { if (Block->Size >= Size) { + u64 PaddingSize = 0; + if (Align > 1) { + // Align uses memory poorly + if (Block->Prev == 0) continue; + + u64 BlockStart = (uptr)Block + sizeof(struct KernelHeapBlock); + u64 BlockEnd = BlockStart + Block->Size; + + if (!(BlockStart < ((BlockStart + Align) & AlignMask) && BlockEnd > ((BlockStart + Align) & AlignMask))) continue; + + PaddingSize = ((BlockStart + Align) & AlignMask) - BlockStart; + } + + if (PaddingSize > 0) { + struct KernelHeapBlock* NewBlock = (struct KernelHeapBlock*)((void*)Block + PaddingSize); + NewBlock->Prev = Block->Prev; + NewBlock->Next = Block->Next; + NewBlock->PrevFree = Block->PrevFree; + NewBlock->NextFree = Block->NextFree; + NewBlock->Free = Block->Free; + NewBlock->Size = Block->Size - PaddingSize; + + // This is incredibly slow + struct KernelHeapBlock* Next = Zone->First; + while (Next != 0) { + struct KernelHeapBlock* NextNext = Next->Next; + if (Next->Prev == Block) Next->Prev = NewBlock; + if (Next->Next == Block) Next->Next = NewBlock; + if (Next->PrevFree == Block) Next->PrevFree = NewBlock; + if (Next->NextFree == Block) Next->NextFree = NewBlock; + Next = NextNext; + } + + // GOD. + if (NewBlock->Prev != 0) NewBlock->Prev->Size += (uptr)Block + PaddingSize; + + Block = NewBlock; + } + s64 SplitSize = (s64)Block->Size - Size - (sizeof(struct KernelHeapBlock) * 2) - 8; if (SplitSize > 0) { @@ -179,7 +267,14 @@ void* KernelHeapAlloc(u32 Size, u32 Flags) { } } - return 0; + if (Iteration < 3) { + KernelHeapGrow(KernelHeapLast, 20, 0); + return KernelHeapAllocInternal(Size, Align, Flags, Iteration + 1); + } else return 0; +} + +void* KernelHeapAlloc(u32 Size, u32 Align, u32 Flags) { + return KernelHeapAllocInternal(Size, Align, Flags, 0); } void KernelHeapFree(void* Address) { diff --git a/lcrash/mm/kmalloc.h b/lcrash/mm/kmalloc.h index ae5b3bb..9383ac3 100644 --- a/lcrash/mm/kmalloc.h +++ b/lcrash/mm/kmalloc.h @@ -10,7 +10,7 @@ int KernelHeapInitialize(); /** * Allocate memory */ -void* KernelHeapAlloc(u32 Size, u32 Flags); +void* KernelHeapAlloc(u32 Size, u32 Align, u32 Flags); /** * Free memory diff --git a/lcrash/mm/virt.c b/lcrash/mm/virt.c new file mode 100644 index 0000000..5ad1a6c --- /dev/null +++ b/lcrash/mm/virt.c @@ -0,0 +1,74 @@ +#include + +#include +#include + +u64 (*VmemOriginalPML4)[512] = 0; +u64 (*VmemPML4)[512] = 0; + +void VmemInitialize() { + // Copy control registers + u64 CR3; + asm ("mov %%cr3, %0" : "=r" (CR3)); + + u64 CR4; + asm ("mov %%cr4, %0" : "=r" (CR4)); + + if (CR4 & 0x800) Panic("5 Level paging not supported"); + + u64 (*OriginalPML4)[512] = (u64(*)[512])(CR3 & 0x0007fffffffff000); + u64 (*NewPML4)[512] = KernelHeapAlloc(sizeof(u64) * 512, 0x1000, 0); + + for (int i = 0; i < 512; i++) { + if ((*OriginalPML4)[i] & 1) { + u64 (*OriginalPDPT)[512] = (u64(*)[512])(((*OriginalPML4)[i] & 0x0007fffffffff000)); + u64 (*NewPDPT)[512] = KernelHeapAlloc(sizeof(u64) * 512, 0x1000, 0); + + for (int j = 0; j < 512; j++) { + if ((*OriginalPDPT)[j] & 1) { + u64 (*OriginalPD)[512] = (u64(*)[512])(((*OriginalPDPT)[j] & 0x000ffffffffff000)); + u64 (*NewPD)[512] = KernelHeapAlloc(sizeof(u64) * 512, 0x1000, 0); + + for (int k = 0; k < 512; k++) { + if ((*OriginalPD)[k] & 1) { + u64 (*OriginalPT)[512] = (u64(*)[512])(((*OriginalPD)[k] & 0x000ffffffffff000)); + u64 (*NewPT)[512] = KernelHeapAlloc(sizeof(u64) * 512, 0x1000, 0); + + if ((s64)NewPT <= 0) Panic("Failed to allocate memory"); + + for (int l = 0; l < 512; l++) { + //if ((*OriginalPT)[l] & 1) { + // (*NewPT)[l] = (*OriginalPT)[l]; + //} else (*NewPT)[l] = 0;* + (*NewPT)[l] = (*OriginalPT)[l] | 0x87; + } + + NewPT = (void*)((u64)OriginalPT | 0x87); + + (*NewPD)[k] = (u64)NewPT; + } else (*NewPD)[k] = 0; + } + + NewPD = (void*)((uptr)NewPD | (((*OriginalPDPT)[j]) & ~0x0007fffffffff000)); + + (*NewPDPT)[j] = (u64)NewPD; + } else (*NewPDPT)[j] = 0; + } + + NewPDPT = (void*)((uptr)NewPDPT | (((*OriginalPML4)[i]) & ~0x0007fffffffff000)); + + (*NewPML4)[i] = (u64)NewPDPT; + } else (*NewPML4)[i] = 0; + } + + // Save these + VmemOriginalPML4 = OriginalPML4; + VmemPML4 = NewPML4; + + // Load our new page table + CR3 ^= (u64)VmemOriginalPML4; + CR3 |= ((u64)VmemPML4) & 0x0007fffffffff000; + asm volatile ("mov %q0, %%cr3" : : "r" (CR3)); + + Panic("FUCK"); +} diff --git a/lcrash/mm/virt.h b/lcrash/mm/virt.h new file mode 100644 index 0000000..2a9de51 --- /dev/null +++ b/lcrash/mm/virt.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void VmemInitialize(); diff --git a/lcrash/pci/pci.c b/lcrash/pci/pci.c index 3d939e8..cdd2442 100644 --- a/lcrash/pci/pci.c +++ b/lcrash/pci/pci.c @@ -2,22 +2,46 @@ #include #include +#include bool PciIsPresent = false; bool PciSupportsECM = false; -void PciInitialize() { - // Try to figure out if we have PCIe - if (AcpiPresent()) { - struct AcpiMCFG* BridgeTable = AcpiGetTable("MCFG"); +void* PciBusses[256] = {}; - // Guess not - if (BridgeTable == NULL) goto nopcie; +void PciScanDevice(u32 Bus, u32 Device) { + struct PciConfigurationSpaceHeader* DeviceHeader = (struct PciConfigurationSpaceHeader*)(PciBusses[Bus] + Device * 0x800); + // Is a device connected here? + if (DeviceHeader->VendorID != 0xFFFF) { while (1) {} } +} -nopcie: Panic("Failed to initialize PCI"); +void PciScanBus(u32 Bus) { + // Scan bus devices + for (int i = 0; i < 32; i++) PciScanDevice(Bus, i); +} + +void PciInitialize() { + // Try to figure out if we have PCIe + if (!AcpiPresent()) Panic("Failed to initialize PCI"); + + 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++) { + 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 + PciScanBus(0); return; } diff --git a/lcrash/pci/pci.h b/lcrash/pci/pci.h index 493f09c..efed49c 100644 --- a/lcrash/pci/pci.h +++ b/lcrash/pci/pci.h @@ -2,6 +2,28 @@ #include +/** + * bwaaaaaa, the many ways to touch PCI things + */ +struct [[gnu::packed]] PciConfigurationSpaceHeader { + u16 VendorID; + u16 DeviceID; + u16 Status; + u16 Command; + u8 RevisionID : 8; + u32 ClassCode : 24; + u8 CacheLineSize; + u8 MasterLatencyTimer; + u8 HeaderType; + u8 BIST; + u8 Reserved[0x20]; + u8 CapabilitiesPointer; + u8 Reserved2[7]; + u8 InterruptLine; + u8 InterruptPin; + u8 Reserved3[2]; +}; + /** * Initialize the PCI code. */