Cleanup loader and unify init and spawn paths.
This commit is contained in:
parent
1676ae4056
commit
1df34b2d2e
@ -56,6 +56,7 @@ typedef struct Process {
|
|||||||
uint64_t pid;
|
uint64_t pid;
|
||||||
AS *space;
|
AS *space;
|
||||||
Spinlock lock;
|
Spinlock lock;
|
||||||
|
uintptr_t entrypoint;
|
||||||
uint64_t nextThreadID;
|
uint64_t nextThreadID;
|
||||||
uintptr_t ustackNext; // Next user stack
|
uintptr_t ustackNext; // Next user stack
|
||||||
TAILQ_ENTRY(Process) processList;
|
TAILQ_ENTRY(Process) processList;
|
||||||
|
@ -19,6 +19,13 @@
|
|||||||
|
|
||||||
#include <sys/vfs.h>
|
#include <sys/vfs.h>
|
||||||
|
|
||||||
|
extern Handle *Console_OpenHandle();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loader_CheckHeader --
|
||||||
|
*
|
||||||
|
* Check that the program has a valid ELF header.
|
||||||
|
*/
|
||||||
bool
|
bool
|
||||||
Loader_CheckHeader(const Elf64_Ehdr *ehdr)
|
Loader_CheckHeader(const Elf64_Ehdr *ehdr)
|
||||||
{
|
{
|
||||||
@ -39,125 +46,15 @@ Loader_CheckHeader(const Elf64_Ehdr *ehdr)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
/*
|
||||||
Loader_LoadFirst(Thread *thr, VNode *vn, void *buf, uint64_t len)
|
* LoaderLoadSegment --
|
||||||
{
|
*
|
||||||
int i;
|
* Loads a single segment into the target address space. This function
|
||||||
const Elf64_Ehdr *ehdr;
|
* loads a single page at a time because it has to lookup the address
|
||||||
const Elf64_Phdr *phdr;
|
* mappings through the page tables.
|
||||||
AS *as = thr->space;
|
*/
|
||||||
|
static void
|
||||||
ehdr = (const Elf64_Ehdr *)(buf);
|
LoaderLoadSegment(AS *as, VNode *vn, uintptr_t vaddr,
|
||||||
phdr = (const Elf64_Phdr *)(buf + ehdr->e_phoff);
|
|
||||||
|
|
||||||
if (!Loader_CheckHeader(ehdr)) {
|
|
||||||
Log(loader, "Not a valid executable!\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log(loader, "%8s %16s %8s %8s\n", "Offset", "VAddr", "FileSize", "MemSize");
|
|
||||||
for (i = 0; i < ehdr->e_phnum; i++)
|
|
||||||
{
|
|
||||||
ASSERT(phdr[i].p_type != PT_DYNAMIC);
|
|
||||||
if (phdr[i].p_type == PT_LOAD) {
|
|
||||||
uint64_t va = phdr[i].p_vaddr;
|
|
||||||
uint64_t memsz = phdr[i].p_memsz;
|
|
||||||
Log(loader, "%08llx %016llx %08llx %08llx\n", phdr[i].p_offset,
|
|
||||||
phdr[i].p_vaddr, phdr[i].p_filesz, phdr[i].p_memsz);
|
|
||||||
|
|
||||||
// Make sure it is page aligned
|
|
||||||
va = va & ~(uint64_t)PGMASK;
|
|
||||||
memsz += phdr[i].p_vaddr - va;
|
|
||||||
|
|
||||||
Log(loader, "AllocMap %016llx %08llx\n", va, memsz);
|
|
||||||
if (!PMap_AllocMap(as, va, memsz, PTE_W)) {
|
|
||||||
// XXX: Cleanup!
|
|
||||||
ASSERT(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PMap_AllocMap(as, MEM_USERSPACE_STKBASE, MEM_USERSPACE_STKLEN, PTE_W);
|
|
||||||
PMap_LoadAS(as); // Reload CR3
|
|
||||||
|
|
||||||
for (i = 0; i < ehdr->e_phnum; i++)
|
|
||||||
{
|
|
||||||
ASSERT(phdr[i].p_type != PT_DYNAMIC);
|
|
||||||
if (phdr[i].p_type == PT_LOAD) {
|
|
||||||
if (phdr[i].p_filesz != 0) {
|
|
||||||
Log(loader, "Read %lx %lx %lx\n", phdr[i].p_vaddr, phdr[i].p_offset, phdr[i].p_filesz);
|
|
||||||
VFS_Read(vn, (void *)phdr[i].p_vaddr,
|
|
||||||
phdr[i].p_offset, phdr[i].p_filesz);
|
|
||||||
}
|
|
||||||
memset((void *)(phdr[i].p_vaddr + phdr[i].p_filesz),
|
|
||||||
0,
|
|
||||||
(uintptr_t)(phdr[i].p_memsz - phdr[i].p_filesz));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log(loader, "Jumping to userspace\n");
|
|
||||||
|
|
||||||
uintptr_t ap[3];
|
|
||||||
ap[0] = 0;
|
|
||||||
ap[1] = 0;
|
|
||||||
ap[2] = 0xDEADBEEF;
|
|
||||||
uintptr_t rsp = MEM_USERSPACE_STKTOP - PGSIZE;
|
|
||||||
|
|
||||||
Copy_Out(&ap[0], rsp, sizeof(uintptr_t)*3);
|
|
||||||
|
|
||||||
TrapFrame tf;
|
|
||||||
memset(&tf, 0, sizeof(tf));
|
|
||||||
tf.ds = SEL_UDS | 3;
|
|
||||||
tf.rip = ehdr->e_entry;
|
|
||||||
tf.cs = SEL_UCS | 3;
|
|
||||||
tf.rsp = rsp;
|
|
||||||
tf.ss = SEL_UDS | 3;
|
|
||||||
tf.rflags = RFLAGS_IF;
|
|
||||||
tf.rdi = rsp;
|
|
||||||
Trap_Pop(&tf);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle *Console_OpenHandle();
|
|
||||||
|
|
||||||
void
|
|
||||||
Loader_LoadInit()
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
void *pg;
|
|
||||||
VNode *init;
|
|
||||||
|
|
||||||
pg = PAlloc_AllocPage();
|
|
||||||
if (!pg)
|
|
||||||
Panic("Not enough memory!");
|
|
||||||
|
|
||||||
init = VFS_Lookup("/sbin/init");
|
|
||||||
status = VFS_Open(init);
|
|
||||||
if (status < 0)
|
|
||||||
Panic("Loading init process failed!");
|
|
||||||
status = VFS_Read(init, pg, 0, 1024);
|
|
||||||
if (status < 0)
|
|
||||||
Panic("Reading init process failed!");
|
|
||||||
|
|
||||||
Thread *thr = Sched_Current();
|
|
||||||
|
|
||||||
// Open stdin/out/err
|
|
||||||
Handle *handle = Console_OpenHandle();
|
|
||||||
Handle_Add(thr->proc, handle);
|
|
||||||
handle = Console_OpenHandle();
|
|
||||||
Handle_Add(thr->proc, handle);
|
|
||||||
handle = Console_OpenHandle();
|
|
||||||
Handle_Add(thr->proc, handle);
|
|
||||||
|
|
||||||
Loader_LoadFirst(thr, init, pg, 1024);
|
|
||||||
|
|
||||||
VFS_Close(init);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
LoaderFileHelper(AS *as, VNode *vn, uintptr_t vaddr,
|
|
||||||
uintptr_t offset, uintptr_t len)
|
uintptr_t offset, uintptr_t len)
|
||||||
{
|
{
|
||||||
void *raddr;
|
void *raddr;
|
||||||
@ -187,8 +84,14 @@ LoaderFileHelper(AS *as, VNode *vn, uintptr_t vaddr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/*
|
||||||
LoaderZeroHelper(AS *as, uintptr_t vaddr, uintptr_t len)
|
* LoaderZeroSegment --
|
||||||
|
*
|
||||||
|
* Zeroes a segment of memory in the target address space. This is done
|
||||||
|
* one page a time while translating the virtual address to physical.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
LoaderZeroSegment(AS *as, uintptr_t vaddr, uintptr_t len)
|
||||||
{
|
{
|
||||||
void *raddr;
|
void *raddr;
|
||||||
|
|
||||||
@ -215,6 +118,11 @@ LoaderZeroHelper(AS *as, uintptr_t vaddr, uintptr_t len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loader_Load --
|
||||||
|
*
|
||||||
|
* Load the ELF binary into the process belonging to the thread.
|
||||||
|
*/
|
||||||
bool
|
bool
|
||||||
Loader_Load(Thread *thr, VNode *vn, void *buf, uint64_t len)
|
Loader_Load(Thread *thr, VNode *vn, void *buf, uint64_t len)
|
||||||
{
|
{
|
||||||
@ -261,17 +169,101 @@ Loader_Load(Thread *thr, VNode *vn, void *buf, uint64_t len)
|
|||||||
ASSERT(phdr[i].p_type != PT_DYNAMIC);
|
ASSERT(phdr[i].p_type != PT_DYNAMIC);
|
||||||
if (phdr[i].p_type == PT_LOAD) {
|
if (phdr[i].p_type == PT_LOAD) {
|
||||||
if (phdr[i].p_filesz != 0) {
|
if (phdr[i].p_filesz != 0) {
|
||||||
LoaderFileHelper(as, vn, phdr[i].p_vaddr,
|
LoaderLoadSegment(as, vn, phdr[i].p_vaddr,
|
||||||
phdr[i].p_offset, phdr[i].p_filesz);
|
phdr[i].p_offset, phdr[i].p_filesz);
|
||||||
}
|
}
|
||||||
LoaderZeroHelper(as,
|
LoaderZeroSegment(as,
|
||||||
phdr[i].p_vaddr + phdr[i].p_filesz,
|
phdr[i].p_vaddr + phdr[i].p_filesz,
|
||||||
phdr[i].p_memsz - phdr[i].p_filesz);
|
phdr[i].p_memsz - phdr[i].p_filesz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread_SetupUThread(thr, ehdr->e_entry, MEM_USERSPACE_STKTOP - PGSIZE);
|
/* Save the process entry point (i.e., _start) */
|
||||||
|
thr->proc->entrypoint = ehdr->e_entry;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loader_LoadInit --
|
||||||
|
*
|
||||||
|
* The init process is created from the execution kernel thread that
|
||||||
|
* initializes the system. This function initializes the thread and
|
||||||
|
* process state then loads the init binary.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Loader_LoadInit()
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
void *pg;
|
||||||
|
VNode *initvn;
|
||||||
|
|
||||||
|
pg = PAlloc_AllocPage();
|
||||||
|
if (!pg)
|
||||||
|
Panic("Not enough memory!");
|
||||||
|
|
||||||
|
initvn = VFS_Lookup("/sbin/init");
|
||||||
|
status = VFS_Open(initvn);
|
||||||
|
if (status < 0)
|
||||||
|
Panic("Loading init process failed!");
|
||||||
|
status = VFS_Read(initvn, pg, 0, 1024);
|
||||||
|
if (status < 0)
|
||||||
|
Panic("Reading init process failed!");
|
||||||
|
|
||||||
|
Thread *thr = Sched_Current();
|
||||||
|
|
||||||
|
// Open stdin/out/err
|
||||||
|
Handle *handle = Console_OpenHandle();
|
||||||
|
Handle_Add(thr->proc, handle);
|
||||||
|
handle = Console_OpenHandle();
|
||||||
|
Handle_Add(thr->proc, handle);
|
||||||
|
handle = Console_OpenHandle();
|
||||||
|
Handle_Add(thr->proc, handle);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load init binary
|
||||||
|
*/
|
||||||
|
Loader_Load(thr, initvn, pg, 1024);
|
||||||
|
|
||||||
|
VFS_Close(initvn);
|
||||||
|
|
||||||
|
Log(loader, "Jumping to userspace\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reload the page tables for the current process
|
||||||
|
*/
|
||||||
|
PMap_LoadAS(thr->space); // Reload CR3
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pass in zero arguments with null pointers to init
|
||||||
|
*/
|
||||||
|
uintptr_t ap[3];
|
||||||
|
ap[0] = 0;
|
||||||
|
ap[1] = 0;
|
||||||
|
ap[2] = 0xDEADBEEF;
|
||||||
|
uintptr_t rsp = MEM_USERSPACE_STKTOP - PGSIZE;
|
||||||
|
|
||||||
|
Copy_Out(&ap[0], rsp, sizeof(uintptr_t)*3);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The last step is to return into userspace handing control to init. We
|
||||||
|
* create a valid trap frame and return into userspace using Trap_Pop().
|
||||||
|
*/
|
||||||
|
TrapFrame tf;
|
||||||
|
memset(&tf, 0, sizeof(tf));
|
||||||
|
tf.ds = SEL_UDS | 3;
|
||||||
|
tf.rip = thr->proc->entrypoint;
|
||||||
|
tf.cs = SEL_UCS | 3;
|
||||||
|
tf.rsp = rsp;
|
||||||
|
tf.ss = SEL_UDS | 3;
|
||||||
|
tf.rflags = RFLAGS_IF;
|
||||||
|
tf.rdi = rsp;
|
||||||
|
Trap_Pop(&tf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We should never reach this point!
|
||||||
|
*/
|
||||||
|
Panic("Unreachable: Trap_Pop() returned!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,6 +168,9 @@ Syscall_Spawn(uint64_t user_path, uint64_t user_argv)
|
|||||||
|
|
||||||
Loader_Load(thr, file, pg, 1024);
|
Loader_Load(thr, file, pg, 1024);
|
||||||
|
|
||||||
|
/* Initialize the trap frame for entering into the process. */
|
||||||
|
Thread_SetupUThread(thr, proc->entrypoint, MEM_USERSPACE_STKTOP - PGSIZE);
|
||||||
|
|
||||||
/* Translate mapping for stack page */
|
/* Translate mapping for stack page */
|
||||||
argstart = (char *)DMPA2VA(PMap_Translate(thr->space, MEM_USERSPACE_STKTOP - PGSIZE));
|
argstart = (char *)DMPA2VA(PMap_Translate(thr->space, MEM_USERSPACE_STKTOP - PGSIZE));
|
||||||
argstart += sizeof(uintptr_t)*8;
|
argstart += sizeof(uintptr_t)*8;
|
||||||
|
Loading…
Reference in New Issue
Block a user