From 3d2eb900a3f390f6969a0d477e4287dfd8ca7043 Mon Sep 17 00:00:00 2001
From: Amelia Coutard <eliottulio.coutard@gmail.com>
Date: Tue, 1 Aug 2023 06:00:06 +0200
Subject: [PATCH] Changed processes to save all (general-purpose) registers on
 syscalls (except for r11 and rcx, of course). Will keep working on them later

---
 doc.txt               |  4 +-
 kernel/src/elf64.cpp  |  3 --
 kernel/src/kernel.cpp |  6 ++-
 kernel/src/ring3.S    | 96 +++++++++++++++++++++++++++----------------
 kernel/src/ring3.cpp  |  4 ++
 kernel/src/ring3.hpp  | 30 ++++++++------
 6 files changed, 88 insertions(+), 55 deletions(-)

diff --git a/doc.txt b/doc.txt
index 75829d0..307d7f8 100644
--- a/doc.txt
+++ b/doc.txt
@@ -12,8 +12,8 @@ isos documentation:
 0000'7FFF'FFFF'0000 ↔ 0000'8000'0000'0000 - stack: 64KiB
 -- Invalid addresses --
 FFFF'8000'0000'0000 ↔ FFFF'C000'0000'0000 - physical memory: 64TiB
-FFFF'C000'0000'0000 ↔ FFFF'C000'1000'0000 - process information table: 256MiB, 2048 processes, 4093 ports/process
-FFFF'C000'1000'0000 ↔ FFFF'FFFF'8000'0000 - unmapped: 64TiB - 2GiB - 128MiB - 64KiB
+FFFF'C000'0000'0000 ↔ ____'____'____'____ - process information table: 2048 processes, 4093 ports/process
+____'____'____'____ ↔ FFFF'FFFF'8000'0000 - unmapped
 FFFF'FFFF'8000'0000 ↔10000'0000'0000'0000 - kernel: 2GiB
 
 ---------------------------
diff --git a/kernel/src/elf64.cpp b/kernel/src/elf64.cpp
index acc4244..c129d07 100644
--- a/kernel/src/elf64.cpp
+++ b/kernel/src/elf64.cpp
@@ -33,7 +33,6 @@ void os::elf::load_elf(os::process& result, std::byte* start, std::size_t length
 	constexpr std::size_t stack_size = 16 * 0x1000 /* 64KiB */;
 	std::byte* const stack = (std::byte*)0x0000'8000'0000'0000 - stack_size;
 
-	result.exists = true;
 	result.PML4T = phys_ptr<paging::PML4T>(os::paging::page_allocator.allocate(1).ptr.get_phys_addr());
 	result.rip = std::uint64_t(elf_header.entry);
 	result.rsp = std::uint64_t(stack + stack_size);
@@ -43,8 +42,6 @@ void os::elf::load_elf(os::process& result, std::byte* start, std::size_t length
 	result.r13 = 0;
 	result.r14 = 0;
 	result.r15 = 0;
-	result.mxcsr = 0;
-	result.x87cw = 0;
 
 	// Copy kernel mappings to the new virtual address space.
 	memset(result.PML4T->contents, 0, 256 * sizeof(os::paging::PML4E));
diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp
index 1fd5a1c..2035138 100644
--- a/kernel/src/kernel.cpp
+++ b/kernel/src/kernel.cpp
@@ -59,6 +59,7 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 
 		os::paging::setup_page(PML4T, (void*)0xFFFF'C000'0000'0000, 1, 0); // The startup module.
 
+		bool module_specified = false;
 		for (auto it = multiboot2::next(info); it->type != multiboot2::info::type_t::end; it = multiboot2::next(it)) {
 			switch (it->type) {
 			case multiboot2::info::type_t::memory_map:
@@ -79,7 +80,8 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 				break;
 			case multiboot2::info::type_t::modules:
 				os::print("{}->{}: {}\n", multiboot2::modules_mod_start(it), multiboot2::modules_mod_end(it), multiboot2::modules_string(it));
-				os::assert(!os::get_process(0).exists, "Multiple modules specified in the multiboot. This is unsupported.");
+				os::assert(!module_specified, "Multiple modules specified in the multiboot. This is unsupported.");
+				module_specified = true;
 				os::elf::load_elf(os::get_process(0),
 				                  (std::byte*)multiboot2::modules_mod_start(it),
 				                  multiboot2::modules_mod_end(it) - multiboot2::modules_mod_start(it),
@@ -89,7 +91,7 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 			}
 		}
 
-		os::assert(os::get_process(0).exists, "No modules specified in the multiboot. This is unsupported.");
+		os::assert(module_specified, "No modules specified in the multiboot. This is unsupported.");
 
 		// kernel_start and kernel_end are aligned to 4K by the linker script.
 		const os::phys_ptr<os::paging::page> kernel_s = ([]() {
diff --git a/kernel/src/ring3.S b/kernel/src/ring3.S
index dd23354..5551cff 100644
--- a/kernel/src/ring3.S
+++ b/kernel/src/ring3.S
@@ -37,45 +37,53 @@ load_tss:
 
 .globl syscall_64bit_handler
 syscall_64bit_handler:
-	mov %rax, rax_save
-	movq current_pid, %rax
-	shl $17, %rax # * 0x1000 * 32 (i.e. the size of a process)
-	addq process_struct_table, %rax
-	# %rax now contains the address of the current process struct.
-	movq %rcx, 0x10(%rax) # %rip
-	movq %rbx, 0x18(%rax)
-	movq %rsp, 0x20(%rax)
-	movq %rbp, 0x28(%rax)
-	movq %r12, 0x30(%rax)
-	movq %r13, 0x38(%rax)
-	movq %r14, 0x40(%rax)
-	movq %r15, 0x48(%rax)
-	fstcw 0x58(%rax)
-	# Current process registers have now all been saved.
-	mov rax_save, %rax
-
-	mov %r10, %rcx
+	# Save all registers:
+	.irp reg,rax,rbx,rcx,rdx,rsp,rbp,rsi,rdi,r8,r9,r10,r11,r12,r13,r14,r15
+		mov %\reg, save_reg_tmp_\reg
+	.endr
+	# Setup stack:
+	mov $stack_top, %rsp
+	# Get process data location:
+	mov current_pid, %rdi
+	call get_process
+	# Really save all regs:
+	.irp reg,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+		mov save_regs_tmp + \reg * 8, %rbx # Get %r\reg
+		mov %rbx, 8 + \reg * 8(%rax) # And store it.
+	.endr
+	mov save_reg_tmp_rcx, %rbx # Save the rip also.
+	mov %rbx, 0x88(%rax)
+	# Get ready for syscall:
+	mov save_reg_tmp_rdi, %rdi
+	mov save_reg_tmp_rsi, %rsi
+	mov save_reg_tmp_rdx, %rdx
+	mov save_reg_tmp_r10, %rcx # Syscall ABI -> C ABI
+	mov save_reg_tmp_r8, %r8
+	mov save_reg_tmp_r9, %r9
+	mov save_reg_tmp_rax, %rax
 	cmp $syscall_n, %rax
-	mov $stack_top, %rsp # Setup stack
 	jae incorrect_syscall
 	callq *syscalls_call_table(, %rax, 8)
 syscall_end:
-	mov %rax, rax_save
-	movq current_pid, %rax
-	shl $17, %rax # * 0x1000 * 32 (i.e. the size of a process)
-	addq process_struct_table, %rax
-	# %rax now contains the address of the current process struct.
-	movq 0x10(%rax), %rcx # %rip
-	movq 0x18(%rax), %rbx
-	movq 0x20(%rax), %rsp
-	movq 0x28(%rax), %rbp
-	movq 0x30(%rax), %r12
-	movq 0x38(%rax), %r13
-	movq 0x40(%rax), %r14
-	movq 0x48(%rax), %r15
-	fldcw 0x58(%rax)
-	# Current process registers have now all been loaded.
-	mov rax_save, %rax
+	mov %rax, %rbp # Save the return
+	mov %rdx, %rbx # registers.
+	# Get process data location:
+	mov current_pid, %rdi
+	call get_process
+	# Restore all regs:
+	.irp reg,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+		mov 8 + \reg * 8(%rax), %rbx # Get %r\reg
+		mov %rbx, save_regs_tmp + \reg * 8 # And restore it.
+	.endr
+	mov %rbp, save_reg_tmp_rax # Restore the return
+	mov %rbx, save_reg_tmp_rdx # registers as well.
+	mov 0x88(%rax), %rbx # Save the rip in place of rcx, because this is sysret.
+	mov %rbx, save_reg_tmp_rcx
+	# Really restore all regs:
+	.irp reg,rax,rbx,rcx,rdx,rsp,rbp,rsi,rdi,r8,r9,r10,r11,r12,r13,r14,r15
+		mov save_reg_tmp_\reg, %\reg
+	.endr
+	# Current process registers have now all been restored.
 	sysretq
 incorrect_syscall:
 	call syscall_rax_error_handler
@@ -90,4 +98,20 @@ syscalls_call_table:
 process_struct_table: .quad 0xFFFFC00000000000
 
 .section .data
-rax_save: .quad 1
+save_regs_tmp:
+save_reg_tmp_rax: .quad 1
+save_reg_tmp_rbx: .quad 1
+save_reg_tmp_rcx: .quad 1
+save_reg_tmp_rdx: .quad 1
+save_reg_tmp_rsp: .quad 1
+save_reg_tmp_rbp: .quad 1
+save_reg_tmp_rsi: .quad 1
+save_reg_tmp_rdi: .quad 1
+save_reg_tmp_r8: .quad 1
+save_reg_tmp_r9: .quad 1
+save_reg_tmp_r10: .quad 1
+save_reg_tmp_r11: .quad 1
+save_reg_tmp_r12: .quad 1
+save_reg_tmp_r13: .quad 1
+save_reg_tmp_r14: .quad 1
+save_reg_tmp_r15: .quad 1
diff --git a/kernel/src/ring3.cpp b/kernel/src/ring3.cpp
index 847cbaf..c8b8400 100644
--- a/kernel/src/ring3.cpp
+++ b/kernel/src/ring3.cpp
@@ -69,4 +69,8 @@ extern "C" void os::syscall_rax_error_handler() {
 	os::assert(false, "Incorrect %rax for syscall.");
 }
 
+os::process& os::get_process(std::uint64_t pid) {
+	os::assert(pid < 2048, "Invalid pid: {}.\n", pid);
+	return ((process*)0xFFFF'C000'0000'0000)[pid];
+}
 std::uint64_t os::current_pid;
diff --git a/kernel/src/ring3.hpp b/kernel/src/ring3.hpp
index 7d26636..49069bf 100644
--- a/kernel/src/ring3.hpp
+++ b/kernel/src/ring3.hpp
@@ -61,31 +61,37 @@ struct port {
 };
 
 struct process {
-	bool exists;
 	phys_ptr<paging::PML4T> PML4T;
-	std::uint64_t rip;
+	std::uint64_t rax;
 	std::uint64_t rbx;
+	std::uint64_t rcx;
+	std::uint64_t rdx;
 	std::uint64_t rsp;
 	std::uint64_t rbp;
+	std::uint64_t rsi;
+	std::uint64_t rdi;
+	std::uint64_t r8;
+	std::uint64_t r9;
+	std::uint64_t r10;
+	std::uint64_t r11;
 	std::uint64_t r12;
 	std::uint64_t r13;
 	std::uint64_t r14;
 	std::uint64_t r15;
-	std::uint64_t mxcsr; // UNUSED for now.
-	std::uint64_t x87cw;
-	port ports[4093];
+	std::uint64_t rip;
+	port ports[2043];
+	char padding[16];
 };
-static_assert(sizeof(process) == 0x1000 * 32);
+static_assert(sizeof(process) == 4096 * 16);
+static_assert(0xFFFF'C000'0000'0000 + sizeof(process) * 2048 < 0xFFFF'FFFF'8000'0000);
+
+extern "C" process& get_process(std::uint64_t pid);
 
-inline process& get_process(std::uint64_t pid) {
-	os::assert(pid < 2048, "Invalid pid: {}.\n", pid);
-	return ((process*)0xFFFF'C000'0000'0000)[pid];
-}
 inline bool process_exists(std::uint64_t pid) {
-	return pid < 2048 && get_process(pid).exists;
+	return pid < 2048;
 }
 inline bool port_exists(std::uint64_t pid, std::uint64_t port) {
-	return port < 4093 && process_exists(pid) && get_process(pid).ports[port].exists;
+	return port < 2043 && process_exists(pid) && get_process(pid).ports[port].exists;
 }
 
 extern "C" std::uint64_t current_pid;
-- 
2.46.0