mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-09 17:44:56 +09: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
Notes:
sideshowbarker
2024-07-19 18:45:05 +09:00
Author: https://github.com/awesomekling
Commit: b824f15619
10 changed files with 141 additions and 16 deletions
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Assertions.h"
|
||||||
#include "OwnPtr.h"
|
#include "OwnPtr.h"
|
||||||
#include "StdLib.h"
|
#include "StdLib.h"
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,9 @@ int puts(const char* str)
|
||||||
|
|
||||||
void ExecSpace::initializeBuiltins()
|
void ExecSpace::initializeBuiltins()
|
||||||
{
|
{
|
||||||
|
#ifndef SERENITY
|
||||||
m_symbols.set("puts", { (char*)puts, 0 });
|
m_symbols.set("puts", { (char*)puts, 0 });
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SERENITY
|
#ifdef SERENITY
|
||||||
|
@ -86,8 +88,13 @@ char* ExecSpace::symbolPtr(const char* name)
|
||||||
|
|
||||||
char* ExecSpace::allocateArea(String&& name, unsigned size)
|
char* ExecSpace::allocateArea(String&& name, unsigned size)
|
||||||
{
|
{
|
||||||
char* ptr = static_cast<char*>(kmalloc(size));
|
char* ptr;
|
||||||
ASSERT(ptr);
|
if (hookableAlloc)
|
||||||
|
ptr = static_cast<char*>(hookableAlloc(name, size));
|
||||||
|
else
|
||||||
|
ptr = static_cast<char*>(kmalloc(size));
|
||||||
|
if (size)
|
||||||
|
ASSERT(ptr);
|
||||||
m_areas.append(make<Area>(move(name), ptr, size));
|
m_areas.append(make<Area>(move(name), ptr, size));
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Function.h>
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
#include <AK/MappedFile.h>
|
#include <AK/MappedFile.h>
|
||||||
#include <AK/OwnPtr.h>
|
#include <AK/OwnPtr.h>
|
||||||
|
@ -37,6 +38,8 @@ public:
|
||||||
ExecSpace();
|
ExecSpace();
|
||||||
~ExecSpace();
|
~ExecSpace();
|
||||||
|
|
||||||
|
Function<void*(const String&, size_t)> hookableAlloc;
|
||||||
|
|
||||||
#ifdef SERENITY
|
#ifdef SERENITY
|
||||||
bool loadELF(ByteBuffer&&);
|
bool loadELF(ByteBuffer&&);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -161,20 +161,27 @@ bool MemoryManager::unmapRegionsForTask(Task& task)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MemoryManager::mapRegion(Task& task, Task::Region& region)
|
||||||
|
{
|
||||||
|
auto& zone = *region.zone;
|
||||||
|
for (size_t i = 0; i < zone.m_pages.size(); ++i) {
|
||||||
|
auto laddr = region.linearAddress.offset(i * PAGE_SIZE);
|
||||||
|
auto pte = ensurePTE(laddr);
|
||||||
|
pte.setPhysicalPageBase(zone.m_pages[i].get());
|
||||||
|
pte.setPresent(true);
|
||||||
|
pte.setWritable(true);
|
||||||
|
pte.setUserAllowed(!task.isRing0());
|
||||||
|
|
||||||
|
//kprintf("MM: >> Mapped L%x => P%x <<\n", laddr, zone.m_pages[i].get());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool MemoryManager::mapRegionsForTask(Task& task)
|
bool MemoryManager::mapRegionsForTask(Task& task)
|
||||||
{
|
{
|
||||||
for (auto& region : task.m_regions) {
|
for (auto& region : task.m_regions) {
|
||||||
auto& zone = *region->zone;
|
if (!mapRegion(task, *region))
|
||||||
for (size_t i = 0; i < zone.m_pages.size(); ++i) {
|
return false;
|
||||||
auto laddr = region->linearAddress.offset(i * PAGE_SIZE);
|
|
||||||
auto pte = ensurePTE(laddr);
|
|
||||||
pte.setPhysicalPageBase(zone.m_pages[i].get());
|
|
||||||
pte.setPresent(true);
|
|
||||||
pte.setWritable(true);
|
|
||||||
pte.setUserAllowed(!task.isRing0());
|
|
||||||
|
|
||||||
//kprintf("MM: >> Mapped L%x => P%x <<\n", laddr, zone.m_pages[i].get());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <AK/RetainPtr.h>
|
#include <AK/RetainPtr.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
|
#include "Task.h"
|
||||||
|
|
||||||
class Task;
|
class Task;
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@ public:
|
||||||
// HACK: don't use this jeez :(
|
// HACK: don't use this jeez :(
|
||||||
byte* quickMapOnePage(PhysicalAddress);
|
byte* quickMapOnePage(PhysicalAddress);
|
||||||
|
|
||||||
|
bool mapRegion(Task&, Task::Region&);
|
||||||
bool mapRegionsForTask(Task&);
|
bool mapRegionsForTask(Task&);
|
||||||
bool unmapRegionsForTask(Task&);
|
bool unmapRegionsForTask(Task&);
|
||||||
|
|
||||||
|
|
100
Kernel/Task.cpp
100
Kernel/Task.cpp
|
@ -7,6 +7,7 @@
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include <VirtualFileSystem/FileHandle.h>
|
#include <VirtualFileSystem/FileHandle.h>
|
||||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||||
|
#include <ELFLoader/ExecSpace.h>
|
||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
|
|
||||||
Task* current;
|
Task* current;
|
||||||
|
@ -103,6 +104,104 @@ Task::Region* Task::allocateRegion(size_t size, String&& name)
|
||||||
return m_regions.last().ptr();
|
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)
|
Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
|
||||||
: m_name(n)
|
: m_name(n)
|
||||||
, m_entry(e)
|
, 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);
|
kprintf("sys$exit: %s(%u) exit with status %d\n", name().characters(), pid(), status);
|
||||||
|
|
||||||
setState(Exiting);
|
setState(Exiting);
|
||||||
dumpRegions();
|
|
||||||
|
|
||||||
s_tasks->remove(this);
|
s_tasks->remove(this);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,9 @@ class Zone;
|
||||||
class Task : public InlineLinkedListNode<Task> {
|
class Task : public InlineLinkedListNode<Task> {
|
||||||
friend class InlineLinkedListNode<Task>;
|
friend class InlineLinkedListNode<Task>;
|
||||||
public:
|
public:
|
||||||
|
static Task* create(const String& path, uid_t, gid_t);
|
||||||
|
Task(String&& name, uid_t, gid_t);
|
||||||
|
|
||||||
#ifdef TASK_SANITY_CHECKS
|
#ifdef TASK_SANITY_CHECKS
|
||||||
static void checkSanity(const char* msg = nullptr);
|
static void checkSanity(const char* msg = nullptr);
|
||||||
#else
|
#else
|
||||||
|
|
Binary file not shown.
|
@ -27,7 +27,7 @@
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
|
|
||||||
#define TEST_VFS
|
#define TEST_VFS
|
||||||
#define TEST_ELF_LOADER
|
//#define TEST_ELF_LOADER
|
||||||
//#define TEST_CRASHY_USER_PROCESSES
|
//#define TEST_CRASHY_USER_PROCESSES
|
||||||
|
|
||||||
static void motd_main() NORETURN;
|
static void motd_main() NORETURN;
|
||||||
|
@ -167,6 +167,8 @@ static void init_stage2()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
auto* idTask = Task::create("/bin/id", (uid_t)209, (gid_t)1985);
|
||||||
|
|
||||||
//new Task(motd_main, "motd", IPC::Handle::MotdTask, Task::Ring0);
|
//new Task(motd_main, "motd", IPC::Handle::MotdTask, Task::Ring0);
|
||||||
//new Task(syscall_test_main, "syscall_test", IPC::Handle::MotdTask, Task::Ring3);
|
//new Task(syscall_test_main, "syscall_test", IPC::Handle::MotdTask, Task::Ring3);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,9 @@ extern "C" int main(int, char**);
|
||||||
extern "C" int _start()
|
extern "C" int _start()
|
||||||
{
|
{
|
||||||
// FIXME: Pass appropriate argc/argv.
|
// FIXME: Pass appropriate argc/argv.
|
||||||
main(0, nullptr);
|
int status = main(0, nullptr);
|
||||||
|
|
||||||
|
Syscall::invoke(Syscall::PosixExit, status);
|
||||||
|
|
||||||
// Birger's birthday <3
|
// Birger's birthday <3
|
||||||
return 20150614;
|
return 20150614;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue