Compare commits
No commits in common. "3598dacbed6167059a5b90901bf621ec47b7e749" and "6e269c6bc4ca52064f526ff52ddc36f117fab1b5" have entirely different histories.
3598dacbed
...
6e269c6bc4
@ -175,10 +175,28 @@ static Result<void> load_service(const os::Path& path)
|
|||||||
|
|
||||||
if (parts[0].view() == "Command")
|
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]);
|
service.command = move(parts[1]);
|
||||||
continue;
|
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[0].view() == "Restart")
|
||||||
{
|
{
|
||||||
if (parts[1].view() == "true" || parts[1].view().to_uint().value_or(0) == 1)
|
if (parts[1].view() == "true" || parts[1].view().to_uint().value_or(0) == 1)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Name=mount-home
|
Name=mount-home
|
||||||
Description=Mount the user's home directory on a writable filesystem.
|
Description=Mount the user's home directory on a writable filesystem.
|
||||||
Command=/etc/startup/mount-home.sh
|
Script=/etc/startup/mount-home.sh
|
||||||
Wait=true
|
Wait=true
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
#!/bin/sh
|
|
||||||
mount -t tmpfs tmpfs /home/selene
|
mount -t tmpfs tmpfs /home/selene
|
||||||
chown selene:selene /home/selene
|
chown selene:selene /home/selene
|
||||||
|
@ -60,9 +60,7 @@ set(SOURCES
|
|||||||
src/fs/devices/FramebufferDevice.cpp
|
src/fs/devices/FramebufferDevice.cpp
|
||||||
src/fs/devices/UARTDevice.cpp
|
src/fs/devices/UARTDevice.cpp
|
||||||
src/fs/InitRD.cpp
|
src/fs/InitRD.cpp
|
||||||
src/binfmt/ELF.cpp
|
src/thread/ELF.cpp
|
||||||
src/binfmt/BinaryFormat.cpp
|
|
||||||
src/binfmt/Script.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if("${LUNA_ARCH}" MATCHES "x86_64")
|
if("${LUNA_ARCH}" MATCHES "x86_64")
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
#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)
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
@ -1,147 +0,0 @@
|
|||||||
#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,61 +0,0 @@
|
|||||||
#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));
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
#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,7 +1,6 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "arch/CPU.h"
|
#include "arch/CPU.h"
|
||||||
#include "arch/Timer.h"
|
#include "arch/Timer.h"
|
||||||
#include "binfmt/BinaryFormat.h"
|
|
||||||
#include "boot/Init.h"
|
#include "boot/Init.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "fs/InitRD.h"
|
#include "fs/InitRD.h"
|
||||||
@ -46,8 +45,6 @@ void reap_thread()
|
|||||||
mark_critical(InitRD::populate_vfs(), "Failed to load files from the initial ramdisk");
|
mark_critical(InitRD::populate_vfs(), "Failed to load files from the initial ramdisk");
|
||||||
mark_critical(DeviceRegistry::init(), "Failed to register initial devices");
|
mark_critical(DeviceRegistry::init(), "Failed to register initial devices");
|
||||||
|
|
||||||
mark_critical(BinaryFormat::init(), "Failed to register initial binary formats");
|
|
||||||
|
|
||||||
auto init =
|
auto init =
|
||||||
mark_critical(VFS::resolve_path("/bin/preinit", Credentials {}), "Can't find init in the initial ramfs!");
|
mark_critical(VFS::resolve_path("/bin/preinit", Credentials {}), "Can't find init in the initial ramfs!");
|
||||||
auto init_thread =
|
auto init_thread =
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "binfmt/BinaryFormat.h"
|
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
|
#include "thread/ELF.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
#include "thread/ThreadImage.h"
|
#include "thread/ThreadImage.h"
|
||||||
#include <bits/modes.h>
|
#include <bits/modes.h>
|
||||||
@ -70,17 +70,9 @@ Result<u64> sys_execve(Registers* regs, SyscallArgs args)
|
|||||||
kdbgln("exec: attempting to replace current image with %s", path.chars());
|
kdbgln("exec: attempting to replace current image with %s", path.chars());
|
||||||
#endif
|
#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 guard = make_scope_guard([current] { MMU::switch_page_directory(current->self_directory()); });
|
||||||
|
|
||||||
auto image = TRY(ThreadImage::try_load_from_binary(loader));
|
auto image = TRY(ThreadImage::try_load_from_elf(inode));
|
||||||
|
|
||||||
argv = TRY(loader->cmdline(move(argv)));
|
|
||||||
|
|
||||||
u64 user_argv = TRY(image->push_string_vector_on_stack(argv));
|
u64 user_argv = TRY(image->push_string_vector_on_stack(argv));
|
||||||
usize user_argc = argv.size();
|
usize user_argc = argv.size();
|
||||||
|
128
kernel/src/thread/ELF.cpp
Normal file
128
kernel/src/thread/ELF.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#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,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "binfmt/BinaryFormat.h"
|
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "memory/AddressSpace.h"
|
#include "memory/AddressSpace.h"
|
||||||
#include <luna/SharedPtr.h>
|
|
||||||
#include <luna/Types.h>
|
#include <luna/Types.h>
|
||||||
|
|
||||||
#define ELFMAG "\177ELF"
|
#define ELFMAG "\177ELF"
|
||||||
@ -49,20 +47,12 @@ typedef struct
|
|||||||
u64 p_align; /* Segment alignment */
|
u64 p_align; /* Segment alignment */
|
||||||
} Elf64_Phdr;
|
} Elf64_Phdr;
|
||||||
|
|
||||||
class ELFLoader : public BinaryFormatLoader
|
struct ELFData
|
||||||
{
|
{
|
||||||
public:
|
u64 entry;
|
||||||
Result<bool> sniff() override;
|
};
|
||||||
Result<u64> load(AddressSpace* space) override;
|
|
||||||
|
namespace ELFLoader
|
||||||
Result<Vector<String>> cmdline(Vector<String> args) override;
|
{
|
||||||
|
Result<ELFData> load(SharedPtr<VFS::Inode> inode, AddressSpace* space);
|
||||||
StringView format() const override
|
|
||||||
{
|
|
||||||
return "elf";
|
|
||||||
}
|
|
||||||
|
|
||||||
ELFLoader(SharedPtr<VFS::Inode> inode);
|
|
||||||
|
|
||||||
static Result<SharedPtr<BinaryFormatLoader>> create(SharedPtr<VFS::Inode> inode, void*);
|
|
||||||
};
|
};
|
@ -1,8 +1,8 @@
|
|||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
|
#include "ELF.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "arch/CPU.h"
|
#include "arch/CPU.h"
|
||||||
#include "arch/MMU.h"
|
#include "arch/MMU.h"
|
||||||
#include "binfmt/ELF.h"
|
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "thread/ThreadImage.h"
|
#include "thread/ThreadImage.h"
|
||||||
#include <luna/Alignment.h>
|
#include <luna/Alignment.h>
|
||||||
@ -147,10 +147,7 @@ namespace Scheduler
|
|||||||
|
|
||||||
auto guard = make_scope_guard([&] { delete thread; });
|
auto guard = make_scope_guard([&] { delete thread; });
|
||||||
|
|
||||||
// Contrary to other programs, which use BinaryFormat::create_loader(), init must be a native executable.
|
auto image = TRY(ThreadImage::try_load_from_elf(inode));
|
||||||
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 argv = TRY(image->push_string_vector_on_stack(args));
|
||||||
u64 envp = TRY(image->push_string_vector_on_stack(env));
|
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 {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<OwnedPtr<ThreadImage>> ThreadImage::try_load_from_binary(SharedPtr<BinaryFormatLoader> loader)
|
Result<OwnedPtr<ThreadImage>> ThreadImage::try_load_from_elf(SharedPtr<VFS::Inode> inode)
|
||||||
{
|
{
|
||||||
auto image = TRY(make_owned<ThreadImage>());
|
auto image = TRY(make_owned<ThreadImage>());
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ Result<OwnedPtr<ThreadImage>> ThreadImage::try_load_from_binary(SharedPtr<Binary
|
|||||||
|
|
||||||
auto guard = make_scope_guard([=] { MMU::switch_page_directory(old_directory); });
|
auto guard = make_scope_guard([=] { MMU::switch_page_directory(old_directory); });
|
||||||
|
|
||||||
const u64 entry = TRY(loader->load(address_space.ptr()));
|
const ELFData data = TRY(ELFLoader::load(inode, address_space.ptr()));
|
||||||
|
|
||||||
Stack user_stack;
|
Stack user_stack;
|
||||||
TRY(create_user_stack(user_stack, address_space.ptr()));
|
TRY(create_user_stack(user_stack, address_space.ptr()));
|
||||||
@ -44,7 +44,7 @@ Result<OwnedPtr<ThreadImage>> ThreadImage::try_load_from_binary(SharedPtr<Binary
|
|||||||
guard.deactivate();
|
guard.deactivate();
|
||||||
|
|
||||||
image->m_user_stack = user_stack;
|
image->m_user_stack = user_stack;
|
||||||
image->m_program_entry = entry;
|
image->m_loaded_image_data = data;
|
||||||
image->m_address_space = move(address_space);
|
image->m_address_space = move(address_space);
|
||||||
image->m_sp = user_stack.top();
|
image->m_sp = user_stack.top();
|
||||||
|
|
||||||
@ -57,12 +57,14 @@ Result<OwnedPtr<ThreadImage>> ThreadImage::clone_from_thread(Thread* parent)
|
|||||||
|
|
||||||
auto address_space = TRY(parent->address_space->clone());
|
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));
|
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 };
|
Stack kernel_stack { kernel_stack_base, 4 * ARCH_PAGE_SIZE };
|
||||||
|
|
||||||
image->m_kernel_stack = kernel_stack;
|
image->m_kernel_stack = kernel_stack;
|
||||||
image->m_user_stack = parent->stack;
|
image->m_user_stack = parent->stack;
|
||||||
image->m_program_entry = parent->ip();
|
image->m_loaded_image_data = data;
|
||||||
image->m_address_space = move(address_space);
|
image->m_address_space = move(address_space);
|
||||||
image->m_sp = parent->sp();
|
image->m_sp = parent->sp();
|
||||||
|
|
||||||
@ -101,7 +103,7 @@ void ThreadImage::apply(Thread* thread)
|
|||||||
{
|
{
|
||||||
thread->init_regs_user();
|
thread->init_regs_user();
|
||||||
|
|
||||||
thread->set_ip(m_program_entry);
|
thread->set_ip(m_loaded_image_data.entry);
|
||||||
|
|
||||||
if (m_kernel_stack.bottom()) thread->kernel_stack = m_kernel_stack;
|
if (m_kernel_stack.bottom()) thread->kernel_stack = m_kernel_stack;
|
||||||
thread->stack = m_user_stack;
|
thread->stack = m_user_stack;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "ELF.h"
|
||||||
#include "arch/CPU.h"
|
#include "arch/CPU.h"
|
||||||
#include "arch/MMU.h"
|
#include "arch/MMU.h"
|
||||||
#include "binfmt/BinaryFormat.h"
|
|
||||||
#include "fs/VFS.h"
|
#include "fs/VFS.h"
|
||||||
#include "memory/AddressSpace.h"
|
#include "memory/AddressSpace.h"
|
||||||
#include "thread/Thread.h"
|
#include "thread/Thread.h"
|
||||||
@ -18,7 +18,7 @@ class Thread;
|
|||||||
class ThreadImage
|
class ThreadImage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static Result<OwnedPtr<ThreadImage>> try_load_from_binary(SharedPtr<BinaryFormatLoader> inode);
|
static Result<OwnedPtr<ThreadImage>> try_load_from_elf(SharedPtr<VFS::Inode> inode);
|
||||||
|
|
||||||
static Result<OwnedPtr<ThreadImage>> clone_from_thread(Thread* parent);
|
static Result<OwnedPtr<ThreadImage>> clone_from_thread(Thread* parent);
|
||||||
|
|
||||||
@ -31,6 +31,6 @@ class ThreadImage
|
|||||||
OwnedPtr<AddressSpace> m_address_space;
|
OwnedPtr<AddressSpace> m_address_space;
|
||||||
Stack m_user_stack;
|
Stack m_user_stack;
|
||||||
Stack m_kernel_stack;
|
Stack m_kernel_stack;
|
||||||
u64 m_program_entry;
|
ELFData m_loaded_image_data;
|
||||||
u64 m_sp;
|
u64 m_sp;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user