Hacky execve

This commit is contained in:
2024-04-14 14:18:31 +02:00
parent 180cdd7993
commit fffc513b16
7 changed files with 112 additions and 52 deletions

View File

@@ -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;"

View File

@@ -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:

View File

@@ -28,6 +28,8 @@
#include "task.hpp"
#include "timer.hpp"
#include <globals.hpp>
// 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;
}

View File

@@ -10,6 +10,7 @@
void setup_syscalls();
extern "C" void _syscall_entrypoint();
extern "C" void _execve_entrypoint();
extern "C" void _syscall_ret();

View File

@@ -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<VMA>(new VMA(_ownAddressSpace.get()));
task_pointer *taskptr = static_cast<task_pointer *>(
_vma->mmap_mem(reinterpret_cast<void *>(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<task_pointer *>(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<VMA>(new VMA(_ownAddressSpace.get()));
task_pointer *taskptr = static_cast<task_pointer *>(
_vma->mmap_mem(reinterpret_cast<void *>(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<task_pointer *>(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<VMA>(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<task_pointer *>(
_vma->mmap_mem(reinterpret_cast<void *>(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<task_pointer *>(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;
}

View File

@@ -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 {

View File

@@ -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);
}
}
}