diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 9804193e..34e89fd2 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -44,10 +44,10 @@ namespace Kernel ~Process(); void cleanup_function(Thread*); - void register_to_scheduler(); + BAN::ErrorOr setup_initial_process_stack(MemoryBackedRegion&, BAN::Span argv, BAN::Span envp, BAN::Span auxv); + void exit(int status, int signal); - void add_thread(Thread*); // returns true if thread was the last one bool on_thread_exit(Thread&); diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index bb78238d..8b5c2fd2 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -41,22 +41,20 @@ namespace Kernel // TODO: userspace stack size is hard limited, maybe make this dynamic? #if ARCH(x86_64) static constexpr size_t userspace_stack_size { 32 << 20 }; + static constexpr vaddr_t userspace_stack_base { 0x0000700000000000 }; #elif ARCH(i686) static constexpr size_t userspace_stack_size { 4 << 20 }; + static constexpr vaddr_t userspace_stack_base { 0xB0000000 }; #endif public: static BAN::ErrorOr create_kernel(entry_t, void*); - static BAN::ErrorOr create_userspace(Process*, PageTable&); + static BAN::ErrorOr create_userspace(Process*, PageTable&, vaddr_t userspace_stack_vaddr, size_t userspace_stack_size, vaddr_t entry_point, vaddr_t stack_pointer); ~Thread(); - BAN::ErrorOr thread_create(entry_t, void*); - BAN::ErrorOr clone(Process*, uintptr_t sp, uintptr_t ip); void setup_process_cleanup(); - BAN::ErrorOr initialize_userspace(vaddr_t entry, BAN::Span argv, BAN::Span envp, BAN::Span auxv); - // Returns true, if thread is going to trigger signal 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(); } VirtualRange& kernel_stack() { return *m_kernel_stack; } - MemoryBackedRegion& userspace_stack() { ASSERT(is_userspace() && m_userspace_stack); return *m_userspace_stack; } - static Thread& current(); static pid_t current_tid(); @@ -157,8 +153,6 @@ namespace Kernel private: Thread(pid_t tid, Process*); - void setup_exec(vaddr_t ip, vaddr_t sp); - static void on_exit_trampoline(Thread*); void on_exit(); @@ -180,7 +174,6 @@ namespace Kernel BAN::UniqPtr m_keep_alive_page_table; BAN::UniqPtr m_kernel_stack; - MemoryBackedRegion* m_userspace_stack { nullptr }; const pid_t m_tid { 0 }; State m_state { State::NotStarted }; Process* m_process { nullptr }; @@ -188,6 +181,9 @@ namespace Kernel BAN::Atomic m_is_detached { 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_gsbase { 0 }; diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index eb655ec1..b357dcd2 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -97,25 +97,19 @@ namespace Kernel 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::create_userspace(const Credentials& credentials, BAN::StringView path, BAN::Span arguments) { 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_root_file = VirtualFileSystem::get().root_file(); - process->m_page_table = BAN::UniqPtr::adopt(MUST(PageTable::create_userspace())); + process->m_page_table = BAN::UniqPtr::adopt(TRY(PageTable::create_userspace())); TRY(process->m_cmdline.emplace_back()); TRY(process->m_cmdline.back().append(path)); @@ -125,17 +119,12 @@ namespace Kernel 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_inode = executable_file.inode; 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) - TRY(process->add_mapped_region(BAN::move(region))); + TRY(process->m_mapped_regions.push_back(BAN::move(region))); executable.regions.clear(); TRY(process->m_executable.append(executable_file.canonical_path)); @@ -145,6 +134,24 @@ namespace Kernel if (executable_inode->mode().mode & +Inode::Mode::ISGID) 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 auxiliary_vector; 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({ .a_type = LibELF::AT_PAGESZ, .a_un = { .a_val = PAGE_SIZE }, @@ -182,12 +180,12 @@ namespace Kernel TRY(auxiliary_vector.push_back({ .a_type = LibELF::AT_STACK_BASE, - .a_un = { .a_ptr = reinterpret_cast(thread->userspace_stack().vaddr()) }, + .a_un = { .a_ptr = reinterpret_cast(userspace_stack->vaddr()) }, })); TRY(auxiliary_vector.push_back({ .a_type = LibELF::AT_STACK_SIZE, - .a_un = { .a_ptr = reinterpret_cast(thread->userspace_stack().size()) }, + .a_un = { .a_ptr = reinterpret_cast(userspace_stack->size()) }, })); TRY(auxiliary_vector.push_back({ @@ -195,20 +193,39 @@ namespace Kernel .a_un = { .a_val = 0 }, })); - BAN::Optional 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->add_mapped_region(BAN::move(tls_result.region))); - tls_addr = tls_result.addr; - } - - TRY(thread->initialize_userspace( - executable.entry_point, + const vaddr_t initial_stack_pointer = TRY(process->setup_initial_process_stack( + *userspace_stack, process->m_cmdline.span(), process->m_environ.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 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 ARCH(x86_64) @@ -220,12 +237,118 @@ namespace Kernel #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(); - process->add_thread(thread); - process->register_to_scheduler(); + return process; } + BAN::ErrorOr Process::setup_initial_process_stack(MemoryBackedRegion& stack_region, BAN::Span argv, BAN::Span envp, BAN::Span 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(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(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) : m_credentials(credentials) , m_open_file_descriptors(m_credentials) @@ -266,12 +389,6 @@ namespace Kernel 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) { { @@ -304,21 +421,14 @@ namespace Kernel // NOTE: We must unmap ranges while the page table is still alive 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)); } bool Process::on_thread_exit(Thread& thread) { - { - 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; - } + // TODO: if main thread exists, should we delete its stack? LockGuard _(m_process_lock); @@ -830,12 +940,23 @@ namespace Kernel BAN::String executable_path; TRY(executable_path.append(executable_file.canonical_path)); - // This is ugly but thread insterts userspace stack to process' memory region - BAN::swap(m_mapped_regions, new_mapped_regions); - auto new_thread_or_error = Thread::create_userspace(this, *new_page_table); - BAN::swap(m_mapped_regions, new_mapped_regions); - auto* new_thread = TRY(new_thread_or_error); - BAN::ScopeGuard new_thread_deleter([new_thread] { delete new_thread; }); + 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 + ); + + 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 auxiliary_vector; TRY(auxiliary_vector.reserve(5 + 2 * executable.interp_base.has_value())); @@ -860,16 +981,6 @@ namespace Kernel .a_un = { .a_ptr = reinterpret_cast(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({ .a_type = LibELF::AT_PAGESZ, .a_un = { .a_val = PAGE_SIZE }, @@ -882,12 +993,12 @@ namespace Kernel TRY(auxiliary_vector.push_back({ .a_type = LibELF::AT_STACK_BASE, - .a_un = { .a_ptr = reinterpret_cast(new_thread->userspace_stack().vaddr()) }, + .a_un = { .a_ptr = reinterpret_cast(userspace_stack->vaddr()) }, })); TRY(auxiliary_vector.push_back({ .a_type = LibELF::AT_STACK_SIZE, - .a_un = { .a_ptr = reinterpret_cast(new_thread->userspace_stack().size()) }, + .a_un = { .a_ptr = reinterpret_cast(userspace_stack->size()) }, })); TRY(auxiliary_vector.push_back({ @@ -895,30 +1006,57 @@ namespace Kernel .a_un = { .a_val = 0 }, })); - TRY(new_thread->initialize_userspace( - executable.entry_point, + const vaddr_t initial_stack_pointer = TRY(setup_initial_process_stack( + *userspace_stack, str_argv.span(), str_envp.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 tls_addr; if (executable.master_tls.has_value()) { 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))); -#if ARCH(x86_64) - new_thread->set_fsbase(tls_result.addr); -#elif ARCH(i686) - new_thread->set_gsbase(tls_result.addr); -#else -#error -#endif + tls_addr = tls_result.addr; } BAN::sort::sort(new_mapped_regions.begin(), new_mapped_regions.end(), [](auto& a, auto& b) { 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); // 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); 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! ASSERT(m_threads.size() == 1); @@ -948,7 +1079,6 @@ namespace Kernel m_threads.front()->m_process = nullptr; m_threads.front()->give_keep_alive_page_table(BAN::move(m_page_table)); - new_thread_deleter.disable(); MUST(Processor::scheduler().add_thread(new_thread)); m_threads.front() = new_thread; @@ -3402,13 +3532,43 @@ namespace Kernel BAN::ErrorOr 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(initial_stack_pointer) = arg; + + auto* thread = TRY(Thread::create_userspace( + this, + page_table(), + stack_vaddr, + stack_size, + reinterpret_cast(entry), + initial_stack_pointer + )); + thread->m_signal_block_mask = Thread::current().m_signal_block_mask; + LockGuard _(m_process_lock); - auto* new_thread = TRY(Thread::current().thread_create(entry, arg)); - MUST(m_threads.push_back(new_thread)); - MUST(Processor::scheduler().add_thread(new_thread)); + TRY(m_threads.push_back(thread)); + if (auto ret = Processor::scheduler().add_thread(thread); ret.is_error()) + { + m_threads.pop_back(); + delete thread; + return ret.release_error(); + } - return new_thread->tid(); + return thread->tid(); } BAN::ErrorOr Process::sys_thread_exit(void* value) diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 6f30fae4..306a26f7 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -18,12 +18,6 @@ namespace Kernel 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"); -#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_userspace_thread(); @@ -198,7 +192,7 @@ namespace Kernel return thread; } - BAN::ErrorOr Thread::create_userspace(Process* process, PageTable& page_table) + BAN::ErrorOr 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); @@ -212,22 +206,32 @@ namespace Kernel thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range( page_table, - { s_user_stack_addr_start, USERSPACE_END }, + { userspace_stack_base, USERSPACE_END }, kernel_stack_size, PageTable::Flags::ReadWrite | PageTable::Flags::Present, true )); - auto userspace_stack = TRY(MemoryBackedRegion::create( - page_table, - userspace_stack_size, - { s_user_stack_addr_start, USERSPACE_END }, - MemoryRegion::Type::PRIVATE, - PageTable::Flags::UserSupervisor | PageTable::Flags::ReadWrite | PageTable::Flags::Present, - O_RDWR - )); - thread->m_userspace_stack = userspace_stack.ptr(); - TRY(process->add_mapped_region(BAN::move(userspace_stack))); + thread->m_userspace_stack_vaddr = userspace_stack_vaddr; + thread->m_userspace_stack_size = userspace_stack_size; + + // Initialize stack for returning + PageTable::with_fast_page(thread->kernel_stack().paddr_of(thread->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, stack_pointer); + 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, entry_point); + }); + + thread->m_yield_registers = {}; + thread->m_yield_registers.ip = reinterpret_cast(start_userspace_thread); + thread->m_yield_registers.sp = thread->kernel_stack_top() - 5 * sizeof(uintptr_t); thread_deleter.disable(); @@ -311,26 +315,6 @@ namespace Kernel Processor::gdt().set_cpu_index(Processor::current_index()); } - BAN::ErrorOr 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(&arg), - sizeof(void*) - )); - - const vaddr_t entry_addr = reinterpret_cast(entry); - thread->setup_exec(entry_addr, thread->userspace_stack().vaddr() + thread->userspace_stack().size() - sizeof(void*)); - - return thread; - } - BAN::ErrorOr Thread::clone(Process* new_process, uintptr_t sp, uintptr_t ip) { ASSERT(m_is_userspace); @@ -345,7 +329,7 @@ namespace Kernel thread->m_kernel_stack = TRY(VirtualRange::create_to_vaddr_range( new_process->page_table(), - { s_user_stack_addr_start, USERSPACE_END }, + { userspace_stack_base, USERSPACE_END }, kernel_stack_size, PageTable::Flags::ReadWrite | PageTable::Flags::Present, true @@ -362,9 +346,8 @@ namespace Kernel ); }); - const auto stack_index = new_process->find_mapped_region(m_userspace_stack->vaddr()); - thread->m_userspace_stack = static_cast(new_process->m_mapped_regions[stack_index].ptr()); - ASSERT(thread->m_userspace_stack->vaddr() == m_userspace_stack->vaddr()); + thread->m_userspace_stack_vaddr = m_userspace_stack_vaddr; + thread->m_userspace_stack_size = m_userspace_stack_size; thread->m_fsbase = m_fsbase; thread->m_gsbase = m_gsbase; @@ -385,151 +368,23 @@ namespace Kernel return thread; } - BAN::ErrorOr Thread::initialize_userspace(vaddr_t entry, BAN::Span argv, BAN::Span envp, BAN::Span 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(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(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(start_userspace_thread); - m_yield_registers.sp = kernel_stack_top() - 5 * sizeof(uintptr_t); - } - void Thread::setup_process_cleanup() { ASSERT(Processor::get_interrupt_state() == InterruptState::Disabled); + static entry_t entry = [](void* process_ptr) { + auto* thread = &Thread::current(); + auto* process = static_cast(process_ptr); + ASSERT(thread->m_process == process); + + process->cleanup_function(thread); + + thread->m_delete_process = true; + + // will call on thread exit after return + }; + m_state = State::NotStarted; - static entry_t entry( - [](void* process_ptr) - { - auto* thread = &Thread::current(); - auto* process = static_cast(process_ptr); - - ASSERT(thread->m_process == process); - - process->cleanup_function(thread); - - thread->m_delete_process = true; - - // will call on thread exit after return - } - ); m_signal_pending_mask = 0; m_signal_block_mask = ~0ull;