102 lines
2.5 KiB
C++
102 lines
2.5 KiB
C++
#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())
|
|
{
|
|
task->address_space.detach();
|
|
VMM::switch_to_user_address_space(task->address_space);
|
|
}
|
|
|
|
// 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;
|
|
} |