From b824f156197d8f2552442ecf0c8073ff28308941 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 22 Oct 2018 15:42:39 +0200 Subject: [PATCH] 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. --- AK/Function.h | 1 + ELFLoader/ExecSpace.cpp | 11 ++++- ELFLoader/ExecSpace.h | 3 ++ Kernel/MemoryManager.cpp | 29 +++++++----- Kernel/MemoryManager.h | 2 + Kernel/Task.cpp | 100 ++++++++++++++++++++++++++++++++++++++- Kernel/Task.h | 3 ++ Kernel/_fs_contents | Bin 1024000 -> 1024000 bytes Kernel/init.cpp | 4 +- LibC/entry.cpp | 4 +- 10 files changed, 141 insertions(+), 16 deletions(-) diff --git a/AK/Function.h b/AK/Function.h index 0fef35abe84..34a2bc68fc9 100644 --- a/AK/Function.h +++ b/AK/Function.h @@ -25,6 +25,7 @@ #pragma once +#include "Assertions.h" #include "OwnPtr.h" #include "StdLib.h" diff --git a/ELFLoader/ExecSpace.cpp b/ELFLoader/ExecSpace.cpp index fb6d55a0dde..cbcc8568a5e 100644 --- a/ELFLoader/ExecSpace.cpp +++ b/ELFLoader/ExecSpace.cpp @@ -22,7 +22,9 @@ int puts(const char* str) void ExecSpace::initializeBuiltins() { +#ifndef SERENITY m_symbols.set("puts", { (char*)puts, 0 }); +#endif } #ifdef SERENITY @@ -86,8 +88,13 @@ char* ExecSpace::symbolPtr(const char* name) char* ExecSpace::allocateArea(String&& name, unsigned size) { - char* ptr = static_cast(kmalloc(size)); - ASSERT(ptr); + char* ptr; + if (hookableAlloc) + ptr = static_cast(hookableAlloc(name, size)); + else + ptr = static_cast(kmalloc(size)); + if (size) + ASSERT(ptr); m_areas.append(make(move(name), ptr, size)); return ptr; } diff --git a/ELFLoader/ExecSpace.h b/ELFLoader/ExecSpace.h index 1e22468af43..432bf0a82ec 100644 --- a/ELFLoader/ExecSpace.h +++ b/ELFLoader/ExecSpace.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -37,6 +38,8 @@ public: ExecSpace(); ~ExecSpace(); + Function hookableAlloc; + #ifdef SERENITY bool loadELF(ByteBuffer&&); #else diff --git a/Kernel/MemoryManager.cpp b/Kernel/MemoryManager.cpp index 1d85aca254c..019242a741e 100644 --- a/Kernel/MemoryManager.cpp +++ b/Kernel/MemoryManager.cpp @@ -161,20 +161,27 @@ bool MemoryManager::unmapRegionsForTask(Task& task) 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) { for (auto& region : task.m_regions) { - 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()); - } + if (!mapRegion(task, *region)) + return false; } return true; } diff --git a/Kernel/MemoryManager.h b/Kernel/MemoryManager.h index 7c6910a5da1..a597280add0 100644 --- a/Kernel/MemoryManager.h +++ b/Kernel/MemoryManager.h @@ -6,6 +6,7 @@ #include #include #include +#include "Task.h" class Task; @@ -49,6 +50,7 @@ public: // HACK: don't use this jeez :( byte* quickMapOnePage(PhysicalAddress); + bool mapRegion(Task&, Task::Region&); bool mapRegionsForTask(Task&); bool unmapRegionsForTask(Task&); diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 96b5508564e..cab2b17ea65 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -7,6 +7,7 @@ #include "system.h" #include #include +#include #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); diff --git a/Kernel/Task.h b/Kernel/Task.h index eaf338b212c..2e230bf2ef3 100644 --- a/Kernel/Task.h +++ b/Kernel/Task.h @@ -16,6 +16,9 @@ class Zone; class Task : public InlineLinkedListNode { friend class InlineLinkedListNode; public: + static Task* create(const String& path, uid_t, gid_t); + Task(String&& name, uid_t, gid_t); + #ifdef TASK_SANITY_CHECKS static void checkSanity(const char* msg = nullptr); #else diff --git a/Kernel/_fs_contents b/Kernel/_fs_contents index fb6d9448f36ba6b201e761b0b70a326d0b1b8c3d..db5b3cfb2f3358430ca1cf5f1bad4fba1af69283 100644 GIT binary patch delta 295 zcmZoTVApWKZi5aB=dDX;qwfQ;z-ChxXGX?j8yVY~HgT|M^DziAFq9lU8+{KbdGAuQ zka4?^F(VK&0WmWWvj8zG5VLI;GG^!d$@pQrq7KJYHqOpNJ0?mpFr00ezRie3ar+G; zjs_-1x$Tjr9O5jDFQyk-a+EU)On+&~;m_zW-O`F9C+It_?9{F GCjbCa7+j$M delta 282 zcmZoTVApWKZi5aBXU@^H(Pco)zuA<