2023-03-16 21:44:58 +00:00
|
|
|
#include "ELF.h"
|
|
|
|
#include "Log.h"
|
|
|
|
#include "fs/VFS.h"
|
|
|
|
#include "memory/MemoryManager.h"
|
|
|
|
#include "sys/Syscall.h"
|
|
|
|
#include "thread/Scheduler.h"
|
|
|
|
#include "thread/ThreadImage.h"
|
|
|
|
#include <bits/modes.h>
|
|
|
|
#include <luna/CString.h>
|
|
|
|
#include <luna/ScopeGuard.h>
|
2023-03-18 20:55:16 +00:00
|
|
|
#include <luna/Vector.h>
|
|
|
|
|
|
|
|
static Result<Vector<OwnedStringView>> copy_string_vector_from_userspace(u64 address)
|
|
|
|
{
|
|
|
|
Vector<OwnedStringView> result;
|
|
|
|
|
|
|
|
const u64* user_vector = (const u64*)address;
|
|
|
|
|
2023-03-18 20:56:34 +00:00
|
|
|
u64 string_addr;
|
2023-03-18 20:55:16 +00:00
|
|
|
while (true)
|
|
|
|
{
|
2023-03-18 20:56:34 +00:00
|
|
|
if (!MemoryManager::copy_from_user_typed(user_vector, &string_addr)) return err(EFAULT);
|
|
|
|
if (!string_addr) break;
|
2023-03-18 20:55:16 +00:00
|
|
|
|
2023-03-18 20:56:34 +00:00
|
|
|
auto string = TRY(MemoryManager::strdup_from_user(string_addr));
|
2023-03-18 20:55:16 +00:00
|
|
|
TRY(result.try_append(move(string)));
|
|
|
|
user_vector++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2023-03-16 21:44:58 +00:00
|
|
|
|
2023-03-18 21:25:19 +00:00
|
|
|
static Result<u64> copy_string_vector_to_userspace(const Vector<OwnedStringView>& vec, ThreadImage& image)
|
|
|
|
{
|
|
|
|
Vector<u64> user_vec;
|
|
|
|
for (const auto& item : vec)
|
|
|
|
{
|
|
|
|
// Copy each individual string and retrieve a userspace pointer to said copy
|
|
|
|
u64 addr = TRY(image.push_mem_on_stack((const u8*)item.chars(), item.length() + 1));
|
|
|
|
TRY(user_vec.try_append(addr));
|
|
|
|
}
|
|
|
|
|
|
|
|
TRY(user_vec.try_append((u64) nullptr));
|
|
|
|
// Copy the actual vector of userspace pointers to the stack
|
|
|
|
return TRY(image.push_mem_on_stack((u8*)user_vec.data(), user_vec.size() * sizeof(u64)));
|
|
|
|
}
|
|
|
|
|
2023-03-16 21:44:58 +00:00
|
|
|
Result<u64> sys_exec(Registers* regs, SyscallArgs args)
|
|
|
|
{
|
|
|
|
auto path = TRY(MemoryManager::strdup_from_user(args[0]));
|
2023-03-18 20:55:16 +00:00
|
|
|
auto argv = TRY(copy_string_vector_from_userspace(args[1]));
|
|
|
|
|
|
|
|
// FIXME: Make sure argv is not too big.
|
2023-03-16 21:44:58 +00:00
|
|
|
|
|
|
|
auto inode = TRY(VFS::resolve_path(path.chars()));
|
|
|
|
|
|
|
|
// Not executable
|
|
|
|
if ((inode->mode() & S_IXUSR) != S_IXUSR) return err(EACCES);
|
|
|
|
|
|
|
|
kinfoln("exec: attempting to replace current image with %s", path.chars());
|
|
|
|
|
|
|
|
auto current = Scheduler::current();
|
|
|
|
|
2023-03-18 21:25:19 +00:00
|
|
|
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->directory); });
|
|
|
|
|
2023-03-16 21:44:58 +00:00
|
|
|
auto image = TRY(ThreadImage::try_load_from_elf(inode));
|
|
|
|
|
2023-03-18 21:25:19 +00:00
|
|
|
kdbgln("exec: copying argv to image memory (argc = %zu)", argv.size());
|
|
|
|
|
|
|
|
u64 user_argv = TRY(copy_string_vector_to_userspace(argv, *image));
|
|
|
|
usize user_argc = argv.size();
|
|
|
|
|
2023-03-16 21:44:58 +00:00
|
|
|
// From now on, nothing should fail.
|
|
|
|
|
|
|
|
kinfoln("exec: image load ok, will now replace existing process image");
|
|
|
|
|
2023-03-18 21:25:19 +00:00
|
|
|
guard.deactivate();
|
|
|
|
|
2023-03-18 20:55:16 +00:00
|
|
|
// FIXME: Close O_CLOEXEC file descriptors.
|
|
|
|
// for (int i = 0; i < FD_MAX; i++) { current->fd_table[i] = {}; }
|
2023-03-16 21:44:58 +00:00
|
|
|
|
|
|
|
MMU::delete_userspace_page_directory(current->directory);
|
|
|
|
|
2023-03-24 20:05:38 +00:00
|
|
|
current->name = argv[0].chars();
|
|
|
|
|
2023-03-16 21:44:58 +00:00
|
|
|
image->apply(current);
|
|
|
|
|
|
|
|
MMU::switch_page_directory(current->directory);
|
|
|
|
|
2023-03-18 21:25:19 +00:00
|
|
|
current->set_arguments(user_argc, user_argv, 0, 0);
|
|
|
|
|
2023-03-16 21:44:58 +00:00
|
|
|
memcpy(regs, ¤t->regs, sizeof(*regs));
|
|
|
|
|
|
|
|
kinfoln("exec: done");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2023-03-18 22:45:48 +00:00
|
|
|
|
|
|
|
Result<u64> sys_fork(Registers* regs, SyscallArgs)
|
|
|
|
{
|
|
|
|
auto current = Scheduler::current();
|
|
|
|
|
|
|
|
auto guard = make_scope_guard([current] { MMU::switch_page_directory(current->directory); });
|
|
|
|
|
|
|
|
kinfoln("fork: trying to duplicate process %lu", current->id);
|
|
|
|
|
|
|
|
memcpy(¤t->regs, regs, sizeof(*regs));
|
|
|
|
|
|
|
|
auto image = TRY(ThreadImage::clone_from_thread(current));
|
|
|
|
|
|
|
|
auto thread = TRY(new_thread());
|
|
|
|
|
|
|
|
thread->state = ThreadState::Runnable;
|
|
|
|
thread->is_kernel = false;
|
2023-03-24 16:37:04 +00:00
|
|
|
thread->parent_id = current->id;
|
2023-03-18 22:45:48 +00:00
|
|
|
thread->fp_data.save();
|
|
|
|
|
|
|
|
for (int i = 0; i < FD_MAX; i++) { thread->fd_table[i] = current->fd_table[i]; }
|
|
|
|
|
|
|
|
image->apply(thread);
|
|
|
|
|
|
|
|
memcpy(&thread->regs, regs, sizeof(*regs));
|
|
|
|
|
|
|
|
thread->set_return(0);
|
|
|
|
|
|
|
|
Scheduler::add_thread(thread);
|
|
|
|
|
|
|
|
return thread->id;
|
|
|
|
}
|