Separate out ELF header parsing to another file
This commit is contained in:
parent
13139779f2
commit
69eb6e10c8
|
@ -24,6 +24,7 @@ SET(src_files
|
|||
${CMAKE_SOURCE_DIR}/chroma/system/memory/abstract_allocator.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/memory/physmem.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/drivers/keyboard.c
|
||||
${CMAKE_SOURCE_DIR}/chroma/system/drivers/elf.c
|
||||
)
|
||||
|
||||
SET(lib_files
|
||||
|
|
|
@ -11,6 +11,30 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ELF headers hate me.
|
||||
* Let's do this the hard way. */
|
||||
|
||||
#define ELF_IDENT_MAGIC_OFF 0x0
|
||||
#define ELF_IDENT_CLASS_OFF 0x4
|
||||
#define ELF_IDENT_DATA_OFF 0x5
|
||||
#define ELF_IDENT_VERSION_OFF 0x6
|
||||
#define ELF_IDENT_OSABI_OFF 0x7
|
||||
#define ELF_IDENT_ABI_VERSION_OFF 0x8
|
||||
#define ELF_IDENT_PAD_OFF 0x9
|
||||
#define ELFTYPE_OFF 0x10
|
||||
#define ELFMACHINE_OFF 0x12
|
||||
#define ELFVERSION_OFF 0x14
|
||||
#define ELFENTRY_OFF 0x18
|
||||
#define ELFPHOFF_OFF 0x20
|
||||
#define ELFSHOFF_OFF 0x28
|
||||
#define ELFFLAGS_OFF 0x30
|
||||
#define ELFEHSIZE_OFF 0x34
|
||||
#define ELFPHENTSIZE_OFF 0x36
|
||||
#define ELFPHNUM_OFF 0x38
|
||||
#define ELFSHENTSIZE_OFF 0x3A
|
||||
#define ELFSHNUM_OFF 0x3C
|
||||
#define ELFSHSTRNDX_OFF 0x40
|
||||
|
||||
#define BOOT_MAGIC "BOOT"
|
||||
|
||||
/* minimum protocol level:
|
||||
|
@ -108,30 +132,6 @@ typedef struct {
|
|||
} __attribute__((packed)) bootinfo;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t Magic;
|
||||
uint8_t Class;
|
||||
uint8_t Endianness;
|
||||
uint8_t Version;
|
||||
uint8_t ABI;
|
||||
uint8_t ABIVersion;
|
||||
uint8_t Unused[7];
|
||||
uint16_t Type;
|
||||
uint16_t TargetArchitecture;
|
||||
uint32_t ELFVersion;
|
||||
size_t EntryPoint;
|
||||
size_t ProgramHeadersTable;
|
||||
size_t SectionHeadersTable;
|
||||
uint32_t Flags;
|
||||
uint16_t ELFHeaderSize;
|
||||
uint16_t ProgramHeadersEntrySize;
|
||||
uint16_t ProgramHeaderEntries;
|
||||
uint16_t SectionHeadersEntrySize;
|
||||
uint16_t SectionHeaderEntries;
|
||||
uint16_t SectionHeaderNameEntry;
|
||||
uint8_t End;
|
||||
} __attribute__((packed)) ELF64Header_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -20,48 +20,13 @@ address_space_t KernelAddressSpace;
|
|||
|
||||
int Main(void) {
|
||||
KernelAddressSpace = (address_space_t) {0};
|
||||
KernelLocation = 0x112600;
|
||||
|
||||
SerialPrintf("\r\n[ boot] Booting Chroma..\r\n");
|
||||
SerialPrintf("[ boot] Kernel loaded at 0x%p, ends at 0x%p, is %d bytes long.\r\n", KernelAddr, KernelEnd, KernelEnd - KernelAddr);
|
||||
SerialPrintf("[ boot] Initrd is physically at 0x%p, and is %d bytes long.\r\n", bootldr.initrd_ptr, bootldr.initrd_size);
|
||||
SerialPrintf("[ boot] Initrd's header is 0x%p\r\n", FIXENDIAN32(*((volatile uint32_t*)(bootldr.initrd_ptr))));
|
||||
|
||||
SerialPrintf("[ boot] Searching for kernel... Constants start at 0x%p\r\n", &_kernel_text_start);
|
||||
// We stop at the constants in the kernel, otherwise we'll read the constant ELF64MAGIC which is stored inside the kernel...
|
||||
|
||||
size_t headerLoc = 0;
|
||||
for(size_t i = KernelAddr; i < KernelEnd; i++) {
|
||||
if(i < (size_t) (&_kernel_text_start) - KernelAddr) {
|
||||
if(*((volatile uint32_t*)(i)) == ELF64MAGIC) {
|
||||
SerialPrintf("[ boot] Matched kernel header at 0x%p.\r\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int flag = 0;
|
||||
|
||||
if(headerLoc) {
|
||||
ELF64Header_t* PotentialKernelHeader = (ELF64Header_t*) &headerLoc;
|
||||
SerialPrintf(
|
||||
"[ boot] Considering ELF with:\r\n\tBitness %d\r\n\tEntry point 0x%p\r\n\tFile type %s : %d\r\n\tArchitecture %s : %d\r\n",
|
||||
PotentialKernelHeader->Class == 2 ? 64 : 32, PotentialKernelHeader->EntryPoint, PotentialKernelHeader->Type == 0x02 ? "EXECUTABLE" : "OTHER", PotentialKernelHeader->Type, PotentialKernelHeader->TargetArchitecture == 0x3E ? "AMD64" : "OTHER", PotentialKernelHeader->TargetArchitecture);
|
||||
if(PotentialKernelHeader->EntryPoint == KernelAddr) {
|
||||
SerialPrintf("[ boot] Header at 0x%p matches kernel header.\r\n", headerLoc);
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
if(!flag) {
|
||||
|
||||
for(size_t i = 0; i < 8; i++) {
|
||||
SerialPrintf("[ boot] Header dump part %d: 0x%x\r\n", i, *((volatile uint32_t*)(headerLoc + i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!flag) {
|
||||
SerialPrintf("[ boot] Unable to find kernel in memory. Fatal error.\r\n");
|
||||
//for(;;) {}
|
||||
}
|
||||
ParseKernelHeader(bootldr.initrd_ptr);
|
||||
|
||||
SerialPrintf("[ boot] The bootloader has put the paging tables at 0x%p.\r\n", ReadControlRegister(3));
|
||||
|
||||
|
|
91
chroma/system/drivers/elf.c
Normal file
91
chroma/system/drivers/elf.c
Normal file
|
@ -0,0 +1,91 @@
|
|||
#include <kernel/chroma.h>
|
||||
/************************
|
||||
*** Team Kitty, 2020 ***
|
||||
*** Chroma ***
|
||||
***********************/
|
||||
|
||||
/*
|
||||
* This file provides utility functions for parsing ELF headers.
|
||||
* This exists so that the kernel can find itself for remapping,
|
||||
* but I may end up using ELF as the kernel's executable format.
|
||||
* Writing an ELF loader is on the to-do list, after all.
|
||||
! This needs to be cleaned up.
|
||||
! This creates a mess of numbers on the print
|
||||
! This is hacky and hardcoded as heck and needs to be fixed
|
||||
*/
|
||||
extern size_t KernelLocation;
|
||||
|
||||
int ParseKernelHeader(size_t InitrdPtr) {
|
||||
int flag = 0;
|
||||
|
||||
SerialPrintf("[ boot] Searching for kernel... Constants start at 0x%p / 0x%p\r\n", ((size_t) (&_kernel_text_start) - KernelAddr) + InitrdPtr, (size_t) (&_kernel_text_start));
|
||||
// We stop at the constants in the kernel, otherwise we'll read the constant ELF64MAGIC which is stored inside the kernel...
|
||||
|
||||
size_t headerLoc = 0;
|
||||
for(size_t i = InitrdPtr; i < ((size_t) (&_kernel_text_start) - KernelAddr) + InitrdPtr; i++) {
|
||||
if(*((volatile uint32_t*)(i)) == ELF64MAGIC) {
|
||||
SerialPrintf("[ boot] Matched kernel header at 0x%p.\r\n", i);
|
||||
headerLoc = i;
|
||||
}
|
||||
|
||||
if(FIXENDIAN32(*((volatile uint32_t*)(i))) == ELF64MAGIC) {
|
||||
SerialPrintf("[ boot] Matched little-endian kernel header at 0x%p.\r\n", i);
|
||||
headerLoc = i;
|
||||
}
|
||||
}
|
||||
|
||||
if(headerLoc) {
|
||||
/* For whatever reason, reading a size_t here fails. The max that seems to work is uint16_t, so we read in the
|
||||
* 64 bit address by constructing it from 4 individual reads.
|
||||
* Note that these 4 reads are little endian, so we need to flip them around individually
|
||||
*/
|
||||
uint16_t EntryPoint0 = FIXENDIAN16(*((volatile uint16_t*)(headerLoc + ELFENTRY_OFF)));
|
||||
uint16_t EntryPoint1 = FIXENDIAN16(*((volatile uint16_t*)(headerLoc + ELFENTRY_OFF + 2)));
|
||||
uint16_t EntryPoint2 = FIXENDIAN16(*((volatile uint16_t*)(headerLoc + ELFENTRY_OFF + 4)));
|
||||
uint16_t EntryPoint3 = FIXENDIAN16(*((volatile uint16_t*)(headerLoc + ELFENTRY_OFF + 6)));
|
||||
size_t EntryPoint = ((size_t) EntryPoint0 << 48) | ((size_t) EntryPoint1 << 32) | ((size_t) EntryPoint2 << 16) | ((size_t) EntryPoint3);
|
||||
|
||||
/* At this point, EntryPoint is a little-endian 64 bit integer. That means we have to fix its endianness in order to read it */
|
||||
SerialPrintf("[ boot] Fixing entry point from 0x%p to 0x%p\r\n", EntryPoint, FIXENDIAN64(EntryPoint));
|
||||
EntryPoint = FIXENDIAN64(EntryPoint);
|
||||
|
||||
/* Now we can continue as normal */
|
||||
uint8_t HeaderClass = *((volatile uint8_t*)(headerLoc + ELF_IDENT_CLASS_OFF));
|
||||
uint16_t ExecutableType = (uint16_t) *((volatile uint8_t*)(headerLoc + ELFTYPE_OFF));
|
||||
uint16_t MachineType = (uint16_t) *((volatile uint8_t*)(headerLoc + ELFMACHINE_OFF));
|
||||
|
||||
|
||||
SerialPrintf(
|
||||
"[ boot] ELF header at 0x%p.\r\n\tConsidering ELF with:\r\n\tBitness %d: %d\r\n\tEntry point 0x%p\r\n\tFile type %s : 0x%x\r\n\tArchitecture %s : 0x%x\r\n",
|
||||
headerLoc,
|
||||
HeaderClass == 2 ? 64 : 32,
|
||||
HeaderClass,
|
||||
EntryPoint,
|
||||
ExecutableType == FIXENDIAN16(0x0200) ? "EXECUTABLE" : "OTHER",
|
||||
FIXENDIAN16(ExecutableType),
|
||||
MachineType == FIXENDIAN16(0x3E00) ? "AMD64" : "OTHER",
|
||||
FIXENDIAN16(MachineType));
|
||||
|
||||
|
||||
|
||||
|
||||
if(EntryPoint == (size_t) (&_kernel_text_start)) {
|
||||
SerialPrintf("[ boot] Header at 0x%p matches kernel header.\r\n", headerLoc);
|
||||
flag = 1;
|
||||
// At this point, we've found the right ELF64 executable!
|
||||
// Great, now we can map it into the proper place
|
||||
KernelLocation = headerLoc;
|
||||
}
|
||||
|
||||
if(!flag) {
|
||||
|
||||
for(char i = 0; i < 64; i++) {
|
||||
SerialPrintf("[ boot] Header dump part %x: 0x%x\r\n", i, *((volatile uint8_t*)(headerLoc + i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return flag;
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user