mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 05:20:30 +00:00
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!
This commit is contained in:
parent
99ee6acd69
commit
9a71c7759a
Notes:
sideshowbarker
2024-07-19 18:37:37 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/9a71c7759a0
16 changed files with 258 additions and 57 deletions
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -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,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 };
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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() == ®ion) {
|
||||
// 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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue