From fffc513b1622492b07fbe00ce820e7d4c3e387e3 Mon Sep 17 00:00:00 2001 From: Stepan Usatiuk Date: Sun, 14 Apr 2024 14:18:31 +0200 Subject: [PATCH] Hacky execve --- .../newlib/libc/sys/ficus/syscalls.c | 4 +- src/arch/x86/syscalls.asm | 18 ++- src/arch/x86/syscalls.cpp | 23 +++- src/arch/x86/syscalls.hpp | 1 + src/arch/x86/task.cpp | 104 +++++++++++------- src/arch/x86/task.hpp | 3 + src/test/init.c | 11 +- 7 files changed, 112 insertions(+), 52 deletions(-) diff --git a/ficus-toolchain/newlib/newlib-4.4.0.20231231/newlib/libc/sys/ficus/syscalls.c b/ficus-toolchain/newlib/newlib-4.4.0.20231231/newlib/libc/sys/ficus/syscalls.c index a6aadc04e..e42c31b3f 100644 --- a/ficus-toolchain/newlib/newlib-4.4.0.20231231/newlib/libc/sys/ficus/syscalls.c +++ b/ficus-toolchain/newlib/newlib-4.4.0.20231231/newlib/libc/sys/ficus/syscalls.c @@ -13,13 +13,13 @@ uint64_t _do_syscall(uint64_t id_rdi, uint64_t a1_rsi, uint64_t a2_rdx, uint64_t a3_rcx) { register uint64_t res asm("rax"); if (id_rdi != SYSCALL_FORK_ID) - asm volatile("syscall; mov (0x10016), %%rsp;" // TASK_POINTER->ret_sp_val + asm volatile("syscall; mov (0x10010), %%rsp;" // TASK_POINTER->ret_sp_val : "=ra"(res) : "D"(id_rdi), "S"(a1_rsi), "d"(a2_rdx), "a"(a3_rcx) : "cc", "rcx", "r8", "r9", "r10", "r11", "r15", "memory"); else - asm volatile("syscall; mov (0x10016), %%rsp;" // TASK_POINTER->ret_sp_val + asm volatile("syscall; mov (0x10010), %%rsp;" // TASK_POINTER->ret_sp_val "pop %%r15;" "pop %%r14;" "pop %%r13;" diff --git a/src/arch/x86/syscalls.asm b/src/arch/x86/syscalls.asm index 57ffb9ee2..e6335f394 100644 --- a/src/arch/x86/syscalls.asm +++ b/src/arch/x86/syscalls.asm @@ -19,9 +19,9 @@ _syscall_entrypoint: push r15 .not_fork: - mov [0x10016], rsp ; TASK_POINTER->ret_sp_val - mov [0x10024], r11 ; TASK_POINTER->ret_flags - mov [0x10032], rcx ; TASK_POINTER->ret_ip + mov [0x10010], rsp ; TASK_POINTER->ret_sp_val + mov [0x10018], r11 ; TASK_POINTER->ret_flags + mov [0x10020], rcx ; TASK_POINTER->ret_ip mov rsp, [0x10008] ; TASK_POINTER->entry_ksp_val mov rcx, rax ; FIXME: Not needed anymore @@ -32,7 +32,15 @@ _syscall_entrypoint: _syscall_ret: cli - mov r11, [0x10024] ; TASK_POINTER->ret_flags - mov rcx, [0x10032] ; TASK_POINTER->ret_ip + mov r11, [0x10018] ; TASK_POINTER->ret_flags + mov rcx, [0x10020] ; TASK_POINTER->ret_ip o64 sysret .end: +section .text + +global _execve_entrypoint:function (_execve_entrypoint.end - _execve_entrypoint) +_execve_entrypoint: + mov rsp,[0x10010] ; TASK_POINTER->ret_sp_val + mov rcx,[0x10028] ; TASK_POINTER->exec_ip + jmp rcx +.end: diff --git a/src/arch/x86/syscalls.cpp b/src/arch/x86/syscalls.cpp index f03781587..02b1ca6dc 100644 --- a/src/arch/x86/syscalls.cpp +++ b/src/arch/x86/syscalls.cpp @@ -28,6 +28,8 @@ #include "task.hpp" #include "timer.hpp" +#include + // Don't forget the correct order // Shockingly, it doesn't immediately break and even something simple as putchar works // even with completely broken 16-bit segments somehow @@ -185,11 +187,22 @@ uint64_t syscall_execve(const char *pathname, char *const argv[], char *const en ElfParser elfParser(read_data); - Task *utask = new Task(Task::TaskMode::TASKMODE_USER, (void (*)()) elfParser.get_entrypoint(), pathname); - if (elfParser.copy_to(utask)) - utask->start(); - else - return -1; + uint64_t flags_bak = ((task_pointer *) (TASK_POINTER))->ret_flags; + Scheduler::cur_task()->user_reset(); + + if (!elfParser.copy_to(Scheduler::cur_task())) + assert(false); + + // FIXME: that seems... hacky + char *trampoline = (char *) Scheduler::cur_task()->_vma->mmap_mem((void *) 0x5000, 4096, 0, PAGE_USER | PAGE_RW); + char *trampoline_w = (char *) HHDM_P2V(Scheduler::cur_task()->_addressSpace->virt2real(trampoline)); + for (int i = 0; i < 100; i++) { + *(trampoline_w + i) = *(((char *) &_execve_entrypoint) + i); + } + + ((task_pointer *) (TASK_POINTER))->ret_ip = (uint64_t) trampoline; + ((task_pointer *) (TASK_POINTER))->exec_ip = elfParser.get_entrypoint(); + ((task_pointer *) (TASK_POINTER))->ret_flags = flags_bak; return 0; } diff --git a/src/arch/x86/syscalls.hpp b/src/arch/x86/syscalls.hpp index f91a39fe9..cedca3259 100644 --- a/src/arch/x86/syscalls.hpp +++ b/src/arch/x86/syscalls.hpp @@ -10,6 +10,7 @@ void setup_syscalls(); extern "C" void _syscall_entrypoint(); +extern "C" void _execve_entrypoint(); extern "C" void _syscall_ret(); diff --git a/src/arch/x86/task.cpp b/src/arch/x86/task.cpp index 642a2d890..7f21d108f 100644 --- a/src/arch/x86/task.cpp +++ b/src/arch/x86/task.cpp @@ -187,6 +187,64 @@ static void trampoline(void *rdi, void (*rsi_entrypoint)()) { Scheduler::remove_self(); } +void Task::user_setup() { + assert(_mode == TaskMode::TASKMODE_USER); + _frame.cs = Arch::GDT::gdt_code_user.selector() | 0x3; + _frame.ss = Arch::GDT::gdt_data_user.selector() | 0x3; + _ownAddressSpace = UniquePtr(new AddressSpace()); + _vma = UniquePtr(new VMA(_ownAddressSpace.get())); + + task_pointer *taskptr = static_cast( + _vma->mmap_mem(reinterpret_cast(TASK_POINTER), + sizeof(task_pointer), 0, PAGE_RW | PAGE_USER)); // FIXME: this is probably unsafe + assert((uintptr_t) taskptr == TASK_POINTER); + + task_pointer *taskptr_real = reinterpret_cast(HHDM_P2V(_ownAddressSpace->virt2real(taskptr))); + + _entry_ksp_val = ((((uintptr_t) _kstack->_ptr) + (TASK_SS - 9) - 1) & (~0xFULL)); // Ensure 16byte alignment + // It should be aligned before call, therefore it actually should be aligned here + assert((_entry_ksp_val & 0xFULL) == 0); + + taskptr_real->taskptr = this; + taskptr_real->entry_ksp_val = _entry_ksp_val; + taskptr_real->ret_sp = 0x0; + + void *ustack = _vma->mmap_mem(NULL, TASK_SS, 0, PAGE_RW | PAGE_USER); + _vma->map_kern(); + + // Ensure 16byte alignment + _frame.sp = ((((uintptr_t) ustack) + (TASK_SS - 17) - 1) & (~0xFULL)) + 8; +} + +void Task::user_reset() { + assert(_mode == TaskMode::TASKMODE_USER); + + // FIXME: + // delete _ownAddressSpace.release(); + + _vma = UniquePtr(new VMA(_ownAddressSpace.get())); + + task_pointer *taskptr = static_cast( + _vma->mmap_mem(reinterpret_cast(TASK_POINTER), + sizeof(task_pointer), 0, PAGE_RW | PAGE_USER)); // FIXME: this is probably unsafe + assert((uintptr_t) taskptr == TASK_POINTER); + + task_pointer *taskptr_real = reinterpret_cast(HHDM_P2V(_ownAddressSpace->virt2real(taskptr))); + + _entry_ksp_val = ((((uintptr_t) _kstack->_ptr) + (TASK_SS - 9) - 1) & (~0xFULL)); // Ensure 16byte alignment + // It should be aligned before call, therefore it actually should be aligned here + assert((_entry_ksp_val & 0xFULL) == 0); + + taskptr_real->taskptr = this; + taskptr_real->entry_ksp_val = _entry_ksp_val; + + void *ustack = _vma->mmap_mem(NULL, TASK_SS, 0, PAGE_RW | PAGE_USER); + _vma->map_kern(); + + // Ensure 16byte alignment + taskptr_real->ret_sp = ((((uintptr_t) ustack) + (TASK_SS - 17) - 1) & (~0xFULL)) + 8; +} + Task::Task(Task::TaskMode mode, void (*entrypoint)(), const char *name) { _name = name; @@ -199,51 +257,23 @@ Task::Task(Task::TaskMode mode, void (*entrypoint)(), const char *name) { if (mode == TaskMode::TASKMODE_KERN) { _frame.cs = Arch::GDT::gdt_code.selector(); _frame.ss = Arch::GDT::gdt_data.selector(); - } else if (mode == TaskMode::TASKMODE_USER) { - _frame.cs = Arch::GDT::gdt_code_user.selector() | 0x3; - _frame.ss = Arch::GDT::gdt_data_user.selector() | 0x3; - } else { - assert(false); } for (int i = 0; i < 512; i++) _fxsave->_fxsave[i] = 0; _frame.flags = flags(); _frame.guard = Arch::kIDT_GUARD; - if (mode == TaskMode::TASKMODE_USER) { - _ownAddressSpace = UniquePtr(new AddressSpace()); - _vma = UniquePtr(new VMA(_ownAddressSpace.get())); - } + _state = TaskState::TS_BLOCKED; + _mode = mode; + _pid = max_pid.fetch_add(1); + _used_time = 0; + + if (mode == TaskMode::TASKMODE_USER) + user_setup(); + _addressSpace = mode == TaskMode::TASKMODE_KERN ? KERN_AddressSpace : _ownAddressSpace.get(); - _state = TaskState::TS_BLOCKED; - _mode = mode; - _pid = max_pid.fetch_add(1); - _used_time = 0; - if (mode == TaskMode::TASKMODE_USER) { - task_pointer *taskptr = static_cast( - _vma->mmap_mem(reinterpret_cast(TASK_POINTER), - sizeof(task_pointer), 0, PAGE_RW | PAGE_USER)); // FIXME: this is probably unsafe - assert((uintptr_t) taskptr == TASK_POINTER); - - task_pointer *taskptr_real = reinterpret_cast(HHDM_P2V(_addressSpace->virt2real(taskptr))); - - _entry_ksp_val = ((((uintptr_t) _kstack->_ptr) + (TASK_SS - 9) - 1) & (~0xFULL)); // Ensure 16byte alignment - // It should be aligned before call, therefore it actually should be aligned here - assert((_entry_ksp_val & 0xFULL) == 0); - - taskptr_real->taskptr = this; - taskptr_real->entry_ksp_val = _entry_ksp_val; - taskptr_real->ret_sp = 0x0; - } - - if (mode == TaskMode::TASKMODE_USER) { - void *ustack = _vma->mmap_mem(NULL, TASK_SS, 0, PAGE_RW | PAGE_USER); - _vma->map_kern(); - - // Ensure 16byte alignment - _frame.sp = ((((uintptr_t) ustack) + (TASK_SS - 17) - 1) & (~0xFULL)) + 8; - } else { + if (mode == TaskMode::TASKMODE_KERN) { _frame.sp = ((((uintptr_t) _kstack->_ptr) + (TASK_SS - 9) - 1) & (~0xFULL)) + 8; } diff --git a/src/arch/x86/task.hpp b/src/arch/x86/task.hpp index d66b917ba..e80e1cf32 100644 --- a/src/arch/x86/task.hpp +++ b/src/arch/x86/task.hpp @@ -58,6 +58,8 @@ public: ~ Task(); Task *clone(); + void user_setup(); + void user_reset(); //private: struct KernStack { @@ -95,6 +97,7 @@ struct task_pointer { uint64_t ret_sp; uint64_t ret_flags; uint64_t ret_ip; + uint64_t exec_ip; } __attribute__((packed)); namespace Scheduler { diff --git a/src/test/init.c b/src/test/init.c index 3b6561234..dfb3e906b 100644 --- a/src/test/init.c +++ b/src/test/init.c @@ -33,7 +33,10 @@ int main() { printf("\n %s \n", buf); } while (1) { - execve("hello2", 0, 0); + if (fork() == 0) + execve("hello2", 0, 0); + else + wait(NULL); print_mem(); sleep(500); } @@ -49,8 +52,10 @@ int main() { } else if (strcmp(line, "tasks") == 0) { print_tasks(); } else { - execve(line, 0, 0); - // sleep(10000); + if (fork() == 0) + execve(line, 0, 0); + else + wait(NULL); } } } \ No newline at end of file