]> git.ameliathe1st.gay Git - voyage-au-centre-des-fichiers.git/commitdiff
Implemented a very simple way of jumping to userspace
authorAmelia Coutard <eliottulio.coutard@gmail.com>
Tue, 11 Oct 2022 11:55:06 +0000 (13:55 +0200)
committerAmelia Coutard <eliottulio.coutard@gmail.com>
Tue, 11 Oct 2022 11:55:06 +0000 (13:55 +0200)
src/boot.S
src/kernel.cpp
src/ring3.S [new file with mode: 0644]
src/ring3.cpp [new file with mode: 0644]
src/ring3.hpp [new file with mode: 0644]

index d26574870ec14064b3e04d9517c1eb6fcc9a1f9a..fe2f52fcda8fc85113b83ccb1b7969366da9bf42 100644 (file)
@@ -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
index baf2dc78f1590d4a221389342f4625afaf691df0..850c108e5dfa829abab07396a5eb1bd650f2cc2a 100644 (file)
@@ -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 (file)
index 0000000..3e21c2e
--- /dev/null
@@ -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 (file)
index 0000000..282f0bb
--- /dev/null
@@ -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 (file)
index 0000000..e19e354
--- /dev/null
@@ -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();
+
+}