mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 03:27:44 +00:00
Launching an arbitrary ELF executable from disk works! :^)
This is so cool! It's a bit messy now with two Task constructors, but eventually they should fold into a single constructor somehow.
This commit is contained in:
parent
befeabd8fe
commit
b824f15619
10 changed files with 141 additions and 16 deletions
100
Kernel/Task.cpp
100
Kernel/Task.cpp
|
@ -7,6 +7,7 @@
|
|||
#include "system.h"
|
||||
#include <VirtualFileSystem/FileHandle.h>
|
||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||
#include <ELFLoader/ExecSpace.h>
|
||||
#include "MemoryManager.h"
|
||||
|
||||
Task* current;
|
||||
|
@ -103,6 +104,104 @@ Task::Region* Task::allocateRegion(size_t size, String&& name)
|
|||
return m_regions.last().ptr();
|
||||
}
|
||||
|
||||
Task* Task::create(const String& path, uid_t uid, gid_t gid)
|
||||
{
|
||||
auto parts = path.split('/');
|
||||
if (parts.isEmpty())
|
||||
return nullptr;
|
||||
|
||||
auto handle = VirtualFileSystem::the().open(path);
|
||||
if (!handle)
|
||||
return nullptr;
|
||||
|
||||
auto elfData = handle->readEntireFile();
|
||||
if (!elfData)
|
||||
return nullptr;
|
||||
|
||||
Task* t = new Task(parts.takeLast(), uid, gid);
|
||||
|
||||
ExecSpace space;
|
||||
space.hookableAlloc = [&] (const String& name, size_t size) {
|
||||
if (!size)
|
||||
return (void*)nullptr;
|
||||
size = ((size / 4096) + 1) * 4096;
|
||||
Region* region = t->allocateRegion(size, String(name));
|
||||
ASSERT(region);
|
||||
MemoryManager::the().mapRegion(*t, *region);
|
||||
return (void*)region->linearAddress.asPtr();
|
||||
};
|
||||
bool success = space.loadELF(move(elfData));
|
||||
if (!success) {
|
||||
delete t;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
t->m_tss.eip = (dword)space.symbolPtr("_start");
|
||||
|
||||
// Add this task to head of task list (meaning it's next to run too, ATM.)
|
||||
cli();
|
||||
s_tasks->prepend(t);
|
||||
system.nprocess++;
|
||||
kprintf("Task %u (%s) spawned @ %p\n", t->pid(), t->name().characters(), t->m_tss.eip);
|
||||
sti();
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Task::Task(String&& name, uid_t uid, gid_t gid)
|
||||
: m_name(move(name))
|
||||
, m_pid(next_pid++)
|
||||
, m_uid(uid)
|
||||
, m_gid(gid)
|
||||
, m_state(Runnable)
|
||||
, m_ring(Ring3)
|
||||
{
|
||||
m_nextRegion = LinearAddress(0x600000);
|
||||
|
||||
memset(&m_tss, 0, sizeof(m_tss));
|
||||
memset(&m_ldtEntries, 0, sizeof(m_ldtEntries));
|
||||
|
||||
allocateLDT();
|
||||
|
||||
// Only IF is set when a task boots.
|
||||
m_tss.eflags = 0x0202;
|
||||
|
||||
WORD codeSegment = 0x1b;
|
||||
WORD dataSegment = 0x23;
|
||||
WORD stackSegment = dataSegment;
|
||||
|
||||
m_tss.ds = dataSegment;
|
||||
m_tss.es = dataSegment;
|
||||
m_tss.fs = dataSegment;
|
||||
m_tss.gs = dataSegment;
|
||||
m_tss.ss = stackSegment;
|
||||
m_tss.cs = codeSegment;
|
||||
|
||||
m_tss.cr3 = MemoryManager::the().pageDirectoryBase().get();
|
||||
|
||||
// NOTE: Each task gets 16KB of stack.
|
||||
static const DWORD defaultStackSize = 16384;
|
||||
|
||||
auto* region = allocateRegion(defaultStackSize, "stack");
|
||||
ASSERT(region);
|
||||
m_stackTop = region->linearAddress.offset(defaultStackSize).get() & 0xfffffff8;
|
||||
m_tss.esp = m_stackTop;
|
||||
|
||||
// Set up a separate stack for Ring0.
|
||||
// FIXME: Don't leak this stack.
|
||||
m_kernelStack = kmalloc(defaultStackSize);
|
||||
DWORD ring0StackTop = ((DWORD)m_kernelStack + defaultStackSize) & 0xffffff8;
|
||||
m_tss.ss0 = 0x10;
|
||||
m_tss.esp0 = ring0StackTop;
|
||||
|
||||
// HACK: Ring2 SS in the TSS is the current PID.
|
||||
m_tss.ss2 = m_pid;
|
||||
|
||||
m_farPtr.offset = 0x98765432;
|
||||
|
||||
ASSERT(m_pid);
|
||||
}
|
||||
|
||||
Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
|
||||
: m_name(n)
|
||||
, m_entry(e)
|
||||
|
@ -241,7 +340,6 @@ void Task::sys$exit(int status)
|
|||
kprintf("sys$exit: %s(%u) exit with status %d\n", name().characters(), pid(), status);
|
||||
|
||||
setState(Exiting);
|
||||
dumpRegions();
|
||||
|
||||
s_tasks->remove(this);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue