summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authordzwdz2021-07-24 16:55:15 +0200
committerdzwdz2021-07-24 16:55:15 +0200
commit4d5e930c48cded790f77497911706aa8f5ff0965 (patch)
treeb256d379f5841d28a74fb28b6d01720cb14a5878 /src/kernel
parent67a359d8c4b9f5cb3d2e1fb9602ebe5dfd3978cf (diff)
save all registers on syscalls
Diffstat (limited to 'src/kernel')
-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
-rw-r--r--src/kernel/main.c2
-rw-r--r--src/kernel/proc.c4
-rw-r--r--src/kernel/proc.h4
-rw-r--r--src/kernel/syscalls.c5
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);