Forráskód Böngészése

Implement loading of linked ELF executables.

This took me a couple hours. :^)

The ELF loading code now allocates a single region for the entire
file and creates virtual memory mappings for the sections as needed.

Very nice!
Andreas Kling 6 éve
szülő
commit
9a71c7759a

+ 12 - 0
ELFLoader/ELFImage.h

@@ -67,6 +67,7 @@ public:
         unsigned size() const { return m_sectionHeader.sh_size; }
         unsigned entrySize() const { return m_sectionHeader.sh_entsize; }
         unsigned entryCount() const { return size() / entrySize(); }
+        dword address() const { return m_sectionHeader.sh_addr; }
         const char* rawData() const { return m_image.rawData(m_sectionHeader.sh_offset); }
         bool isUndefined() const { return m_sectionIndex == SHN_UNDEF; }
         const RelocationSection relocations() const;
@@ -115,6 +116,7 @@ public:
     const Symbol symbol(unsigned) const;
     const Section section(unsigned) const;
 
+    template<typename F> void forEachSection(F) const;
     template<typename F> void forEachSectionOfType(unsigned, F) const;
     template<typename F> void forEachSymbol(F) const;
 
@@ -122,6 +124,9 @@ public:
     // FIXME: I don't love this API.
     const Section lookupSection(const char* name) const;
 
+    bool isExecutable() const { return header().e_type == ET_EXEC; }
+    bool isRelocatable() const { return header().e_type == ET_REL; }
+
 private:
     bool parseHeader();
     const char* rawData(unsigned offset) const;
@@ -142,6 +147,13 @@ private:
     unsigned m_stringTableSectionIndex { 0 };
 };
 
+template<typename F>
+inline void ELFImage::forEachSection(F func) const
+{
+    for (unsigned i = 0; i < sectionCount(); ++i)
+        func(section(i));
+}
+
 template<typename F>
 inline void ELFImage::forEachSectionOfType(unsigned type, F func) const
 {

+ 25 - 4
ELFLoader/ELFLoader.cpp

@@ -40,13 +40,26 @@ bool ELFLoader::layout()
     kprintf("[ELFLoader] Layout\n");
 #endif
     bool failed = false;
+    dword highestOffset = 0;
+    dword sizeNeeded = 0;
+    m_image->forEachSection([&] (auto& section) {
+        if (section.offset() > highestOffset) {
+            highestOffset = section.offset();
+            sizeNeeded = highestOffset + section.size();
+        }
+    });
+#ifdef ELFLOADER_DEBUG
+    kprintf("[ELFLoader] Highest section offset: %u, Size needed: %u\n", highestOffset, sizeNeeded);
+#endif
+    m_execSpace.allocateUniverse(sizeNeeded);
+
     m_image->forEachSectionOfType(SHT_PROGBITS, [this, &failed] (const ELFImage::Section& section) {
 #ifdef ELFLOADER_DEBUG
         kprintf("[ELFLoader] Allocating progbits section: %s\n", section.name());
 #endif
         if (!section.size())
             return true;
-        char* ptr = m_execSpace.allocateArea(section.name(), section.size());
+        char* ptr = m_execSpace.allocateArea(section.name(), section.size(), section.offset(), LinearAddress(section.address()));
         if (!ptr) {
             kprintf("ELFLoader: failed to allocate section '%s'\n", section.name());
             failed = true;
@@ -62,7 +75,7 @@ bool ELFLoader::layout()
 #endif
         if (!section.size())
             return true;
-        char* ptr = m_execSpace.allocateArea(section.name(), section.size());
+        char* ptr = m_execSpace.allocateArea(section.name(), section.size(), section.offset(), LinearAddress(section.address()));
         if (!ptr) {
             kprintf("ELFLoader: failed to allocate section '%s'\n", section.name());
             failed = true;
@@ -163,8 +176,16 @@ void ELFLoader::exportSymbols()
 #ifdef ELFLOADER_DEBUG
         kprintf("symbol: %u, type=%u, name=%s, section=%u\n", symbol.index(), symbol.type(), symbol.name(), symbol.sectionIndex());
 #endif
-        if (symbol.type() == STT_FUNC)
-            m_execSpace.addSymbol(symbol.name(), areaForSection(symbol.section()) + symbol.value(), symbol.size());
+        if (symbol.type() == STT_FUNC) {
+            char* ptr;
+            if (m_image->isExecutable())
+                ptr = (char*)symbol.value();
+            else if (m_image->isRelocatable())
+                ptr = areaForSection(symbol.section()) + symbol.value();
+            else
+                ASSERT_NOT_REACHED();
+            m_execSpace.addSymbol(symbol.name(), ptr, symbol.size());
+        }
         // FIXME: What about other symbol types?
         return true;
     });

+ 19 - 7
ELFLoader/ExecSpace.cpp

@@ -101,19 +101,31 @@ char* ExecSpace::symbolPtr(const char* name)
     return nullptr;
 }
 
-char* ExecSpace::allocateArea(String&& name, unsigned size)
+void ExecSpace::allocateUniverse(size_t size)
 {
-    char* ptr;
+    ASSERT(!m_universe);
     if (hookableAlloc)
-        ptr = static_cast<char*>(hookableAlloc(name, size));
+        m_universe = static_cast<char*>(hookableAlloc("elf-sec", size));
     else
-        ptr = static_cast<char*>(kmalloc(size));
-    if (size)
-        ASSERT(ptr);
-    m_areas.append(make<Area>(move(name), ptr, size));
+        m_universe = static_cast<char*>(kmalloc(size));
+}
+
+char* ExecSpace::allocateArea(String&& name, unsigned size, dword offset, LinearAddress laddr)
+{
+    ASSERT(m_universe);
+    char* ptr = m_universe + offset;
+    m_areas.append(make<Area>(move(name), offset, ptr, size, laddr));
     return ptr;
 }
 
+void ExecSpace::forEachArea(Function<void(const String& name, dword offset, size_t size, LinearAddress)> callback)
+{
+    for (auto& a : m_areas) {
+        auto& area = *a;
+        callback(area.name, area.offset, area.size, area.laddr);
+    }
+}
+
 void ExecSpace::addSymbol(String&& name, char* ptr, unsigned size)
 {
     m_symbols.set(move(name), { ptr, size });

+ 11 - 2
ELFLoader/ExecSpace.h

@@ -11,16 +11,20 @@ class ELFLoader;
 class ExecSpace {
 public:
     struct Area {
-        Area(String&& n, char* m, unsigned s)
+        Area(String&& n, dword o, char* m, unsigned s, LinearAddress l)
             : name(move(n))
+            , offset(o)
             , memory(m)
             , size(s)
+            , laddr(l)
         {
         }
 
         String name;
+        dword offset { 0 };
         char* memory { 0 };
         unsigned size { 0 };
+        LinearAddress laddr;
     };
 
     struct PtrAndSize {
@@ -48,13 +52,18 @@ public:
 
     char* symbolPtr(const char* name);
 
-    char* allocateArea(String&& name, unsigned size);
+    char* allocateArea(String&& name, unsigned size, dword offset, LinearAddress);
     void addSymbol(String&& name, char* ptr, unsigned size);
 
+    void allocateUniverse(size_t);
+
+    void forEachArea(Function<void(const String& name, dword offset, size_t size, LinearAddress)>);
+
 private:
     void initializeBuiltins();
 
     Vector<OwnPtr<Area>> m_areas;
     HashMap<String, PtrAndSize> m_symbols;
+    char* m_universe { nullptr };
 };
 

+ 2 - 4
Kernel/Makefile

@@ -55,8 +55,7 @@ ARCH_FLAGS =
 STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib
 KERNEL_FLAGS = -ffreestanding -fno-stack-protector -fno-ident
 WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings
-FLAVOR_FLAGS = -mregparm=3 -march=i386 -m32 -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -fmerge-all-constants -fno-unroll-loops -falign-functions=1 -falign-jumps=1 -falign-loops=1 -fno-pie -fno-pic
-#FLAVOR_FLAGS = -mregparm=3 -march=i386 -m32 -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections
+FLAVOR_FLAGS = -mregparm=3 -march=i386 -m32 -fno-exceptions -fno-rtti -fmerge-all-constants -fno-unroll-loops -fno-pie -fno-pic
 OPTIMIZATION_FLAGS = -Os -fno-asynchronous-unwind-tables
 INCLUDE_FLAGS = -I.. -I.
 
@@ -65,11 +64,10 @@ DEFINES = -DSERENITY -DSANITIZE_PTRS
 CXXFLAGS = $(WARNING_FLAGS) $(OPTIMIZATION_FLAGS) $(KERNEL_FLAGS) $(FLAVOR_FLAGS) $(ARCH_FLAGS) $(STANDARD_FLAGS) $(INCLUDE_FLAGS) $(DEFINES)
 #CXX = /usr/local/gcc-4.8.1-for-linux64/bin/x86_64-pc-linux-g++
 #LD = /usr/local/gcc-4.8.1-for-linux64/bin/x86_64-pc-linux-ld
-CXX = g++
+CXX = g++-8
 LD = ld
 LDFLAGS = -T linker.ld --strip-debug -melf_i386 --gc-sections --build-id=none -z norelro -z now
 
-
 all: $(KERNEL) $(IMAGE) kernel.map
 
 kernel.map: kernel

+ 69 - 7
Kernel/MemoryManager.cpp

@@ -8,7 +8,7 @@
 
 static MemoryManager* s_the;
 
-MemoryManager& MemoryManager::the()
+MemoryManager& MM
 {
     return *s_the;
 }
@@ -43,8 +43,8 @@ void MemoryManager::initializePaging()
 
     identityMap(LinearAddress(4096), 4 * MB);
  
-    // Put pages between 4MB and 16MB in the page freelist.
-    for (size_t i = (4 * MB) + 1024; i < (16 * MB); i += PAGE_SIZE) {
+    // Put pages between 4MB and 8MB in the page freelist.
+    for (size_t i = (4 * MB) + PAGE_SIZE; i < (8 * MB); i += PAGE_SIZE) {
         m_freePages.append(PhysicalAddress(i));
     }
 
@@ -56,6 +56,14 @@ void MemoryManager::initializePaging()
     );
 }
 
+void* MemoryManager::allocatePageTable()
+{
+    auto ppages = allocatePhysicalPages(1);
+    dword address = ppages[0].get();
+    identityMap(LinearAddress(address), 4096);
+    return (void*)address;
+}
+
 auto MemoryManager::ensurePTE(LinearAddress linearAddress) -> PageTableEntry
 {
     ASSERT_INTERRUPTS_DISABLED();
@@ -76,8 +84,13 @@ auto MemoryManager::ensurePTE(LinearAddress linearAddress) -> PageTableEntry
             pde.setPresent(true);
             pde.setWritable(true);
         } else {
-            // FIXME: We need an allocator!
-            ASSERT_NOT_REACHED();
+            auto* pageTable = allocatePageTable();
+            kprintf("allocated page table %u (for laddr=%p) at %p\n", pageDirectoryIndex, linearAddress.get(), pageTable);
+            memset(pageTable, 0, 4096);
+            pde.setPageTableBase((dword)pageTable);
+            pde.setUserAllowed(true);
+            pde.setPresent(true);
+            pde.setWritable(true);
         }
     }
     return PageTableEntry(&pde.pageTableBase()[pageTableIndex]);
@@ -190,7 +203,27 @@ bool MemoryManager::unmapRegion(Task& task, Task::Region& region)
         pte.setWritable(false);
         pte.setUserAllowed(false);
         flushTLB(laddr);
-//        kprintf("MM: >> Unmapped L%x => P%x <<\n", laddr, zone.m_pages[i].get());
+        //kprintf("MM: >> Unmapped L%x => P%x <<\n", laddr, zone.m_pages[i].get());
+    }
+    return true;
+}
+
+bool MemoryManager::unmapSubregion(Task& task, Task::Subregion& subregion)
+{
+    InterruptDisabler disabler;
+    auto& region = *subregion.region;
+    auto& zone = *region.zone;
+    size_t numPages = subregion.size / 4096;
+    ASSERT(numPages);
+    for (size_t i = 0; i < numPages; ++i) {
+        auto laddr = subregion.linearAddress.offset(i * PAGE_SIZE);
+        auto pte = ensurePTE(laddr);
+        pte.setPhysicalPageBase(0);
+        pte.setPresent(false);
+        pte.setWritable(false);
+        pte.setUserAllowed(false);
+        flushTLB(laddr);
+        //kprintf("MM: >> Unmapped subregion %s L%x => P%x <<\n", subregion.name.characters(), laddr, zone.m_pages[i].get());
     }
     return true;
 }
@@ -202,6 +235,31 @@ bool MemoryManager::unmapRegionsForTask(Task& task)
         if (!unmapRegion(task, *region))
             return false;
     }
+    for (auto& subregion : task.m_subregions) {
+        if (!unmapSubregion(task, *subregion))
+            return false;
+    }
+    return true;
+}
+
+bool MemoryManager::mapSubregion(Task& task, Task::Subregion& subregion)
+{
+    InterruptDisabler disabler;
+    auto& region = *subregion.region;
+    auto& zone = *region.zone;
+    size_t firstPage = subregion.offset / 4096;
+    size_t numPages = subregion.size / 4096;
+    ASSERT(numPages);
+    for (size_t i = 0; i < numPages; ++i) {
+        auto laddr = subregion.linearAddress.offset(i * PAGE_SIZE);
+        auto pte = ensurePTE(laddr);
+        pte.setPhysicalPageBase(zone.m_pages[firstPage + i].get());
+        pte.setPresent(true);
+        pte.setWritable(true);
+        pte.setUserAllowed(!task.isRing0());
+        flushTLB(laddr);
+        //kprintf("MM: >> Mapped subregion %s L%x => P%x (%u into region)<<\n", subregion.name.characters(), laddr, zone.m_pages[firstPage + i].get(), subregion.offset);
+    }
     return true;
 }
 
@@ -229,6 +287,10 @@ bool MemoryManager::mapRegionsForTask(Task& task)
         if (!mapRegion(task, *region))
             return false;
     }
+    for (auto& subregion : task.m_subregions) {
+        if (!mapSubregion(task, *subregion))
+            return false;
+    }
     return true;
 }
 
@@ -243,7 +305,7 @@ bool copyToZone(Zone& zone, const void* data, size_t size)
     auto* dataptr = (const byte*)data;
     size_t remaining = size;
     for (size_t i = 0; i < zone.m_pages.size(); ++i) {
-        byte* dest = MemoryManager::the().quickMapOnePage(zone.m_pages[i]);
+        byte* dest = MM.quickMapOnePage(zone.m_pages[i]);
         kprintf("memcpy(%p, %p, %u)\n", dest, dataptr, min(PAGE_SIZE, remaining));
         memcpy(dest, dataptr, min(PAGE_SIZE, remaining));
         dataptr += PAGE_SIZE;

+ 9 - 0
Kernel/MemoryManager.h

@@ -35,6 +35,8 @@ private:
 
 bool copyToZone(Zone&, const void* data, size_t);
 
+#define MM MemoryManager::the()
+
 class MemoryManager {
 public:
     static MemoryManager& the() PURE;
@@ -50,6 +52,11 @@ public:
     // HACK: don't use this jeez :(
     byte* quickMapOnePage(PhysicalAddress);
 
+    bool mapSubregion(Task&, Task::Subregion&);
+    bool unmapSubregion(Task&, Task::Subregion&);
+    bool mapSubregionsForTask(Task&);
+    bool unmapSubregionsForTask(Task&);
+
     bool mapRegion(Task&, Task::Region&);
     bool unmapRegion(Task&, Task::Region&);
     bool mapRegionsForTask(Task&);
@@ -63,6 +70,8 @@ private:
     void flushEntireTLB();
     void flushTLB(LinearAddress);
 
+    void* allocatePageTable();
+
     void protectMap(LinearAddress, size_t length);
     void identityMap(LinearAddress, size_t length);
 

+ 4 - 4
Kernel/ProcFileSystem.cpp

@@ -49,8 +49,8 @@ ByteBuffer procfs$pid_stack(Task& task)
 {
     InterruptDisabler disabler;
     if (current != &task) {
-        MemoryManager::the().unmapRegionsForTask(*current);
-        MemoryManager::the().mapRegionsForTask(task);
+        MM.unmapRegionsForTask(*current);
+        MM.mapRegionsForTask(task);
     }
     struct RecognizedSymbol {
         dword address;
@@ -78,8 +78,8 @@ ByteBuffer procfs$pid_stack(Task& task)
     }
     buffer.trim(bufptr - (char*)buffer.pointer());
     if (current != &task) {
-        MemoryManager::the().unmapRegionsForTask(task);
-        MemoryManager::the().mapRegionsForTask(*current);
+        MM.unmapRegionsForTask(task);
+        MM.mapRegionsForTask(*current);
     }
     return buffer;
 }

+ 65 - 18
Kernel/Task.cpp

@@ -13,6 +13,7 @@
 #include "i8253.h"
 #include "RTC.h"
 #include "ProcFileSystem.h"
+#include <AK/StdLib.h>
 
 //#define DEBUG_IO
 //#define TASK_DEBUG
@@ -132,9 +133,9 @@ Task::Region* Task::allocateRegion(size_t size, String&& name)
 {
     // FIXME: This needs sanity checks. What if this overlaps existing regions?
 
-    auto zone = MemoryManager::the().createZone(size);
+    auto zone = MM.createZone(size);
     ASSERT(zone);
-    m_regions.append(make<Region>(m_nextRegion, size, move(zone), move(name)));
+    m_regions.append(adopt(*new Region(m_nextRegion, size, move(zone), move(name))));
     m_nextRegion = m_nextRegion.offset(size).offset(16384);
     return m_regions.last().ptr();
 }
@@ -144,7 +145,7 @@ bool Task::deallocateRegion(Region& region)
     for (size_t i = 0; i < m_regions.size(); ++i) {
         if (m_regions[i].ptr() == &region) {
             // FIXME: This seems racy.
-            MemoryManager::the().unmapRegion(*this, region);
+            MM.unmapRegion(*this, region);
             m_regions.remove(i);
             return true;
         }
@@ -168,7 +169,7 @@ void* Task::sys$mmap(void* addr, size_t size)
     auto* region = allocateRegion(size, "mmap");
     if (!region)
         return (void*)-1;
-    MemoryManager::the().mapRegion(*this, *region);
+    MM.mapRegion(*this, *region);
     return (void*)region->linearAddress.get();
 }
 
@@ -250,39 +251,55 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren
     t->m_arguments = move(taskArguments);
 
     ExecSpace space;
+    Region* region = nullptr;
     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));
+        region = t->allocateRegion(size, String(name));
         ASSERT(region);
-        MemoryManager::the().mapRegion(*t, *region);
+        MM.mapRegion(*t, *region);
         return (void*)region->linearAddress.asPtr();
     };
     bool success = space.loadELF(move(elfData));
     if (!success) {
         // FIXME: This is ugly. If we need to do this, it should be at a different level.
-        MemoryManager::the().unmapRegionsForTask(*t);
-        MemoryManager::the().mapRegionsForTask(*current);
+        MM.unmapRegionsForTask(*t);
+        MM.mapRegionsForTask(*current);
         delete t;
         kprintf("Failure loading ELF %s\n", path.characters());
         error = -ENOEXEC;
         return nullptr;
     }
 
+    space.forEachArea([&] (const String& name, dword offset, size_t size, LinearAddress laddr) {
+        if (laddr.isNull())
+            return;
+        dword roundedOffset = offset & 0xfffff000;
+        size_t roundedSize = 4096 * ceilDiv((offset - roundedOffset) + size, 4096u);
+        LinearAddress roundedLaddr = laddr;
+        roundedLaddr.mask(0xfffff000);
+        t->m_subregions.append(make<Subregion>(*region, roundedOffset, roundedSize, roundedLaddr, String(name)));
+#ifdef SUBREGION_DEBUG
+        kprintf("   req subregion %s (offset: %u, size: %u) @ %p\n", name.characters(), offset, size, laddr.get());
+        kprintf("actual subregion %s (offset: %u, size: %u) @ %p\n", name.characters(), roundedOffset, roundedSize, roundedLaddr.get());
+#endif
+        MM.mapSubregion(*t, *t->m_subregions.last());
+    });
+
     t->m_tss.eip = (dword)space.symbolPtr("_start");
     if (!t->m_tss.eip) {
         // FIXME: This is ugly. If we need to do this, it should be at a different level.
-        MemoryManager::the().unmapRegionsForTask(*t);
-        MemoryManager::the().mapRegionsForTask(*current);
+        MM.unmapRegionsForTask(*t);
+        MM.mapRegionsForTask(*current);
         delete t;
         error = -ENOEXEC;
         return nullptr;
     }
 
     // FIXME: This is ugly. If we need to do this, it should be at a different level.
-    MemoryManager::the().unmapRegionsForTask(*t);
-    MemoryManager::the().mapRegionsForTask(*current);
+    MM.unmapRegionsForTask(*t);
+    MM.mapRegionsForTask(*current);
 
     s_tasks->prepend(t);
     system.nprocess++;
@@ -299,7 +316,7 @@ int Task::sys$get_arguments(int* argc, char*** argv)
     auto* region = allocateRegion(4096, "argv");
     if (!region)
         return -ENOMEM;
-    MemoryManager::the().mapRegion(*this, *region);
+    MM.mapRegion(*this, *region);
     char* argpage = (char*)region->linearAddress.get();
     *argc = m_arguments.size();
     *argv = (char**)argpage;
@@ -380,7 +397,7 @@ Task::Task(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring)
     m_tss.ss = ss;
     m_tss.cs = cs;
 
-    m_tss.cr3 = MemoryManager::the().pageDirectoryBase().get();
+    m_tss.cr3 = MM.pageDirectoryBase().get();
 
     if (isRing0()) {
         // FIXME: This memory is leaked.
@@ -435,6 +452,18 @@ void Task::dumpRegions()
             region->size,
             region->name.characters());
     }
+
+    kprintf("Task %s(%u) subregions:\n", name().characters(), pid());
+    kprintf("REGION    OFFSET    BEGIN       END         SIZE        NAME\n");
+    for (auto& subregion : m_subregions) {
+        kprintf("%x  %x  %x -- %x    %x    %s\n",
+            subregion->region->linearAddress.get(),
+            subregion->offset,
+            subregion->linearAddress.get(),
+            subregion->linearAddress.offset(subregion->size - 1).get(),
+            subregion->size,
+            subregion->name.characters());
+    }
 }
 
 void Task::sys$exit(int status)
@@ -446,7 +475,7 @@ void Task::sys$exit(int status)
 
     setState(Exiting);
 
-    MemoryManager::the().unmapRegionsForTask(*this);
+    MM.unmapRegionsForTask(*this);
 
     s_tasks->remove(this);
 
@@ -474,7 +503,7 @@ void Task::taskDidCrash(Task* crashedTask)
 
     s_tasks->remove(crashedTask);
 
-    MemoryManager::the().unmapRegionsForTask(*crashedTask);
+    MM.unmapRegionsForTask(*crashedTask);
 
     if (!scheduleNewTask()) {
         kprintf("Task::taskDidCrash: Failed to schedule a new task :(\n");
@@ -630,11 +659,11 @@ static bool contextSwitch(Task* t)
         if (current->state() == Task::Running)
             current->setState(Task::Runnable);
 
-        bool success = MemoryManager::the().unmapRegionsForTask(*current);
+        bool success = MM.unmapRegionsForTask(*current);
         ASSERT(success);
     }
 
-    bool success = MemoryManager::the().mapRegionsForTask(*t);
+    bool success = MM.mapRegionsForTask(*t);
     ASSERT(success);
 
     current = t;
@@ -911,6 +940,20 @@ Task::Region::~Region()
 {
 }
 
+Task::Subregion::Subregion(Region& r, dword o, size_t s, LinearAddress l, String&& n)\
+    : region(r)
+    , offset(o)
+    , size(s)
+    , linearAddress(l)
+    , name(move(n))
+{
+}
+
+
+Task::Subregion::~Subregion()
+{
+}
+
 bool Task::isValidAddressForKernel(LinearAddress laddr) const
 {
     InterruptDisabler disabler;
@@ -928,5 +971,9 @@ bool Task::isValidAddressForUser(LinearAddress laddr) const
         if (laddr >= region->linearAddress && laddr < region->linearAddress.offset(region->size))
             return true;
     }
+    for (auto& subregion: m_subregions) {
+        if (laddr >= subregion->linearAddress && laddr < subregion->linearAddress.offset(subregion->size))
+            return true;
+    }
     return false;
 }

+ 17 - 3
Kernel/Task.h

@@ -112,7 +112,7 @@ public:
     static void taskDidCrash(Task*);
 
     size_t regionCount() const { return m_regions.size(); }
-    const Vector<OwnPtr<Region>>& regions() const { return m_regions; }
+    const Vector<RetainPtr<Region>>& regions() const { return m_regions; }
     void dumpRegions();
 
     void didSchedule() { ++m_timesScheduled; }
@@ -166,7 +166,7 @@ private:
 
     RetainPtr<VirtualFileSystem::Node> m_cwd;
 
-    struct Region {
+    struct Region : public Retainable<Region> {
         Region(LinearAddress, size_t, RetainPtr<Zone>&&, String&&);
         ~Region();
         LinearAddress linearAddress;
@@ -174,12 +174,26 @@ private:
         RetainPtr<Zone> zone;
         String name;
     };
+
+    struct Subregion {
+        Subregion(Region&, dword offset, size_t, LinearAddress, String&& name);
+        ~Subregion();
+
+        RetainPtr<Region> region;
+        dword offset;
+        size_t size { 0 };
+        LinearAddress linearAddress;
+        String name;
+    };
+
     Region* allocateRegion(size_t, String&& name);
+    Region* allocateRegion(size_t, String&& name, LinearAddress);
     bool deallocateRegion(Region& region);
 
     Region* regionFromRange(LinearAddress, size_t);
 
-    Vector<OwnPtr<Region>> m_regions;
+    Vector<RetainPtr<Region>> m_regions;
+    Vector<OwnPtr<Subregion>> m_subregions;
 
     // FIXME: Implement some kind of ASLR?
     LinearAddress m_nextRegion;

+ 13 - 1
Kernel/i386.cpp

@@ -218,10 +218,22 @@ void exception_14_handler()
     kprintf("eax=%x ebx=%x ecx=%x edx=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx);
     kprintf("ebp=%x esp=%x esi=%x edi=%x\n", regs.ebp, esp, regs.esi, regs.edi);
 
+    byte* codeptr = (byte*)regs.eip;
+    kprintf("code: %b %b %b %b %b %b %b %b\n",
+            codeptr[0],
+            codeptr[1],
+            codeptr[2],
+            codeptr[3],
+            codeptr[4],
+            codeptr[5],
+            codeptr[6],
+            codeptr[7]
+    );
+
     if (current->isRing0())
         HANG;
 
-    auto response = MemoryManager::the().handlePageFault(PageFault(exception_code, LinearAddress(faultAddress)));
+    auto response = MM.handlePageFault(PageFault(exception_code, LinearAddress(faultAddress)));
 
     if (response == PageFaultResponse::ShouldCrash) {
         kprintf("Crashing after unresolved page fault\n");

+ 2 - 0
Kernel/types.h

@@ -80,6 +80,8 @@ public:
     LinearAddress() { }
     explicit LinearAddress(dword address) : m_address(address) { }
 
+    bool isNull() const { return m_address == 0; }
+
     LinearAddress offset(dword o) const { return LinearAddress(m_address + o); }
     dword get() const { return m_address; }
     void set(dword address) { m_address = address; }

+ 1 - 1
LibC/Makefile

@@ -22,7 +22,7 @@ INCLUDE_FLAGS = -I.. -I.
 DEFINES = -DSERENITY -DSANITIZE_PTRS
 
 CXXFLAGS = $(WARNING_FLAGS) $(OPTIMIZATION_FLAGS) $(LIBC_FLAGS) $(FLAVOR_FLAGS) $(ARCH_FLAGS) $(STANDARD_FLAGS) $(INCLUDE_FLAGS) $(DEFINES)
-CXX = g++
+CXX = g++-8
 LD = ld
 AR = ar
 LDFLAGS = -T linker.ld --strip-debug -melf_i386 --gc-sections --build-id=none -z norelro -z now

+ 1 - 1
LibC/stdio.cpp

@@ -7,7 +7,7 @@
 
 #define ALWAYS_INLINE __attribute__ ((always_inline))
 
-static const char h[] = { '0','1','2','3','4','5','6','7', '8','9','a','b','c','d','e','f' };
+static constexpr const char* h = "0123456789abcdef";
 
 template<typename PutChFunc>
 ALWAYS_INLINE int printHex(PutChFunc putch, char*& bufptr, dword number, byte fields)

+ 3 - 3
Userland/Makefile

@@ -30,17 +30,17 @@ ARCH_FLAGS =
 STANDARD_FLAGS = -std=c++17 -nostdinc++ -nostdlib
 USERLAND_FLAGS = -ffreestanding -fno-stack-protector -fno-ident
 WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings
-FLAVOR_FLAGS = -fomit-frame-pointer -mregparm=3 -march=i386 -m32 -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -fmerge-all-constants -fno-unroll-loops -falign-functions=1 -falign-jumps=1 -falign-loops=1 -fno-pie -fno-pic
+FLAVOR_FLAGS = -march=i386 -mregparm=3 -m32 -fno-exceptions -fno-rtti -fmerge-all-constants -fno-unroll-loops -fno-pie -fno-pic
 OPTIMIZATION_FLAGS = -Os -fno-asynchronous-unwind-tables
 INCLUDE_FLAGS = -I.. -I.
 
 DEFINES = -DSERENITY -DSANITIZE_PTRS -DUSERLAND
 
 CXXFLAGS = $(WARNING_FLAGS) $(OPTIMIZATION_FLAGS) $(USERLAND_FLAGS) $(FLAVOR_FLAGS) $(ARCH_FLAGS) $(STANDARD_FLAGS) $(INCLUDE_FLAGS) $(DEFINES)
-CXX = g++
+CXX = g++-8
 LD = ld
 AR = ar
-LDFLAGS = -r -static --strip-debug -melf_i386 --build-id=none -z norelro -z now -e _start
+LDFLAGS = -static --strip-debug -melf_i386 --build-id=none -z norelro -z now -e _start --gc-sections
 
 all: $(OBJS) $(APPS)
 

+ 5 - 2
Userland/ls.cpp

@@ -1,21 +1,24 @@
 #include <LibC/stdio.h>
 #include <LibC/unistd.h>
 #include <LibC/dirent.h>
+#include <LibC/errno.h>
+#include <LibC/string.h>
 
 int main(int c, char** v)
 {
     DIR* dirp = opendir(".");
     if (!dirp) {
-        printf("opendir failed :(\n");
+        perror("opendir failed");
         return 1;
     }
     char pathbuf[256];
     while (auto* de = readdir(dirp)) {
         sprintf(pathbuf, "%s", de->d_name);
+
         stat st;
         int rc = lstat(pathbuf, &st);
         if (rc == -1) {
-            printf("Failed to stat '%s'\n", pathbuf);
+            printf("lstat(%s) failed: %s\n", pathbuf, strerror(errno));
             return 2;
         }