From acf0c1333d620821820b2246e1c7acc0aaf0bd44 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Mon, 22 Jul 2024 19:31:21 +0200
Subject: kernel: use IRET instead of SYSRET for switching into usermode

I want to implement a new syscall for returning from "interrupts" (my
crappy take on Plan 9's notes / UNIX signals), and I've realized that
I can't use SYSRET for that, as it clobbers RCX and R11.

This hasn't been an issue so far, as I've only been switching into usermode
to return from syscalls, but now I might be switching into it at arbitrary
moments (right after an interrupt handler recovers from a page fault, etc).

I could make it so I switch between IRET and SYSRET depending on the context,
but I don't think it's worth it.
---
 src/kernel/arch/amd64/sysenter.s | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

(limited to 'src/kernel/arch/amd64')

diff --git a/src/kernel/arch/amd64/sysenter.s b/src/kernel/arch/amd64/sysenter.s
index c1af69f..8d91c4a 100644
--- a/src/kernel/arch/amd64/sysenter.s
+++ b/src/kernel/arch/amd64/sysenter.s
@@ -2,6 +2,7 @@
 .set SEG_r0code, 1
 .set SEG_r3code32, 3
 .set SEG_r3data, 4
+.set SEG_r3code, 5
 
 .set IA32_STAR, 0xC0000081
 .set IA32_LSTAR, 0xC0000082
@@ -40,16 +41,22 @@ stored_rsp:
 pagedir_current:
 	.skip 8
 
+// temporarily used for IRET
+	.skip 8
+	.skip 8
+	.skip 8
+	.skip 8
+	.skip 8
+dumb_stack:
+
 .global _sysexit_real
 .type _sysexit_real, @function
 _sysexit_real:
-	/* TODO check if SYSRET correctly sets segments
 	mov $(SEG_r3data << 3 | 3), %ax
 	mov %ax, %ds
 	mov %ax, %es
 	mov %ax, %fs
 	mov %ax, %gs
-	*/
 
 	/* The state image referenced with an FXRSTOR instruction must have
 	 * been saved using an  FXSAVE instruction or be in the same format
@@ -81,8 +88,14 @@ _sysexit_real:
 	// enable paging
 	mov (pagedir_current), %rsp
 	mov %rsp, %cr3
-	mov (stored_rsp), %rsp
-	sysretq
+
+	mov $dumb_stack, %rsp
+	push $(SEG_r3data << 3 | 3) /* SS */
+	push (stored_rsp) /* SP */
+	push %r11 /* FLAGS */
+	push $(SEG_r3code << 3 | 3) /* CS */
+	push %rcx /* IP */
+	iretq
 
 sysenter_stage1:
 	cli
-- 
cgit v1.2.3