summaryrefslogtreecommitdiff
path: root/src/kernel/arch
diff options
context:
space:
mode:
authordzwdz2021-07-24 16:55:15 +0200
committerdzwdz2021-07-24 16:55:15 +0200
commit4d5e930c48cded790f77497911706aa8f5ff0965 (patch)
treeb256d379f5841d28a74fb28b6d01720cb14a5878 /src/kernel/arch
parent67a359d8c4b9f5cb3d2e1fb9602ebe5dfd3978cf (diff)
save all registers on syscalls
Diffstat (limited to 'src/kernel/arch')
-rw-r--r--src/kernel/arch/generic.h3
-rw-r--r--src/kernel/arch/i386/registers.h13
-rw-r--r--src/kernel/arch/i386/sysenter.c27
-rw-r--r--src/kernel/arch/i386/sysenter.s27
4 files changed, 47 insertions, 23 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