]> code.bitgloo.com Git - clyne/osdev.git/commitdiff
enter user mode
authorClyne Sullivan <clyne@bitgloo.com>
Sun, 29 Sep 2024 12:03:04 +0000 (08:03 -0400)
committerClyne Sullivan <clyne@bitgloo.com>
Sun, 29 Sep 2024 12:03:04 +0000 (08:03 -0400)
Makefile
gdt.cpp
gdt.hpp
idt.cpp
kernel.cpp
memory.cpp

index cb089919eb0c7023fc8fce7d525f81b5cc1e5a87..284f931e0fc3b75a6a45c52845ca3fb800397ecb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -39,5 +39,5 @@ clean:
 
 run: myos.iso
        @echo "  QEMU"
-       @qemu-system-i386 -drive file=$<,index=2,media=cdrom -monitor stdio -no-reboot #-s -S #-d int
+       @qemu-system-i386 -drive file=$<,index=2,media=cdrom -monitor stdio -no-reboot -s -S #-d int
 
diff --git a/gdt.cpp b/gdt.cpp
index 27b9f4215487159e3e55c485902ac8d3d33b5d8e..383d1a4104e74d66cb2624b51d66d03b6e6168d4 100644 (file)
--- 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));
+}
+
diff --git a/gdt.hpp b/gdt.hpp
index 0d7a9b66dd63eaa952dba4471942217f17e1b179..de5e8fcb79364abd28ce3e2654c050c5477a4eb5 100644 (file)
--- a/gdt.hpp
+++ b/gdt.hpp
@@ -2,6 +2,7 @@
 #define GDT_HPP
 
 void gdt_initialize();
+void enter_user_mode(void (*func)());
 
 #endif // GDT_HPP
 
diff --git a/idt.cpp b/idt.cpp
index 0dc0f73ea0026cc38fef8fe8f573282797518d87..c889c14667846fdf886340c76323d302551a4846 100644 (file)
--- a/idt.cpp
+++ b/idt.cpp
@@ -8,6 +8,8 @@
 
 extern TextOutput& term;
 
+static constexpr unsigned InterruptCount = 49;
+
 static constexpr std::uint8_t TaskGate   = 0x5;
 static constexpr std::uint8_t IntrGate16 = 0x6;
 static constexpr std::uint8_t TrapGate16 = 0x7;
@@ -25,7 +27,7 @@ struct idt_entry_bits {
     std::uint32_t offset_high            : 16;
 } __attribute__((packed));
 
-static std::array<Callback, 48> callbacks;
+static std::array<Callback, InterruptCount> callbacks;
 
 extern "C"
 void interruptGeneralHandler(Registers regs)
@@ -91,10 +93,12 @@ struct StubEntry
 static auto idt =
     []<std::size_t... ints>(std::index_sequence<ints...>) {
         return std::array<idt_entry_bits, 256> { StubEntry<ints>()... };
-    }(std::make_index_sequence<48>{});
+    }(std::make_index_sequence<InterruptCount>{});
 
 void idt_initialize()
 {
+    idt[0x28].dpl = 3;
+
     auto idtr = reinterpret_cast<std::uint64_t>(idt.data());
     idtr <<= 16;
     idtr |= idt.size() * sizeof(idt[0]);
index cbeab58658275146f6dd88f8d5b3a9f477ef23bc..350a11e07b37b207fa528ac0206b4e7961db8db0 100644 (file)
@@ -67,6 +67,16 @@ void kernel_main(void)
     ata_probe(bus1, ATA::Master, "1:0");
     ata_probe(bus1, ATA::Slave,  "1:1");
 
+    idt_register_callback(0x28, [](auto& regs) {
+        term.write(static_cast<char>(regs.eax));
+    });
+
+    term.write("Entering user mode...\n");
+    enter_user_mode([] {
+        asm volatile("int $0x28" :: "a" ('Z'));
+        for (;;);
+    });
+
     for (;;) {
         const auto ch = keyboard_read();
         if (ch)
index 59e2bbeb9a20a3c4918b879e8a25403952d13c54..710701d8934e94d26ebbc5ac93477eb65c27f564 100644 (file)
@@ -8,7 +8,7 @@ struct PageDirectory
     static constexpr std::uint32_t NotPresent = 0x2;
 
     PageDirectory(): value(NotPresent) {}
-    PageDirectory(void *addr): value(reinterpret_cast<std::uint32_t>(addr) | 3) {}
+    PageDirectory(void *addr): value(reinterpret_cast<std::uint32_t>(addr) | 7) {}
 
     std::uint32_t value;
 };
@@ -39,7 +39,7 @@ void memory_initialize()
 
     std::uint32_t addr = 0;
     for (auto& p : pageTable) {
-        p = addr | 3; // supervisor, r/w, present
+        p = addr | 7; // supervisor, r/w, present
         addr += 0x1000;
     }