93 lines
4.0 KiB
C
93 lines
4.0 KiB
C
#ifndef FROSTBYTE_ELF_H
|
|
#define FROSTBYTE_ELF_H
|
|
|
|
#include "types.h"
|
|
|
|
typedef struct Elf64Header {
|
|
uint8 ident[16];
|
|
uint16 type;
|
|
uint16 machine;
|
|
uint32 version;
|
|
uint64 entry;
|
|
uint64 programHeaderOffset;
|
|
uint64 sectionHeaderOffset;
|
|
uint32 flags;
|
|
uint16 headerSize;
|
|
uint16 programHeaderEntrySize;
|
|
uint16 programHeaderCount;
|
|
uint16 sectionHeaderEntrySize;
|
|
uint16 sectionHeaderCount;
|
|
uint16 sectionNameIndex;
|
|
} __attribute__((packed)) Elf64Header;
|
|
|
|
typedef struct Elf64ProgramHeader {
|
|
uint32 type;
|
|
uint32 flags;
|
|
uint64 offset;
|
|
uint64 virtualAddr;
|
|
uint64 physicalAddr;
|
|
uint64 fileSize;
|
|
uint64 memorySize;
|
|
uint64 align;
|
|
} __attribute__((packed)) Elf64ProgramHeader;
|
|
|
|
uint64 elfLoad(const void* image, uint64 imageSize);
|
|
|
|
/* Maps one ELF64 program header's p_flags (segmentFlags: standard PF_X=1/
|
|
PF_W=2/PF_R=4 bit values) onto the extra paging.h leaf-PTE bits
|
|
(pageWrite, pageNoExecute) elfLoad passes to pagingMapUserRangeExact for
|
|
that segment -- real per-segment W^X (a binary's own .text/.rodata ends
|
|
up read-only+executable, its .data/.bss read-write+non-executable)
|
|
instead of one blanket writable+executable range for the whole image.
|
|
Pure address-flag arithmetic, no paging/scheduler/VFS state touched, so
|
|
it is fully unit-testable (elfTest.c) the same way elfSlotBase and
|
|
friends already are. */
|
|
uint64 elfSegmentPagingFlags(uint32 segmentFlags);
|
|
|
|
/* Every userspace binary in this kernel is linked (Makefile --defsym
|
|
USER_BASE=...) at a fixed, elfSlotSize-aligned base of its own, since
|
|
there is one shared address space system-wide (no per-process page
|
|
tables/CR3) and no relocation support (-fno-pic): two binaries must
|
|
simply never overlap. kmain.c's boot-time spawnUser calls hardcode each
|
|
binary's stack/brk address following the same base+offset pattern by
|
|
hand; elfSlotStackTop/elfSlotBrkStart let syscall.c's exec()/spawn()
|
|
(a path resolved at runtime, not known at kmain.c's compile time)
|
|
derive the same addresses purely from the ELF's own entry point. */
|
|
#define elfSlotSize 0x10000000ull
|
|
#define elfSlotStackOffset 0x08000000ull
|
|
#define elfSlotBrkOffset 0x04000000ull
|
|
|
|
uint64 elfSlotBase(uint64 entry);
|
|
uint64 elfSlotStackTop(uint64 entry);
|
|
uint64 elfSlotBrkStart(uint64 entry);
|
|
|
|
/* Ceiling on argv entries any single exec()/spawn()/boot launch can pass
|
|
(syscall.c's copyUserArgv enforces the same bound while copying them out
|
|
of userspace). Chosen together with the 256-byte per-argument cap
|
|
syscall.c already uses for path-like strings so that
|
|
elfMaxArgs*256 + a few hundred bytes of pointers/argc never comes close
|
|
to execStackSize (syscall.c) or kmain.c's userStackSize -- both far
|
|
larger than any realistic argv list this kernel's own binaries pass. */
|
|
#define elfMaxArgs 16
|
|
|
|
/* Lays out a process's very first stack frame the way a real x86_64 SysV
|
|
process entry looks (used by user/crt.S's _start): from stackTop down,
|
|
the argument strings themselves, then (16-byte aligned per the ABI)
|
|
argc, argv[0..argc-1], and a NULL argv terminator -- *outRsp is where
|
|
_start should start executing with, pointing at argc.
|
|
argv/argc are already kernel-side data (copyUserArgv, doExec/doSpawn in
|
|
syscall.c, or a literal array for kmain.c's boot spawnUser) by the time
|
|
this runs; this function only ever writes into [stackTop-stackSize,
|
|
stackTop), which the caller must have already mapped (pagingMapUserRange)
|
|
-- same contract as elfLoad's segment writes.
|
|
Returns false, writing nothing, if argc is out of [0, elfMaxArgs] or the
|
|
strings plus the fixed-size argv/argc area do not fit in stackSize bytes
|
|
-- unreachable for every call site in this kernel today given the bound
|
|
above, but checked rather than assumed so a future caller with a bigger
|
|
argv (or a deliberately tiny stack in elfTest.c) fails cleanly instead of
|
|
silently writing before stackTop-stackSize. */
|
|
bool elfBuildInitialStack(uint64 stackTop, uint64 stackSize, const char* const* argv,
|
|
int argc, uint64* outRsp);
|
|
|
|
#endif
|