2022-10-12 15:42:01 +00:00
|
|
|
#define MODULE "exec"
|
|
|
|
|
|
|
|
#include "assert.h"
|
|
|
|
#include "errno.h"
|
|
|
|
#include "interrupts/Interrupts.h"
|
|
|
|
#include "memory/MemoryManager.h"
|
2022-10-12 16:04:20 +00:00
|
|
|
#include "std/stdlib.h"
|
|
|
|
#include "std/string.h"
|
2022-10-12 15:42:01 +00:00
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
2022-10-12 16:04:20 +00:00
|
|
|
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.
|
2022-10-12 15:42:01 +00:00
|
|
|
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.
|
2022-10-12 16:04:20 +00:00
|
|
|
ELFImage* image = ELFLoader::load_elf_from_filesystem(kpathname);
|
2022-10-12 15:42:01 +00:00
|
|
|
if (!image)
|
|
|
|
{
|
|
|
|
MemoryManager::release_pages((void*)allocated_stack, TASK_PAGES_IN_STACK);
|
|
|
|
Scheduler::current_task()->image = nullptr;
|
2022-10-12 16:04:20 +00:00
|
|
|
kfree(kpathname);
|
|
|
|
kerrorln("exec(): ERROR: Failed to load program. Previous program has already been freed, thus cannot "
|
|
|
|
"return to it.");
|
2022-10-12 15:42:01 +00:00
|
|
|
return Scheduler::task_exit(context, -255);
|
|
|
|
}
|
|
|
|
|
2022-10-12 16:04:20 +00:00
|
|
|
kfree(kpathname);
|
|
|
|
|
2022-10-12 15:42:01 +00:00
|
|
|
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;
|
|
|
|
}
|