diff options
author | dzwdz | 2021-07-24 16:55:15 +0200 |
---|---|---|
committer | dzwdz | 2021-07-24 16:55:15 +0200 |
commit | 4d5e930c48cded790f77497911706aa8f5ff0965 (patch) | |
tree | b256d379f5841d28a74fb28b6d01720cb14a5878 /src/kernel | |
parent | 67a359d8c4b9f5cb3d2e1fb9602ebe5dfd3978cf (diff) |
save all registers on syscalls
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/arch/generic.h | 3 | ||||
-rw-r--r-- | src/kernel/arch/i386/registers.h | 13 | ||||
-rw-r--r-- | src/kernel/arch/i386/sysenter.c | 27 | ||||
-rw-r--r-- | src/kernel/arch/i386/sysenter.s | 27 | ||||
-rw-r--r-- | src/kernel/main.c | 2 | ||||
-rw-r--r-- | src/kernel/proc.c | 4 | ||||
-rw-r--r-- | src/kernel/proc.h | 4 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 5 |
8 files changed, 52 insertions, 33 deletions
diff --git a/src/kernel/arch/generic.h b/src/kernel/arch/generic.h index 8db079c..f816c71 100644 --- a/src/kernel/arch/generic.h +++ b/src/kernel/arch/generic.h @@ -1,5 +1,6 @@ #pragma once +#include <kernel/arch/i386/registers.h> #include <kernel/arch/log.h> #include <stdbool.h> @@ -17,7 +18,7 @@ void halt_cpu(); // src/arch/i386/sysenter.s void sysexit(void (*fun)(), void *stack_top); void sysenter_setup(); -int syscall_handler(int, int, int, int, void *stack, void *eip); +int syscall_handler(int, int, int, int); // all of those can allocate memory struct pagedir *pagedir_new(); diff --git a/src/kernel/arch/i386/registers.h b/src/kernel/arch/i386/registers.h new file mode 100644 index 0000000..feba157 --- /dev/null +++ b/src/kernel/arch/i386/registers.h @@ -0,0 +1,13 @@ +#pragma once +#include <stdint.h> + +struct registers { + uint32_t eax, ebx, ecx, edx, esi, edi; + void *ebp, *esp, *eip; +}; + +// saves a return value according to the SysV ABI +inline void regs_savereturn(struct registers *regs, uint64_t value) { + regs->eax = value; + regs->edx = value >> 32; +} diff --git a/src/kernel/arch/i386/sysenter.c b/src/kernel/arch/i386/sysenter.c new file mode 100644 index 0000000..91dac2e --- /dev/null +++ b/src/kernel/arch/i386/sysenter.c @@ -0,0 +1,27 @@ +#include <kernel/arch/generic.h> +#include <kernel/proc.h> + +void sysenter_stage2(int edi, int esi, void *ebp, void *esp, + int ebx, int edx, int ecx, int eax) +{ + uint64_t val; + process_current->regs = (struct registers) { + // EAX and EDX will get overriden with the return value later on + + .eax = eax, + .ecx = ecx, + .edx = edx, + .ebx = ebx, + .esi = esi, + .edi = edi, + + .esp = (void*) ecx, // not a typo, part of my calling convention + .eip = (void*) edx, // ^ + .ebp = ebp, + }; + + val = syscall_handler(eax, ebx, esi, edi); + regs_savereturn(&process_current->regs, val); + + process_switch(process_current); // TODO process_resume +} diff --git a/src/kernel/arch/i386/sysenter.s b/src/kernel/arch/i386/sysenter.s index 64b7d01..a982dd8 100644 --- a/src/kernel/arch/i386/sysenter.s +++ b/src/kernel/arch/i386/sysenter.s @@ -42,34 +42,17 @@ sysenter_setup: wrmsr mov $IA32_SYSENTER_EIP, %ecx - mov $sysenter_handler, %eax + mov $sysenter_stage1, %eax wrmsr ret -sysenter_handler: - pushal - push %edx - push %ecx - push %edi - push %esi - push %ebx - push %eax +sysenter_stage1: + pushal // register dump mov %cr0, %eax and $0x7FFFFFFF, %eax // disable paging mov %eax, %cr0 - call syscall_handler - - // save the return value - mov %eax, 52(%esp) // 24 [top of eflags] + 7*4 [skip until EAX] - mov %edx, 40(%esp) // 24 + 4*4 [skip until EBX] - - mov %cr0, %eax - or $0x80000000, %eax // enable paging - mov %eax, %cr0 - - add $24, %esp - popal - sysexit + call sysenter_stage2 + jmp halt_cpu diff --git a/src/kernel/main.c b/src/kernel/main.c index 004be15..ce69bc2 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -14,7 +14,7 @@ static void run_init(struct kmain_info *info) { for (uintptr_t off = 0; off < info->init.size; off += PAGE_SIZE) pagedir_map(proc->pages, init_base + off, info->init.at + off, true, true); - proc->eip = init_base; + proc->regs.eip = init_base; log_const("switching..."); process_switch(proc); diff --git a/src/kernel/proc.c b/src/kernel/proc.c index a3adf41..a64d5ee 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -11,7 +11,7 @@ struct process *process_new() { // map the stack to the last page in memory pagedir_map(proc->pages, (void*)~PAGE_MASK, page_alloc(1), true, true); - proc->stack_top = proc->esp = (void*) ~0xF; + proc->stack_top = proc->regs.esp = (void*) ~0xF; // map the kernel // yup, .text is writeable too. the plan is to not map the kernel @@ -26,5 +26,5 @@ struct process *process_new() { void process_switch(struct process *proc) { process_current = proc; pagedir_switch(proc->pages); - sysexit(proc->eip, proc->esp); + sysexit(proc->regs.eip, proc->regs.esp); } diff --git a/src/kernel/proc.h b/src/kernel/proc.h index 745db8d..a40d3ca 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -3,10 +3,8 @@ struct process { void *stack_top; - void *esp; - void *eip; - struct pagedir *pages; + struct registers regs; }; extern struct process *process_current; diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 1bc1a44..27e835d 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -25,10 +25,7 @@ int sc_debuglog(const char *msg, size_t len) { return len; } -int syscall_handler(int num, int a, int b, int c, void *stack, void *eip) { - process_current->esp = stack; - process_current->eip = eip; - +int syscall_handler(int num, int a, int b, int c) { switch (num) { case SC_EXIT: sc_exit((void*)a, b); |