#define MODULE "exec" #include "errno.h" #include "interrupts/Interrupts.h" #include "kassert.h" #include "memory/MemoryManager.h" #include "memory/PMM.h" #include "memory/VMM.h" #include "std/stdlib.h" #include "std/string.h" #include "sys/Syscall.h" #include "sys/elf/ELFLoader.h" #include "thread/Scheduler.h" void sys_exec(Context* context, const char* pathname) { /*context->rax = -ENOSYS; // FIXME: Make exec() work under separate address spaces. return;*/ char* kpathname = Syscall::strdup_from_user(pathname); if (!kpathname) { context->rax = -EFAULT; return; } kinfoln("exec(): executing %s", kpathname); VFS::Node* program = VFS::resolve_path(kpathname); if (!program) { kfree(kpathname); context->rax = -ENOENT; return; } if (program->type == VFS_DIRECTORY) { kfree(kpathname); context->rax = -EISDIR; return; } long memusage; if ((memusage = ELFLoader::check_elf_image(program)) < 0) { kfree(kpathname); context->rax = -ENOEXEC; return; } uint64_t allocated_stack = (uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); if (!allocated_stack) { kfree(kpathname); context->rax = -ENOMEM; return; } uint64_t allocated_stack_phys = VMM::get_physical(allocated_stack); if ((uint64_t)memusage > PMM::get_free()) { kfree(kpathname); MemoryManager::release_pages((void*)allocated_stack, TASK_PAGES_IN_STACK); context->rax = -ENOMEM; return; } Interrupts::disable(); ASSERT(!Interrupts::are_enabled()); // This part is pretty sensitive. Task* task = Scheduler::current_task(); ASSERT(task); if (task->address_space.is_cloned()) { kdbgln("Detaching cloned address space, %p, %s", (void*)task->address_space.get_pml4(), task->address_space.is_cloned() ? "is cloned" : "is not cloned"); task->address_space.detach(); VMM::switch_to_user_address_space(task->address_space); kdbgln("Detached cloned address space, %p, %s", (void*)task->address_space.get_pml4(), task->address_space.is_cloned() ? "is cloned" : "is not cloned"); } // At this point, pretty much nothing can fail. ELFImage* image = ELFLoader::load_elf_from_vfs(program); ASSERT(image); // If check_elf_image succeeded, load_elf_from_vfs MUST succeed, unless something has gone terribly // wrong. task->allocated_stack = allocated_stack; for (uint64_t i = 0; i < TASK_PAGES_IN_STACK; i++) { VMM::map(allocated_stack + (i * PAGE_SIZE), allocated_stack_phys + (i * PAGE_SIZE), MAP_READ_WRITE | MAP_USER); } Scheduler::reset_task(task, image); set_context_from_task(*task, context); kfree(kpathname); return; }