From e40da55691ad2c36b349ace7cd368394976a1d6d Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Sat, 6 Mar 2021 16:01:29 +0200 Subject: GDT: flush segment registers on lgdt --- src/gdt.cc | 36 ++++++++++++++++++++++++++++-------- src/gdt.h | 41 +++++++++++++++++++++-------------------- src/gdt/segmentdescriptor.cc | 10 +++++++++- src/idt.cc | 1 + src/idt.h | 2 -- src/kernel.cc | 5 ++--- toolchain.makefile | 2 +- 7 files changed, 62 insertions(+), 35 deletions(-) diff --git a/src/gdt.cc b/src/gdt.cc index 9c86888..cb210a2 100644 --- a/src/gdt.cc +++ b/src/gdt.cc @@ -3,19 +3,39 @@ using seg = GDT::SegmentDescriptor; -GDT::GDT() - : segments{seg::make<0>(0, {.present = false}), // null segment - seg::make<0>(0, {.present = false}), // unused segment ??? - seg::make<0xffffffff>(0, {.r_w = true, .exe = true, .segment = true}), // code segment - seg::make<0xffffffff>(0, {.r_w = true, .segment = true})} // data segment -{ +static_assert(sizeof(GDT::Pointer) == 6); + +constexpr uint32_t null_sz = 0; +constexpr uint32_t kseg_sz = 64 * 1024 * 1024 + 0xfff; + +static GDT::SegmentDescriptor segments[256]{ + [GDT::null0] = seg::make(0, {}), + [GDT::kcode] = seg::make(0, {.r_w = true, .exe = true, .segment = true, .present = true}), + [GDT::kdata] = seg::make(0, {.r_w = true, .segment = true, .present = true}), +}; + +GDT::GDT() { Pointer gdtr{.limit = sizeof(segments) - 1, .base = reinterpret_cast(segments)}; asm volatile("lgdt %0" : : "p"(gdtr)); + // flush the segment registers + const auto cs = descriptor(kcode); + const auto ds = descriptor(kdata); + + asm volatile( + "jmp %0,$.reload_cs\n\t" // far jump takes cs + ".reload_cs:\n\t" + " mov %1, %%ds\n\t" // ds + " mov %1, %%es\n\t" + " mov %1, %%fs\n\t" + " mov %1, %%gs\n\t" + " mov %1, %%ss\n\t" ::"i"(cs), + "r"(ds)); + printk("GDT installed at ", uhex{gdtr.base}, '\n'); } -uint16_t GDT::codeDescriptor() const { - return static_cast(reinterpret_cast(&segments[2]) - +uint16_t GDT::descriptor(GDT::SegmentMap i) const { + return static_cast(reinterpret_cast(&segments[i]) - reinterpret_cast(&segments)); } diff --git a/src/gdt.h b/src/gdt.h index bb7181b..6aeaa33 100644 --- a/src/gdt.h +++ b/src/gdt.h @@ -27,11 +27,6 @@ class GDT { public: - GDT(); - ~GDT() = default; - - uint16_t codeDescriptor() const; - struct Pointer { uint16_t limit; uint32_t base; @@ -41,18 +36,24 @@ public: public: enum Ring : unsigned int { Ring0 = 0x0, Ring1 = 0x1, Ring2 = 0x2, Ring3 = 0x3 }; struct Access { - bool accessed : 1 = false; // if 0, is set by processor when accessed - bool r_w : 1 = false; // on code segment: read toggle - // on data segment: write toggle - bool direction_conforming : 1 = false; // TODO - bool exe : 1 = false; // true for code segment, false for data segment - bool segment : 1 = false; // segment bit: 1 for code/data segments - // 0 for gates and tss - Ring privilege : 2 = Ring0; // descriptor privilege level - bool present : 1 = true; // must be 1 for every active segment + bool accessed : 1 = false; // if 0, is set by processor when accessed + bool r_w : 1 = false; // on code segment: read toggle + // on data segment: write toggle + bool direction : 1 = false; // TODO + bool exe : 1 = false; // true for code segment, false for data segment + bool segment : 1 = false; // segment bit: 1 for code/data segments + // 0 for gates and tss + Ring privilege : 2 = Ring0; // descriptor privilege level + bool present : 1 = false; // must be 1 for every active segment + + constexpr operator uint8_t() const { + return static_cast(accessed) | static_cast(r_w << 1) | static_cast(direction << 2) | + static_cast(exe << 3) | static_cast(segment << 4) | + static_cast(privilege << 5) | static_cast(present << 7); + } } __attribute__((packed)); - SegmentDescriptor() { access.present = false; }; + constexpr SegmentDescriptor() { access.present = false; }; template static SegmentDescriptor make(uint32_t base, Access type) { @@ -94,11 +95,11 @@ public: unsigned int base_31_24 : 8 = 0; // high bits of segment address } __attribute__((packed)); + enum SegmentMap { null0, kcode, kdata }; + + GDT(); + ~GDT() = default; -private: - SegmentDescriptor segments[256]; + uint16_t descriptor(SegmentMap) const; }; -static_assert(sizeof(GDT::Pointer) == 6); -static_assert(sizeof(GDT::SegmentDescriptor) == 8); -static_assert(sizeof(GDT::SegmentDescriptor::Access) == 1); diff --git a/src/gdt/segmentdescriptor.cc b/src/gdt/segmentdescriptor.cc index baf4753..dadd65b 100644 --- a/src/gdt/segmentdescriptor.cc +++ b/src/gdt/segmentdescriptor.cc @@ -1,4 +1,12 @@ -#include "../gdt.h" +#include "gdt.h" + +using seg = GDT::SegmentDescriptor; + +static_assert(sizeof(seg) == 8); +static_assert(sizeof(seg::Access) == 1); +static_assert((seg::Access{}) == 0x00); +static_assert((seg::Access{.r_w = true, .exe = true, .segment = true, .present = true}) == 0x9a); +static_assert((seg::Access{.r_w = true, .segment = true, .present = true}) == 0x92); GDT::SegmentDescriptor::SegmentDescriptor(uint32_t base, uint32_t limit, GDT::SegmentDescriptor::Access type) : access(type) { diff --git a/src/idt.cc b/src/idt.cc index 5be738a..5022f3e 100644 --- a/src/idt.cc +++ b/src/idt.cc @@ -6,6 +6,7 @@ static_assert(sizeof(IDT::Pointer) == 6); constexpr uint8_t irq_base = 0x20; +static IDT::Entry table[256]; static InterruptHandler* handlers[256] = {nullptr}; bool IDT::install(uint8_t irq, InterruptHandler* h) { diff --git a/src/idt.h b/src/idt.h index ce5209c..01662ad 100644 --- a/src/idt.h +++ b/src/idt.h @@ -48,8 +48,6 @@ public: void enable() { asm volatile("sti"); } private: - Entry table[256]; - static bool install(uint8_t, InterruptHandler*); static bool uninstall(uint8_t, InterruptHandler*); }; diff --git a/src/kernel.cc b/src/kernel.cc index 85d4124..372b5bb 100644 --- a/src/kernel.cc +++ b/src/kernel.cc @@ -49,9 +49,8 @@ void kernel_main([[maybe_unused]] uint32_t mb_magic, [[maybe_unused]] uint32_t m // dump_gdt(); GDT gdt; - IDT idt{gdt.codeDescriptor()}; - - Scheduler s{gdt.codeDescriptor()}; + IDT idt{gdt.descriptor(GDT::kcode)}; + Scheduler s{gdt.descriptor(GDT::kcode)}; Keyboard kb; idt.enable(); diff --git a/toolchain.makefile b/toolchain.makefile index ae791c1..aa13852 100644 --- a/toolchain.makefile +++ b/toolchain.makefile @@ -12,7 +12,7 @@ LD_FLAGS := -T linker.ld CXX := clang++ TEST_CXX := clang++ -CXX_FLAGS := -std=c++20 \ +CXX_FLAGS := -std=c++20 -g \ -mkernel -ffreestanding -nostdlib -nostdinc -nostdinc++ \ -Wall -Wextra -Werror=pedantic -O2 \ -Werror=date-time \ -- cgit v1.2.1