From: Amelia Coutard <eliottulio.coutard@gmail.com>
Date: Tue, 11 Oct 2022 11:55:06 +0000 (+0200)
Subject: Implemented a very simple way of jumping to userspace
X-Git-Url: https://git.ameliathe1st.gay/?a=commitdiff_plain;h=e79110fb09e1f7a59f14d79c5ac2ca688ce3cefd;p=voyage-au-centre-des-fichiers.git

Implemented a very simple way of jumping to userspace
---

diff --git a/src/boot.S b/src/boot.S
index d265748..fe2f52f 100644
--- a/src/boot.S
+++ b/src/boot.S
@@ -112,6 +112,10 @@ phys_mem_map: .skip 0x1000 * 128 - 8
 stack_bottom:
 .skip 1024 * 16 # 16KiB
 stack_top:
+interrupt_stack_bottom:
+.skip 1024 * 16 # 16KiB
+.globl interrupt_stack_top
+interrupt_stack_top:
 
 .section .bootstrap_text
 .code32
diff --git a/src/kernel.cpp b/src/kernel.cpp
index baf2dc7..850c108 100644
--- a/src/kernel.cpp
+++ b/src/kernel.cpp
@@ -3,8 +3,11 @@
 #include "utils.hpp"
 #include "serial.hpp"
 #include "interrupts.hpp"
+#include "ring3.hpp"
 
 os::idt<32> idt;
+extern "C" os::tss TSS;
+extern "C" char interrupt_stack_top;
 extern "C" os::paging::PML4T PML4T;
 
 extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_start> info) {
@@ -136,7 +139,28 @@ extern "C" void kmain(unsigned long magic, os::phys_ptr<const multiboot2::info_s
 	os::print("Mapping:\n");
 	os::paging::print_mapping(PML4T);
 
-	while (true) {
-		os::hlt();
-	}
+	// Allow userspaaaaaaaaace in ring 3. Otherwise, we just immediately page fault.
+	// Will make it a module soon-ish.
+	PML4T.contents[511].base_address()->contents[510].U_S(true);
+	PML4T.contents[511].base_address()->contents[511].U_S(true);
+	PML4T.contents[511].U_S(true);
+
+	os::print("Load ring 3 interrupts stack:\n");
+	os::set_ring0_stack(TSS, std::uint64_t(&interrupt_stack_top));
+	os::print("Load TSS:\n");
+	os::load_tss();
+	os::print("Enable syscalls:\n");
+	os::enable_syscalls();
+	os::print("Trying move to ring 3:\n");
+	os::ftl_to_userspace();
+}
+
+extern "C" std::uint64_t syscall(std::uint64_t in1);
+
+extern "C" void userspaaaaaaaaace() {
+	syscall('a');
+	syscall('b');
+	syscall('c');
+	syscall('\n');
+	while (true) { asm volatile("nop"); }
 }
diff --git a/src/ring3.S b/src/ring3.S
new file mode 100644
index 0000000..3e21c2e
--- /dev/null
+++ b/src/ring3.S
@@ -0,0 +1,27 @@
+.section .text
+
+.globl ftl_to_userspace
+ftl_to_userspace:
+	mov $userspaaaaaaaaace, %rcx
+	mov $0x202, %r11 # EFLAGS
+	sysretq
+
+.globl syscall_64bit_handler
+syscall_64bit_handler:
+	push %rcx
+	mov %r10, %rcx
+	call syscall_64bit_handler_cpp
+	pop %rcx
+	sysretq
+
+.globl load_tss
+load_tss:
+	mov $GDT.TSS, %ax
+	ltr %ax
+	ret
+
+.globl syscall
+syscall:
+	mov %rcx, %r10
+	syscall
+	ret
diff --git a/src/ring3.cpp b/src/ring3.cpp
new file mode 100644
index 0000000..282f0bb
--- /dev/null
+++ b/src/ring3.cpp
@@ -0,0 +1,27 @@
+#include "ring3.hpp"
+#include "utils.hpp"
+#include "serial.hpp"
+
+void os::set_ring0_stack(os::tss& tss, std::uint64_t stack) {
+	tss.rsp0 = stack;
+}
+
+extern "C" void syscall_64bit_handler();
+
+void os::enable_syscalls() {
+	// Enable bit 0 (SYSCALL Enable) of msr IA32_EFER.
+	// This is required to enable syscall/sysret on x86_64 intel.
+	os::set_msr(0xC0000080, os::get_msr(0xC0000080) | (1 << 0));
+	os::set_msr(0xC0000081,
+		(std::uint64_t(8  - 8 + 0b11) << 48) + // sysret_cs_and_ss (e.g., userspace segments)
+		(std::uint64_t(24 - 8 + 0b00) << 32) + // syscall_cs_and_ss (e.g., kernelspace segments)
+		std::uint64_t(0) // syscall_target_eip, only relevant to 32-bits so useless here
+	);
+	os::set_msr(0xC0000082, std::uint64_t(&syscall_64bit_handler)); // RIP for 64-bit program
+	os::set_msr(0xC0000083, 0); // RIP for 32-bit program, we ignore this one because the OS is only supposed to support programs running with 64 bits.
+	os::set_msr(0xC0000084, 0x00000000); // syscall flag mask, we don't want to change the flags for now.
+}
+
+extern "C" void syscall_64bit_handler_cpp(std::uint64_t v) {
+	os::printc((char)v);
+}
diff --git a/src/ring3.hpp b/src/ring3.hpp
new file mode 100644
index 0000000..e19e354
--- /dev/null
+++ b/src/ring3.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <cstdint>
+
+namespace os {
+
+struct __attribute__((packed)) tss {
+	std::uint32_t reserved_1;
+	std::uint64_t rsp0;
+	std::uint64_t rsp1;
+	std::uint64_t rsp2;
+	std::uint64_t reserved_2;
+	std::uint64_t ist1;
+	std::uint64_t ist2;
+	std::uint64_t ist3;
+	std::uint64_t ist4;
+	std::uint64_t ist5;
+	std::uint64_t ist6;
+	std::uint64_t ist7;
+	char reserved_3[10];
+	std::uint16_t iopb;
+};
+
+void set_ring0_stack(tss& tss, std::uint64_t stack);
+extern "C" void load_tss();
+void enable_syscalls();
+extern "C" void ftl_to_userspace();
+
+}