2023-03-16 21:44:58 +00:00
|
|
|
#include "thread/ThreadImage.h"
|
|
|
|
#include "memory/MemoryManager.h"
|
|
|
|
#include "thread/Thread.h"
|
2023-06-19 08:41:32 +00:00
|
|
|
#include <luna/Alignment.h>
|
2023-03-18 21:25:19 +00:00
|
|
|
#include <luna/CString.h>
|
2023-03-16 21:44:58 +00:00
|
|
|
|
2023-05-04 14:36:24 +00:00
|
|
|
static constexpr usize DEFAULT_USER_STACK_PAGES = 6;
|
|
|
|
static constexpr usize DEFAULT_USER_STACK_SIZE = DEFAULT_USER_STACK_PAGES * ARCH_PAGE_SIZE;
|
2023-07-12 14:06:56 +00:00
|
|
|
static constexpr u64 THREAD_STACK_BASE = 0x10000;
|
2023-05-04 14:36:24 +00:00
|
|
|
|
2023-07-12 14:06:56 +00:00
|
|
|
static Result<void> create_user_stack(Stack& user_stack, AddressSpace* space)
|
2023-03-16 21:44:58 +00:00
|
|
|
{
|
2023-05-04 14:36:24 +00:00
|
|
|
TRY(MemoryManager::alloc_at_zeroed(THREAD_STACK_BASE, DEFAULT_USER_STACK_PAGES,
|
|
|
|
MMU::ReadWrite | MMU::NoExecute | MMU::User));
|
2023-03-16 21:44:58 +00:00
|
|
|
|
2023-07-12 14:06:56 +00:00
|
|
|
auto guard = make_scope_guard([] { MemoryManager::unmap_owned(THREAD_STACK_BASE, DEFAULT_USER_STACK_PAGES); });
|
2023-03-16 21:44:58 +00:00
|
|
|
|
2023-07-12 14:06:56 +00:00
|
|
|
if (!TRY(space->test_and_alloc_region(THREAD_STACK_BASE, DEFAULT_USER_STACK_PAGES, true))) return err(ENOMEM);
|
2023-03-16 21:44:58 +00:00
|
|
|
|
|
|
|
guard.deactivate();
|
|
|
|
|
2023-05-04 14:36:24 +00:00
|
|
|
user_stack = { THREAD_STACK_BASE, DEFAULT_USER_STACK_SIZE };
|
2023-03-16 21:44:58 +00:00
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
Result<OwnedPtr<ThreadImage>> ThreadImage::try_load_from_elf(SharedPtr<VFS::Inode> inode)
|
|
|
|
{
|
|
|
|
auto image = TRY(make_owned<ThreadImage>());
|
|
|
|
|
2023-07-09 18:38:04 +00:00
|
|
|
auto address_space = TRY(AddressSpace::try_create());
|
2023-03-16 21:44:58 +00:00
|
|
|
|
|
|
|
auto old_directory = MMU::get_page_directory();
|
|
|
|
|
2023-07-09 18:38:04 +00:00
|
|
|
MMU::switch_page_directory(address_space->page_directory());
|
2023-03-16 21:44:58 +00:00
|
|
|
|
2023-07-09 18:32:42 +00:00
|
|
|
auto guard = make_scope_guard([=] { MMU::switch_page_directory(old_directory); });
|
2023-03-16 21:44:58 +00:00
|
|
|
|
2023-07-09 18:38:04 +00:00
|
|
|
const ELFData data = TRY(ELFLoader::load(inode, address_space.ptr()));
|
2023-03-16 21:44:58 +00:00
|
|
|
|
|
|
|
Stack user_stack;
|
2023-07-12 14:06:56 +00:00
|
|
|
TRY(create_user_stack(user_stack, address_space.ptr()));
|
2023-03-16 21:44:58 +00:00
|
|
|
|
|
|
|
guard.deactivate();
|
|
|
|
|
|
|
|
image->m_user_stack = user_stack;
|
|
|
|
image->m_loaded_image_data = data;
|
2023-07-09 18:38:04 +00:00
|
|
|
image->m_address_space = move(address_space);
|
2023-03-18 21:25:19 +00:00
|
|
|
image->m_sp = user_stack.top();
|
2023-03-16 21:44:58 +00:00
|
|
|
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
2023-03-18 22:45:48 +00:00
|
|
|
Result<OwnedPtr<ThreadImage>> ThreadImage::clone_from_thread(Thread* parent)
|
|
|
|
{
|
|
|
|
auto image = TRY(make_owned<ThreadImage>());
|
|
|
|
|
2023-07-09 18:38:04 +00:00
|
|
|
auto address_space = TRY(parent->address_space->clone());
|
2023-03-18 22:45:48 +00:00
|
|
|
|
|
|
|
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;
|
2023-07-09 18:38:04 +00:00
|
|
|
image->m_address_space = move(address_space);
|
2023-03-18 22:45:48 +00:00
|
|
|
image->m_sp = parent->sp();
|
|
|
|
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
2023-03-18 21:25:19 +00:00
|
|
|
Result<u64> ThreadImage::push_mem_on_stack(const u8* mem, usize size)
|
|
|
|
{
|
|
|
|
if ((m_sp - size) < m_user_stack.bottom()) return err(E2BIG);
|
|
|
|
|
|
|
|
if (!MemoryManager::validate_user_write((void*)(m_sp - size), size)) return err(EFAULT);
|
|
|
|
|
|
|
|
m_sp -= size;
|
|
|
|
|
|
|
|
memcpy((void*)m_sp, mem, size);
|
|
|
|
|
|
|
|
return m_sp;
|
|
|
|
}
|
|
|
|
|
2023-04-07 12:36:24 +00:00
|
|
|
Result<u64> ThreadImage::push_string_vector_on_stack(const Vector<String>& vec)
|
|
|
|
{
|
|
|
|
Vector<u64> user_vec;
|
|
|
|
for (const auto& item : vec)
|
|
|
|
{
|
|
|
|
// Copy each individual string and retrieve a userspace pointer to said copy
|
|
|
|
u64 addr = TRY(push_mem_on_stack((const u8*)item.chars(), item.length() + 1));
|
|
|
|
TRY(user_vec.try_append(addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
TRY(user_vec.try_append((u64) nullptr));
|
|
|
|
// Copy the actual vector of userspace pointers to the stack
|
|
|
|
return TRY(push_mem_on_stack((u8*)user_vec.data(), user_vec.size() * sizeof(u64)));
|
|
|
|
}
|
|
|
|
|
2023-03-16 21:44:58 +00:00
|
|
|
void ThreadImage::apply(Thread* thread)
|
|
|
|
{
|
|
|
|
thread->init_regs_user();
|
|
|
|
|
|
|
|
thread->set_ip(m_loaded_image_data.entry);
|
|
|
|
|
2023-07-12 14:06:56 +00:00
|
|
|
if (m_kernel_stack.bottom()) thread->kernel_stack = m_kernel_stack;
|
2023-03-16 21:44:58 +00:00
|
|
|
thread->stack = m_user_stack;
|
2023-06-19 08:41:32 +00:00
|
|
|
thread->set_sp(align_down<16>(m_sp));
|
2023-03-16 21:44:58 +00:00
|
|
|
|
2023-07-09 18:38:04 +00:00
|
|
|
thread->active_directory = m_address_space->page_directory();
|
2023-03-16 21:44:58 +00:00
|
|
|
|
2023-07-09 18:38:04 +00:00
|
|
|
thread->address_space = move(m_address_space);
|
2023-03-16 21:44:58 +00:00
|
|
|
}
|