kernel: Add a framework to add more executable formats, possibly from userspace
This lets us implement shebangs and possibly an interface similar to Linux's binfmt_misc.
This commit is contained in:
parent
6e269c6bc4
commit
1c76675e40
@ -60,7 +60,8 @@ 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
|
||||
)
|
||||
|
||||
if("${LUNA_ARCH}" MATCHES "x86_64")
|
||||
|
37
kernel/src/binfmt/BinaryFormat.cpp
Normal file
37
kernel/src/binfmt/BinaryFormat.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "binfmt/BinaryFormat.h"
|
||||
#include "binfmt/ELF.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));
|
||||
|
||||
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(const String& path, 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(const String&, 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(const String& path, 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*);
|
||||
};
|
@ -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(path), 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