aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2021-02-07 23:09:21 +0200
committerAqua-sama <aqua@iserlohn-fortress.net>2021-02-07 23:09:21 +0200
commit0425e5a7943bd2eaeca8f4dd1079da9b5493253d (patch)
tree7ecb6630697046ab400f44556bc68e8baf76c676
parentRename kernel/ to src/ (diff)
downloadkernel.cpp-0425e5a7943bd2eaeca8f4dd1079da9b5493253d.tar.xz
Loading GDT
-rw-r--r--src/gdt.cc25
-rw-r--r--src/gdt.h66
-rw-r--r--src/kernel.cc15
-rw-r--r--src/kernel/dump_gdt.cc8
-rw-r--r--src/makefile4
5 files changed, 114 insertions, 4 deletions
diff --git a/src/gdt.cc b/src/gdt.cc
new file mode 100644
index 0000000..202fe77
--- /dev/null
+++ b/src/gdt.cc
@@ -0,0 +1,25 @@
+#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;
+}
+
+GDT::GDT()
+ : segments{{0, 0, 0}, // null segment
+ {0, 64 * 1024 * 1024 /* 64MB */, 0x9a}, // code segment
+ {0, 64 * 1024 * 1024 /* 64MB */, 0x92}} // 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
new file mode 100644
index 0000000..99a6da2
--- /dev/null
+++ b/src/gdt.h
@@ -0,0 +1,66 @@
+#pragma once
+
+#include <types.h>
+
+/* From OSDev wiki:
+ *
+ * Segment
+ * a logically contiguous chunk of memory with consistent properties (CPU's speaking)
+ *
+ * Segment Register
+ * a register of your CPU that refers to a segment for a special use (e.g. SS, CS, DS ...)
+ *
+ * Selector
+ * a reference to a descriptor you can load into a segment register; the selector is an offset of a descriptor table
+ * entry. These entries are 8 bytes long. Therefore, bits 3 and up only declare the descriptor table entry offset, while
+ * bit 2 specifies if this selector is a GDT or LDT selector (LDT - bit set, GDT - bit cleared), and bits 0 - 1 declare
+ * the ring level that needs to correspond to the descriptor table entry's DPL field. If it doesn't, a General
+ * Protection Fault occurs; if it does correspond then the CPL level of the selector used is changed accordingly.
+ *
+ * Descriptor
+ * a memory structure (part of a table) that tells the CPU the attributes of a given segment
+ */
+
+class GDT {
+public:
+ GDT();
+ ~GDT() = default;
+
+ struct Pointer {
+ uint16_t limit;
+ uint32_t base;
+ } __attribute((packed));
+
+ class SegmentDescriptor {
+ public:
+ SegmentDescriptor(uint32_t base = 0, uint32_t limit = 0, uint8_t type = 0);
+ [[nodiscard]] uint32_t base() const;
+ [[nodiscard]] uint32_t limit() const;
+
+ private:
+ /*
+ * |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| | | | | | | | | | | | | | |16|15| | | | | | | | | | | | | | | 0|
+ *
+ * limit size of segment - 1, either in bytes or in 4KiB chunks (check flags)
+ * base address of segment
+ * access
+ * 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;
+ } __attribute__((packed));
+
+private:
+ SegmentDescriptor segments[256];
+};
+
+static_assert(sizeof(GDT::Pointer) == 6);
+static_assert(sizeof(GDT::SegmentDescriptor) == 8);
diff --git a/src/kernel.cc b/src/kernel.cc
index c083364..2fa90e3 100644
--- a/src/kernel.cc
+++ b/src/kernel.cc
@@ -10,17 +10,26 @@
#include <stdlib.h>
#include <types.h>
+#include "gdt.h"
#include "vga.h"
-extern "C" void dump_multiboot(uint32_t mb_magic, uint32_t mb_addr);
+extern "C" {
+void dump_multiboot(uint32_t mb_magic, uint32_t mb_addr);
+void dump_gdt();
-extern "C" void kernel_main(uint32_t mb_magic, uint32_t mb_addr) {
+void kernel_main([[maybe_unused]] uint32_t mb_magic, [[maybe_unused]] uint32_t mb_addr) {
VGA terminal;
Console::set(&terminal);
printk("Hello, kernel World!\n");
- dump_multiboot(mb_magic, mb_addr);
+ // dump_multiboot(mb_magic, mb_addr);
+ dump_gdt();
+
+ printk("Setting new GDT\n");
+ GDT gdt;
+ dump_gdt();
abort();
}
+} // extern "C"
diff --git a/src/kernel/dump_gdt.cc b/src/kernel/dump_gdt.cc
new file mode 100644
index 0000000..718ada6
--- /dev/null
+++ b/src/kernel/dump_gdt.cc
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include "../gdt.h"
+
+extern "C" void dump_gdt() {
+ GDT::Pointer gdtr{0, 0};
+ asm volatile("sgdt %0" : "=m"(gdtr) :);
+ printk("GDT at ", uhex{gdtr.base}, " , limit=", gdtr.limit, '\n');
+}
diff --git a/src/makefile b/src/makefile
index 86c8877..7902dbf 100644
--- a/src/makefile
+++ b/src/makefile
@@ -1,5 +1,7 @@
AS_OBJ += src/boot.o
CXX_OBJ += src/kernel.o \
+ src/kernel/dump_gdt.o \
src/kernel/dump_multiboot.o \
- src/vga.o
+ src/vga.o \
+ src/gdt.o