[lcrash] ADD: Add memory management code

This commit is contained in:
xwashere 2024-04-19 08:30:56 -04:00
parent fc7520c16f
commit 5f750e66d6
Signed by: XWasHere
GPG Key ID: 042F8BFA1B0EF93B
26 changed files with 1164 additions and 225 deletions

View File

@ -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 (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)))
(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 (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")))))
(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))

View File

@ -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)

View File

@ -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
*/

71
lcrash/cmdline.c Normal file
View File

@ -0,0 +1,71 @@
/// Kernel command line code, extremely slow, extremely unsafe, extremely painful
#include <lcrash/cmdline.h>
#include <lcrash/types.h>
#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;
}

15
lcrash/cmdline.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include <lcrash/types.h>
/**
* 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);

36
lcrash/debug/debug.c Normal file
View File

@ -0,0 +1,36 @@
#include <lcrash/debug/debug.h>
#include <lcrash/gdb/gdb.h>
#include <lcrash/mm/kmalloc.h>
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");
}

13
lcrash/debug/debug.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <lcrash/types.h>
/**
* Initialize extended debugging
*
* \return 0 on success
*/
int DebugInitialize();
[[noreturn]]
void Panic(const c8* Error);

84
lcrash/driver/sysbus.h Normal file
View File

@ -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
*/

View File

@ -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; }

View File

@ -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()))

48
lcrash/elf/elf.h Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include <lcrash/types.h>
#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;
};

View File

View File

@ -31,4 +31,7 @@ struct GdbDataBlock {
/// Base address of the kernel
void* KernelBase;
/// Pointer to Extended Debug Information Block
void* EDIB;
};

View File

@ -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.");
}

View File

@ -2,6 +2,11 @@
/// super awesome...
#include <lcrash/gdb/gdb.h>
#include <lcrash/pci/pci.h>
#include <lcrash/mm/phys.h>
#include <lcrash/mm/kmalloc.h>
#include <lcrash/cmdline.h>
#include <lcrash/debug/debug.h>
#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) {}
}

11
lcrash/math.c Normal file
View File

@ -0,0 +1,11 @@
#include <lcrash/math.h>
s64 RaiseInteger(s64 Base, u64 Exponent) {
s64 Ret = 1;
if (Exponent >= 0) {
for (int i = 0; i < Exponent; i++) Ret *= Base;
}
return Ret;
}

6
lcrash/math.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <lcrash/types.h>
/// Raise Base to the Exponent power
s64 RaiseInteger(s64 Base, u64 Exponent);

187
lcrash/mm/kmalloc.c Normal file
View File

@ -0,0 +1,187 @@
#include <lcrash/mm/kmalloc.h>
#include <lcrash/mm/phys.h>
/**
* 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) {
}

18
lcrash/mm/kmalloc.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <lcrash/types.h>
/**
* Initialize kernel heap, returns 0 on success
*/
int KernelHeapInitialize();
/**
* Allocate memory
*/
void* KernelHeapAlloc(u32 Size, u32 Flags);
/**
* Free memory
*/
void KernelHeapFree(void* Address);

500
lcrash/mm/phys.c Normal file
View File

@ -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 <lcrash/mm/phys.h>
#include <lcrash/types.h>
#include <lcrash/elf/elf.h>
#include <lcrash/efi/efi.h>
#include <lcrash/efi/memmap.h>
#include <lcrash/lnxboot.h>
#include <lcrash/cmdline.h>
#include <lcrash/math.h>
#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 <BIG AREA>
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;
}

37
lcrash/mm/phys.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <lcrash/types.h>
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);

24
lcrash/pci/pci.c Normal file
View File

@ -0,0 +1,24 @@
#include <lcrash/pci/pci.h>
#include <lcrash/acpi/acpi.h>
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; }

14
lcrash/pci/pci.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include <lcrash/types.h>
/**
* Initialize the PCI code.
*/
void PciInitialize();
/// PCI is usable
bool PciPresent();
/// PCIE is usable
bool PciePresent();

View File

@ -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 <lcrash/elf/elf.h>
#include <lcrash/lnxboot.h>
/// 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*);

View File

@ -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

View File

@ -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