Kernel: Don't allocate userspace stacks in Thread
Thread only cares about stack's vaddr and size. Stacks are now allocated before creating the threads.
This commit is contained in:
@@ -44,10 +44,10 @@ namespace Kernel
|
|||||||
~Process();
|
~Process();
|
||||||
void cleanup_function(Thread*);
|
void cleanup_function(Thread*);
|
||||||
|
|
||||||
void register_to_scheduler();
|
BAN::ErrorOr<vaddr_t> setup_initial_process_stack(MemoryBackedRegion&, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv);
|
||||||
|
|
||||||
void exit(int status, int signal);
|
void exit(int status, int signal);
|
||||||
|
|
||||||
void add_thread(Thread*);
|
|
||||||
// returns true if thread was the last one
|
// returns true if thread was the last one
|
||||||
bool on_thread_exit(Thread&);
|
bool on_thread_exit(Thread&);
|
||||||
|
|
||||||
|
|||||||
@@ -41,22 +41,20 @@ namespace Kernel
|
|||||||
// TODO: userspace stack size is hard limited, maybe make this dynamic?
|
// TODO: userspace stack size is hard limited, maybe make this dynamic?
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
static constexpr size_t userspace_stack_size { 32 << 20 };
|
static constexpr size_t userspace_stack_size { 32 << 20 };
|
||||||
|
static constexpr vaddr_t userspace_stack_base { 0x0000700000000000 };
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
static constexpr size_t userspace_stack_size { 4 << 20 };
|
static constexpr size_t userspace_stack_size { 4 << 20 };
|
||||||
|
static constexpr vaddr_t userspace_stack_base { 0xB0000000 };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<Thread*> create_kernel(entry_t, void*);
|
static BAN::ErrorOr<Thread*> create_kernel(entry_t, void*);
|
||||||
static BAN::ErrorOr<Thread*> create_userspace(Process*, PageTable&);
|
static BAN::ErrorOr<Thread*> create_userspace(Process*, PageTable&, vaddr_t userspace_stack_vaddr, size_t userspace_stack_size, vaddr_t entry_point, vaddr_t stack_pointer);
|
||||||
~Thread();
|
~Thread();
|
||||||
|
|
||||||
BAN::ErrorOr<Thread*> thread_create(entry_t, void*);
|
|
||||||
|
|
||||||
BAN::ErrorOr<Thread*> clone(Process*, uintptr_t sp, uintptr_t ip);
|
BAN::ErrorOr<Thread*> clone(Process*, uintptr_t sp, uintptr_t ip);
|
||||||
void setup_process_cleanup();
|
void setup_process_cleanup();
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize_userspace(vaddr_t entry, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv);
|
|
||||||
|
|
||||||
// Returns true, if thread is going to trigger signal
|
// Returns true, if thread is going to trigger signal
|
||||||
bool is_interrupted_by_signal(bool skip_stop_and_cont = false) const;
|
bool is_interrupted_by_signal(bool skip_stop_and_cont = false) const;
|
||||||
|
|
||||||
@@ -112,8 +110,6 @@ namespace Kernel
|
|||||||
vaddr_t kernel_stack_top() const { return m_kernel_stack->vaddr() + m_kernel_stack->size(); }
|
vaddr_t kernel_stack_top() const { return m_kernel_stack->vaddr() + m_kernel_stack->size(); }
|
||||||
VirtualRange& kernel_stack() { return *m_kernel_stack; }
|
VirtualRange& kernel_stack() { return *m_kernel_stack; }
|
||||||
|
|
||||||
MemoryBackedRegion& userspace_stack() { ASSERT(is_userspace() && m_userspace_stack); return *m_userspace_stack; }
|
|
||||||
|
|
||||||
static Thread& current();
|
static Thread& current();
|
||||||
static pid_t current_tid();
|
static pid_t current_tid();
|
||||||
|
|
||||||
@@ -157,8 +153,6 @@ namespace Kernel
|
|||||||
private:
|
private:
|
||||||
Thread(pid_t tid, Process*);
|
Thread(pid_t tid, Process*);
|
||||||
|
|
||||||
void setup_exec(vaddr_t ip, vaddr_t sp);
|
|
||||||
|
|
||||||
static void on_exit_trampoline(Thread*);
|
static void on_exit_trampoline(Thread*);
|
||||||
void on_exit();
|
void on_exit();
|
||||||
|
|
||||||
@@ -180,7 +174,6 @@ namespace Kernel
|
|||||||
BAN::UniqPtr<PageTable> m_keep_alive_page_table;
|
BAN::UniqPtr<PageTable> m_keep_alive_page_table;
|
||||||
|
|
||||||
BAN::UniqPtr<VirtualRange> m_kernel_stack;
|
BAN::UniqPtr<VirtualRange> m_kernel_stack;
|
||||||
MemoryBackedRegion* m_userspace_stack { nullptr };
|
|
||||||
const pid_t m_tid { 0 };
|
const pid_t m_tid { 0 };
|
||||||
State m_state { State::NotStarted };
|
State m_state { State::NotStarted };
|
||||||
Process* m_process { nullptr };
|
Process* m_process { nullptr };
|
||||||
@@ -188,6 +181,9 @@ namespace Kernel
|
|||||||
BAN::Atomic<bool> m_is_detached { false };
|
BAN::Atomic<bool> m_is_detached { false };
|
||||||
bool m_delete_process { false };
|
bool m_delete_process { false };
|
||||||
|
|
||||||
|
vaddr_t m_userspace_stack_vaddr { 0 };
|
||||||
|
size_t m_userspace_stack_size { 0 };
|
||||||
|
|
||||||
vaddr_t m_fsbase { 0 };
|
vaddr_t m_fsbase { 0 };
|
||||||
vaddr_t m_gsbase { 0 };
|
vaddr_t m_gsbase { 0 };
|
||||||
|
|
||||||
|
|||||||
@@ -97,25 +97,19 @@ namespace Kernel
|
|||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::register_to_scheduler()
|
|
||||||
{
|
|
||||||
// FIXME: Allow failing...
|
|
||||||
{
|
|
||||||
SpinLockGuard _(s_process_lock);
|
|
||||||
MUST(s_processes.push_back(this));
|
|
||||||
}
|
|
||||||
for (auto* thread : m_threads)
|
|
||||||
MUST(Processor::scheduler().add_thread(thread));
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<Process*> Process::create_userspace(const Credentials& credentials, BAN::StringView path, BAN::Span<BAN::StringView> arguments)
|
BAN::ErrorOr<Process*> Process::create_userspace(const Credentials& credentials, BAN::StringView path, BAN::Span<BAN::StringView> arguments)
|
||||||
{
|
{
|
||||||
auto* process = create_process(credentials, 0);
|
auto* process = create_process(credentials, 0);
|
||||||
|
BAN::ScopeGuard process_deleter([process] {
|
||||||
|
process->m_mapped_regions.clear();
|
||||||
|
process->m_page_table.clear();
|
||||||
|
delete process;
|
||||||
|
});
|
||||||
|
|
||||||
process->m_working_directory = VirtualFileSystem::get().root_file();
|
process->m_working_directory = VirtualFileSystem::get().root_file();
|
||||||
process->m_root_file = VirtualFileSystem::get().root_file();
|
process->m_root_file = VirtualFileSystem::get().root_file();
|
||||||
|
|
||||||
process->m_page_table = BAN::UniqPtr<PageTable>::adopt(MUST(PageTable::create_userspace()));
|
process->m_page_table = BAN::UniqPtr<PageTable>::adopt(TRY(PageTable::create_userspace()));
|
||||||
|
|
||||||
TRY(process->m_cmdline.emplace_back());
|
TRY(process->m_cmdline.emplace_back());
|
||||||
TRY(process->m_cmdline.back().append(path));
|
TRY(process->m_cmdline.back().append(path));
|
||||||
@@ -125,17 +119,12 @@ namespace Kernel
|
|||||||
TRY(process->m_cmdline.back().append(argument));
|
TRY(process->m_cmdline.back().append(argument));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* thread = TRY(Thread::create_userspace(process, process->page_table()));
|
|
||||||
BAN::ScopeGuard thread_deleter([thread] { delete thread; });
|
|
||||||
|
|
||||||
LockGuard _(process->m_process_lock);
|
|
||||||
|
|
||||||
auto executable_file = TRY(process->find_file(AT_FDCWD, path.data(), O_EXEC));
|
auto executable_file = TRY(process->find_file(AT_FDCWD, path.data(), O_EXEC));
|
||||||
auto executable_inode = executable_file.inode;
|
auto executable_inode = executable_file.inode;
|
||||||
|
|
||||||
auto executable = TRY(ELF::load_from_inode(process->m_root_file.inode, executable_inode, process->m_credentials, process->page_table()));
|
auto executable = TRY(ELF::load_from_inode(process->m_root_file.inode, executable_inode, process->m_credentials, process->page_table()));
|
||||||
for (auto& region : executable.regions)
|
for (auto& region : executable.regions)
|
||||||
TRY(process->add_mapped_region(BAN::move(region)));
|
TRY(process->m_mapped_regions.push_back(BAN::move(region)));
|
||||||
executable.regions.clear();
|
executable.regions.clear();
|
||||||
|
|
||||||
TRY(process->m_executable.append(executable_file.canonical_path));
|
TRY(process->m_executable.append(executable_file.canonical_path));
|
||||||
@@ -145,6 +134,24 @@ namespace Kernel
|
|||||||
if (executable_inode->mode().mode & +Inode::Mode::ISGID)
|
if (executable_inode->mode().mode & +Inode::Mode::ISGID)
|
||||||
process->m_credentials.set_egid(executable_inode->gid());
|
process->m_credentials.set_egid(executable_inode->gid());
|
||||||
|
|
||||||
|
process->m_shared_page_vaddr = process->page_table().reserve_free_page(executable.interp_base.value_or(0x400000), USERSPACE_END);
|
||||||
|
if (process->m_shared_page_vaddr == 0)
|
||||||
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
|
process->page_table().map_page_at(
|
||||||
|
Processor::shared_page_paddr(),
|
||||||
|
process->m_shared_page_vaddr,
|
||||||
|
PageTable::UserSupervisor | PageTable::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
auto userspace_stack = TRY(MemoryBackedRegion::create(
|
||||||
|
process->page_table(),
|
||||||
|
Thread::userspace_stack_size,
|
||||||
|
{ Thread::userspace_stack_base, USERSPACE_END },
|
||||||
|
MemoryRegion::Type::PRIVATE,
|
||||||
|
PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present,
|
||||||
|
O_RDWR
|
||||||
|
));
|
||||||
|
|
||||||
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
||||||
TRY(auxiliary_vector.reserve(5 + 2 * executable.interp_base.has_value()));
|
TRY(auxiliary_vector.reserve(5 + 2 * executable.interp_base.has_value()));
|
||||||
|
|
||||||
@@ -161,15 +168,6 @@ namespace Kernel
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
process->m_shared_page_vaddr = process->page_table().reserve_free_page(executable.interp_base.value_or(0x400000), USERSPACE_END);
|
|
||||||
if (process->m_shared_page_vaddr == 0)
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
process->page_table().map_page_at(
|
|
||||||
Processor::shared_page_paddr(),
|
|
||||||
process->m_shared_page_vaddr,
|
|
||||||
PageTable::UserSupervisor | PageTable::Present
|
|
||||||
);
|
|
||||||
|
|
||||||
TRY(auxiliary_vector.push_back({
|
TRY(auxiliary_vector.push_back({
|
||||||
.a_type = LibELF::AT_PAGESZ,
|
.a_type = LibELF::AT_PAGESZ,
|
||||||
.a_un = { .a_val = PAGE_SIZE },
|
.a_un = { .a_val = PAGE_SIZE },
|
||||||
@@ -182,12 +180,12 @@ namespace Kernel
|
|||||||
|
|
||||||
TRY(auxiliary_vector.push_back({
|
TRY(auxiliary_vector.push_back({
|
||||||
.a_type = LibELF::AT_STACK_BASE,
|
.a_type = LibELF::AT_STACK_BASE,
|
||||||
.a_un = { .a_ptr = reinterpret_cast<void*>(thread->userspace_stack().vaddr()) },
|
.a_un = { .a_ptr = reinterpret_cast<void*>(userspace_stack->vaddr()) },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
TRY(auxiliary_vector.push_back({
|
TRY(auxiliary_vector.push_back({
|
||||||
.a_type = LibELF::AT_STACK_SIZE,
|
.a_type = LibELF::AT_STACK_SIZE,
|
||||||
.a_un = { .a_ptr = reinterpret_cast<void*>(thread->userspace_stack().size()) },
|
.a_un = { .a_ptr = reinterpret_cast<void*>(userspace_stack->size()) },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
TRY(auxiliary_vector.push_back({
|
TRY(auxiliary_vector.push_back({
|
||||||
@@ -195,20 +193,39 @@ namespace Kernel
|
|||||||
.a_un = { .a_val = 0 },
|
.a_un = { .a_val = 0 },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
BAN::Optional<vaddr_t> tls_addr;
|
const vaddr_t initial_stack_pointer = TRY(process->setup_initial_process_stack(
|
||||||
if (executable.master_tls.has_value())
|
*userspace_stack,
|
||||||
{
|
|
||||||
auto tls_result = TRY(process->initialize_thread_local_storage(process->page_table(), *executable.master_tls));
|
|
||||||
TRY(process->add_mapped_region(BAN::move(tls_result.region)));
|
|
||||||
tls_addr = tls_result.addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRY(thread->initialize_userspace(
|
|
||||||
executable.entry_point,
|
|
||||||
process->m_cmdline.span(),
|
process->m_cmdline.span(),
|
||||||
process->m_environ.span(),
|
process->m_environ.span(),
|
||||||
auxiliary_vector.span()
|
auxiliary_vector.span()
|
||||||
));
|
));
|
||||||
|
|
||||||
|
const vaddr_t userspace_stack_vaddr = userspace_stack->vaddr();
|
||||||
|
const vaddr_t userspace_stack_size = userspace_stack->size();
|
||||||
|
TRY(process->m_mapped_regions.push_back(BAN::move(userspace_stack)));
|
||||||
|
|
||||||
|
BAN::Optional<vaddr_t> tls_addr;
|
||||||
|
if (executable.master_tls.has_value())
|
||||||
|
{
|
||||||
|
auto tls_result = TRY(process->initialize_thread_local_storage(process->page_table(), *executable.master_tls));
|
||||||
|
TRY(process->m_mapped_regions.push_back(BAN::move(tls_result.region)));
|
||||||
|
tls_addr = tls_result.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
BAN::sort::sort(process->m_mapped_regions.begin(), process->m_mapped_regions.end(), [](const auto& a, const auto& b) {
|
||||||
|
return a->vaddr() < b->vaddr();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* thread = TRY(Thread::create_userspace(
|
||||||
|
process,
|
||||||
|
process->page_table(),
|
||||||
|
userspace_stack_vaddr,
|
||||||
|
userspace_stack_size,
|
||||||
|
executable.entry_point,
|
||||||
|
initial_stack_pointer
|
||||||
|
));
|
||||||
|
BAN::ScopeGuard thread_deleter([thread] { delete thread; });
|
||||||
|
|
||||||
if (tls_addr.has_value())
|
if (tls_addr.has_value())
|
||||||
{
|
{
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
@@ -220,12 +237,118 @@ namespace Kernel
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: make sure the last two `MUST`s don't fail
|
||||||
|
TRY(process->m_threads.reserve(1));
|
||||||
|
TRY(Processor::scheduler().bind_thread_to_processor(thread, Processor::current_id()));
|
||||||
|
|
||||||
|
{
|
||||||
|
SpinLockGuard _(s_process_lock);
|
||||||
|
TRY(s_processes.push_back(process));
|
||||||
|
}
|
||||||
|
|
||||||
|
MUST(process->m_threads.push_back(thread));
|
||||||
|
MUST(Processor::scheduler().add_thread(thread));
|
||||||
|
|
||||||
|
process_deleter.disable();
|
||||||
thread_deleter.disable();
|
thread_deleter.disable();
|
||||||
process->add_thread(thread);
|
|
||||||
process->register_to_scheduler();
|
|
||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<vaddr_t> Process::setup_initial_process_stack(MemoryBackedRegion& stack_region, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv)
|
||||||
|
{
|
||||||
|
// System V ABI: Initial process stack
|
||||||
|
|
||||||
|
size_t needed_size = 0;
|
||||||
|
|
||||||
|
// argc
|
||||||
|
needed_size += sizeof(uintptr_t);
|
||||||
|
|
||||||
|
// argv
|
||||||
|
needed_size += (argv.size() + 1) * sizeof(uintptr_t);
|
||||||
|
for (auto arg : argv)
|
||||||
|
needed_size += arg.size() + 1;
|
||||||
|
|
||||||
|
// envp
|
||||||
|
needed_size += (envp.size() + 1) * sizeof(uintptr_t);
|
||||||
|
for (auto env : envp)
|
||||||
|
needed_size += env.size() + 1;
|
||||||
|
|
||||||
|
// auxv
|
||||||
|
needed_size += auxv.size() * sizeof(LibELF::AuxiliaryVector);
|
||||||
|
|
||||||
|
if (auto rem = needed_size % alignof(char*))
|
||||||
|
needed_size += alignof(char*) - rem;
|
||||||
|
|
||||||
|
if (needed_size > stack_region.size())
|
||||||
|
return BAN::Error::from_errno(ENOBUFS);
|
||||||
|
|
||||||
|
vaddr_t vaddr = stack_region.vaddr() + stack_region.size() - needed_size;
|
||||||
|
|
||||||
|
const size_t page_count = BAN::Math::div_round_up<size_t>(needed_size, PAGE_SIZE);
|
||||||
|
for (size_t i = 0; i < page_count; i++)
|
||||||
|
TRY(stack_region.allocate_page_containing(vaddr + i * PAGE_SIZE, true));
|
||||||
|
|
||||||
|
const auto stack_copy_buf =
|
||||||
|
[&stack_region](BAN::ConstByteSpan buffer, vaddr_t vaddr) -> void
|
||||||
|
{
|
||||||
|
ASSERT(vaddr >= stack_region.vaddr());
|
||||||
|
ASSERT(vaddr + buffer.size() <= stack_region.vaddr() + stack_region.size());
|
||||||
|
MUST(stack_region.copy_data_to_region(vaddr - stack_region.vaddr(), buffer.data(), buffer.size()));
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto stack_push_buf =
|
||||||
|
[&stack_copy_buf, &vaddr](BAN::ConstByteSpan buffer) -> void
|
||||||
|
{
|
||||||
|
stack_copy_buf(buffer, vaddr);
|
||||||
|
vaddr += buffer.size();
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto stack_push_uint =
|
||||||
|
[&stack_push_buf](uintptr_t value) -> void
|
||||||
|
{
|
||||||
|
stack_push_buf(BAN::ConstByteSpan::from(value));
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto stack_push_str =
|
||||||
|
[&stack_push_buf](BAN::StringView string) -> void
|
||||||
|
{
|
||||||
|
const uint8_t* string_u8 = reinterpret_cast<const uint8_t*>(string.data());
|
||||||
|
stack_push_buf(BAN::ConstByteSpan(string_u8, string.size() + 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
// argc
|
||||||
|
stack_push_uint(argv.size());
|
||||||
|
|
||||||
|
// argv
|
||||||
|
const vaddr_t argv_vaddr = vaddr;
|
||||||
|
vaddr += argv.size() * sizeof(uintptr_t);
|
||||||
|
stack_push_uint(0);
|
||||||
|
|
||||||
|
// envp
|
||||||
|
const vaddr_t envp_vaddr = vaddr;
|
||||||
|
vaddr += envp.size() * sizeof(uintptr_t);
|
||||||
|
stack_push_uint(0);
|
||||||
|
|
||||||
|
// auxv
|
||||||
|
for (auto aux : auxv)
|
||||||
|
stack_push_buf(BAN::ConstByteSpan::from(aux));
|
||||||
|
|
||||||
|
// information
|
||||||
|
for (size_t i = 0; i < argv.size(); i++)
|
||||||
|
{
|
||||||
|
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), argv_vaddr + i * sizeof(uintptr_t));
|
||||||
|
stack_push_str(argv[i]);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < envp.size(); i++)
|
||||||
|
{
|
||||||
|
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), envp_vaddr + i * sizeof(uintptr_t));
|
||||||
|
stack_push_str(envp[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack_region.vaddr() + stack_region.size() - needed_size;
|
||||||
|
}
|
||||||
|
|
||||||
Process::Process(const Credentials& credentials, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp)
|
Process::Process(const Credentials& credentials, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp)
|
||||||
: m_credentials(credentials)
|
: m_credentials(credentials)
|
||||||
, m_open_file_descriptors(m_credentials)
|
, m_open_file_descriptors(m_credentials)
|
||||||
@@ -266,12 +389,6 @@ namespace Kernel
|
|||||||
return valid_pgrp;
|
return valid_pgrp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process::add_thread(Thread* thread)
|
|
||||||
{
|
|
||||||
LockGuard _(m_process_lock);
|
|
||||||
MUST(m_threads.push_back(thread));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Process::cleanup_function(Thread* thread)
|
void Process::cleanup_function(Thread* thread)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@@ -304,21 +421,14 @@ namespace Kernel
|
|||||||
// NOTE: We must unmap ranges while the page table is still alive
|
// NOTE: We must unmap ranges while the page table is still alive
|
||||||
m_mapped_regions.clear();
|
m_mapped_regions.clear();
|
||||||
|
|
||||||
|
// After we give our page table to the thread, we cannot get rescheduled
|
||||||
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
thread->give_keep_alive_page_table(BAN::move(m_page_table));
|
thread->give_keep_alive_page_table(BAN::move(m_page_table));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Process::on_thread_exit(Thread& thread)
|
bool Process::on_thread_exit(Thread& thread)
|
||||||
{
|
{
|
||||||
{
|
// TODO: if main thread exists, should we delete its stack?
|
||||||
RWLockWRGuard _(m_memory_region_lock);
|
|
||||||
|
|
||||||
const size_t index = find_mapped_region(thread.userspace_stack().vaddr());
|
|
||||||
ASSERT(m_mapped_regions[index].ptr() == thread.m_userspace_stack);
|
|
||||||
|
|
||||||
m_mapped_regions.remove(index);
|
|
||||||
|
|
||||||
thread.m_userspace_stack = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
|
|
||||||
@@ -830,12 +940,23 @@ namespace Kernel
|
|||||||
BAN::String executable_path;
|
BAN::String executable_path;
|
||||||
TRY(executable_path.append(executable_file.canonical_path));
|
TRY(executable_path.append(executable_file.canonical_path));
|
||||||
|
|
||||||
// This is ugly but thread insterts userspace stack to process' memory region
|
const vaddr_t shared_page_vaddr = new_page_table->reserve_free_page(executable.interp_base.value_or(0x400000), USERSPACE_END);
|
||||||
BAN::swap(m_mapped_regions, new_mapped_regions);
|
if (shared_page_vaddr == 0)
|
||||||
auto new_thread_or_error = Thread::create_userspace(this, *new_page_table);
|
return BAN::Error::from_errno(ENOMEM);
|
||||||
BAN::swap(m_mapped_regions, new_mapped_regions);
|
new_page_table->map_page_at(
|
||||||
auto* new_thread = TRY(new_thread_or_error);
|
Processor::shared_page_paddr(),
|
||||||
BAN::ScopeGuard new_thread_deleter([new_thread] { delete new_thread; });
|
shared_page_vaddr,
|
||||||
|
PageTable::UserSupervisor | PageTable::Present
|
||||||
|
);
|
||||||
|
|
||||||
|
auto userspace_stack = TRY(MemoryBackedRegion::create(
|
||||||
|
*new_page_table,
|
||||||
|
Thread::userspace_stack_size,
|
||||||
|
{ Thread::userspace_stack_base, USERSPACE_END },
|
||||||
|
MemoryRegion::Type::PRIVATE,
|
||||||
|
PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present,
|
||||||
|
O_RDWR
|
||||||
|
));
|
||||||
|
|
||||||
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
BAN::Vector<LibELF::AuxiliaryVector> auxiliary_vector;
|
||||||
TRY(auxiliary_vector.reserve(5 + 2 * executable.interp_base.has_value()));
|
TRY(auxiliary_vector.reserve(5 + 2 * executable.interp_base.has_value()));
|
||||||
@@ -860,16 +981,6 @@ namespace Kernel
|
|||||||
.a_un = { .a_ptr = reinterpret_cast<void*>(executable.interp_base.value()) },
|
.a_un = { .a_ptr = reinterpret_cast<void*>(executable.interp_base.value()) },
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const vaddr_t shared_page_vaddr = new_page_table->reserve_free_page(executable.interp_base.value_or(0x400000), USERSPACE_END);
|
|
||||||
if (shared_page_vaddr == 0)
|
|
||||||
return BAN::Error::from_errno(ENOMEM);
|
|
||||||
new_page_table->map_page_at(
|
|
||||||
Processor::shared_page_paddr(),
|
|
||||||
shared_page_vaddr,
|
|
||||||
PageTable::UserSupervisor | PageTable::Present
|
|
||||||
);
|
|
||||||
|
|
||||||
TRY(auxiliary_vector.push_back({
|
TRY(auxiliary_vector.push_back({
|
||||||
.a_type = LibELF::AT_PAGESZ,
|
.a_type = LibELF::AT_PAGESZ,
|
||||||
.a_un = { .a_val = PAGE_SIZE },
|
.a_un = { .a_val = PAGE_SIZE },
|
||||||
@@ -882,12 +993,12 @@ namespace Kernel
|
|||||||
|
|
||||||
TRY(auxiliary_vector.push_back({
|
TRY(auxiliary_vector.push_back({
|
||||||
.a_type = LibELF::AT_STACK_BASE,
|
.a_type = LibELF::AT_STACK_BASE,
|
||||||
.a_un = { .a_ptr = reinterpret_cast<void*>(new_thread->userspace_stack().vaddr()) },
|
.a_un = { .a_ptr = reinterpret_cast<void*>(userspace_stack->vaddr()) },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
TRY(auxiliary_vector.push_back({
|
TRY(auxiliary_vector.push_back({
|
||||||
.a_type = LibELF::AT_STACK_SIZE,
|
.a_type = LibELF::AT_STACK_SIZE,
|
||||||
.a_un = { .a_ptr = reinterpret_cast<void*>(new_thread->userspace_stack().size()) },
|
.a_un = { .a_ptr = reinterpret_cast<void*>(userspace_stack->size()) },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
TRY(auxiliary_vector.push_back({
|
TRY(auxiliary_vector.push_back({
|
||||||
@@ -895,30 +1006,57 @@ namespace Kernel
|
|||||||
.a_un = { .a_val = 0 },
|
.a_un = { .a_val = 0 },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
TRY(new_thread->initialize_userspace(
|
const vaddr_t initial_stack_pointer = TRY(setup_initial_process_stack(
|
||||||
executable.entry_point,
|
*userspace_stack,
|
||||||
str_argv.span(),
|
str_argv.span(),
|
||||||
str_envp.span(),
|
str_envp.span(),
|
||||||
auxiliary_vector.span()
|
auxiliary_vector.span()
|
||||||
));
|
));
|
||||||
|
|
||||||
|
const vaddr_t userspace_stack_vaddr = userspace_stack->vaddr();
|
||||||
|
const vaddr_t userspace_stack_size = userspace_stack->size();
|
||||||
|
TRY(new_mapped_regions.emplace_back(BAN::move(userspace_stack)));
|
||||||
|
|
||||||
|
BAN::Optional<vaddr_t> tls_addr;
|
||||||
if (executable.master_tls.has_value())
|
if (executable.master_tls.has_value())
|
||||||
{
|
{
|
||||||
auto tls_result = TRY(initialize_thread_local_storage(*new_page_table, *executable.master_tls));
|
auto tls_result = TRY(initialize_thread_local_storage(*new_page_table, *executable.master_tls));
|
||||||
TRY(new_mapped_regions.emplace_back(BAN::move(tls_result.region)));
|
TRY(new_mapped_regions.emplace_back(BAN::move(tls_result.region)));
|
||||||
#if ARCH(x86_64)
|
tls_addr = tls_result.addr;
|
||||||
new_thread->set_fsbase(tls_result.addr);
|
|
||||||
#elif ARCH(i686)
|
|
||||||
new_thread->set_gsbase(tls_result.addr);
|
|
||||||
#else
|
|
||||||
#error
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::sort::sort(new_mapped_regions.begin(), new_mapped_regions.end(), [](auto& a, auto& b) {
|
BAN::sort::sort(new_mapped_regions.begin(), new_mapped_regions.end(), [](auto& a, auto& b) {
|
||||||
return a->vaddr() < b->vaddr();
|
return a->vaddr() < b->vaddr();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
auto* new_thread = TRY(Thread::create_userspace(
|
||||||
|
this,
|
||||||
|
*new_page_table,
|
||||||
|
userspace_stack_vaddr,
|
||||||
|
userspace_stack_size,
|
||||||
|
executable.entry_point,
|
||||||
|
initial_stack_pointer
|
||||||
|
));
|
||||||
|
if (tls_addr.has_value())
|
||||||
|
{
|
||||||
|
#if ARCH(x86_64)
|
||||||
|
new_thread->set_fsbase(tls_addr.value());
|
||||||
|
#elif ARCH(i686)
|
||||||
|
new_thread->set_gsbase(tls_addr.value());
|
||||||
|
#else
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: bind new thread to this processor so it wont be rescheduled before end of this function
|
||||||
|
// and so that adding the thread to the scheduler cannot fail
|
||||||
|
if (auto ret = Scheduler::bind_thread_to_processor(new_thread, Processor::current_id()); ret.is_error())
|
||||||
|
{
|
||||||
|
Processor::set_interrupt_state(InterruptState::Enabled);
|
||||||
|
delete new_thread;
|
||||||
|
return ret.release_error();
|
||||||
|
}
|
||||||
|
|
||||||
RWLockWRGuard wr_guard(m_memory_region_lock);
|
RWLockWRGuard wr_guard(m_memory_region_lock);
|
||||||
|
|
||||||
// NOTE: this is done before disabling interrupts and moving the threads as
|
// NOTE: this is done before disabling interrupts and moving the threads as
|
||||||
@@ -929,13 +1067,6 @@ namespace Kernel
|
|||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Enabled);
|
||||||
Processor::set_interrupt_state(InterruptState::Disabled);
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
|
|
||||||
// NOTE: bind new thread to this processor so it wont be rescheduled before end of this function
|
|
||||||
if (auto ret = Scheduler::bind_thread_to_processor(new_thread, Processor::current_id()); ret.is_error())
|
|
||||||
{
|
|
||||||
Processor::set_interrupt_state(InterruptState::Enabled);
|
|
||||||
return ret.release_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
// after this point, everything is initialized and nothing can fail!
|
// after this point, everything is initialized and nothing can fail!
|
||||||
|
|
||||||
ASSERT(m_threads.size() == 1);
|
ASSERT(m_threads.size() == 1);
|
||||||
@@ -948,7 +1079,6 @@ namespace Kernel
|
|||||||
m_threads.front()->m_process = nullptr;
|
m_threads.front()->m_process = nullptr;
|
||||||
m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table));
|
m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table));
|
||||||
|
|
||||||
new_thread_deleter.disable();
|
|
||||||
MUST(Processor::scheduler().add_thread(new_thread));
|
MUST(Processor::scheduler().add_thread(new_thread));
|
||||||
m_threads.front() = new_thread;
|
m_threads.front() = new_thread;
|
||||||
|
|
||||||
@@ -3402,13 +3532,43 @@ namespace Kernel
|
|||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_thread_create(void (*entry)(void*), void* arg)
|
BAN::ErrorOr<long> Process::sys_thread_create(void (*entry)(void*), void* arg)
|
||||||
{
|
{
|
||||||
|
auto userspace_stack = TRY(MemoryBackedRegion::create(
|
||||||
|
page_table(),
|
||||||
|
Thread::userspace_stack_size,
|
||||||
|
{ Thread::userspace_stack_base, USERSPACE_END },
|
||||||
|
MemoryRegion::Type::PRIVATE,
|
||||||
|
PageTable::UserSupervisor | PageTable::ReadWrite | PageTable::Present,
|
||||||
|
O_RDWR
|
||||||
|
));
|
||||||
|
|
||||||
|
const vaddr_t stack_vaddr = userspace_stack->vaddr();
|
||||||
|
const size_t stack_size = userspace_stack->size();
|
||||||
|
TRY(add_mapped_region(BAN::move(userspace_stack)));
|
||||||
|
|
||||||
|
const vaddr_t initial_stack_pointer = stack_vaddr + stack_size - sizeof(void*);
|
||||||
|
*reinterpret_cast<void**>(initial_stack_pointer) = arg;
|
||||||
|
|
||||||
|
auto* thread = TRY(Thread::create_userspace(
|
||||||
|
this,
|
||||||
|
page_table(),
|
||||||
|
stack_vaddr,
|
||||||
|
stack_size,
|
||||||
|
reinterpret_cast<vaddr_t>(entry),
|
||||||
|
initial_stack_pointer
|
||||||
|
));
|
||||||
|
thread->m_signal_block_mask = Thread::current().m_signal_block_mask;
|
||||||
|
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
|
|
||||||
auto* new_thread = TRY(Thread::current().thread_create(entry, arg));
|
TRY(m_threads.push_back(thread));
|
||||||
MUST(m_threads.push_back(new_thread));
|
if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error())
|
||||||
MUST(Processor::scheduler().add_thread(new_thread));
|
{
|
||||||
|
m_threads.pop_back();
|
||||||
|
delete thread;
|
||||||
|
return ret.release_error();
|
||||||
|
}
|
||||||
|
|
||||||
return new_thread->tid();
|
return thread->tid();
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<long> Process::sys_thread_exit(void* value)
|
BAN::ErrorOr<long> Process::sys_thread_exit(void* value)
|
||||||
|
|||||||
@@ -18,12 +18,6 @@ namespace Kernel
|
|||||||
static_assert(SYS_SIGPROCMASK == 78, "this is hard coded in arch/*/Signal.S");
|
static_assert(SYS_SIGPROCMASK == 78, "this is hard coded in arch/*/Signal.S");
|
||||||
static_assert(SIG_SETMASK == 3, "this is hard coded in arch/*/Signal.S");
|
static_assert(SIG_SETMASK == 3, "this is hard coded in arch/*/Signal.S");
|
||||||
|
|
||||||
#if ARCH(x86_64)
|
|
||||||
static constexpr vaddr_t s_user_stack_addr_start = 0x0000700000000000;
|
|
||||||
#elif ARCH(i686)
|
|
||||||
static constexpr vaddr_t s_user_stack_addr_start = 0xB0000000;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern "C" [[noreturn]] void start_kernel_thread();
|
extern "C" [[noreturn]] void start_kernel_thread();
|
||||||
extern "C" [[noreturn]] void start_userspace_thread();
|
extern "C" [[noreturn]] void start_userspace_thread();
|
||||||
|
|
||||||
@@ -198,7 +192,7 @@ namespace Kernel
|
|||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<Thread*> Thread::create_userspace(Process* process, PageTable& page_table)
|
BAN::ErrorOr<Thread*> Thread::create_userspace(Process* process, PageTable& page_table, vaddr_t userspace_stack_vaddr, size_t userspace_stack_size, vaddr_t entry_point, vaddr_t stack_pointer)
|
||||||
{
|
{
|
||||||
ASSERT(process);
|
ASSERT(process);
|
||||||
|
|
||||||
@@ -212,22 +206,32 @@ namespace Kernel
|
|||||||
|
|
||||||
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
|
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
|
||||||
page_table,
|
page_table,
|
||||||
{ s_user_stack_addr_start, USERSPACE_END },
|
{ userspace_stack_base, USERSPACE_END },
|
||||||
kernel_stack_size,
|
kernel_stack_size,
|
||||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||||
true
|
true
|
||||||
));
|
));
|
||||||
|
|
||||||
auto userspace_stack = TRY(MemoryBackedRegion::create(
|
thread->m_userspace_stack_vaddr = userspace_stack_vaddr;
|
||||||
page_table,
|
thread->m_userspace_stack_size = userspace_stack_size;
|
||||||
userspace_stack_size,
|
|
||||||
{ s_user_stack_addr_start, USERSPACE_END },
|
// Initialize stack for returning
|
||||||
MemoryRegion::Type::PRIVATE,
|
PageTable::with_fast_page(thread->kernel_stack().paddr_of(thread->kernel_stack_top() - PAGE_SIZE), [=] {
|
||||||
PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
uintptr_t cur_sp = PageTable::fast_page() + PAGE_SIZE;
|
||||||
O_RDWR
|
write_to_stack(cur_sp, 0x20 | 3);
|
||||||
));
|
write_to_stack(cur_sp, stack_pointer);
|
||||||
thread->m_userspace_stack = userspace_stack.ptr();
|
write_to_stack(cur_sp, 0x202);
|
||||||
TRY(process->add_mapped_region(BAN::move(userspace_stack)));
|
#if ARCH(x86_64)
|
||||||
|
write_to_stack(cur_sp, 0x28 | 3);
|
||||||
|
#elif ARCH(i686)
|
||||||
|
write_to_stack(cur_sp, 0x18 | 3);
|
||||||
|
#endif
|
||||||
|
write_to_stack(cur_sp, entry_point);
|
||||||
|
});
|
||||||
|
|
||||||
|
thread->m_yield_registers = {};
|
||||||
|
thread->m_yield_registers.ip = reinterpret_cast<vaddr_t>(start_userspace_thread);
|
||||||
|
thread->m_yield_registers.sp = thread->kernel_stack_top() - 5 * sizeof(uintptr_t);
|
||||||
|
|
||||||
thread_deleter.disable();
|
thread_deleter.disable();
|
||||||
|
|
||||||
@@ -311,26 +315,6 @@ namespace Kernel
|
|||||||
Processor::gdt().set_cpu_index(Processor::current_index());
|
Processor::gdt().set_cpu_index(Processor::current_index());
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<Thread*> Thread::thread_create(entry_t entry, void* arg)
|
|
||||||
{
|
|
||||||
auto* thread = TRY(create_userspace(m_process, m_process->page_table()));
|
|
||||||
|
|
||||||
if (Processor::get_current_sse_thread() == this)
|
|
||||||
save_sse();
|
|
||||||
memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage));
|
|
||||||
|
|
||||||
TRY(thread->userspace_stack().copy_data_to_region(
|
|
||||||
thread->m_userspace_stack->size() - sizeof(void*),
|
|
||||||
reinterpret_cast<const uint8_t*>(&arg),
|
|
||||||
sizeof(void*)
|
|
||||||
));
|
|
||||||
|
|
||||||
const vaddr_t entry_addr = reinterpret_cast<vaddr_t>(entry);
|
|
||||||
thread->setup_exec(entry_addr, thread->userspace_stack().vaddr() + thread->userspace_stack().size() - sizeof(void*));
|
|
||||||
|
|
||||||
return thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<Thread*> Thread::clone(Process* new_process, uintptr_t sp, uintptr_t ip)
|
BAN::ErrorOr<Thread*> Thread::clone(Process* new_process, uintptr_t sp, uintptr_t ip)
|
||||||
{
|
{
|
||||||
ASSERT(m_is_userspace);
|
ASSERT(m_is_userspace);
|
||||||
@@ -345,7 +329,7 @@ namespace Kernel
|
|||||||
|
|
||||||
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
|
thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range(
|
||||||
new_process->page_table(),
|
new_process->page_table(),
|
||||||
{ s_user_stack_addr_start, USERSPACE_END },
|
{ userspace_stack_base, USERSPACE_END },
|
||||||
kernel_stack_size,
|
kernel_stack_size,
|
||||||
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
PageTable::Flags::ReadWrite | PageTable::Flags::Present,
|
||||||
true
|
true
|
||||||
@@ -362,9 +346,8 @@ namespace Kernel
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto stack_index = new_process->find_mapped_region(m_userspace_stack->vaddr());
|
thread->m_userspace_stack_vaddr = m_userspace_stack_vaddr;
|
||||||
thread->m_userspace_stack = static_cast<MemoryBackedRegion*>(new_process->m_mapped_regions[stack_index].ptr());
|
thread->m_userspace_stack_size = m_userspace_stack_size;
|
||||||
ASSERT(thread->m_userspace_stack->vaddr() == m_userspace_stack->vaddr());
|
|
||||||
|
|
||||||
thread->m_fsbase = m_fsbase;
|
thread->m_fsbase = m_fsbase;
|
||||||
thread->m_gsbase = m_gsbase;
|
thread->m_gsbase = m_gsbase;
|
||||||
@@ -385,142 +368,13 @@ namespace Kernel
|
|||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> Thread::initialize_userspace(vaddr_t entry, BAN::Span<BAN::String> argv, BAN::Span<BAN::String> envp, BAN::Span<LibELF::AuxiliaryVector> auxv)
|
|
||||||
{
|
|
||||||
// System V ABI: Initial process stack
|
|
||||||
|
|
||||||
ASSERT(m_is_userspace);
|
|
||||||
ASSERT(m_userspace_stack);
|
|
||||||
|
|
||||||
size_t needed_size = 0;
|
|
||||||
|
|
||||||
// argc
|
|
||||||
needed_size += sizeof(uintptr_t);
|
|
||||||
|
|
||||||
// argv
|
|
||||||
needed_size += (argv.size() + 1) * sizeof(uintptr_t);
|
|
||||||
for (auto arg : argv)
|
|
||||||
needed_size += arg.size() + 1;
|
|
||||||
|
|
||||||
// envp
|
|
||||||
needed_size += (envp.size() + 1) * sizeof(uintptr_t);
|
|
||||||
for (auto env : envp)
|
|
||||||
needed_size += env.size() + 1;
|
|
||||||
|
|
||||||
// auxv
|
|
||||||
needed_size += auxv.size() * sizeof(LibELF::AuxiliaryVector);
|
|
||||||
|
|
||||||
if (auto rem = needed_size % alignof(char*))
|
|
||||||
needed_size += alignof(char*) - rem;
|
|
||||||
|
|
||||||
if (needed_size > m_userspace_stack->size())
|
|
||||||
return BAN::Error::from_errno(ENOBUFS);
|
|
||||||
|
|
||||||
vaddr_t vaddr = userspace_stack().vaddr() + userspace_stack().size() - needed_size;
|
|
||||||
|
|
||||||
const size_t page_count = BAN::Math::div_round_up<size_t>(needed_size, PAGE_SIZE);
|
|
||||||
for (size_t i = 0; i < page_count; i++)
|
|
||||||
TRY(m_userspace_stack->allocate_page_containing(vaddr + i * PAGE_SIZE, true));
|
|
||||||
|
|
||||||
const auto stack_copy_buf =
|
|
||||||
[this](BAN::ConstByteSpan buffer, vaddr_t vaddr) -> void
|
|
||||||
{
|
|
||||||
ASSERT(vaddr >= m_userspace_stack->vaddr());
|
|
||||||
ASSERT(vaddr + buffer.size() <= m_userspace_stack->vaddr() + m_userspace_stack->size());
|
|
||||||
MUST(m_userspace_stack->copy_data_to_region(vaddr - m_userspace_stack->vaddr(), buffer.data(), buffer.size()));
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto stack_push_buf =
|
|
||||||
[&stack_copy_buf, &vaddr](BAN::ConstByteSpan buffer) -> void
|
|
||||||
{
|
|
||||||
stack_copy_buf(buffer, vaddr);
|
|
||||||
vaddr += buffer.size();
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto stack_push_uint =
|
|
||||||
[&stack_push_buf](uintptr_t value) -> void
|
|
||||||
{
|
|
||||||
stack_push_buf(BAN::ConstByteSpan::from(value));
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto stack_push_str =
|
|
||||||
[&stack_push_buf](BAN::StringView string) -> void
|
|
||||||
{
|
|
||||||
const uint8_t* string_u8 = reinterpret_cast<const uint8_t*>(string.data());
|
|
||||||
stack_push_buf(BAN::ConstByteSpan(string_u8, string.size() + 1));
|
|
||||||
};
|
|
||||||
|
|
||||||
// argc
|
|
||||||
stack_push_uint(argv.size());
|
|
||||||
|
|
||||||
// argv
|
|
||||||
const vaddr_t argv_vaddr = vaddr;
|
|
||||||
vaddr += argv.size() * sizeof(uintptr_t);
|
|
||||||
stack_push_uint(0);
|
|
||||||
|
|
||||||
// envp
|
|
||||||
const vaddr_t envp_vaddr = vaddr;
|
|
||||||
vaddr += envp.size() * sizeof(uintptr_t);
|
|
||||||
stack_push_uint(0);
|
|
||||||
|
|
||||||
// auxv
|
|
||||||
for (auto aux : auxv)
|
|
||||||
stack_push_buf(BAN::ConstByteSpan::from(aux));
|
|
||||||
|
|
||||||
// information
|
|
||||||
for (size_t i = 0; i < argv.size(); i++)
|
|
||||||
{
|
|
||||||
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), argv_vaddr + i * sizeof(uintptr_t));
|
|
||||||
stack_push_str(argv[i]);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < envp.size(); i++)
|
|
||||||
{
|
|
||||||
stack_copy_buf(BAN::ConstByteSpan::from(vaddr), envp_vaddr + i * sizeof(uintptr_t));
|
|
||||||
stack_push_str(envp[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_exec(entry, m_userspace_stack->vaddr() + m_userspace_stack->size() - needed_size);
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::setup_exec(vaddr_t ip, vaddr_t sp)
|
|
||||||
{
|
|
||||||
ASSERT(is_userspace());
|
|
||||||
m_state = State::NotStarted;
|
|
||||||
|
|
||||||
// Signal mask is inherited
|
|
||||||
|
|
||||||
// Initialize stack for returning
|
|
||||||
PageTable::with_fast_page(kernel_stack().paddr_of(kernel_stack_top() - PAGE_SIZE), [=] {
|
|
||||||
uintptr_t cur_sp = PageTable::fast_page() + PAGE_SIZE;
|
|
||||||
write_to_stack(cur_sp, 0x20 | 3);
|
|
||||||
write_to_stack(cur_sp, sp);
|
|
||||||
write_to_stack(cur_sp, 0x202);
|
|
||||||
#if ARCH(x86_64)
|
|
||||||
write_to_stack(cur_sp, 0x28 | 3);
|
|
||||||
#elif ARCH(i686)
|
|
||||||
write_to_stack(cur_sp, 0x18 | 3);
|
|
||||||
#endif
|
|
||||||
write_to_stack(cur_sp, ip);
|
|
||||||
});
|
|
||||||
|
|
||||||
m_yield_registers = {};
|
|
||||||
m_yield_registers.ip = reinterpret_cast<vaddr_t>(start_userspace_thread);
|
|
||||||
m_yield_registers.sp = kernel_stack_top() - 5 * sizeof(uintptr_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::setup_process_cleanup()
|
void Thread::setup_process_cleanup()
|
||||||
{
|
{
|
||||||
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled);
|
||||||
|
|
||||||
m_state = State::NotStarted;
|
static entry_t entry = [](void* process_ptr) {
|
||||||
static entry_t entry(
|
|
||||||
[](void* process_ptr)
|
|
||||||
{
|
|
||||||
auto* thread = &Thread::current();
|
auto* thread = &Thread::current();
|
||||||
auto* process = static_cast<Process*>(process_ptr);
|
auto* process = static_cast<Process*>(process_ptr);
|
||||||
|
|
||||||
ASSERT(thread->m_process == process);
|
ASSERT(thread->m_process == process);
|
||||||
|
|
||||||
process->cleanup_function(thread);
|
process->cleanup_function(thread);
|
||||||
@@ -528,8 +382,9 @@ namespace Kernel
|
|||||||
thread->m_delete_process = true;
|
thread->m_delete_process = true;
|
||||||
|
|
||||||
// will call on thread exit after return
|
// will call on thread exit after return
|
||||||
}
|
};
|
||||||
);
|
|
||||||
|
m_state = State::NotStarted;
|
||||||
|
|
||||||
m_signal_pending_mask = 0;
|
m_signal_pending_mask = 0;
|
||||||
m_signal_block_mask = ~0ull;
|
m_signal_block_mask = ~0ull;
|
||||||
|
|||||||
Reference in New Issue
Block a user