From 6da213d840f07a2921091a6d2fab7efa5ec5cdfa Mon Sep 17 00:00:00 2001
From: Clyne Sullivan <clyne@bitgloo.com>
Date: Sun, 29 Sep 2024 08:03:04 -0400
Subject: enter user mode

---
 gdt.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 89 insertions(+), 1 deletion(-)

(limited to 'gdt.cpp')

diff --git a/gdt.cpp b/gdt.cpp
index 27b9f42..383d1a4 100644
--- a/gdt.cpp
+++ b/gdt.cpp
@@ -19,7 +19,21 @@ struct gdt_entry_bits {
     std::uint32_t base_high              :  8;
 } __attribute__((packed));
 
-constinit static const std::array<gdt_entry_bits, 3> gdt {{
+struct TSSEntry
+{
+    std::uint32_t prevTSS;
+    std::uint32_t esp0;
+    std::uint32_t ss0;
+    std::uint32_t unused[23];
+} __attribute__((packed));
+
+static TSSEntry tss = {
+    .prevTSS = 0,
+    .esp0 = 0,
+    .ss0 = 0x10
+};
+
+static const std::array<gdt_entry_bits, 6> gdt {{
     {},
     /* kernel_code = */ {
         .limit_low = 0xFFFF,
@@ -54,6 +68,57 @@ constinit static const std::array<gdt_entry_bits, 3> gdt {{
         .big = 1,
         .gran = 1,
         .base_high = 0x00
+    },
+    /* user_code = */ {
+        .limit_low = 0xFFFF,
+        .base_low = 0x0000,
+        .accessed = 0,
+        .read_write = 1,
+        .conforming_expand_down = 0,
+        .code = 1,
+        .code_data_segment = 1,
+        .DPL = 3,
+        .present = 1,
+        .limit_high = 0xF,
+        .available = 0,
+        .long_mode = 0,
+        .big = 1,
+        .gran = 1,
+        .base_high = 0x00
+    },
+    /* user_data = */ {
+        .limit_low = 0xFFFF,
+        .base_low = 0x0000,
+        .accessed = 0,
+        .read_write = 1,
+        .conforming_expand_down = 0,
+        .code = 0,
+        .code_data_segment = 1,
+        .DPL = 3,
+        .present = 1,
+        .limit_high = 0xF,
+        .available = 0,
+        .long_mode = 0,
+        .big = 1,
+        .gran = 1,
+        .base_high = 0x00
+    },
+    /* tss = */ {
+        .limit_low = sizeof(TSSEntry),
+        .base_low = (std::uint32_t)&tss & 0xFFFFFF,
+        .accessed = 1,
+        .read_write = 0,
+        .conforming_expand_down = 0,
+        .code = 1,
+        .code_data_segment = 0,
+        .DPL = 0,
+        .present = 1,
+        .limit_high = 0,
+        .available = 0,
+        .long_mode = 0,
+        .big = 0,
+        .gran = 0,
+        .base_high = (std::uint32_t)&tss >> 24
     }
 }};
 
@@ -76,6 +141,29 @@ void gdt_initialize()
         mov %%eax, %%fs
         mov %%eax, %%gs
         mov %%eax, %%ss
+
+        mov $0x28, %%ax
+        ltr %%ax
     )" :: "m"(gdtr));
 }
 
+void enter_user_mode(void (*func)())
+{
+    asm volatile("mov %%esp, %0" : "=r" (tss.esp0));
+
+    asm volatile(R"(
+        mov $0x23, %%ax
+        mov %%ax, %%ds
+        mov %%ax, %%es
+        mov %%ax, %%fs
+        mov %%ax, %%gs
+        mov %%esp, %%eax
+        push $0x23
+        push %%esp
+        pushf
+        push $0x1b
+        push %0
+        iret
+    )" :: "b"(func));
+}
+
-- 
cgit v1.2.3