Compare commits
3 Commits
6e269c6bc4
...
3598dacbed
Author | SHA1 | Date | |
---|---|---|---|
3598dacbed | |||
3638d3da46 | |||
1c76675e40 |
@ -175,28 +175,10 @@ static Result<void> load_service(const os::Path& path)
|
||||
|
||||
if (parts[0].view() == "Command")
|
||||
{
|
||||
if (!service.command.is_empty())
|
||||
{
|
||||
do_log("[init] 'Command' cannot be specified after 'Script' has already been set! (%s)\n",
|
||||
line.chars());
|
||||
return {};
|
||||
}
|
||||
service.command = move(parts[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parts[0].view() == "Script")
|
||||
{
|
||||
if (!service.command.is_empty())
|
||||
{
|
||||
do_log("[init] 'Script' cannot be specified after 'Command' has already been set! (%s)\n",
|
||||
line.chars());
|
||||
return {};
|
||||
}
|
||||
service.command = TRY(String::format("/bin/sh -- %s"_sv, parts[1].chars()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parts[0].view() == "Restart")
|
||||
{
|
||||
if (parts[1].view() == "true" || parts[1].view().to_uint().value_or(0) == 1)
|
||||
|
@ -1,4 +1,4 @@
|
||||
Name=mount-home
|
||||
Description=Mount the user's home directory on a writable filesystem.
|
||||
Script=/etc/startup/mount-home.sh
|
||||
Command=/etc/startup/mount-home.sh
|
||||
Wait=true
|
||||
|
@ -1,2 +1,3 @@
|
||||
#!/bin/sh
|
||||
mount -t tmpfs tmpfs /home/selene
|
||||
chown selene:selene /home/selene
|
||||
|
@ -60,7 +60,9 @@ set(SOURCES
|
||||
src/fs/devices/FramebufferDevice.cpp
|
||||
src/fs/devices/UARTDevice.cpp
|
||||
src/fs/InitRD.cpp
|
||||
src/thread/ELF.cpp
|
||||
src/binfmt/ELF.cpp
|
||||
src/binfmt/BinaryFormat.cpp
|
||||
src/binfmt/Script.cpp
|
||||
)
|
||||
|
||||
if("${LUNA_ARCH}" MATCHES "x86_64")
|
||||
|
39
kernel/src/binfmt/BinaryFormat.cpp
Normal file
39
kernel/src/binfmt/BinaryFormat.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "binfmt/BinaryFormat.h"
|
||||
#include "binfmt/ELF.h"
|
||||
#include "binfmt/Script.h"
|
||||
|
||||
struct BinaryFormatDescriptor
|
||||
{
|
||||
binfmt_loader_creator_t creator;
|
||||
void* arg;
|
||||
};
|
||||
|
||||
Vector<BinaryFormatDescriptor> g_binary_formats;
|
||||
|
||||
Result<void> BinaryFormat::init()
|
||||
{
|
||||
TRY(register_binary_format(ELFLoader::create, nullptr));
|
||||
TRY(register_binary_format(ScriptLoader::create, nullptr));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void> BinaryFormat::register_binary_format(binfmt_loader_creator_t creator, void* arg)
|
||||
{
|
||||
return g_binary_formats.try_append({ creator, arg });
|
||||
}
|
||||
|
||||
Result<SharedPtr<BinaryFormatLoader>> BinaryFormat::create_loader(SharedPtr<VFS::Inode> inode)
|
||||
{
|
||||
for (const auto& format : g_binary_formats)
|
||||
{
|
||||
auto loader = TRY(format.creator(inode, format.arg));
|
||||
if (TRY(loader->sniff())) return loader;
|
||||
}
|
||||
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
BinaryFormatLoader::BinaryFormatLoader(SharedPtr<VFS::Inode> inode) : m_inode(inode)
|
||||
{
|
||||
}
|
32
kernel/src/binfmt/BinaryFormat.h
Normal file
32
kernel/src/binfmt/BinaryFormat.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include "fs/VFS.h"
|
||||
#include "memory/AddressSpace.h"
|
||||
|
||||
class BinaryFormatLoader : public Shareable
|
||||
{
|
||||
public:
|
||||
virtual Result<bool> sniff() = 0;
|
||||
virtual Result<u64> load(AddressSpace* space) = 0;
|
||||
|
||||
virtual StringView format() const = 0;
|
||||
|
||||
virtual Result<Vector<String>> cmdline(Vector<String> args) = 0;
|
||||
|
||||
virtual ~BinaryFormatLoader() = default;
|
||||
|
||||
BinaryFormatLoader(SharedPtr<VFS::Inode>);
|
||||
|
||||
protected:
|
||||
SharedPtr<VFS::Inode> m_inode;
|
||||
};
|
||||
|
||||
typedef Result<SharedPtr<BinaryFormatLoader>> (*binfmt_loader_creator_t)(SharedPtr<VFS::Inode>, void*);
|
||||
|
||||
namespace BinaryFormat
|
||||
{
|
||||
Result<void> init();
|
||||
|
||||
Result<void> register_binary_format(binfmt_loader_creator_t creator, void* arg);
|
||||
|
||||
Result<SharedPtr<BinaryFormatLoader>> create_loader(SharedPtr<VFS::Inode> inode);
|
||||
}
|
147
kernel/src/binfmt/ELF.cpp
Normal file
147
kernel/src/binfmt/ELF.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
#include "binfmt/ELF.h"
|
||||
#include "Log.h"
|
||||
#include "arch/CPU.h"
|
||||
#include "arch/MMU.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include <luna/Alignment.h>
|
||||
#include <luna/Alloc.h>
|
||||
#include <luna/CString.h>
|
||||
#include <luna/ScopeGuard.h>
|
||||
|
||||
static bool can_execute_segment(u32 flags)
|
||||
{
|
||||
return flags & 1;
|
||||
}
|
||||
|
||||
static bool can_write_segment(u32 flags)
|
||||
{
|
||||
return flags & 2;
|
||||
}
|
||||
|
||||
/*static bool can_write_and_execute_segment(u32 flags)
|
||||
{
|
||||
return can_write_segment(flags) && can_execute_segment(flags);
|
||||
}*/
|
||||
|
||||
Result<bool> ELFLoader::sniff()
|
||||
{
|
||||
u8 buf[SELFMAG];
|
||||
usize nread = TRY(m_inode->read(buf, 0, sizeof buf));
|
||||
if (nread < SELFMAG) return false;
|
||||
|
||||
return !memcmp(buf, ELFMAG, SELFMAG);
|
||||
}
|
||||
|
||||
Result<u64> ELFLoader::load(AddressSpace* space)
|
||||
{
|
||||
Elf64_Ehdr elf_header;
|
||||
usize nread = TRY(m_inode->read((u8*)&elf_header, 0, sizeof elf_header));
|
||||
|
||||
if (nread < sizeof elf_header)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF header does not fit in file");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF header has no valid magic");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF object is not 64-bit");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (elf_header.e_ident[EI_DATA] != ELFDATA2LSB)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF object is not 2's complement little-endian");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (elf_header.e_type != ET_EXEC)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF object is not an executable");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (elf_header.e_machine != EM_MACH)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF object's target architecture does not match the current one (%s)",
|
||||
CPU::platform_string().chars());
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (elf_header.e_phnum == 0)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF object has no program headers");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
#ifdef ELF_DEBUG
|
||||
kdbgln("ELF: Loading ELF with entry=%#.16lx", elf_header.e_entry);
|
||||
#endif
|
||||
|
||||
usize i;
|
||||
Elf64_Phdr program_header;
|
||||
|
||||
for (TRY(m_inode->read((u8*)&program_header, elf_header.e_phoff, sizeof program_header)), i = 0;
|
||||
i < elf_header.e_phnum;
|
||||
i++, TRY(m_inode->read((u8*)&program_header, elf_header.e_phoff + (i * elf_header.e_phentsize),
|
||||
sizeof program_header)))
|
||||
{
|
||||
if (program_header.p_type == PT_LOAD)
|
||||
{
|
||||
#ifdef ELF_DEBUG
|
||||
kdbgln("ELF: Loading segment (offset=%zu, base=%#.16lx, filesize=%zu, memsize=%zu)",
|
||||
program_header.p_offset, program_header.p_vaddr, program_header.p_filesz, program_header.p_memsz);
|
||||
#endif
|
||||
|
||||
u64 base_vaddr = align_down<ARCH_PAGE_SIZE>(program_header.p_vaddr);
|
||||
u64 vaddr_diff = program_header.p_vaddr - base_vaddr;
|
||||
/*expect(!can_write_and_execute_segment(program_header.p_flags),
|
||||
"Segment is both writable and executable");*/
|
||||
|
||||
int flags = MMU::User | MMU::NoExecute;
|
||||
if (can_write_segment(program_header.p_flags)) flags |= MMU::ReadWrite;
|
||||
if (can_execute_segment(program_header.p_flags)) flags &= ~MMU::NoExecute;
|
||||
|
||||
if (!TRY(space->test_and_alloc_region(
|
||||
base_vaddr, get_blocks_from_size(program_header.p_memsz + vaddr_diff, ARCH_PAGE_SIZE), true)))
|
||||
return err(ENOMEM);
|
||||
|
||||
// Allocate physical memory for the segment
|
||||
TRY(MemoryManager::alloc_at(
|
||||
base_vaddr, get_blocks_from_size(program_header.p_memsz + vaddr_diff, ARCH_PAGE_SIZE), flags));
|
||||
|
||||
// Zero out unused memory (before the start of the segment)
|
||||
memset((void*)base_vaddr, 0, vaddr_diff);
|
||||
|
||||
// Load the file section of the segment
|
||||
m_inode->read((u8*)program_header.p_vaddr, program_header.p_offset, program_header.p_filesz);
|
||||
|
||||
// Fill out the rest of the segment with 0s
|
||||
memset((void*)(program_header.p_vaddr + program_header.p_filesz), 0,
|
||||
program_header.p_memsz - program_header.p_filesz);
|
||||
}
|
||||
else { kwarnln("ELF: Encountered non-loadable program header, skipping"); }
|
||||
}
|
||||
|
||||
return elf_header.e_entry;
|
||||
}
|
||||
|
||||
Result<Vector<String>> ELFLoader::cmdline(Vector<String> args)
|
||||
{
|
||||
return args;
|
||||
}
|
||||
|
||||
ELFLoader::ELFLoader(SharedPtr<VFS::Inode> inode) : BinaryFormatLoader(inode)
|
||||
{
|
||||
}
|
||||
|
||||
Result<SharedPtr<BinaryFormatLoader>> ELFLoader::create(SharedPtr<VFS::Inode> inode, void*)
|
||||
{
|
||||
return (SharedPtr<BinaryFormatLoader>)TRY(make_shared<ELFLoader>(inode));
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "binfmt/BinaryFormat.h"
|
||||
#include "fs/VFS.h"
|
||||
#include "memory/AddressSpace.h"
|
||||
#include <luna/SharedPtr.h>
|
||||
#include <luna/Types.h>
|
||||
|
||||
#define ELFMAG "\177ELF"
|
||||
@ -47,12 +49,20 @@ typedef struct
|
||||
u64 p_align; /* Segment alignment */
|
||||
} Elf64_Phdr;
|
||||
|
||||
struct ELFData
|
||||
class ELFLoader : public BinaryFormatLoader
|
||||
{
|
||||
u64 entry;
|
||||
};
|
||||
public:
|
||||
Result<bool> sniff() override;
|
||||
Result<u64> load(AddressSpace* space) override;
|
||||
|
||||
namespace ELFLoader
|
||||
{
|
||||
Result<ELFData> load(SharedPtr<VFS::Inode> inode, AddressSpace* space);
|
||||
Result<Vector<String>> cmdline(Vector<String> args) override;
|
||||
|
||||
StringView format() const override
|
||||
{
|
||||
return "elf";
|
||||
}
|
||||
|
||||
ELFLoader(SharedPtr<VFS::Inode> inode);
|
||||
|
||||
static Result<SharedPtr<BinaryFormatLoader>> create(SharedPtr<VFS::Inode> inode, void*);
|
||||
};
|
61
kernel/src/binfmt/Script.cpp
Normal file
61
kernel/src/binfmt/Script.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include "binfmt/Script.h"
|
||||
#include "binfmt/ELF.h"
|
||||
#include "thread/Scheduler.h"
|
||||
|
||||
#define SHEBANG "#!"
|
||||
|
||||
Result<bool> ScriptLoader::sniff()
|
||||
{
|
||||
u8 buf[2];
|
||||
usize nread = TRY(m_inode->read(buf, 0, sizeof buf));
|
||||
if (nread < 2) return false;
|
||||
|
||||
return !memcmp(buf, SHEBANG, 2);
|
||||
}
|
||||
|
||||
Result<u64> ScriptLoader::load(AddressSpace* space)
|
||||
{
|
||||
u8 buf[256];
|
||||
usize nread = TRY(m_inode->read(buf, 2, 255));
|
||||
if (!nread) return err(ENOEXEC);
|
||||
for (usize i = 0; i < nread; i++)
|
||||
{
|
||||
if (buf[i] == '\n') buf[i] = '\0';
|
||||
else if (buf[i] == '\r' && (i + 1) < nread && buf[i + 1] == '\n')
|
||||
buf[i] = buf[i + 1] = '\0';
|
||||
else
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
auto view = StringView { (const char*)buf };
|
||||
m_interpreter_cmdline = TRY(view.split(" "));
|
||||
if (!m_interpreter_cmdline.size()) return err(ENOEXEC);
|
||||
|
||||
auto& interpreter_path = m_interpreter_cmdline[0];
|
||||
auto* current = Scheduler::current();
|
||||
|
||||
auto interpreter =
|
||||
TRY(VFS::resolve_path(interpreter_path.chars(), current->auth, current->current_directory, true));
|
||||
if (!VFS::can_execute(interpreter, current->auth)) return err(EACCES);
|
||||
|
||||
auto loader = TRY(ELFLoader::create(interpreter, nullptr));
|
||||
return loader->load(space);
|
||||
}
|
||||
|
||||
Result<Vector<String>> ScriptLoader::cmdline(Vector<String> args)
|
||||
{
|
||||
Vector<String> new_args;
|
||||
for (auto& arg : m_interpreter_cmdline) { TRY(new_args.try_append(move(arg))); }
|
||||
for (auto& arg : args) { TRY(new_args.try_append(move(arg))); }
|
||||
return new_args;
|
||||
}
|
||||
|
||||
ScriptLoader::ScriptLoader(SharedPtr<VFS::Inode> inode) : BinaryFormatLoader(inode)
|
||||
{
|
||||
}
|
||||
|
||||
Result<SharedPtr<BinaryFormatLoader>> ScriptLoader::create(SharedPtr<VFS::Inode> inode, void*)
|
||||
{
|
||||
return (SharedPtr<BinaryFormatLoader>)TRY(make_shared<ScriptLoader>(inode));
|
||||
}
|
25
kernel/src/binfmt/Script.h
Normal file
25
kernel/src/binfmt/Script.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "binfmt/BinaryFormat.h"
|
||||
#include "fs/VFS.h"
|
||||
#include "memory/AddressSpace.h"
|
||||
|
||||
class ScriptLoader : public BinaryFormatLoader
|
||||
{
|
||||
public:
|
||||
Result<bool> sniff() override;
|
||||
Result<u64> load(AddressSpace* space) override;
|
||||
|
||||
Result<Vector<String>> cmdline(Vector<String> args) override;
|
||||
|
||||
StringView format() const override
|
||||
{
|
||||
return "script";
|
||||
}
|
||||
|
||||
ScriptLoader(SharedPtr<VFS::Inode> inode);
|
||||
|
||||
static Result<SharedPtr<BinaryFormatLoader>> create(SharedPtr<VFS::Inode> inode, void*);
|
||||
|
||||
private:
|
||||
Vector<String> m_interpreter_cmdline;
|
||||
};
|
@ -1,6 +1,7 @@
|
||||
#include "Log.h"
|
||||
#include "arch/CPU.h"
|
||||
#include "arch/Timer.h"
|
||||
#include "binfmt/BinaryFormat.h"
|
||||
#include "boot/Init.h"
|
||||
#include "config.h"
|
||||
#include "fs/InitRD.h"
|
||||
@ -45,6 +46,8 @@ void reap_thread()
|
||||
mark_critical(InitRD::populate_vfs(), "Failed to load files from the initial ramdisk");
|
||||
mark_critical(DeviceRegistry::init(), "Failed to register initial devices");
|
||||
|
||||
mark_critical(BinaryFormat::init(), "Failed to register initial binary formats");
|
||||
|
||||
auto init =
|
||||
mark_critical(VFS::resolve_path("/bin/preinit", Credentials {}), "Can't find init in the initial ramfs!");
|
||||
auto init_thread =
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include "Log.h"
|
||||
#include "binfmt/BinaryFormat.h"
|
||||
#include "fs/VFS.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "sys/Syscall.h"
|
||||
#include "thread/ELF.h"
|
||||
#include "thread/Scheduler.h"
|
||||
#include "thread/ThreadImage.h"
|
||||
#include <bits/modes.h>
|
||||
@ -70,9 +70,17 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
||||
kdbgln("exec: attempting to replace current image with %s", path.chars());
|
||||
#endif
|
||||
|
||||
auto loader = TRY(BinaryFormat::create_loader(inode));
|
||||
|
||||
#ifdef EXEC_DEBUG
|
||||
kdbgln("exec: created loader for binary format %s", loader->format().chars());
|
||||
#endif
|
||||
|
||||
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory()); });
|
||||
|
||||
auto image = TRY(ThreadImage::try_load_from_elf(inode));
|
||||
auto image = TRY(ThreadImage::try_load_from_binary(loader));
|
||||
|
||||
argv = TRY(loader->cmdline(move(argv)));
|
||||
|
||||
u64 user_argv = TRY(image->push_string_vector_on_stack(argv));
|
||||
usize user_argc = argv.size();
|
||||
|
@ -1,128 +0,0 @@
|
||||
#include "ELF.h"
|
||||
#include "Log.h"
|
||||
#include "arch/CPU.h"
|
||||
#include "arch/MMU.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include <luna/Alignment.h>
|
||||
#include <luna/Alloc.h>
|
||||
#include <luna/CString.h>
|
||||
#include <luna/ScopeGuard.h>
|
||||
|
||||
static bool can_execute_segment(u32 flags)
|
||||
{
|
||||
return flags & 1;
|
||||
}
|
||||
|
||||
static bool can_write_segment(u32 flags)
|
||||
{
|
||||
return flags & 2;
|
||||
}
|
||||
|
||||
/*static bool can_write_and_execute_segment(u32 flags)
|
||||
{
|
||||
return can_write_segment(flags) && can_execute_segment(flags);
|
||||
}*/
|
||||
|
||||
namespace ELFLoader
|
||||
{
|
||||
Result<ELFData> load(SharedPtr<VFS::Inode> inode, AddressSpace* space)
|
||||
{
|
||||
Elf64_Ehdr elf_header;
|
||||
usize nread = TRY(inode->read((u8*)&elf_header, 0, sizeof elf_header));
|
||||
|
||||
if (nread < sizeof elf_header)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF header does not fit in file");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF header has no valid magic");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF object is not 64-bit");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (elf_header.e_ident[EI_DATA] != ELFDATA2LSB)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF object is not 2's complement little-endian");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (elf_header.e_type != ET_EXEC)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF object is not an executable");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (elf_header.e_machine != EM_MACH)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF object's target architecture does not match the current one (%s)",
|
||||
CPU::platform_string().chars());
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
if (elf_header.e_phnum == 0)
|
||||
{
|
||||
kerrorln("Error while loading ELF: ELF object has no program headers");
|
||||
return err(ENOEXEC);
|
||||
}
|
||||
|
||||
#ifdef ELF_DEBUG
|
||||
kdbgln("ELF: Loading ELF with entry=%#.16lx", elf_header.e_entry);
|
||||
#endif
|
||||
|
||||
usize i;
|
||||
Elf64_Phdr program_header;
|
||||
|
||||
for (TRY(inode->read((u8*)&program_header, elf_header.e_phoff, sizeof program_header)), i = 0;
|
||||
i < elf_header.e_phnum;
|
||||
i++, TRY(inode->read((u8*)&program_header, elf_header.e_phoff + (i * elf_header.e_phentsize),
|
||||
sizeof program_header)))
|
||||
{
|
||||
if (program_header.p_type == PT_LOAD)
|
||||
{
|
||||
#ifdef ELF_DEBUG
|
||||
kdbgln("ELF: Loading segment (offset=%zu, base=%#.16lx, filesize=%zu, memsize=%zu)",
|
||||
program_header.p_offset, program_header.p_vaddr, program_header.p_filesz,
|
||||
program_header.p_memsz);
|
||||
#endif
|
||||
|
||||
u64 base_vaddr = align_down<ARCH_PAGE_SIZE>(program_header.p_vaddr);
|
||||
u64 vaddr_diff = program_header.p_vaddr - base_vaddr;
|
||||
/*expect(!can_write_and_execute_segment(program_header.p_flags),
|
||||
"Segment is both writable and executable");*/
|
||||
|
||||
int flags = MMU::User | MMU::NoExecute;
|
||||
if (can_write_segment(program_header.p_flags)) flags |= MMU::ReadWrite;
|
||||
if (can_execute_segment(program_header.p_flags)) flags &= ~MMU::NoExecute;
|
||||
|
||||
if (!TRY(space->test_and_alloc_region(
|
||||
base_vaddr, get_blocks_from_size(program_header.p_memsz + vaddr_diff, ARCH_PAGE_SIZE), true)))
|
||||
return err(ENOMEM);
|
||||
|
||||
// Allocate physical memory for the segment
|
||||
TRY(MemoryManager::alloc_at(
|
||||
base_vaddr, get_blocks_from_size(program_header.p_memsz + vaddr_diff, ARCH_PAGE_SIZE), flags));
|
||||
|
||||
// Zero out unused memory (before the start of the segment)
|
||||
memset((void*)base_vaddr, 0, vaddr_diff);
|
||||
|
||||
// Load the file section of the segment
|
||||
inode->read((u8*)program_header.p_vaddr, program_header.p_offset, program_header.p_filesz);
|
||||
|
||||
// Fill out the rest of the segment with 0s
|
||||
memset((void*)(program_header.p_vaddr + program_header.p_filesz), 0,
|
||||
program_header.p_memsz - program_header.p_filesz);
|
||||
}
|
||||
else { kwarnln("ELF: Encountered non-loadable program header, skipping"); }
|
||||
}
|
||||
|
||||
return ELFData { elf_header.e_entry };
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
#include "thread/Scheduler.h"
|
||||
#include "ELF.h"
|
||||
#include "Log.h"
|
||||
#include "arch/CPU.h"
|
||||
#include "arch/MMU.h"
|
||||
#include "binfmt/ELF.h"
|
||||
#include "memory/MemoryManager.h"
|
||||
#include "thread/ThreadImage.h"
|
||||
#include <luna/Alignment.h>
|
||||
@ -147,7 +147,10 @@ namespace Scheduler
|
||||
|
||||
auto guard = make_scope_guard([&] { delete thread; });
|
||||
|
||||
auto image = TRY(ThreadImage::try_load_from_elf(inode));
|
||||
// Contrary to other programs, which use BinaryFormat::create_loader(), init must be a native executable.
|
||||
auto loader = TRY(ELFLoader::create(inode, nullptr));
|
||||
|
||||
auto image = TRY(ThreadImage::try_load_from_binary(loader));
|
||||
u64 argv = TRY(image->push_string_vector_on_stack(args));
|
||||
u64 envp = TRY(image->push_string_vector_on_stack(env));
|
||||
|
||||
|
@ -24,7 +24,7 @@ static Result<void> create_user_stack(Stack& user_stack, AddressSpace* space)
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<OwnedPtr<ThreadImage>> ThreadImage::try_load_from_elf(SharedPtr<VFS::Inode> inode)
|
||||
Result<OwnedPtr<ThreadImage>> ThreadImage::try_load_from_binary(SharedPtr<BinaryFormatLoader> loader)
|
||||
{
|
||||
auto image = TRY(make_owned<ThreadImage>());
|
||||
|
||||
@ -36,7 +36,7 @@ Result<OwnedPtr<ThreadImage>> ThreadImage::try_load_from_elf(SharedPtr<VFS::Inod
|
||||
|
||||
auto guard = make_scope_guard([=] { MMU::switch_page_directory(old_directory); });
|
||||
|
||||
const ELFData data = TRY(ELFLoader::load(inode, address_space.ptr()));
|
||||
const u64 entry = TRY(loader->load(address_space.ptr()));
|
||||
|
||||
Stack user_stack;
|
||||
TRY(create_user_stack(user_stack, address_space.ptr()));
|
||||
@ -44,7 +44,7 @@ Result<OwnedPtr<ThreadImage>> ThreadImage::try_load_from_elf(SharedPtr<VFS::Inod
|
||||
guard.deactivate();
|
||||
|
||||
image->m_user_stack = user_stack;
|
||||
image->m_loaded_image_data = data;
|
||||
image->m_program_entry = entry;
|
||||
image->m_address_space = move(address_space);
|
||||
image->m_sp = user_stack.top();
|
||||
|
||||
@ -57,14 +57,12 @@ Result<OwnedPtr<ThreadImage>> ThreadImage::clone_from_thread(Thread* parent)
|
||||
|
||||
auto address_space = TRY(parent->address_space->clone());
|
||||
|
||||
const ELFData data = { .entry = parent->ip() };
|
||||
|
||||
const u64 kernel_stack_base = TRY(MemoryManager::alloc_for_kernel(4, MMU::ReadWrite | MMU::NoExecute));
|
||||
Stack kernel_stack { kernel_stack_base, 4 * ARCH_PAGE_SIZE };
|
||||
|
||||
image->m_kernel_stack = kernel_stack;
|
||||
image->m_user_stack = parent->stack;
|
||||
image->m_loaded_image_data = data;
|
||||
image->m_program_entry = parent->ip();
|
||||
image->m_address_space = move(address_space);
|
||||
image->m_sp = parent->sp();
|
||||
|
||||
@ -103,7 +101,7 @@ void ThreadImage::apply(Thread* thread)
|
||||
{
|
||||
thread->init_regs_user();
|
||||
|
||||
thread->set_ip(m_loaded_image_data.entry);
|
||||
thread->set_ip(m_program_entry);
|
||||
|
||||
if (m_kernel_stack.bottom()) thread->kernel_stack = m_kernel_stack;
|
||||
thread->stack = m_user_stack;
|
||||
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "ELF.h"
|
||||
#include "arch/CPU.h"
|
||||
#include "arch/MMU.h"
|
||||
#include "binfmt/BinaryFormat.h"
|
||||
#include "fs/VFS.h"
|
||||
#include "memory/AddressSpace.h"
|
||||
#include "thread/Thread.h"
|
||||
@ -18,7 +18,7 @@ class Thread;
|
||||
class ThreadImage
|
||||
{
|
||||
public:
|
||||
static Result<OwnedPtr<ThreadImage>> try_load_from_elf(SharedPtr<VFS::Inode> inode);
|
||||
static Result<OwnedPtr<ThreadImage>> try_load_from_binary(SharedPtr<BinaryFormatLoader> inode);
|
||||
|
||||
static Result<OwnedPtr<ThreadImage>> clone_from_thread(Thread* parent);
|
||||
|
||||
@ -31,6 +31,6 @@ class ThreadImage
|
||||
OwnedPtr<AddressSpace> m_address_space;
|
||||
Stack m_user_stack;
|
||||
Stack m_kernel_stack;
|
||||
ELFData m_loaded_image_data;
|
||||
u64 m_program_entry;
|
||||
u64 m_sp;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user