From c6e0d58e177d91f01b6de80073d066bf03de2913 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Tue, 9 Feb 2021 17:39:08 +0200 Subject: Add more comments to GDT code --- src/gdt.cc | 21 ++++-------------- src/gdt.h | 52 +++++++++++++++++++++++++++++++++++--------- src/gdt/segmentdescriptor.cc | 39 +++++++++++++++++++++++++++++++++ src/kernel.cc | 4 ++++ src/makefile | 3 ++- 5 files changed, 91 insertions(+), 28 deletions(-) create mode 100644 src/gdt/segmentdescriptor.cc diff --git a/src/gdt.cc b/src/gdt.cc index 202fe77..289462b 100644 --- a/src/gdt.cc +++ b/src/gdt.cc @@ -1,24 +1,11 @@ #include "gdt.h" -GDT::SegmentDescriptor::SegmentDescriptor(uint32_t base, uint32_t limit, uint8_t type) { - base_low = base & 0xffff; - base_high = (base >> 16) & 0xff; - base_vhigh = (base >> 24) & 0xff; -} -uint32_t GDT::SegmentDescriptor::base() const { - uint32_t base = base_vhigh; - base = (base << 8) + base_high; - base = (base << 8) + base_low; - return base; -} -uint32_t GDT::SegmentDescriptor::limit() const { - return 0; -} +using seg = GDT::SegmentDescriptor; GDT::GDT() - : segments{{0, 0, 0}, // null segment - {0, 64 * 1024 * 1024 /* 64MB */, 0x9a}, // code segment - {0, 64 * 1024 * 1024 /* 64MB */, 0x92}} // data segment + : segments{seg::make<0>(0, {.present = false}), // null 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 { Pointer gdtr{.limit = sizeof(segments) - 1, .base = reinterpret_cast(segments)}; asm volatile("lgdt %0" : : "p"(gdtr)); diff --git a/src/gdt.h b/src/gdt.h index 99a6da2..244908b 100644 --- a/src/gdt.h +++ b/src/gdt.h @@ -33,15 +33,37 @@ public: class SegmentDescriptor { public: - SegmentDescriptor(uint32_t base = 0, uint32_t limit = 0, uint8_t type = 0); + 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 + } __attribute__((packed)); + + SegmentDescriptor() { access.present = false; }; + + template + static SegmentDescriptor make(uint32_t base, Access a) { + static_assert(limit <= 0xffffu || (limit & 0xfff) == 0xfff); + return SegmentDescriptor(base, limit, a); + } + [[nodiscard]] uint32_t base() const; [[nodiscard]] uint32_t limit() const; private: + SegmentDescriptor(uint32_t base, uint32_t limit, Access a); + /* - * |31| | | | | | |24|23|22| |20|19| | |16|15| | |12|11| | | 8| 7| | | | | | | 0| - * | base (24~31) | G|DB| | A| lim(16~19)| P| DPL | S| Type | base (16~23) | - * | base (0~15) | limit (0~15) | + * |31| | | | | | |24|23|22|21|20|19| | |16|15| | |12|11| | | 8| 7| | | | | | | 0| + * | base_31_24 | G|DB| | A| lim_19_16 | P| DPL | S| Type | base_23_16 | + * | base_15_0 | limit_15_0 | * |31| | | | | | | | | | | | | | |16|15| | | | | | | | | | | | | | | 0| * * limit size of segment - 1, either in bytes or in 4KiB chunks (check flags) @@ -50,12 +72,21 @@ public: * flags defines the segment chunks and 16/32 bit */ - uint16_t limit_low; - uint16_t base_low; - uint8_t base_high; - uint8_t type; - uint8_t flags_limit_high; - uint8_t base_vhigh; + unsigned int limit_15_0 : 16 = 0; // low bits of segment limit + unsigned int base_15_0 : 16 = 0; // low bits of segment base address + unsigned int base_23_16 : 8 = 0; // middle bits of segment base address + + /* access byte */ + Access access; + + unsigned int limit_19_16 : 4 = 0; // high bits of segment limit + /* flags */ + [[maybe_unused]] unsigned int a : 1 = 0; // unused, available for software use + [[maybe_unused]] unsigned int rsv : 1 = 0; // reserved + unsigned int db : 1 = 0; // 0: 16-bit segment; 1: 32-bit segment + unsigned int granularity : 1 = 0; // limit scaled by 4k when set + + unsigned int base_31_24 : 8 = 0; // high bits of segment address } __attribute__((packed)); private: @@ -64,3 +95,4 @@ private: 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 new file mode 100644 index 0000000..94205c8 --- /dev/null +++ b/src/gdt/segmentdescriptor.cc @@ -0,0 +1,39 @@ +#include "../gdt.h" + +GDT::SegmentDescriptor::SegmentDescriptor(uint32_t base, uint32_t limit, GDT::SegmentDescriptor::Access a) : access(a) { + // store base + base_15_0 = base & 0xffff; + base_23_16 = (base >> 16) & 0xff; + base_31_24 = (base >> 24) & 0xff; + + // store limit + if (limit <= 0xffffu) { // 16-bit address space + limit_15_0 = limit & 0xffff; + limit_19_16 = 0; + } else { + db = 1; + // limit is uint32_t, which we need to store in limit_19_16 and limit_15_0, a total of 20 bits + limit = limit >> 12; + limit_15_0 = limit & 0xffff; + limit_19_16 = (limit >> 16) & 0xf; + } + + granularity = 1; +} + +uint32_t GDT::SegmentDescriptor::base() const { + uint32_t base = base_31_24; + base = (base << 8) + base_23_16; + base = (base << 16) + base_15_0; + return base; +} + +uint32_t GDT::SegmentDescriptor::limit() const { + uint32_t limit = 0; + if (db == 1) { + limit = limit_19_16; + limit = limit << 16; + } + limit += limit_15_0; + return 0; +} diff --git a/src/kernel.cc b/src/kernel.cc index 2fa90e3..4569107 100644 --- a/src/kernel.cc +++ b/src/kernel.cc @@ -26,6 +26,10 @@ void kernel_main([[maybe_unused]] uint32_t mb_magic, [[maybe_unused]] uint32_t m // dump_multiboot(mb_magic, mb_addr); dump_gdt(); + printk("GDT::SegmentDescriptor tests\n"); + auto x = GDT::SegmentDescriptor::make<0xffff>(0xdeadbeef, {}); + printk("x.base(): ", uhex{x.base()}, '\n'); + printk("Setting new GDT\n"); GDT gdt; dump_gdt(); diff --git a/src/makefile b/src/makefile index 7902dbf..7b97382 100644 --- a/src/makefile +++ b/src/makefile @@ -4,4 +4,5 @@ CXX_OBJ += src/kernel.o \ src/kernel/dump_gdt.o \ src/kernel/dump_multiboot.o \ src/vga.o \ - src/gdt.o + src/gdt.o \ + src/gdt/segmentdescriptor.o -- cgit v1.2.1