[lcrash] ADD: Add memory management code
This commit is contained in:
parent
fc7520c16f
commit
5f750e66d6
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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
71
lcrash/cmdline.c
Normal 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
15
lcrash/cmdline.h
Normal 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
36
lcrash/debug/debug.c
Normal 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
13
lcrash/debug/debug.h
Normal 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
84
lcrash/driver/sysbus.h
Normal 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
|
||||
*/
|
@ -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; }
|
||||
|
@ -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
48
lcrash/elf/elf.h
Normal 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;
|
||||
};
|
||||
|
||||
|
@ -31,4 +31,7 @@ struct GdbDataBlock {
|
||||
|
||||
/// Base address of the kernel
|
||||
void* KernelBase;
|
||||
|
||||
/// Pointer to Extended Debug Information Block
|
||||
void* EDIB;
|
||||
};
|
||||
|
167
lcrash/lcrash.c
167
lcrash/lcrash.c
@ -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.");
|
||||
}
|
@ -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
11
lcrash/math.c
Normal 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
6
lcrash/math.h
Normal 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
187
lcrash/mm/kmalloc.c
Normal 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
18
lcrash/mm/kmalloc.h
Normal 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
500
lcrash/mm/phys.c
Normal 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
37
lcrash/mm/phys.h
Normal 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
24
lcrash/pci/pci.c
Normal 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
14
lcrash/pci/pci.h
Normal 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();
|
@ -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*);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user