#define MODULE "exec" #include "assert.h" #include "errno.h" #include "interrupts/Interrupts.h" #include "memory/MemoryManager.h" #include "std/stdlib.h" #include "std/string.h" #include "sys/elf/ELFLoader.h" #include "thread/Scheduler.h" void sys_exec(Context* context, const char* pathname) { if (!pathname) { context->rax = -EINVAL; // FIXME: This should probably return EFAULT. return; } kinfoln("exec(): executing %s", pathname); VFS::Node* program = VFS::resolve_path(pathname); if (!program) { context->rax = -ENOENT; return; } uint64_t allocated_stack = (uint64_t)MemoryManager::get_pages(TASK_PAGES_IN_STACK, MAP_READ_WRITE | MAP_USER); if (!allocated_stack) { context->rax = -ENOMEM; return; } char* kpathname = strdup( pathname); // Since we are going to free the original task's memory, we cannot use anything coming from it. // FIXME: This should be done later, but since there is a very high chance that loading the executed program's // ELF image will overwrite ours, we have to do it here. ELFLoader::release_elf_image(Scheduler::current_task()->image); // FIXME: Check the ELF image is valid before loading it into memory. This will allow us to first check, then free // the previous image, then load, which should reduce the chances of loading failing to almost zero. ELFImage* image = ELFLoader::load_elf_from_filesystem(kpathname); if (!image) { MemoryManager::release_pages((void*)allocated_stack, TASK_PAGES_IN_STACK); Scheduler::current_task()->image = nullptr; kfree(kpathname); kerrorln("exec(): ERROR: Failed to load program. Previous program has already been freed, thus cannot " "return to it."); return Scheduler::task_exit(context, -255); } kfree(kpathname); Interrupts::disable(); ASSERT(!Interrupts::are_enabled()); // This part is pretty sensitive. Task* task = Scheduler::current_task(); ASSERT(task); // At this point, pretty much nothing can fail. MemoryManager::release_pages((void*)task->allocated_stack, TASK_PAGES_IN_STACK); task->allocated_stack = allocated_stack; Scheduler::reset_task(task, image); set_context_from_task(*task, context); return; }