diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 4871bd28..b46243d9 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -47,6 +47,7 @@ namespace Kernel pid_t pid() const { return m_pid; } BAN::ErrorOr fork(uintptr_t rsp, uintptr_t rip); + BAN::ErrorOr exec(BAN::StringView path, const char* const* argv, const char* const* envp); BAN::ErrorOr open(BAN::StringView, int); BAN::ErrorOr close(int fd); @@ -85,6 +86,8 @@ namespace Kernel static Process* create_process(); static void register_process(Process*); + BAN::ErrorOr cleanup_and_load_elf(BAN::StringView); + BAN::ErrorOr absolute_path_of(BAN::StringView) const; private: diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index 1ce7a6a1..f48b187d 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -32,6 +32,7 @@ namespace Kernel ~Thread(); BAN::ErrorOr clone(Process*, uintptr_t rsp, uintptr_t rip); + void setup_exec(); pid_t tid() const { return m_tid; } diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index cd65f260..85e03e8e 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -46,49 +46,14 @@ namespace Kernel BAN::ErrorOr Process::create_userspace(BAN::StringView path) { - auto* elf = TRY(LibELF::ELF::load_from_file(path)); - if (!elf->is_native()) - { - derrorln("ELF has invalid architecture"); - return BAN::Error::from_errno(EINVAL); - } - auto* process = create_process(); MUST(process->m_working_directory.push_back('/')); process->m_page_table = MUST(PageTable::create_userspace()); - auto& elf_file_header = elf->file_header_native(); - for (size_t i = 0; i < elf_file_header.e_phnum; i++) + if (auto res = process->cleanup_and_load_elf(path); res.is_error()) { - auto& elf_program_header = elf->program_header_native(i); - - switch (elf_program_header.p_type) - { - case LibELF::PT_NULL: - break; - case LibELF::PT_LOAD: - { - // TODO: Do some relocations or map kernel to higher half? - ASSERT(process->page_table().is_range_free(elf_program_header.p_vaddr, elf_program_header.p_memsz)); - uint8_t flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present; - if (elf_program_header.p_flags & LibELF::PF_W) - flags |= PageTable::Flags::ReadWrite; - size_t page_start = elf_program_header.p_vaddr / PAGE_SIZE; - size_t page_end = BAN::Math::div_round_up(elf_program_header.p_vaddr + elf_program_header.p_memsz, PAGE_SIZE); - - size_t page_count = page_end - page_start + 1; - MUST(process->m_mapped_ranges.push_back(VirtualRange::create(process->page_table(), page_start * PAGE_SIZE, page_count * PAGE_SIZE, flags))); - - { - PageTableScope _(process->page_table()); - memcpy((void*)elf_program_header.p_vaddr, elf->data() + elf_program_header.p_offset, elf_program_header.p_filesz); - memset((void*)(elf_program_header.p_vaddr + elf_program_header.p_filesz), 0, elf_program_header.p_memsz - elf_program_header.p_filesz); - } - break; - } - default: - ASSERT_NOT_REACHED(); - } + delete process; + return res.error(); } char** argv = nullptr; @@ -103,13 +68,9 @@ namespace Kernel process->m_userspace_entry.argc = 1; process->m_userspace_entry.argv = argv; - process->m_userspace_entry.entry = elf_file_header.e_entry; auto* thread = MUST(Thread::create_userspace(process)); process->add_thread(thread); - - delete elf; - register_process(process); return process; } @@ -225,6 +186,110 @@ namespace Kernel return forked; } + BAN::ErrorOr Process::exec(BAN::StringView path, const char* const* argv, const char* const* envp) + { + if (argv == nullptr) + return BAN::Error::from_errno(EFAULT); + + // FIXME: implement environment variables + (void)envp; + + LockGuard lock_guard(m_lock); + + MUST(cleanup_and_load_elf(path)); + + ASSERT(m_threads.size() == 1); + ASSERT(&Process::current() == this); + + int argc = 0; + while (argv[argc]) + argc++; + + { + PageTableScope _(page_table()); + m_userspace_entry.argv = (char**)MUST(allocate(sizeof(char**) * (argc + 1))); + for (int i = 0; i < argc; i++) + { + size_t len = strlen(argv[i]); + m_userspace_entry.argv[i] = (char*)MUST(allocate(len + 1)); + memcpy(m_userspace_entry.argv[i], argv[i], len + 1); + } + m_userspace_entry.argv[argc] = nullptr; + } + + m_userspace_entry.argc = argc; + + CriticalScope _; + lock_guard.~LockGuard(); + m_threads.front()->setup_exec(); + Scheduler::get().execute_current_thread(); + ASSERT_NOT_REACHED(); + } + + + BAN::ErrorOr Process::cleanup_and_load_elf(BAN::StringView path) + { + auto* elf = TRY(LibELF::ELF::load_from_file(path)); + if (!elf->is_native()) + { + derrorln("ELF has invalid architecture"); + return BAN::Error::from_errno(EINVAL); + } + + for (auto* allocator : m_fixed_width_allocators) + delete allocator; + m_fixed_width_allocators.clear(); + + if (m_general_allocator) + delete m_general_allocator; + m_general_allocator = nullptr; + + for (auto* range : m_mapped_ranges) + delete range; + m_mapped_ranges.clear(); + + m_open_files.clear(); + + auto& elf_file_header = elf->file_header_native(); + for (size_t i = 0; i < elf_file_header.e_phnum; i++) + { + auto& elf_program_header = elf->program_header_native(i); + + switch (elf_program_header.p_type) + { + case LibELF::PT_NULL: + break; + case LibELF::PT_LOAD: + { + ASSERT(page_table().is_range_free(elf_program_header.p_vaddr, elf_program_header.p_memsz)); + uint8_t flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present; + if (elf_program_header.p_flags & LibELF::PF_W) + flags |= PageTable::Flags::ReadWrite; + size_t page_start = elf_program_header.p_vaddr / PAGE_SIZE; + size_t page_end = BAN::Math::div_round_up(elf_program_header.p_vaddr + elf_program_header.p_memsz, PAGE_SIZE); + + size_t page_count = page_end - page_start + 1; + MUST(m_mapped_ranges.push_back(VirtualRange::create(page_table(), page_start * PAGE_SIZE, page_count * PAGE_SIZE, flags))); + + { + PageTableScope _(page_table()); + memcpy((void*)elf_program_header.p_vaddr, elf->data() + elf_program_header.p_offset, elf_program_header.p_filesz); + memset((void*)(elf_program_header.p_vaddr + elf_program_header.p_filesz), 0, elf_program_header.p_memsz - elf_program_header.p_filesz); + } + break; + } + default: + ASSERT_NOT_REACHED(); + } + } + + m_userspace_entry.entry = elf_file_header.e_entry; + + delete elf; + + return {}; + } + BAN::ErrorOr Process::open(BAN::StringView path, int flags) { if (flags & ~O_RDWR) diff --git a/kernel/kernel/Scheduler.cpp b/kernel/kernel/Scheduler.cpp index 39be64c2..e3a546d8 100644 --- a/kernel/kernel/Scheduler.cpp +++ b/kernel/kernel/Scheduler.cpp @@ -238,7 +238,6 @@ namespace Kernel void Scheduler::set_current_thread_done() { - VERIFY_STI(); DISABLE_INTERRUPTS(); load_temp_stack(); diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index bd905d80..68ea0dc9 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -69,25 +69,7 @@ namespace Kernel return BAN::Error::from_errno(ENOMEM); } - // Setup registers and entry - static entry_t entry_trampoline( - [](void*) - { - const auto& entry = Process::current().userspace_entry(); - thread_userspace_trampoline(Thread::current().rsp(), entry.entry, entry.argc, entry.argv); - ASSERT_NOT_REACHED(); - } - ); - thread->m_rsp = thread->stack_base() + thread->stack_size(); - thread->m_rip = (uintptr_t)entry_trampoline; - - // Setup stack for returning - { - PageTableScope _(process->page_table()); - write_to_stack(thread->m_rsp, thread); - write_to_stack(thread->m_rsp, &Thread::on_exit); - write_to_stack(thread->m_rsp, nullptr); - } + thread->setup_exec(); return thread; } @@ -141,6 +123,30 @@ namespace Kernel return thread; } + void Thread::setup_exec() + { + ASSERT(is_userspace()); + m_state = State::NotStarted; + static entry_t entry_trampoline( + [](void*) + { + const auto& entry = Process::current().userspace_entry(); + thread_userspace_trampoline(Thread::current().rsp(), entry.entry, entry.argc, entry.argv); + ASSERT_NOT_REACHED(); + } + ); + m_rsp = stack_base() + stack_size(); + m_rip = (uintptr_t)entry_trampoline; + + // Setup stack for returning + { + PageTableScope _(m_process->page_table()); + write_to_stack(m_rsp, this); + write_to_stack(m_rsp, &Thread::on_exit); + write_to_stack(m_rsp, nullptr); + } + } + void Thread::validate_stack() const { if (stack_base() <= m_rsp && m_rsp <= stack_base() + stack_size())