From 5f750e66d6084906a1f5fabea02d9bd1318b95c0 Mon Sep 17 00:00:00 2001 From: xwashere Date: Fri, 19 Apr 2024 08:30:56 -0400 Subject: [PATCH] [lcrash] ADD: Add memory management code --- common/gdb/guile/core.scm | 43 ++- lcrash/CMakeLists.txt | 2 +- lcrash/acpi/acpi.h | 21 ++ lcrash/cmdline.c | 71 +++++ lcrash/cmdline.h | 15 + lcrash/debug/debug.c | 36 +++ lcrash/debug/debug.h | 13 + lcrash/driver/sysbus.h | 84 ++++++ lcrash/efi/memmap.c | 4 + lcrash/efi/memmap.h | 17 ++ lcrash/elf/elf.h | 48 ++++ lcrash/empty.S | 0 lcrash/gdb/gdb.h | 3 + lcrash/lcrash.c | 167 ------------ lcrash/main.c | 23 +- lcrash/math.c | 11 + lcrash/math.h | 6 + lcrash/mm/kmalloc.c | 187 +++++++++++++ lcrash/mm/kmalloc.h | 18 ++ lcrash/mm/phys.c | 500 ++++++++++++++++++++++++++++++++++ lcrash/mm/phys.h | 37 +++ lcrash/pci/pci.c | 24 ++ lcrash/pci/pci.h | 14 + lcrash/setup/compressed/elf.h | 41 +-- lcrash/setup/header.S | 2 +- src/grub/grub.cfg | 2 +- 26 files changed, 1164 insertions(+), 225 deletions(-) create mode 100644 lcrash/cmdline.c create mode 100644 lcrash/cmdline.h create mode 100644 lcrash/debug/debug.c create mode 100644 lcrash/debug/debug.h create mode 100644 lcrash/driver/sysbus.h create mode 100644 lcrash/elf/elf.h delete mode 100644 lcrash/empty.S delete mode 100644 lcrash/lcrash.c create mode 100644 lcrash/math.c create mode 100644 lcrash/math.h create mode 100644 lcrash/mm/kmalloc.c create mode 100644 lcrash/mm/kmalloc.h create mode 100644 lcrash/mm/phys.c create mode 100644 lcrash/mm/phys.h create mode 100644 lcrash/pci/pci.c create mode 100644 lcrash/pci/pci.h diff --git a/common/gdb/guile/core.scm b/common/gdb/guile/core.scm index 25729f7..348bee4 100644 --- a/common/gdb/guile/core.scm +++ b/common/gdb/guile/core.scm @@ -14,6 +14,7 @@ (define btp-i32 (lookup-type "int")) (define btp-i64 (lookup-type "long long")) (define btp-c8 (lookup-type "char")) +(define btp-mem (type-pointer (lookup-type "void"))) (define btp-bool btp-u8) (define btp-uptr btp-u64) @@ -109,25 +110,37 @@ (if (value=? (value-dereference (value-cast (make-value #x100010) (type-pointer btp-bool))) 1) ((lambda () (define new-cckernel-binary-offset (value->integer (value-dereference (value-cast (make-value #x100018) (type-pointer btp-uptr))))) (define new-cckernel-binary-location (string-append build-dir "/lcrash/cckernel")) - (when (not (null? cckernel-binary-location)) - (gdbw-remove-symbol-file cckernel-binary-location) - (set! cckernel-binary-location '()) - (set! cckernel-binary-offset '())) - (gdbw-add-symbol-file new-cckernel-binary-location #:offset new-cckernel-binary-offset) - (set! cckernel-binary-location new-cckernel-binary-location) - (set! cckernel-binary-offset new-cckernel-binary-offset))) + (when (not (equal? new-cckernel-binary-offset cckernel-binary-offset)) + (when (not (null? cckernel-binary-location)) + (gdbw-remove-symbol-file cckernel-binary-location) + (set! cckernel-binary-location '()) + (set! cckernel-binary-offset '())) + (gdbw-add-symbol-file new-cckernel-binary-location #:offset new-cckernel-binary-offset) + (set! cckernel-binary-location new-cckernel-binary-location) + (set! cckernel-binary-offset new-cckernel-binary-offset)))) (display "TODO: CCKERNEL UNLOADED\n")) (if (value=? (value-dereference (value-cast (make-value #x100020) (type-pointer btp-bool))) 1) ((lambda () (define new-kernel-binary-offset (value->integer (value-dereference (value-cast (make-value #x100028) (type-pointer btp-uptr))))) (define new-kernel-binary-location (string-append build-dir "/lcrash/lcrashkern")) - (when (not (null? kernel-binary-location)) - (gdbw-remove-symbol-file kernel-binary-location) - (set! kernel-binary-location '()) - (set! kernel-binary-offset '())) - (gdbw-add-symbol-file new-kernel-binary-location #:offset new-kernel-binary-offset) - (set! kernel-binary-location new-kernel-binary-location) - (set! kernel-binary-offset new-kernel-binary-offset))) - (display "TODO: KERNEL UNLOADED\n"))))) + (when (not (equal? new-kernel-binary-offset kernel-binary-offset)) + (when (not (null? kernel-binary-location)) + (gdbw-remove-symbol-file kernel-binary-location) + (set! kernel-binary-location '()) + (set! kernel-binary-offset '())) + (gdbw-add-symbol-file new-kernel-binary-location #:offset new-kernel-binary-offset) + (set! kernel-binary-location new-kernel-binary-location) + (set! kernel-binary-offset new-kernel-binary-offset)))) + (display "TODO: KERNEL UNLOADED\n")) + + ; EDIB + (when (not (null? kernel-binary-location)) + ((lambda () (define edip-ptr (value-cast (make-value #x100030) (type-pointer (type-pointer (lookup-type "struct DebugExtendedDebugInformationBlock"))))) + (when (not (value=? (value-cast (value-dereference edip-ptr) btp-mem) (value-cast (make-value 0) btp-mem))) + ((lambda () (define edip (value-dereference (value-dereference edip-ptr))) + (when (value->bool (value-field edip "Panic")) + (format #t "!!! KERNEL PANIC !!!\n") + (format #t "MSG: ~a\n" (let ((error (value-field edip "PanicError"))) + (if (value=? error (make-value 0)) "N/A" (value->string error)))))))))))))) ; == Command prefixes == (register-command! (make-command "lwdbg" #:prefix? #t)) diff --git a/lcrash/CMakeLists.txt b/lcrash/CMakeLists.txt index f61b95f..e814bde 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 util.c lnxboot.c acpi/acpi.c efi/efi.c efi/guid.c efi/memmap.c gdb/gdb.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 ) add_executable(lcrashkernld IMPORTED) set_property(TARGET lcrashkernld PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lcrash.ld) diff --git a/lcrash/acpi/acpi.h b/lcrash/acpi/acpi.h index b182479..56c2b44 100644 --- a/lcrash/acpi/acpi.h +++ b/lcrash/acpi/acpi.h @@ -47,6 +47,27 @@ struct AcpiXSDT { struct AcpiSDTHeader* Tables[]; }; +/** + * ECM address for the MCFG table + */ +struct [[gnu::packed]] AcpiMCFGBridge { + void* Address; + u16 SegmentGroup; + u8 StartBus; + u8 EndBus; + u8 Reserved[4]; +}; + +/** + * The memory mapped device table + */ +struct AcpiMCFG { + struct AcpiSDTHeader Header; + + u8 Reserved[8]; + struct AcpiMCFGBridge Bridges[]; +}; + /** * Initialize ACPI code */ diff --git a/lcrash/cmdline.c b/lcrash/cmdline.c new file mode 100644 index 0000000..edc401b --- /dev/null +++ b/lcrash/cmdline.c @@ -0,0 +1,71 @@ +/// Kernel command line code, extremely slow, extremely unsafe, extremely painful + +#include + +#include + +#define POOL_SIZE 0x800 +#define SLOT_COUNT 0x40 + +c8 CmdlineMemoryPool[POOL_SIZE] = {}; +c8* CmdlineKeys[SLOT_COUNT] = {}; +c8* CmdlineValues[SLOT_COUNT] = {}; +u32 CmdlineEntryCount = 0; + +void CmdlineParse(const c8* CommandLine) { + enum PARSE_STATE { PSWS, PSKey, PSValue }; + + int PoolPosition = 0; + int SlotPosition = 0; + c8* KeyStart = 0; + c8* ValueStart = 0; + enum PARSE_STATE State = PSWS; + + for (int i = 0; CommandLine[i] != 0; i++) { + switch (State) { + case PSWS: { + if (!(CommandLine[i] == '\n' + ||CommandLine[i] == '\r' + ||CommandLine[i] == ' ')) { + State = PSKey; + KeyStart = CmdlineMemoryPool + PoolPosition; + } else continue; + } + case PSKey: { + if (CommandLine[i] == '=') { + State = PSValue; + CmdlineKeys[SlotPosition] = KeyStart; + CmdlineMemoryPool[PoolPosition++] = 0; + ValueStart = CmdlineMemoryPool + PoolPosition; + continue; + } else CmdlineMemoryPool[PoolPosition++] = CommandLine[i]; + continue; + } + case PSValue: { + if (CommandLine[i] == '\n' + ||CommandLine[i] == '\r' + ||CommandLine[i] == ' ') { + State = PSWS; + CmdlineValues[SlotPosition++] = ValueStart; + CmdlineMemoryPool[PoolPosition++] = 0; + } else CmdlineMemoryPool[PoolPosition++] = CommandLine[i]; + } + } + } + + if (State == PSValue) CmdlineValues[SlotPosition++] = ValueStart; + + CmdlineEntryCount = SlotPosition; +} + +const c8* CmdlineGet(const c8* Param) { + for (int i = 0; i < CmdlineEntryCount; i++) { + for (int j = 0; Param[j - 1] != 0; j++) { + if (CmdlineKeys[i][j] != Param[j]) goto next; + } + + return CmdlineValues[i]; +next: } + + return 0; +} diff --git a/lcrash/cmdline.h b/lcrash/cmdline.h new file mode 100644 index 0000000..a36413c --- /dev/null +++ b/lcrash/cmdline.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +/** + * Parse the kernel command line + */ +void CmdlineParse(const c8* CommandLine); + +/** + * Get a value from the kernel command line + * + * \warn DO NOT FREE THE VALUE RETURNED + */ +const c8* CmdlineGet(const c8* Param); diff --git a/lcrash/debug/debug.c b/lcrash/debug/debug.c new file mode 100644 index 0000000..93802b6 --- /dev/null +++ b/lcrash/debug/debug.c @@ -0,0 +1,36 @@ +#include + +#include +#include + +struct DebugExtendedDebugInformationBlock { + /// Kernel panic + bool Panic; + + /// Kernel panic error + const c8* PanicError; +}; + +struct DebugExtendedDebugInformationBlock* DebugEDIB = 0; +struct GdbDataBlock* DebugGDB = (struct GdbDataBlock*)0x100000; + +int DebugInitialize() { + DebugEDIB = KernelHeapAlloc(sizeof(struct DebugExtendedDebugInformationBlock), 0); + if (DebugEDIB == 0) return -1; + + DebugGDB->EDIB = DebugEDIB; + DebugEDIB->Panic = false; + DebugEDIB->PanicError = 0; + + return 0; +} + +[[noreturn]] +void Panic(const c8* Error) { + DebugEDIB->PanicError = Error; + DebugEDIB->Panic = true; + DebugGDB->Update++; + + asm("cli"); + while (1) asm("hlt"); +} diff --git a/lcrash/debug/debug.h b/lcrash/debug/debug.h new file mode 100644 index 0000000..d76eb00 --- /dev/null +++ b/lcrash/debug/debug.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +/** + * Initialize extended debugging + * + * \return 0 on success + */ +int DebugInitialize(); + +[[noreturn]] +void Panic(const c8* Error); diff --git a/lcrash/driver/sysbus.h b/lcrash/driver/sysbus.h new file mode 100644 index 0000000..fd39686 --- /dev/null +++ b/lcrash/driver/sysbus.h @@ -0,0 +1,84 @@ +#pragma once + +/** + * The lcrash system bus is a root device which manages all other associated devices, and handles bookkeeping for other subsystems (e.g. classifying devices) + * The system bus supports device names to aid debuggers, however these names are otherwise meaningless and pointers to structures should be used instead + * + * Example device tree: + * /SYSBUS + * /PCI + * /PCI0000:00:00.0 + * $ETHERNET + * /PCI0000:00:00.1 + * $FRAMEBUF + * $TEXTBUF + * /ACPI:0 + * $BATTERY + * /ACPI:1 + * $SERIAL + * /COM:0 + * $SERIAL + * /COM:1 + * $SERIAL + * + * Device capabilities provide a way for devices to expose functionality without writing device specific code, a capability is defined by the following structure + * struct SysbusDeviceCapability { + * // Name of the device capability + * const char* CapabilityName; + * }; + * + * Devices types are defined by the following structure: + * struct SysbusDeviceDescription { + * // Name of the device type + * const char* DeviceName; + * + * // == Instance Management == + * // List of device instances + * struct SysbusDevice** Instances; + * + * // Device initialization code, returns 0 if ok + * int (*CreateDevice)(struct SysbusDevice* Device, void* Data); + * + * // Cleanup code for before a device is deleted, returns 0 if ok + * int (*DeleteDevice)(struct SysbusDevice* Device); + * + * // == Capablities == + * // Returns a capability specific structure if a capability is present, otherwise returns NULL + * void* (*GetCapability)(struct SysbusDevice* Device, struct SysbusDeviceCapability* Capability); + * }; + * + * Devices are stored in the following structure: + * struct SysbusDevice { + * // Pointer to the device type structure + * const struct SysbusDeviceDescription* DeviceDescription; + * + * // Name of the device + * const char* DeviceName; + * + * // Device specific data + * void* DeviceData; + * + * // Child devices + * struct SysbusDevice** Children; + * }; + * + * Drivers can define a new device type by calling `struct SysbusDeviceDescription* SysbusCreateDeviceDescription()` which + * Allocates and returns a device description structure + * + * Drivers must free device types with `void SysbusDeleteDeviceDescription(struct SysbusDeviceDescription* DESCRIPTION)` which + * Deletes a DESCRIPTION's instances + * Deallocates a device DESCRIPTION structure + * + * Drivers can create a new device by calling `struct SysbusDevice* SysbusCreateDevice(struct SysbusDeviceDescription* DESCRIPTION, void* DATA)` which + * DEVICE = Allocate a device structure + * Initializes it by calling DESCRIPTION::CreateDevice(DEVICE, DATA) + * if ok then + * Adds the DEVICE to the DESCRIPTION's instance list + * Returns the DEVICE + * otherwise returns NULL + * + * Drivers must free devices with `void SysbusDeleteDevice(struct SysbusDevice* DEVICE)` which + * Uninitializes the DEVICE by calling DEVICE::DeviceDescription::DeleteDevice(DEVICE) + * Removes the DEVICE from the DEVICE::DeviceDescription's instance list + * Deallocates the DEVICE + */ diff --git a/lcrash/efi/memmap.c b/lcrash/efi/memmap.c index 91f020a..1c70852 100644 --- a/lcrash/efi/memmap.c +++ b/lcrash/efi/memmap.c @@ -35,3 +35,7 @@ void* EfiTranslatePointer(void* FirmwarePointer) { // Well, we tried return 0; } + +struct EfiMemoryDescription *EfiGetStoredMemoryMap() { return StoredMemoryMap; } +u32 EfiGetStoredMemoryMapEntryCount() { return StoredMemoryMapEntryCount; } +u32 EfiGetStoredMemoryMapEntrySize() { return StoredMemoryMapEntrySize; } diff --git a/lcrash/efi/memmap.h b/lcrash/efi/memmap.h index 4540de0..d1e07f8 100644 --- a/lcrash/efi/memmap.h +++ b/lcrash/efi/memmap.h @@ -2,6 +2,8 @@ #include "types.h" +#define EFI_MEMORY_TYPE_CONVENTIONAL_MEMORY 7 + /// EFI Memory Descriptor struct EfiMemoryDescription { EfiUint32 Type; @@ -22,3 +24,18 @@ void EfiLoadStoredMemoryMap( /// Translate a pointer to something we can use using the stored memory map. void* EfiTranslatePointer(void* FirmwarePointer); + +struct EfiMemoryDescription* EfiGetStoredMemoryMap(); +u32 EfiGetStoredMemoryMapEntryCount(); +u32 EfiGetStoredMemoryMapEntrySize(); + +/** + * Iterate through the EFI memory map + * + * \param _Index VAR(int) loop index + * \param _Output VAR(struct EfiMemoryDescription*) variable to store the current entry + */ +#define EFI_MEMORY_MAP_FOREACH_(_Index, _Output) \ + for (_Index = 0, _Output = EfiGetStoredMemoryMap(); \ + _Index < EfiGetStoredMemoryMapEntryCount(); \ + _Index++, _Output = (struct EfiMemoryDescription*)(((void*)_Output) + EfiGetStoredMemoryMapEntrySize())) diff --git a/lcrash/elf/elf.h b/lcrash/elf/elf.h new file mode 100644 index 0000000..0c9dd59 --- /dev/null +++ b/lcrash/elf/elf.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_TLS 7 + +struct [[gnu::packed]] Elf64_Ehdr { + c8 e_ident[16]; + u16 e_type; + u16 e_machine; + u32 e_version; + u64 e_entry; + u64 e_phoff; + u64 e_shoff; + u32 e_flags; + u16 e_ehsize; + u16 e_phentsize; + u16 e_phnum; + u16 e_shentsize; + u16 e_shentnum; + u16 e_shstrndx; +}; + +struct [[gnu::packed]] Elf64_Phdr { + u32 p_type; + u32 p_flags; + u64 p_offset; + u64 p_vaddr; + u64 p_paddr; + u64 p_filesz; + u64 p_memsz; + u64 p_align; +}; + + diff --git a/lcrash/empty.S b/lcrash/empty.S deleted file mode 100644 index e69de29..0000000 diff --git a/lcrash/gdb/gdb.h b/lcrash/gdb/gdb.h index e78c243..43131a6 100644 --- a/lcrash/gdb/gdb.h +++ b/lcrash/gdb/gdb.h @@ -31,4 +31,7 @@ struct GdbDataBlock { /// Base address of the kernel void* KernelBase; + + /// Pointer to Extended Debug Information Block + void* EDIB; }; diff --git a/lcrash/lcrash.c b/lcrash/lcrash.c deleted file mode 100644 index 0be9bd8..0000000 --- a/lcrash/lcrash.c +++ /dev/null @@ -1,167 +0,0 @@ -#include "lnxboot.h" -#include "util.h" -#include "efi/types.h" -#include "efi/memmap.h" -#include "efi/guid.h" - -unsigned short serial_port; - -void outb(unsigned short port, unsigned char value) { - asm volatile ( - "outb %b0, %1" - ::"a" (value) - ,"d" (port) - ); -} - -void serial_putc(char c) { - outb(serial_port, c); -} - -void serial_puts(const char* s) { - while (*s) serial_putc(*(s++)); -} - -void serial_put_formatted_u64(u64 v) { - if (v == 0) { - serial_putc('0'); - } else { - u64 max = 1; - - while (v > max) max *= 10; - - while (v) { - serial_putc('0' + (u8)(v / max)); - - v %= max; - max /= 10; - } - } -} - -/** - * We can't do anything, just hang. - */ -[[noreturn, gnu::naked]] -void Hang() { - // This should make us hang - asm volatile ( - " cli\n" - "1: hlt\n" - " jmp 1b" - ); -} - -/** - * Congratulations, you panicked twice! - */ -[[noreturn]] -void Panic(const char* message) { - // We don't even do anything with the message, but it's nice to have just in case. - Hang(); -} - -void entry64(struct boot_params* boot_params) { - while (1) {}; - - Panic("HELLO WORLD."); - - /* - // get command line from kernel. we likely won't use it, but its nice to have. - u8* cmdline_ptr = (u8*)((u64)setup_info->cmd_line_ptr | ((u64)boot_params->ext_cmd_line_ptr << 32)); - - // do we have efi? - struct EfiSystemTable* systab_ptr = 0; - if (boot_params) { - systab_ptr = (struct EfiSystemTable*)( - (u64)boot_params->efi_info.EfiSystemTable | - ((u64)boot_params->efi_info.EfiSystemTableHigh << 32) - ); - - EfiLoadStoredMemoryMap( - (struct EfiMemoryDescription*)( - (u64)boot_params->efi_info.EfiMemoryMap | - ((u64)boot_params->efi_info.EfiMemoryMapHigh << 32) - ), // this might be 0, we should probably check ---------------V - boot_params->efi_info.EfiMemoryMapSize / boot_params->efi_info.EfiMemoryDescriptionSize, - boot_params->efi_info.EfiMemoryDescriptionSize - ); - } - - // -- find acpi -- - struct AcpiRSDP* AcpiRSDP = 0; - - // check bootparams - if (boot_params->acpi_rsdp_addr) AcpiRSDP = boot_params->acpi_rsdp_addr; - - while (true) { - volatile void* a = &EFI_ACPI_20_TABLE_GUID; - } - - // check efi - if (!AcpiRSDP && systab_ptr && systab_ptr->NumberOfTableEntries) { - struct EfiConfigurationTable* ConfigurationTable = EfiTranslatePointer(systab_ptr->ConfigurationTable); - for (int i = 0; i < systab_ptr->NumberOfTableEntries; i++) { - if (CompareMemory(&ConfigurationTable[i].VendorGuid, &EFI_ACPI_20_TABLE_GUID, sizeof(EfiGuid))) { - AcpiRSDP = ConfigurationTable[i].VendorTable; - while (true) { - volatile void* a = AcpiRSDP; - } - break; - } - } - } - - // we're playing where's waldo with this stupid fucking tableS - if (!AcpiRSDP) { - for (struct AcpiRSDP* addr = 0x00000000; addr < 0x000FFFFF; addr = (void*)addr + 16) { - if (addr->Signature[0] == 'R' && addr->Signature[1] == 'S' - && addr->Signature[2] == 'D' && addr->Signature[3] == ' ' - && addr->Signature[4] == 'P' && addr->Signature[5] == 'T' - && addr->Signature[6] == 'R' && addr->Signature[7] == ' ') { - AcpiRSDP = addr; - break; - } - } - } - - if (!AcpiRSDP) Panic("Failed to find ACPI RSDP"); - - // do we have acpi? - while (1) { - volatile void* p = AcpiRSDP; - } - - // we dont have the privilege of getting a rodata segment. any reads off our stack cause a triple fault - // for some fucking reason. allocate our strings and shit on the stack. - //char s_you_fucked_up[] = "!!! YOU FUCKED UP !!!\n"; - //char s_vga_you_fucked_up[] = "YOU FUCKED UP.\n"; - //char s_description[] = "A SERIOUS ERROR HAS OCCURED AND LINDOWS HAS STOPPED TO PREVENT FURTHER DAMAGE."; - //char s_registers[] = "REGISTERS:"; - //char s_call_trace[] = "CALL TRACE:"; - //char s_dumpcore[] = "[(D)UMP CORE]"; - //char s_poweroff[] = "[(P)OWER OFF]"; - //char s_reboot[] = "[(R)EBOOT ]"; - - // You fucked up. - //serial_puts(s_you_fucked_up); - //serial_puts(s_description); - //serial_putc('\n'); - - // register dump - //serial_puts(s_registers); - //serial_putc('\n'); - //serial_putc('\n'); - - // call trace - //serial_puts(s_call_trace); - //serial_putc('\n'); - //serial_putc('\n'); - - // thing - // serial_puts("test\n"); - // serial_puts(bzhead.cmd_line_ptr); - - // Die.*/ - Panic("Nothing left to do."); -} diff --git a/lcrash/main.c b/lcrash/main.c index 4f9ab0a..2421d75 100644 --- a/lcrash/main.c +++ b/lcrash/main.c @@ -2,6 +2,11 @@ /// super awesome... #include +#include +#include +#include +#include +#include #include "types.h" #include "lnxboot.h" @@ -19,12 +24,28 @@ void entry64(struct boot_params* BootParams) { GdbDataBlock->KernelBase = (void*)BootSetupInfo->code32_start; GdbDataBlock->Update++; + // Parse the kernel command line + CmdlineParse((c8*)( ((uptr)BootSetupInfo->cmd_line_ptr) + |((uptr)BootBootParams->ext_cmd_line_ptr << 32))); + + // Initialize the physical memory manager + if (PmemInitialize()) while (1) {} + + // Initialize the kernel heap + if (KernelHeapInitialize()) while (1) {} + + // Initialize the extended debugging information block + if (DebugInitialize()) while (1) {} + // Initialize EFI code if we had EFI EfiInitialize(); // Initialize ACPI code if we have ACPI AcpiInitialize(); - + + // Initialize PCI code.. + PciInitialize(); + // Hang :) while (1) {} } diff --git a/lcrash/math.c b/lcrash/math.c new file mode 100644 index 0000000..0887a42 --- /dev/null +++ b/lcrash/math.c @@ -0,0 +1,11 @@ +#include + +s64 RaiseInteger(s64 Base, u64 Exponent) { + s64 Ret = 1; + + if (Exponent >= 0) { + for (int i = 0; i < Exponent; i++) Ret *= Base; + } + + return Ret; +} diff --git a/lcrash/math.h b/lcrash/math.h new file mode 100644 index 0000000..b45ce83 --- /dev/null +++ b/lcrash/math.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +/// Raise Base to the Exponent power +s64 RaiseInteger(s64 Base, u64 Exponent); diff --git a/lcrash/mm/kmalloc.c b/lcrash/mm/kmalloc.c new file mode 100644 index 0000000..43cd5b8 --- /dev/null +++ b/lcrash/mm/kmalloc.c @@ -0,0 +1,187 @@ +#include + +#include + +/** + * A block in the kernel heap. the performance is abysmal, this structure may be larger + * than a lot of kernel objects so we'll have about half the memory we could have ^-^ + */ +struct KernelHeapBlock { + /// Next block + struct KernelHeapBlock* Next; + + /// Previous block + struct KernelHeapBlock* Prev; + + /// Next free block + struct KernelHeapBlock* NextFree; + + /// Previous free block + struct KernelHeapBlock* PrevFree; + + /// Block size + u64 Size; + + /// Block is free + bool Free; +}; + +/** + * A structure that describes a specific kernel heap, yes, we can have more than one and, + * yes, most will do the same thing + */ +struct KernelHeapZone { + /// Next heap zone + struct KernelHeapZone* Next; + + /// Previous heap zone + struct KernelHeapZone* Prev; + + /// First heap frame + struct KernelHeapFrame* FirstFrame; + + /// Last heap frame + struct KernelHeapFrame* LastFrame; + + /// First block + struct KernelHeapBlock* First; + + /// Last block + struct KernelHeapBlock* Last; + + /// First free block + struct KernelHeapBlock* FirstFree; + + /// Last free block + struct KernelHeapBlock* LastFree; +}; + +/** + * A block of physical memory owned by a specific heap, where is it stored exactly? In + * the heap of course! + */ +struct KernelHeapFrame { + /// The block + struct PmemAllocation Block; + + /// The block's size + u64 Size; + + /// Linked list jumpscare + struct KernelHeapFrame* NextFrame; + + /// I wonder if this is a pointer that points to the previous frame in a linked + /// list of the structure which stores kernel heap frames + struct KernelHeapFrame* PrevFrame; +}; + +struct KernelHeapZone* KernelHeapFirst = 0; +struct KernelHeapZone* KernelHeapLast = 0; + +/** + * \todo Maybe split the zone allocation code out of the thing + */ +int KernelHeapInitialize() { + // Allocate uh this amount of memory for the heap + struct PmemAllocation Block; + if (PmemAllocateBlock(0x100000, &Block)) return -1; + + // Make our zone + struct KernelHeapZone* Zone = Block.Address; + Zone->Next = 0; + Zone->Prev = 0; + KernelHeapFirst = Zone; + KernelHeapLast = Zone; + + // Make the frame block + struct KernelHeapBlock* FrameBlock = Block.Address + sizeof(struct KernelHeapZone); + FrameBlock->Prev = 0; + FrameBlock->PrevFree = 0; + FrameBlock->Size = sizeof(struct KernelHeapFrame); + FrameBlock->Free = false; + + // Make the frame structure + struct KernelHeapFrame* Frame = Block.Address + + sizeof(struct KernelHeapZone) + + sizeof(struct KernelHeapBlock); + Frame->Block = Block; + Frame->Size = 0x100000; + Frame->NextFrame = 0; + Frame->PrevFrame = 0; + + // 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 = 0; + RootBlock->NextFree = 0; + RootBlock->Free = true; + RootBlock->Size = 0x100000 + - sizeof(struct KernelHeapZone) + - sizeof(struct KernelHeapBlock) + - sizeof(struct KernelHeapFrame) + - sizeof(struct KernelHeapBlock); + + // Fill out the rest of the zone + Zone->FirstFrame = Frame; + Zone->LastFrame = Frame; + Zone->FirstFree = RootBlock; + Zone->LastFree = RootBlock; + Zone->First = FrameBlock; + Zone->Last = RootBlock; + + // Tada! + return 0; +} + +void* KernelHeapAlloc(u32 Size, u32 Flags) { + // 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) { + s64 SplitSize = (s64)Block->Size - Size - (sizeof(struct KernelHeapBlock) * 2) - 8; + + if (SplitSize > 0) { + struct KernelHeapBlock* NewBlock = (struct KernelHeapBlock*)((void*)Block + sizeof(struct KernelHeapBlock) + Size); + NewBlock->Prev = Block; + NewBlock->Next = 0; + NewBlock->PrevFree = Block->PrevFree; + NewBlock->NextFree = Block->NextFree; + NewBlock->Free = true; + NewBlock->Size = (u64)SplitSize; + + // Set zone stuff + if (Block->NextFree == 0) Zone->LastFree = NewBlock; + if (Block->PrevFree == 0) Zone->FirstFree = NewBlock; + if (Block->Next == 0) Zone->Last = NewBlock; + + // Set next free in other blocks + for (struct KernelHeapBlock* ModBlock = Block->Prev; ModBlock != 0 && (Block->NextFree != 0 || Block->NextFree != Block); ModBlock = ModBlock->Prev) { + ModBlock->NextFree = NewBlock; + } + + // Set prev free in other blocks + for (struct KernelHeapBlock* ModBlock = Block->Next; ModBlock != 0 && (Block->PrevFree != 0 || Block->PrevFree != Block); ModBlock = ModBlock->Next) { + ModBlock->PrevFree = NewBlock; + } + + // Block stuff + Block->Next = NewBlock; + } + + Block->Free = 0; + Block->Size = Size; + + return (void*)Block + sizeof(struct KernelHeapBlock); + } + } + } + + return 0; +} + +void KernelHeapFree(void* Address) { + +} diff --git a/lcrash/mm/kmalloc.h b/lcrash/mm/kmalloc.h new file mode 100644 index 0000000..ae5b3bb --- /dev/null +++ b/lcrash/mm/kmalloc.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +/** + * Initialize kernel heap, returns 0 on success + */ +int KernelHeapInitialize(); + +/** + * Allocate memory + */ +void* KernelHeapAlloc(u32 Size, u32 Flags); + +/** + * Free memory + */ +void KernelHeapFree(void* Address); diff --git a/lcrash/mm/phys.c b/lcrash/mm/phys.c new file mode 100644 index 0000000..80e9eab --- /dev/null +++ b/lcrash/mm/phys.c @@ -0,0 +1,500 @@ +/** + * This is extremely bad, a large amount of this code is dangerous and error prone, and if something goes wrong, it has no way to indicate that and roll back the error. + * This needs to be fixed + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#define BUDDY_BLK_(_ORDER, _ADDR) ((_ADDR) >> (_ORDER)) + +/** + * Root table for the memory allocation data, once we know where we want it, it won't need extra memory space. + */ +struct BuddyTable { + /// Minimum size of a block log 2 + u32 StartWidth; + + /// Maximum size of a block log 2 + u32 EndWidth; + + /// Order tables + struct BuddyOrder* Order[64]; +}; + +/** + * The order of a buddy block + */ +struct BuddyOrder { + /// Number of blocks + u64 Count; + + /// Length of Free + u64 Length; + + /// Free blocks + u8 Free[]; +}; + +/** + * Pointer to the buddy root table + */ +struct BuddyTable* PmemBuddyTable = 0; + +/** + * Merge a block + * + * \todo Optimize + */ +void PmemBuddyBlkMerge(u32 MergeTo, u32 Ordr, u64 Address) { + // Nothing to merge + if (Ordr <= PmemBuddyTable->StartWidth) return; + + // Select blocks + struct BuddyOrder* Order = PmemBuddyTable->Order[Ordr - 1]; + u64 LBlock = BUDDY_BLK_(Ordr - 1, Address & ~(1ULL << (Ordr - 1))); + u64 RBlock = BUDDY_BLK_(Ordr - 1, Address | (1ULL << (Ordr - 1))); + + // Mark as used + Order->Free[LBlock >> 3] &= ~(1ULL << (LBlock & 7)); + Order->Free[RBlock >> 3] &= ~(1ULL << (RBlock & 7)); + + // Merge lower blocks + PmemBuddyBlkMerge(MergeTo, Ordr - 1, Address & ~(1ULL << (Ordr - 1))); + PmemBuddyBlkMerge(MergeTo, Ordr - 1, Address | (1ULL << (Ordr - 1))); +} + +/** + * Split a block + */ +void PmemBuddyBlkSplit(u32 Ordr, u64 Address) { + struct BuddyOrder* UOrder = PmemBuddyTable->Order[Ordr]; + struct BuddyOrder* LOrder = PmemBuddyTable->Order[Ordr - 1]; + u64 Block = BUDDY_BLK_(Ordr, Address); + u64 LBlock = BUDDY_BLK_(Ordr - 1, Address & ~(1ULL << (Ordr - 1))); + u64 RBlock = BUDDY_BLK_(Ordr - 1, Address | (1ULL << (Ordr - 1))); + + // Split + UOrder->Free[Block >> 3] &= ~(1ULL << (Block & 7)); + LOrder->Free[LBlock >> 3] |= 1ULL << (LBlock & 7); + LOrder->Free[RBlock >> 3] |= 1ULL << (RBlock & 7); +} + +/** + * Mark a block as allocated + * + * \todo Optimize + */ +void PmemBuddyBlkMarkAlloc(u32 Ordr, u64 Address) { + struct BuddyOrder* Order = PmemBuddyTable->Order[Ordr]; + + u64 Block = BUDDY_BLK_(Ordr, Address); + + // Mark in use + Order->Free[Block >> 3] &= ~(1ULL << (Block & 7)); + + // Merge lower orders + PmemBuddyBlkMerge(Ordr, Ordr, Address); +} + +/** + * Mark a block as free + * + * \todo Optimize + */ +void PmemBuddyBlkMarkFree(u32 Ordr, u64 Address) { + struct BuddyOrder* Order = PmemBuddyTable->Order[Ordr]; + + u64 Block = BUDDY_BLK_(Ordr, Address); + + // Mark free + Order->Free[Block >> 3] |= 1ULL << (Block & 7); + + // Merge + PmemBuddyBlkMerge(Ordr, Ordr, Address); +} + +/** + * Recursively split blocks until one is free + * + * \todo Optimize + */ +void PmemBuddyBlkSplitUp(u32 Ordr, u64 Address) { + struct BuddyOrder* Order = PmemBuddyTable->Order[Ordr]; + u64 Block = BUDDY_BLK_(Ordr, Address); + + // Check if this block is split + if (!(Order->Free[Block >> 3] & (1ULL << (Block & 7)))) { + if (Ordr < PmemBuddyTable->EndWidth) { + PmemBuddyBlkSplitUp(Ordr + 1, Address & (((u64)-1) << Ordr)); + } + } + + // Hopefully we are now + PmemBuddyBlkSplit(Ordr, Address); +} + +/** + * Allocates a block and splits parent blocks if necessary + * + * \todo Optimize + */ +void PmemBuddyBlkAlloc(u32 Ordr, u64 Address) { + //struct BuddyOrder* Order = PmemBuddyTable->Order[Ordr]; + //u64 Block = BUDDY_BLK_(Ordr, Address); + + // Split the block above us + if (Ordr < PmemBuddyTable->EndWidth) { + PmemBuddyBlkSplitUp(Ordr + 1, Address & (((u64)-1) << Ordr)); + } + + PmemBuddyBlkMarkAlloc(Ordr, Address); +} + +/** + * Mark a range as allocated + * + * \todo Optimize + */ +void PmemBuddyMarkAllocRange(void* From, void* To) { + u64 OwningOrder = 0; + for (OwningOrder = PmemBuddyTable->StartWidth; OwningOrder < PmemBuddyTable->EndWidth; OwningOrder++) { + if ((1ULL << OwningOrder) >= (uptr)(To - From)) break; + } + + // Select a "pivot" block to merge relative to + void* CentralBlockStartAddress = (void*)((uptr)From & (-1ULL << OwningOrder)); + void* CentralBlockMidAddress = (void*)((uptr)From | (1ULL << (OwningOrder - 1))); + void* CentralBlockEndAddress = (void*)((uptr)CentralBlockStartAddress + (1ULL << OwningOrder)) - 1; + void* BigAreaBlockEndAddress = (void*)((uptr)To & (-1ULL << OwningOrder)); + + // It's merging time + if (From <= CentralBlockStartAddress && To >= CentralBlockEndAddress) { + PmemBuddyBlkAlloc(OwningOrder, (u64)CentralBlockStartAddress); + + // The rest of the + for (void* Block = CentralBlockEndAddress + 1; Block < BigAreaBlockEndAddress; Block += 1ULL << OwningOrder) { + PmemBuddyBlkAlloc(OwningOrder, (u64)Block); + } + + // Other blocks we need to split + if (BigAreaBlockEndAddress > CentralBlockEndAddress && To > BigAreaBlockEndAddress) { + PmemBuddyMarkAllocRange(BigAreaBlockEndAddress, To); + } + } else { + // Looks like a split + if (From < CentralBlockMidAddress && To >= CentralBlockMidAddress) { + PmemBuddyMarkAllocRange(From, CentralBlockMidAddress - 1); + PmemBuddyMarkAllocRange(CentralBlockMidAddress, To); + } else if (From >= CentralBlockMidAddress) { + PmemBuddyMarkAllocRange(From, CentralBlockEndAddress); + PmemBuddyMarkAllocRange(CentralBlockEndAddress + 1, To); + } + } +} + +int PmemInitialize() { + // Allocate a sizable chunk of stack memory for scanning, we lack + // a heap so we need to be creative with how we store this. + void* BeginAddresses[0x80]; + void* EndAddresses[0x80]; + u32 NextAddress = 0; + + /* + // Find our memory address + if (EfiPresent()) { + // Scan the EFI memory map for usable memory + struct EfiMemoryDescription *Entry; + int Index; + EFI_MEMORY_MAP_FOREACH_(Index, Entry) { + if (Entry->Type == EFI_MEMORY_TYPE_CONVENTIONAL_MEMORY) { + BeginAddresses[NextAddress] = Entry->PhysicalStart; + EndAddresses[NextAddress] = Entry->NumberOfPages * 0x1000 + Entry->PhysicalStart; + NextAddress += 1; + } + } + } else while (true) {} // die + */ + + // Scan BIOS e820 table provided by inferior + for (int i = 0; i < BootBootParams->e820_entries; i++) { + if (BootBootParams->e820_table[i].type == 1) { + BeginAddresses[NextAddress] = (void*)BootBootParams->e820_table[i].base; + EndAddresses[NextAddress] = (void*)BootBootParams->e820_table[i].base + BootBootParams->e820_table[i].length; + + NextAddress += 1; + } + } + + // Mark kernel memory as reserved + const c8* CoreHeaderParam; + if ((CoreHeaderParam = CmdlineGet("elfcorehdr"))) { + /// TODO: Should this be its own function? + if (CoreHeaderParam[0] == '0' && CoreHeaderParam[1] == 'x') { + uptr CoreHeaderAddr = 0; + + for (int i = 2; CoreHeaderParam[i] != 0; i++) { + c8 c = CoreHeaderParam[i]; + + CoreHeaderAddr *= 16; + + if (c >= '0' && c <= '9') { + CoreHeaderAddr += c - '0'; + } else if (c >= 'a' && c <= 'f') { + CoreHeaderAddr += c - 'a'; + } else if (c >= 'A' && c <= 'F') { + CoreHeaderAddr += c - 'A'; + } else break; + } + + // TODO: 32-bit machines? + struct Elf64_Ehdr* CoreHeader = (struct Elf64_Ehdr*)CoreHeaderAddr; + + // We don't check for the ELF signature or version, + // if the kernel doesn't give us anything valid, + // we're fucked anyways + if (CoreHeader->e_type != ET_CORE) goto sort; + + // Scan core dump for kernel memory + void* CoreSegmentLocation = (void*)CoreHeader + CoreHeader->e_phoff; + for (int i = 0; i < CoreHeader->e_phnum; i++) { + struct Elf64_Phdr* Segment = (struct Elf64_Phdr*)CoreSegmentLocation; + + // Only take LOAD areas + if (Segment->p_type == PT_LOAD) { + void* BeginAddr = (void*)Segment->p_paddr; + void* EndAddr = (void*)Segment->p_paddr + Segment->p_memsz; + + long EndSplitScan = NextAddress; + for (int j = 0; j < EndSplitScan; j++) { + if (BeginAddr > BeginAddresses[j] && BeginAddr < EndAddresses[j]) { // Begins in the middle of a block + if (EndAddr < EndAddresses[j]) { + // Create new address block + BeginAddresses[NextAddress] = EndAddr; + EndAddresses[NextAddress] = EndAddresses[j]; + + // Decrease size of old address block + EndAddresses[j] = BeginAddr - 1; + + // Grow + NextAddress += 1; + } else { + // Shrink block + EndAddresses[j] = BeginAddr - 1; + } + } else if (BeginAddr == BeginAddresses[j]) { // Begins at the start of a block + if (EndAddr < EndAddresses[j]) { + // Shrink + EndAddresses[j] = BeginAddr - 1; + } else goto delblk; + } else if (BeginAddr < BeginAddresses[j] && EndAddr >= EndAddresses[j]) { + delblk: + for (int k = 0; k < NextAddress - 1; k++) { + BeginAddresses[k] = BeginAddresses[k + 1]; + EndAddresses[k] = EndAddresses[k + 1]; + } + + NextAddress -= 1; + EndSplitScan -= 1; + } + } + } + + CoreSegmentLocation += CoreHeader->e_phentsize; + } + } + } + + // TODO: Please replace this. + // Sort address ranges with lazily tossed together slow piece of crap +sort: while (true) { + bool KeepGoing = false; + + for (int i = 0; i < NextAddress - 1; i++) { + if (BeginAddresses[i] > BeginAddresses[i + 1]) { + void* Temp = BeginAddresses[i]; + BeginAddresses[i] = BeginAddresses[i + 1]; + BeginAddresses[i + 1] = Temp; + Temp = EndAddresses[i]; + EndAddresses[i] = EndAddresses[i + 1]; + EndAddresses[i + 1] = Temp; + KeepGoing = true; + } + } + + if (!KeepGoing) break; + }; + + // Set up our physical memory table + u64 MemorySize = (u64)EndAddresses[NextAddress - 1]; + u32 BuddyStartWidth = 12; + u32 BuddyEndWidth = 20; + u64 BuddyRange = MemorySize + MemorySize % (1ULL << BuddyEndWidth); + u32 BuddyTableSize = 0; + + // Calculate table size + BuddyTableSize += sizeof(struct BuddyTable); + BuddyTableSize += BuddyTableSize % 8; + for (u32 Width = BuddyStartWidth; Width <= BuddyEndWidth; Width++) { + u64 BlockSize = 1ULL << Width; + u64 BlockCount = BuddyRange / BlockSize; + BlockCount += BlockCount % 8; + BlockCount /= 8; + BlockCount += BlockCount % 8; + BlockCount += sizeof(struct BuddyOrder); + BlockCount += BlockCount % 8; + BuddyTableSize += BlockCount; + } + + // Find a safe area for the allocation tables + for (int i = 0; i < NextAddress; i++) { + if (EndAddresses[i] - BeginAddresses[i] >= BuddyTableSize) { + PmemBuddyTable = (struct BuddyTable*)BeginAddresses[i]; + break; + } + } + + // Uh oh. TODO: We should probably panic here when we figure out how to do that. + if (PmemBuddyTable == 0) while (true) {} + + // Fill out the table + PmemBuddyTable->StartWidth = BuddyStartWidth; + PmemBuddyTable->EndWidth = BuddyEndWidth; + for (int i = 0; i < 64; i++) PmemBuddyTable->Order[i] = 0; + + // Build our order tables + void* NextOrderLocation = (void*)PmemBuddyTable + sizeof(struct BuddyTable); + NextOrderLocation += (uptr)NextOrderLocation % 8; + for (int i = BuddyStartWidth; i <= BuddyEndWidth; i++) { + struct BuddyOrder* Order = (struct BuddyOrder*)NextOrderLocation; + + // I sure hope this gets optimized into a rep + Order->Count = BuddyRange / (1ULL << i); + Order->Length = Order->Count / 8; + Order->Length = Order->Length ? Order->Length : 1; + if (i == BuddyEndWidth) { + for (int j = 0; j < Order->Length; j++) Order->Free[j] = 255; + } else { + for (int j = 0; j < Order->Length; j++) Order->Free[j] = 0; + } + + // Save it + PmemBuddyTable->Order[i] = Order; + + // Calculate next order address + NextOrderLocation += sizeof(struct BuddyOrder); + NextOrderLocation += Order->Length; + NextOrderLocation += (uptr)NextOrderLocation % 8; + } + + // Mark anything we can't touch as used + for (int i = 0; i < NextAddress; i++) { + if (i == 0) { + PmemBuddyMarkAllocRange(0, BeginAddresses[i] - 1); + } + + if (i + 1 == NextAddress) { + PmemBuddyMarkAllocRange(EndAddresses[i], (void*)((1ULL << BuddyEndWidth) * PmemBuddyTable->Order[BuddyEndWidth]->Count) - 1); + } else { + PmemBuddyMarkAllocRange(EndAddresses[i], BeginAddresses[i + 1] - 1); + } + } + + return 0; +} + +/** + * Find a free block of the specified order + * + * \return Returns 0 on success + */ +int PmemBuddyFindBlock(u32 Ordr, u64* Result) { + struct BuddyOrder* Order = PmemBuddyTable->Order[Ordr]; + + // Find our block + for (uptr i = 0; i < Order->Length; i++) { + if (Order->Free[i]) { + for (int sub = 0; sub < 8; sub++) { + if (Order->Free[i] & (1 << sub)) { + // We got it + *Result = (i << 3) | sub; + return 0; + } + } + } + } + + *Result = 0; + return -1; +} + +[[gnu::nonnull(2)]] +int PmemAllocateBlock(uptr RequiredSize, struct PmemAllocation* Allocated) { + // Don't function if the PMM subsystem isn't ready + if (PmemBuddyTable == 0) return -1; + + // We can't make massive allocations + if (RequiredSize > (1 << PmemBuddyTable->EndWidth)) return -1; + + // Calculate how big we need our stuff to be + u32 Order = PmemBuddyTable->StartWidth; + for (; RequiredSize >= (1 << Order) && Order < PmemBuddyTable->EndWidth; Order++); + + // Find a block + u64 Block = 0; + if (PmemBuddyFindBlock(Order, &Block)) { + // We need to split a block to get ours + bool Found = false; + u32 OrderAttempt = Order + 1; + + // Find (a) block(s) to split + u64 ToSplit = 0; + for (; OrderAttempt <= PmemBuddyTable->EndWidth; OrderAttempt++) { + if (!PmemBuddyFindBlock(OrderAttempt, &ToSplit)) { + Found = true; + break; + } + } + + // Out of memory + if (!Found) return -1; + + // Split + for (; OrderAttempt > Order; OrderAttempt--) { + PmemBuddyBlkSplit(OrderAttempt, ToSplit << OrderAttempt); + ToSplit <<= 1; + } + + // Here's our block + Block = ToSplit; + } + + // TODO: This isn't optimal, space is wasted, fix this as soon as possible + PmemBuddyBlkMarkAlloc(Order, Block << Order); + + // Return our crap + Allocated->Address = (void*)(Block << Order); + Allocated->AllocationOrder = Order; + Allocated->AllocationBlock = Block; + + return 0; +} + +[[gnu::nonnull(1)]] +int PmemFreeBlock(struct PmemAllocation* Block) { + // Don't function if the PMM subsystem isn't ready + if (PmemBuddyTable == 0) return -1; + + // Deallocate the block + PmemBuddyBlkMarkFree(Block->AllocationOrder, Block->AllocationBlock << Block->AllocationOrder); + + return 0; +} diff --git a/lcrash/mm/phys.h b/lcrash/mm/phys.h new file mode 100644 index 0000000..56c88e1 --- /dev/null +++ b/lcrash/mm/phys.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +struct PmemAllocation { + /// Allocated address + void* Address; + + /// \internal + u32 AllocationOrder; + + /// \internal + u32 AllocationBlock; +}; + +/** + * Initialize the physical memory manager + * + * \return 0 on OK + */ +int PmemInitialize(); + +/** + * Allocate a block of physical pages + * + * \return 0 on OK + */ +[[gnu::nonnull(2)]] +int PmemAllocateBlock(uptr RequiredSize, struct PmemAllocation* Allocated); + +/** + * Free a block of physical pages + * + * \return 0 on OK + */ +[[gnu::nonnull(1)]] +int PmemFreeBlock(struct PmemAllocation* Block); diff --git a/lcrash/pci/pci.c b/lcrash/pci/pci.c new file mode 100644 index 0000000..1d4d610 --- /dev/null +++ b/lcrash/pci/pci.c @@ -0,0 +1,24 @@ +#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"); + + // Guess not + if (BridgeTable == NULL) goto nopcie; + + while (1) {} + } + +nopcie: while (1) {} + + return; +} + +bool PciPresent() { return PciIsPresent; } +bool PciePresent() { return PciSupportsECM; } diff --git a/lcrash/pci/pci.h b/lcrash/pci/pci.h new file mode 100644 index 0000000..493f09c --- /dev/null +++ b/lcrash/pci/pci.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +/** + * Initialize the PCI code. + */ +void PciInitialize(); + +/// PCI is usable +bool PciPresent(); + +/// PCIE is usable +bool PciePresent(); diff --git a/lcrash/setup/compressed/elf.h b/lcrash/setup/compressed/elf.h index 264180a..03696d4 100644 --- a/lcrash/setup/compressed/elf.h +++ b/lcrash/setup/compressed/elf.h @@ -1,44 +1,7 @@ #pragma once -#include "../../types.h" -#include "../../lnxboot.h" - -#define PT_NULL 0 -#define PT_LOAD 1 -#define PT_DYNAMIC 2 -#define PT_INTERP 3 -#define PT_NOTE 4 -#define PT_SHLIB 5 -#define PT_PHDR 6 -#define PT_TLS 7 - -struct [[gnu::packed]] Elf64_Ehdr { - c8 e_ident[16]; - u16 e_type; - u16 e_machine; - u32 e_version; - u64 e_entry; - u64 e_phoff; - u64 e_shoff; - u32 e_flags; - u16 e_ehsize; - u16 e_phentsize; - u16 e_phnum; - u16 e_shentsize; - u16 e_shentnum; - u16 e_shstrndx; -}; - -struct [[gnu::packed]] Elf64_Phdr { - u32 p_type; - u32 p_flags; - u64 p_offset; - u64 p_vaddr; - u64 p_paddr; - u64 p_filesz; - u64 p_memsz; - u64 p_align; -}; +#include +#include /// We don't have space to allocate memory, so we have no idea where we can pass back ELF state, we'll have to do this all at once void ElfExecute(void* Binary, void* LoadAddr, struct boot_params*); diff --git a/lcrash/setup/header.S b/lcrash/setup/header.S index 038e111..d554aba 100644 --- a/lcrash/setup/header.S +++ b/lcrash/setup/header.S @@ -24,7 +24,7 @@ realmode_switch: .word 0, 0 start_sys_seg: .word 0 .word 0 //kernel_version - 512 type_of_loader: .byte 0 -loadflags: .byte 0x81 +loadflags: .byte 0x01 setup_move_size: .word 0x8000 code32_start: .long 0 # .long 0x100000 ramdisk_image: .long 0 diff --git a/src/grub/grub.cfg b/src/grub/grub.cfg index 3e9e65a..52b3b7f 100644 --- a/src/grub/grub.cfg +++ b/src/grub/grub.cfg @@ -2,5 +2,5 @@ clear # boot -linux /Windows/vmlinux.exe console=tty0 console=ttyS0 root=PARTUUID=48d29da8-2ff8-4f23-ba1a-0e8ccfc329e2 rootflags=force rw init=/Windows/System32/lexecutive.exe loglevel=8 crashkernel=48M dyndbg nokaslr +linux /Windows/vmlinux.exe console=tty0 console=ttyS0 root=PARTUUID=48d29da8-2ff8-4f23-ba1a-0e8ccfc329e2 rootflags=force rw init=/Windows/System32/lexecutive.exe loglevel=8 crashkernel=48M nokaslr boot