aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <clyne@bitgloo.com>2024-09-29 08:03:04 -0400
committerClyne Sullivan <clyne@bitgloo.com>2024-09-29 08:03:04 -0400
commit6da213d840f07a2921091a6d2fab7efa5ec5cdfa (patch)
tree5f381f61049b92b13416f15a4622b87a6aee56f9
parentc7066d295039b833dd026e200a5aa735631bdf34 (diff)
enter user mode
-rw-r--r--Makefile2
-rw-r--r--gdt.cpp90
-rw-r--r--gdt.hpp1
-rw-r--r--idt.cpp8
-rw-r--r--kernel.cpp10
-rw-r--r--memory.cpp4
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_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 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<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]);
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<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)
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<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;
}