From 6da213d840f07a2921091a6d2fab7efa5ec5cdfa Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Sun, 29 Sep 2024 08:03:04 -0400 Subject: [PATCH] enter user mode --- Makefile | 2 +- gdt.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++- gdt.hpp | 1 + idt.cpp | 8 +++-- kernel.cpp | 10 ++++++ memory.cpp | 4 +-- 6 files changed, 109 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index cb08991..284f931 100644 --- 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 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 {{ +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 {{ {}, /* kernel_code = */ { .limit_low = 0xFFFF, @@ -54,6 +68,57 @@ constinit static const std::array 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 0d7a9b6..de5e8fc 100644 --- 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 0dc0f73..c889c14 100644 --- 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 callbacks; +static std::array callbacks; extern "C" void interruptGeneralHandler(Registers regs) @@ -91,10 +93,12 @@ struct StubEntry static auto idt = [](std::index_sequence) { return std::array { StubEntry()... }; - }(std::make_index_sequence<48>{}); + }(std::make_index_sequence{}); void idt_initialize() { + idt[0x28].dpl = 3; + auto idtr = reinterpret_cast(idt.data()); idtr <<= 16; idtr |= idt.size() * sizeof(idt[0]); diff --git a/kernel.cpp b/kernel.cpp index cbeab58..350a11e 100644 --- a/kernel.cpp +++ b/kernel.cpp @@ -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(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) diff --git a/memory.cpp b/memory.cpp index 59e2bbe..710701d 100644 --- a/memory.cpp +++ b/memory.cpp @@ -8,7 +8,7 @@ struct PageDirectory static constexpr std::uint32_t NotPresent = 0x2; PageDirectory(): value(NotPresent) {} - PageDirectory(void *addr): value(reinterpret_cast(addr) | 3) {} + PageDirectory(void *addr): value(reinterpret_cast(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; }