aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2021-02-09 17:39:08 +0200
committerAqua-sama <aqua@iserlohn-fortress.net>2021-02-09 17:39:08 +0200
commitc6e0d58e177d91f01b6de80073d066bf03de2913 (patch)
treee23139d87da7967e36517fe869b3677e3a4bc9c3
parentLoading GDT (diff)
downloadkernel.cpp-c6e0d58e177d91f01b6de80073d066bf03de2913.tar.xz
Add more comments to GDT code
-rw-r--r--src/gdt.cc21
-rw-r--r--src/gdt.h52
-rw-r--r--src/gdt/segmentdescriptor.cc39
-rw-r--r--src/kernel.cc4
-rw-r--r--src/makefile3
5 files changed, 91 insertions, 28 deletions
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<uint32_t>(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 <uint32_t limit>
+ 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