oh yeah we can decompress the kernel now

This commit is contained in:
xwashere 2024-03-28 09:49:31 -04:00
parent 91d3d1b663
commit 8c6bfe0edf
Signed by: XWasHere
GPG Key ID: 042F8BFA1B0EF93B
31 changed files with 940 additions and 80 deletions

View File

@ -24,6 +24,7 @@ set_property(TARGET LindowsLinkerScript PROPERTY IMPORTED_LOCATION "${CMAKE_CURR
# compiler stuff
set(LW_CROSS_CC "${CMAKE_CURRENT_BINARY_DIR}/gcc/prefix/bin/gcc")
set(LW_CROSS_CXX "${CMAKE_CURRENT_BINARY_DIR}/gcc/prefix/bin/g++")
set(LW_CROSS_ASM "${LW_CROSS_CC}")
set(LW_CROSS_LD "${LW_CROSS_CC}")
set(LW_CROSS_INCFLAGS -isystem${CMAKE_CURRENT_BINARY_DIR}/gcc/prefix/include/c++/13.2.0 -isystem${CMAKE_CURRENT_BINARY_DIR}/gcc/prefix/lib/gcc/x86_64-pc-linux-gnu/13.2.0/include -isystem${CMAKE_CURRENT_BINARY_DIR}/gcc/prefix/lib/gcc/x86_64-pc-linux-gnu/13.2.0/include-fixed -isystem${CMAKE_CURRENT_BINARY_DIR}/gcc/prefix/include/c++/13.2.0/x86_64-pc-linux-gnu -isystem${CMAKE_CURRENT_BINARY_DIR}/glibc/prefix/include -isystem${CMAKE_CURRENT_BINARY_DIR}/linux/headers/include)
set(LW_CROSS_CFLAGS -nostdinc ${LW_CROSS_INCFLAGS})
@ -61,6 +62,7 @@ function(lw_project PROJECTNAME)
elseif(${ARG_TARGET} STREQUAL "LINDOWS")
set(CMAKE_C_COMPILER "${LW_CROSS_CC}" PARENT_SCOPE)
set(CMAKE_CXX_COMPILER "${LW_CROSS_CXX}" PARENT_SCOPE)
set(CMAKE_ASM_COMPILER "${LW_CROSS_ASM}" PARENT_SCOPE)
set_property(DIRECTORY . PROPERTY INCLUDE_DIRECTORIES "")
else()
message(FATAL_ERROR "Unrecognized target type \"${ARG_TARGET}\"")

View File

@ -5,14 +5,72 @@ lw_project(lcrash
TARGET LINDOWS
)
lw_add_executable(lcrash
SOURCES lcrash.c efi/memmap.c
enable_language(ASM)
lw_add_executable(lcrashkern
SOURCES lcrash.c util.c efi/guid.c efi/memmap.c gdb/gdb.c
)
add_executable(lcrashkernld IMPORTED)
set_property(TARGET lcrashkernld PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lcrash.ld)
set_property(TARGET lcrashkern PROPERTY LINK_DEPENDS
$<TARGET_FILE:lcrashkernld>
$<TARGET_FILE:LindowsCompilerSpec>
)
set_property(TARGET lcrashkern PROPERTY LINK_OPTIONS -nostdlib -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/lcrash.ld )
target_compile_options(lcrashkern PRIVATE -ggdb -fpic -pie)
target_link_options(lcrashkern PRIVATE -fpic -pie)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lcrashkern.gz
DEPENDS lcrashkern
COMMAND gzip -fk $<TARGET_FILE:lcrashkern> > ${CMAKE_CURRENT_BINARY_DIR}/lcrashkern.gz
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lcrashkern_locs.h
DEPENDS lcrashkern ${CMAKE_CURRENT_BINARY_DIR}/lcrashkern.gz
COMMAND nm ${CMAKE_CURRENT_BINARY_DIR}/lcrashkern | sed -E '"s/([0-9a-f]*) . (.*)/#define KK_\\2 0x\\1/g"' > lcrashkern_locs.h
COMMAND echo -n "'#'define _KKCLEN " >> lcrashkern_locs.h
COMMAND du -b lcrashkern.gz | cut -f 1 >> lcrashkern_locs.h
)
# UnityOS cckernel stuffed into the bzImage
lw_add_executable(cckernel
SOURCES setup/compressed/cckernel.S
setup/compressed/entry64.S
setup/compressed/mem.S
setup/compressed/main.c
setup/compressed/gzip.c
setup/compressed/elf.c
)
add_executable(cckernelld IMPORTED)
set_property(TARGET cckernelld PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/setup/compressed/compressed.ld)
set_property(TARGET cckernel PROPERTY LINK_OPTIONS -nostdlib -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/setup/compressed/compressed.ld)
target_compile_options(cckernel PRIVATE -ggdb -mno-sse -mno-avx) # disable generating SIMD code since we haven't configured it at this stage of the boot thing
set_property(SOURCE setup/compressed/cckernel.S PROPERTY OBJECT_DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/lcrashkern.gz
)
set_property(TARGET cckernel PROPERTY LINK_DEPENDS
$<TARGET_FILE:cckernelld>
)
set(COMPRESSED_KERNEL_PATH ${CMAKE_CURRENT_BINARY_DIR}/lcrashkern.gz)
configure_file(setup/compressed/cckernel.S.in setup/compressed/cckernel.S)
# This is the actual bzImage used by linux/grub
lw_add_executable(lcrash
SOURCES setup/header.S lcrashkern_locs.h
)
target_include_directories(lcrash PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
add_executable(lcrashld IMPORTED)
set_property(TARGET lcrashld PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lcrash.ld)
set_property(TARGET lcrashld PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/setup/setup.ld)
set_property(TARGET lcrash PROPERTY LINK_DEPENDS
$<TARGET_FILE:lcrashld>
$<TARGET_FILE:LindowsCompilerSpec>
$<TARGET_FILE:cckernel>
)
set_property(TARGET lcrash PROPERTY LINK_OPTIONS -nostdlib -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/setup/setup.ld)
add_custom_command(TARGET lcrash POST_BUILD
DEPENDS cckernel
COMMAND bash -c "truncate \"$<TARGET_FILE:lcrash>\" -s \"$((0x$(nm \"$<TARGET_FILE:lcrash>\" | grep \" _end$\" | cut -d\" \" -f 1)))\""
COMMAND dd "if=$<TARGET_FILE:cckernel>" "of=$<TARGET_FILE:lcrash>" conv=notrunc oflag=append
VERBATIM
)
set_property(TARGET lcrash PROPERTY LINK_OPTIONS -nostdlib -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/lcrash.ld)
target_compile_options(lcrash PRIVATE -ggdb)

22
lcrash/acpi/acpi.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "../types.h"
struct AcpiRSDP;
struct AcpiXSDT;
/**
* ACPI Root System Description Pointer
*/
struct [[gnu::packed]] AcpiRSDP {
char Signature[8];
u8 Checksum;
char OEM[6];
u8 Revision;
[[gnu::deprecated]] // we dont care :>
u32 RSDTAddress;
u32 Length;
struct AcpiXSDT* XSDTAddress;
u8 ExtendedChecksum;
u8 Reserved[3];
};

3
lcrash/efi/guid.c Normal file
View File

@ -0,0 +1,3 @@
#include "guid.h"
EfiGuid EFI_ACPI_20_TABLE_GUID = {0x8868e871, 0xe4f1, 0x11d3, {0xbc,0x22,0x00,0x80,0xc7,0x3c,0x88,0x81}};

5
lcrash/efi/guid.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include "./types.h"
extern EfiGuid EFI_ACPI_20_TABLE_GUID;

33
lcrash/efi/memmap.c Normal file
View File

@ -0,0 +1,33 @@
#include "memmap.h"
struct EfiMemoryDescription *StoredMemoryMap;
u32 StoredMemoryMapEntryCount = 0;
u32 StoredMemoryMapEntrySize = 0;
void EfiLoadStoredMemoryMap(
struct EfiMemoryDescription* MemoryMap,
u32 MemoryMapEntryCount,
u32 MemoryMapEntrySize
) {
StoredMemoryMap = MemoryMap;
StoredMemoryMapEntryCount = MemoryMapEntryCount;
StoredMemoryMapEntrySize = MemoryMapEntrySize;
}
/**
* Translate a pointer using what we can recover from the UEFI memory map, may return something invalid.
*/
void* EfiTranslatePointer(void* FirmwarePointer) {
// Scan the memory map for where our thing is
for (int i = 0; i < StoredMemoryMapEntryCount; i++) {
struct EfiMemoryDescription* Entry = (struct EfiMemoryDescription*)((void*)StoredMemoryMap + i * StoredMemoryMapEntrySize);
if (FirmwarePointer >= Entry->VirtualStart &&
FirmwarePointer < Entry->VirtualStart + 0x1000 * Entry->NumberOfPages) {
return FirmwarePointer - Entry->VirtualStart + Entry->PhysicalStart;
}
}
// Well, we tried
return -1;
}

24
lcrash/efi/memmap.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include "types.h"
/// EFI Memory Descriptor
struct EfiMemoryDescription {
EfiUint32 Type;
EfiVoid *PhysicalStart;
EfiVoid *VirtualStart;
EfiUint64 NumberOfPages;
EfiUint64 Attribute;
};
/**
* Load a memory map to use for translating pointers recovered from EFI tables.
*/
void EfiLoadStoredMemoryMap(
struct EfiMemoryDescription* StoredMemoryMap,
u32 StoredMemoryMapEntryCount,
u32 StoredMemoryMapEntrySize
);
/// Translate a pointer to something we can use using the stored memory map.
void* EfiTranslatePointer(void* FirmwarePointer);

54
lcrash/efi/types.h Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include "../types.h"
typedef void EfiVoid;
typedef u8 EfiUint8;
typedef u16 EfiUint16;
typedef u32 EfiUint32;
typedef u64 EfiUint64;
typedef uptr EfiUintN;
typedef c16 EfiChar16;
typedef EfiVoid* EfiHandle;
typedef struct _EfiGuid {
u32 data1;
u16 data2;
u16 data3;
u8 data4[8];
} EfiGuid;
/// Generic EFI table header
struct EfiTableHeader {
EfiUint64 Signature;
EfiUint32 Revision;
EfiUint32 HeaderSize;
EfiUint32 CRC32;
EfiUint32 Reserved;
};
/// EFI System Table
struct EfiSystemTable {
struct EfiTableHeader Hdr;
EfiChar16 *FirmwareVendor;
EfiUint32 FirmwareRevision;
EfiHandle ConsoleInHandle;
EfiVoid *ConIn;
EfiHandle ConsoleOutHandle;
EfiVoid *ConOut;
EfiHandle StandardErrorHandle;
EfiVoid *StdErr;
struct EfiRuntimeServices *RuntimeServices;
struct EfiBootServices *BootServices;
EfiUintN NumberOfTableEntries;
struct EfiConfigurationTable *ConfigurationTable;
};
/// EFI Configuration Table
struct EfiConfigurationTable {
EfiGuid VendorGuid;
EfiVoid *VendorTable;
};

0
lcrash/empty.S Normal file
View File

30
lcrash/gdb/autorun.py Normal file
View File

@ -0,0 +1,30 @@
import functools;
# --- printers for stuff and yeah ---
class EfiGuidPrinter(gdb.ValuePrinter):
"Print an EfiGuid"
def __init__(self, val):
self.__val = val;
def to_string(self):
# it's really disappointing that you cant iterate these silly arrays
d4 = self.__val["data4"];
last = functools.reduce(lambda s, bit: f'{s}{int(bit):0>2X}', [d4[0], d4[1], d4[2], d4[3], d4[4], d4[5], d4[6], d4[7]], "");
return f'{int(self.__val["data1"]):0>8X}-{int(self.__val["data2"]):0>4X}-{int(self.__val["data3"]):0>4X}-{last}';
def add_pretty_printer(name, printer, custom_lookup = None):
def lookup(val):
if val.type.tag == name:
return printer(val);
return None;
gdb.current_objfile().pretty_printers.append(lookup if custom_lookup is None else custom_lookup);
return;
add_pretty_printer("_EfiGuid", EfiGuidPrinter, lambda val: EfiGuidPrinter(val) if val.type.strip_typedefs().tag == "_EfiGuid" else None);
# --- ---

3
lcrash/gdb/gdb.c Normal file
View File

@ -0,0 +1,3 @@
#include "gdb.h"
DEFINE_GDB_PY_SCRIPT("lcrash/gdb/autorun.py")

9
lcrash/gdb/gdb.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#define DEFINE_GDB_PY_SCRIPT(name) \
asm("\
.pushsection \".debug_gdb_scripts\", \"MS\", @progbits, 1\n\
.byte 1\n\
.asciz \""name"\"\n\
.popsection \n\
");

View File

@ -1,31 +1,8 @@
#include "lnxboot.h"
#include "util.h"
#include "efi/types.h"
#include "efi/memmap.h"
extern void _start();
[[gnu::section(".lnxhead")]]
[[gnu::used]]
[[gnu::aligned(1)]]
[[gnu::unavailable("not present at runtime. use setup_info instead")]]
struct setup_info bzhead = {
.setup_sects = 2, // 1 512-byte sector
.boot_flag = 0xAA55,
.syssize = 16,
.jump_instruction = 0xEB,
.jump_offset = sizeof(struct setup_info) - __builtin_offsetof(struct setup_info, signature),
.signature = 0x53726448,
.version = 0x020F,
.loadflags = 0x01, // LOADED_HIGH,
.kernel_alignment = 1,
.relocatable_kernel = 0,
.xloadflags = 0x13, // XLF_KERNEL_64 | XLF_CAN_BE_LOADED_ABOVE_4G | XLF_5LEVEL
.cmdline_size = 255, // max command line size
.init_size = 0x10000 // we dont need THAT much memory
};
struct setup_info* setup_info;
struct boot_params* boot_params;
#include "efi/guid.h"
unsigned short serial_port;
@ -84,28 +61,12 @@ void Panic(const char* message) {
Hang();
}
[[gnu::section(".text._start"), gnu::naked, gnu::no_reorder]]
extern void _start() {
asm ("jmp _start");
asm ( // grab the setup_info and boot_params locations
"mov %%rsi, %1\n"
"mov %%rsi, %0\n"
"addq $0x1f1, %0"
: "=m" (setup_info),
"=m" (boot_params)
);
asm ("jmp entry");
}
void entry64() {
while (1) {};
c16* FirmwareVendor = 0;
Panic("HELLO WORLD.");
/**
* we're in some kind of purgatory between booted and not booted, a lot of devices are currently initialized from the previous
* kernel, but we have no idea where they are, what they are, or how to use them. all we have is the stuff in setup_info and
* boot_params, and whatever we can salvage from the crashed kernel.
*/
[[gnu::section(".text._start"), gnu::no_reorder]]
void entry() {
/*
// 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));
@ -125,11 +86,6 @@ void entry() {
boot_params->efi_info.EfiMemoryMapSize / boot_params->efi_info.EfiMemoryDescriptionSize,
boot_params->efi_info.EfiMemoryDescriptionSize
);
FirmwareVendor = EfiTranslatePointer(systab_ptr->FirmwareVendor);
while (1) {
volatile char* a = FirmwareVendor;
}
}
// -- find acpi --
@ -138,9 +94,22 @@ void entry() {
// 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) {
volatile void* ConfigurationTable = EfiTranslatePointer(systab_ptr->ConfigurationTable);
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
@ -159,7 +128,9 @@ void entry() {
if (!AcpiRSDP) Panic("Failed to find ACPI RSDP");
// do we have acpi?
asm volatile ("ljmp 0");
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.
@ -191,6 +162,6 @@ void entry() {
// serial_puts("test\n");
// serial_puts(bzhead.cmd_line_ptr);
// Die.
// Die.*/
Panic("Nothing left to do.");
}

View File

@ -1,28 +1,33 @@
OUTPUT_FORMAT(elf64-x86-64)
ENTRY(_start)
MEMORY {
code (rx) : ORIGIN = 0x0dfe8000, LENGTH = 0x00001000
data (rw) : ORIGIN = 0x0dff0000, LENGTH = 0x00001000
}
ENTRY(entry64)
SECTIONS {
.lnxhead 0x01f1 : ALIGN(1) {
*(.lnxhead);
. = 0;
.text : {
_text = .;
*(.text);
_etext = .;
}
.rodata : ALIGN(1) {
.rodata : {
_rodata = .;
*(.rodata);
} > data
_erodata = .;
}
/* this section helps us to coerce the linker into not breaking down because of big addresses */
.text._start 0xdfe8000 : ALIGN(1) {
*(.text._start);
} > code
.data : {
_data = .;
*(.data);
_edata = .;
}
.text : ALIGN(512) { *(.text); } > code
.bss : { *(.bss); }
.bss : {
_bss = .;
*(.bss);
_ebss = .;
}
.debug_info 0 : { *(.debug_info); }
.debug_abbrev 0 : { *(.debug_abbrev); }
@ -31,6 +36,7 @@ SECTIONS {
.debug_line 0 : { *(.debug_line); }
.debug_str 0 : { *(.debug_str); }
.debug_line_str 0 : { *(.debug_line_str); }
.debug_gdb_scripts 0 : { *(.debug_gdb_scripts); }
/DISCARD/ : {
*(*);

View File

@ -0,0 +1,6 @@
.section ".cckernel", "a"
.globl _CC_cckernel
_CC_cckernel:
.incbin "@COMPRESSED_KERNEL_PATH@"
.globl _CC_ecckernel
_CC_ecckernel:

View File

@ -0,0 +1,35 @@
OUTPUT_FORMAT(elf64-x86-64)
SECTIONS {
_CC_start = .;
.text : {
*(.text)
}
.cckernel : {
*(.cckernel)
}
_CC_end = .;
.bss : {
*(.bss)
*(COMMON)
}
.debug_info 0 : { *(.debug_info); }
.debug_abbrev 0 : { *(.debug_abbrev); }
.debug_aranges 0 : { *(.debug_aranges); }
.debug_rnglists 0 : { *(.debug_rnglists); }
.debug_line 0 : { *(.debug_line); }
.debug_str 0 : { *(.debug_str); }
.debug_line_str 0 : { *(.debug_line_str); }
.debug_gdb_scripts 0 : { *(.debug_gdb_scripts); }
/DISCARD/ : {
*(*);
}
/* ASSERT(entry64 != 0x200, "entry64 is not the entry point, this should never happen.") */
}

View File

@ -0,0 +1,7 @@
#include "elf.h"
int ElfExecute(void* Binary, void* LoadAddr) {
while (1) {}
}

View File

@ -0,0 +1,36 @@
#pragma once
#include "../../types.h"
[[packed]]
struct 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;
};
[[packed]]
struct 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;
};
/// 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
int ElfExecute(void* Binary, void* LoadAddr);

View File

@ -0,0 +1,32 @@
.section ".text", "ax"
.org 0x200
.global entry64
entry64: // 64-bit entry point for kernel decompression
// get the cckernel image base. if the opcode generated by the assembler changes, this will break
lea -0x207(%rip), %rdi
// we might get some stack space from the previous kernel, but we have no idea how much
// it could just be a few bytes for all we know. it's far safer to just use our own
mov $einit_stack, %rsp
mov %rsp, %rbp
// lets get out of here -- ccmain(rdi: IMGBASE, rsi: BOOTPARAMS)
call ccmain
// what the fuck is going on, why have you returned here, was my work not enough for you
// ungrateful fucking machine. away with you, you do not deserve the privilege of my
// loving grace.
int3
int3
int3
int3
// begone
cli
1: hlt
jmp 1b
.section ".bss"
init_stack: // this should be sufficient for kernel decompression
.skip 0x8000, 0
einit_stack:

View File

@ -0,0 +1,304 @@
#include "gzip.h"
// we build a table of uh everything. this uses a lot of stack space,
void GzipPopulateTable(
u8* InputLengths, // Lengths of symbol bits
uptr InputCount, // Number of symbols
u8* OutputLengths, // Output bit lengths
u32* OutputSymbols, // Output symbols
uptr OutputCount, // Number of outputs
uptr OutputBits // Highest bit length
) {
u32 NextSym[15]; /// Next symbol for a specific bit length
for (int i = 0; i < 15; i++) NextSym[i] = -1;
// Count the symbols in each bit length
u32 CodeCounts[15] = {};
for (int i = 0; i < InputCount; i++) {
CodeCounts[InputLengths[i]]++;
if (NextSym[InputLengths[i]] == -1) NextSym[InputLengths[i]] = i;
}
// Ignore null symbols
CodeCounts[0] = 0;
// Find lowest code for each bit length
u32 Code = 0;
u32 NextCode[15] = {}; // Next code to add to the table
for (u32 Bits = 1; Bits < 15; Bits++) {
Code = (Code + CodeCounts[Bits - 1]) << 1;
NextCode[Bits] = Code;
}
// Fill in the table in a horribly inefficient manner
Code = 0;
for (u32 Bits = 0; Bits < 15; Bits++) {
const uptr OutputMask = ~(-1 << Bits);
for (int i = 0; i < CodeCounts[Bits]; i++) {
// Take the next symbol
Code = NextSym[Bits];
// Set the next next symbol
for (int j = Code + 1; j < InputCount; j++) {
if (InputLengths[j] == Bits) {
NextSym[Bits] = j;
break;
}
}
// reverse the bits i dont fucking know it doesn't work if i dont
u32 Reversed = 0;
for (int j = 0; j < Bits; j++) {
Reversed |= ((NextCode[Bits] >> j) & 1) << (Bits - j - 1);
}
// this is horrible
for (int j = 0; j < OutputCount; j++) {
if ((j & OutputMask) == Reversed) {
OutputLengths[j] = Bits;
OutputSymbols[j] = Code;
}
}
// Next
NextCode[Bits]++;
Code++;
}
}
// "Good Practice" insists that i inform you that this is in fact, a return statement.
return;
}
u64 GzipFetchBits(u8* Stream, u64* Location, uptr Length) {
u64 Output = 0;
for (uptr i = 0; i < Length; i++) {
Output |= ((Stream[*Location / 8] >> (*Location % 8)) & 1) << i;
*Location += 1;
}
return Output;
}
uptr GzipDecompress(c8* Input, uptr InputSize, c8* Output) {
#define TAKE_(_TYPE) (\
(Location += sizeof(_TYPE)), \
*(_TYPE*)(Location - sizeof(_TYPE)) \
)
const u32 LengthAddends[29] = {
3, 4, 5, 6, 7, 8, 9, 10, 11, 13,
15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
67, 83, 99, 115, 131, 163, 195, 227, 258
};
const u32 DistanceAddends[30] = {
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025,
1537, 2049, 3073, 40097, 6145, 8193, 12289, 15385, 24577
};
void* Location = (void*)Input;
void* End = Location + InputSize;
void* BinaryStart = (void*)Output;
// each member hopefully. any bug will result in complete failure c:
// we dont even bother making sure it's valid, we have no way to tell
// the user there's something wrong
while (Location < End) {
c8 Id1 = TAKE_(c8);
c8 Id2 = TAKE_(c8);
u8 Method = TAKE_(u8);
u8 Flags = TAKE_(u8);
u32 LastModified = TAKE_(u32);
u8 ExtraFlags = TAKE_(u8);
u8 OperatingSystem = TAKE_(u8);
// for the magic extra field
u16 XLen = 0;
void* XBuf = 0;
if (Flags & 0x04) { // FLG.FEXTRA
XLen = TAKE_(u16);
XBuf = Location;
Location += XLen;
}
// filename
c8* FileName = 0;
if (Flags & 0x08) { // FLG.FNAME
FileName = Location;
while (TAKE_(c8) != 0) {}
}
// comment
c8* FileComment = 0;
if (Flags & 0x10) { // FLG.FCOMMENT
FileComment = Location;
while (TAKE_(c8) != 0) {}
}
// hash
u16 CRC16 = 0;
if (Flags & 0x02) { // FLG.FHCRC
CRC16 = TAKE_(u16);
}
u8* Stream = Location;
u64 BitLocation = 0;
while (true) {
u8 head = GzipFetchBits(Stream, &BitLocation, 3);
switch ((head & 0x06) >> 1) {
case 0: { // NO COMPRESSION
break;
}
case 1: {
// FIXED HUFFMAN
break;
}
case 2: { // DYNAMIC HUFFMAN
// Get huffman code counts
u64 OperationCount = GzipFetchBits(Stream, &BitLocation, 5) + 257;
u64 DistanceCount = GzipFetchBits(Stream, &BitLocation, 5) + 1;
u64 CodeCount = GzipFetchBits(Stream, &BitLocation, 4) + 4;
const u8 CodeLengthLengthOffset[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
u8 CodeLengthLengthProto[19] = {};
for (int i = 0; i < CodeCount; i++) {
CodeLengthLengthProto[CodeLengthLengthOffset[i]] = GzipFetchBits(Stream, &BitLocation, 3);
}
// Build our decoding tables
u8 CodeLengthLengths[0x80] = {};
u32 CodeLengthSymbols[0x80] = {};
GzipPopulateTable(CodeLengthLengthProto, 19, CodeLengthLengths, CodeLengthSymbols, 0x80, 7);
// Collect lengths
u8 Lengths[OperationCount + DistanceCount] = {};
uptr CurrentLen = 0;
while (CurrentLen < OperationCount + DistanceCount) {
// Fetch the next op
u64 Code = GzipFetchBits(Stream, &BitLocation, 7);
u64 Error = 7 - CodeLengthLengths[Code];
BitLocation -= Error;
Code = CodeLengthSymbols[Code];
if (Code < 16) { // Literal
Lengths[CurrentLen++] = Code;
} else { // Repeat
u64 RepeatCount = 0;
u64 RepeatedLen = 0;
if (Code == 16) {
RepeatCount = 3 + GzipFetchBits(Stream, &BitLocation, 2);
RepeatedLen = Lengths[CurrentLen - 1];
} else if (Code == 17) {
RepeatCount = 3 + GzipFetchBits(Stream, &BitLocation, 3);
} else if (Code == 18) {
RepeatCount =11 + GzipFetchBits(Stream, &BitLocation, 7);
} else {} // Should be unreachable
for (int i = 0; i < RepeatCount; i++) {
Lengths[CurrentLen++] = RepeatedLen;
}
}
}
// Build operation table
u32 OperationMaxBits = 0;
for (int i = 0; i < OperationCount; i++) {
if (Lengths[i] > OperationMaxBits) OperationMaxBits = Lengths[i];
}
// We have no standard library
u32 OperationTableLength = 1;
for (int i = 0; i < OperationMaxBits; i++) OperationTableLength *= 2;
// Tables
u32 OperationSymbols[OperationTableLength + 0x10];
u8 OperationLengths[OperationTableLength + 0x10];
GzipPopulateTable(Lengths, OperationCount,
OperationLengths, OperationSymbols, OperationTableLength,
OperationMaxBits);
// Build distance tables
u32 DistanceMaxBits = 0;
for (int i = 0; i < DistanceCount; i++) {
if (Lengths[OperationCount + i] > DistanceMaxBits) {
DistanceMaxBits = Lengths[OperationCount + i];
}
}
// Power
u32 DistanceTableLength = 1;
for (int i = 0; i < DistanceMaxBits; i++) DistanceTableLength *= 2;
// More tables
u32 DistanceSymbols[DistanceTableLength + 0x10]; // ad dsome padding theres some bugs i cant see
u8 DistanceLengths[DistanceTableLength + 0x10];
GzipPopulateTable(Lengths + OperationCount, DistanceCount,
DistanceLengths, DistanceSymbols, DistanceTableLength,
DistanceMaxBits);
// Inflate
while (Location + BitLocation / 8 < End) {
// Fetch
u32 Code = GzipFetchBits(Stream, &BitLocation, OperationMaxBits);
u64 Error = OperationMaxBits - OperationLengths[Code];
BitLocation -= Error;
Code = OperationSymbols[Code];
if (Code < 256) { // Literal
*Output++ = Code;
} else if (Code == 256) { // End block
break;
} else if (Code < OperationCount) { // Copy
// You'd need to look at the spec yourself to understand this
u32 CopyLength = GzipFetchBits(Stream, &BitLocation,
Code <= 284 && Code > 264
? (Code - 1) / 4 - 65
: 0)
+ LengthAddends[Code - 257];
// More bitstream shit! I'm done formatting this stuff nicely.
Code = GzipFetchBits(Stream, &BitLocation, DistanceMaxBits);
Error = DistanceMaxBits - DistanceLengths[Code];
BitLocation -= Error;
Code = DistanceSymbols[Code];
// make this a s32 because address and offset awaaa
s32 Distance = GzipFetchBits(Stream, &BitLocation,
Code > 3 && Code <= 29
? (Code - 2) / 2
: 0)
+ DistanceAddends[Code];
// Finally copy the thing
for (int i = 0; i < CopyLength; i++) {
Output[i] = Output[i - Distance];
}
Output += CopyLength;
} else { while (1) {} } // Unreachable unless invalid
}
break;
}
case 3: {
// THIS SHOULD NEVER HAPPEN
break;
}
}
if (head & 0x01) break; // BFINAL
}
// I think this is necessary but im not completely sure
Location += BitLocation / 8 + 1;
// trailer..? hey siri, what's the opposite of a header?
u32 CRC32 = TAKE_(u32);
u32 InputSize = TAKE_(u32);
}
return (void*)Output - BinaryStart;
#undef TAKE_
}

View File

@ -0,0 +1,5 @@
#pragma once
#include "../../types.h"
uptr GzipDecompress(c8* Input, uptr InputSize, c8* Output);

View File

@ -0,0 +1,30 @@
#include "../../lnxboot.h"
#include "gzip.h"
#include "elf.h"
extern void* _CC_cckernel;
extern void* _CC_ecckernel;
/// C entry point for cckernel
[[noreturn]]
void ccmain(void* imgbase, struct boot_params* boot_params) {
struct setup_info* setup_info = (struct setup_info*)((void*)boot_params + 0x1f1);
char* kernel_load_addr = (char*)setup_info->code32_start;
if (kernel_load_addr == 0) kernel_load_addr = (char*)0x100000;
char* cckernel = imgbase + (uptr)&_CC_cckernel;
//for (long i = 0; i < setup_info->payload_length; i++) {
// kernel_load_addr[i] = cckernel[i];
//}
// decompress the kernel
uptr BinaryLength = GzipDecompress(cckernel, (u8*)&_CC_ecckernel - (u8*)&_CC_cckernel, kernel_load_addr);
// start the kernel
ElfExecute(kernel_load_addr, kernel_load_addr + BinaryLength + 0x1000 - BinaryLength % 0x1000);
// we fucked up
while (1) {}
}

View File

@ -0,0 +1,9 @@
/// File with support code for gcc memory stuff
.section ".text", "ax"
.globl memset
memset:
mov %rdx, %rcx
mov %sil, %al
rep stosb (%rdi)
mov %rdi, %rax
ret

64
lcrash/setup/header.S Normal file
View File

@ -0,0 +1,64 @@
#include <lcrashkern_locs.h>
.extern _end
.extern cckernel_size
.extern cckernel_start
.section ".header", "ax"
.globl setup_info
setup_sects: .byte setup_sectors - 1
root_flags: .word 0
syssize: .long KK__ebss / 16
ram_size: .word 0
vid_mode: .word 0
root_dev: .word 0
boot_flag: .word 0xAA55
.globl _start
_start:
jump: .byte 0xeb
.byte -2 // entrylow - 1f
1:
signature: .ascii "HdrS"
version: .word 0x020f
realmode_switch: .word 0, 0
start_sys_seg: .word 0
.word 0 //kernel_version - 512
type_of_loader: .byte 0
loadflags: .byte 0x81
setup_move_size: .word 0x8000
code32_start: .long 0 # .long 0x100000
ramdisk_image: .long 0
ramdisk_size: .long 0
bootsect_kludge: .long 0
heap_end_ptr: .word 0 # _end + 512
ext_loader_ver: .byte 0
ext_loader_type: .byte 0
cmd_line_ptr: .long 0
initrd_addr_max: .long 0x7fffffff
kernel_alignment: .long 1
relocatable_kernel: .byte 1
min_alignment: .byte 1
xloadflags: .word 0x13
cmdline_size: .long 512
hardware_subarch: .long 0
hardware_subarch_data: .quad 0
payload_offset: .long _end // cckernel_start
payload_length: .long _KKCLEN // cckernel_size
setup_data: .quad 0
pref_address: .quad 0
init_size: .long 0x20000 // a bit of space
handover_offset: .long 0 // TODO
kernel_info_offset: .long 0 // TODO
/* .globl entrylow
.section ".entrytext", "ax"
entrylow:
1: jmp 1b
2: jmp 2b
3: jmp 3b
4: jmp 4b
5: jmp 5b
6: jmp 6b
7: jmp 7b
.section ".initdata", "a"
kernel_version: .asciz "lcrash 0.1.0"*/

37
lcrash/setup/setup.ld Normal file
View File

@ -0,0 +1,37 @@
/* linker script shamelessly ripped from the linux kernel */
OUTPUT_FORMAT(elf64-x86-64)
ENTRY(_start)
SECTIONS {
. = 0;
. = 0x1F1;
.header : { *(.header); }
.entrytext : { *(.entrytext); }
.inittext : { *(.inittext); }
.initdata : { *(.initdata); }
/* i dont actually know what this does, but it seems important */
.signature : {
setup_sig = .;
LONG(0x5a5aaa55);
setup_size = ALIGN(ABSOLUTE(.), 4096);
setup_sectors = ABSOLUTE(setup_size / 512);
}
. = ALIGN(16);
.bss : {
__bss_start = .;
*(.bss);
__bss_end = .;
}
. = ALIGN(0x1000);
_end = .;
/DISCARD/ : {
*(.note.*);
}
}

29
lcrash/types.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long s64;
typedef char c8;
typedef short c16;
#define true 1
#define false 0
typedef u8 bool;
#if __SIZEOF_POINTER__ == 4
typedef u32 uptr;
typedef s32 sptr;
#elif __SIZEOF_POINTER__ == 8
typedef u64 uptr;
typedef s64 sptr;
#else
#error What the fuck? [pointers are not 4 or 8 bytes long]
#endif

13
lcrash/util.c Normal file
View File

@ -0,0 +1,13 @@
#include "util.h"
#include "types.h"
bool CompareMemory(void* Addr1, void* Addr2, uptr Length) {
u8* Data1 = Addr1;
u8* Data2 = Addr2;
for (uptr i = 0; i < Length; i++) {
if (Data1[i] != Data2[i]) return false;
}
return true;
}

8
lcrash/util.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
#include "types.h"
/**
* Compare the data at two memory addresses
*/
bool CompareMemory(void* Addr1, void* Addr2, uptr Length);

16
scripts/gdb/lcrash.gdb Normal file
View File

@ -0,0 +1,16 @@
define info bootparams
set $f_info_bootparams_boot_params = (struct boot_params*)$arg0
set $f_info_bootparams_efi_system_table = (struct EfiSystemTable*)(((long)$f_info_bootparams_boot_params->efi_info.EfiSystemTable) | ((long)$f_info_bootparams_boot_params->efi_info.EfiSystemTableHigh << 32))
set $f_info_bootparams_efi_memory_map = (struct EfiMemoryDescription*)(((long)$f_info_bootparams_boot_params->efi_info.EfiMemoryMap) | ((long)$f_info_bootparams_boot_params->efi_info.EfiMemoryMapHigh << 32))
printf "Boot Params: *0x%llx\n", $f_info_bootparams_boot_params
printf " EFI info:\n"
printf " System Table: *0x%llx\n", $f_info_bootparams_efi_system_table
printf " Memory map: *0x%llx\n", $f_info_bootparams_efi_memory_map
set $f_info_bootparams_i = 0
while $f_info_bootparams_i < $f_info_bootparams_boot_params->efi_info.EfiMemoryMapSize
set $f_info_bootparams_mmcurrentdesc = (struct EfiMemoryDescription*)((void*)$f_info_bootparams_efi_memory_map + $f_info_bootparams_i)
printf " Entry 0x%016llx-0x%016llx -> 0x%016llx T:%016llx A:%016llx\n", $f_info_bootparams_mmcurrentdesc->VirtualStart, $f_info_bootparams_mmcurrentdesc->VirtualStart + 0x1000 * $f_info_bootparams_mmcurrentdesc->NumberOfPages, $f_info_bootparams_mmcurrentdesc->PhysicalStart, $f_info_bootparams_mmcurrentdesc->Type, $f_info_bootparams_mmcurrentdesc->Attribute
set $f_info_bootparams_i += $f_info_bootparams_boot_params->efi_info.EfiMemoryDescriptionSize
end
end

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=16M
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
boot

View File

@ -5074,14 +5074,23 @@ CONFIG_DEBUG_MISC=y
#
# Compile-time checks and compiler options
#
CONFIG_DEBUG_INFO=y
CONFIG_AS_HAS_NON_CONST_LEB128=y
CONFIG_DEBUG_INFO_NONE=y
# CONFIG_DEBUG_INFO_NONE is not set
# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set
# CONFIG_DEBUG_INFO_DWARF4 is not set
# CONFIG_DEBUG_INFO_DWARF5 is not set
CONFIG_DEBUG_INFO_DWARF5=y
# CONFIG_DEBUG_INFO_REDUCED is not set
# CONFIG_DEBUG_INFO_COMPRESSED_NONE is not set
CONFIG_DEBUG_INFO_COMPRESSED_ZLIB=y
# CONFIG_DEBUG_INFO_COMPRESSED_ZSTD is not set
# CONFIG_DEBUG_INFO_SPLIT is not set
CONFIG_PAHOLE_HAS_SPLIT_BTF=y
CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y
CONFIG_GDB_SCRIPTS=y
CONFIG_FRAME_WARN=2048
# CONFIG_STRIP_ASM_SYMS is not set
# CONFIG_READABLE_ASM is not set
CONFIG_READABLE_ASM=y
# CONFIG_HEADERS_INSTALL is not set
# CONFIG_DEBUG_SECTION_MISMATCH is not set
CONFIG_SECTION_MISMATCH_WARN_ONLY=y