From 4e21175e8efad7e1df9342f51816eff1d39c6fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Quei=C3=9Fner?= Date: Thu, 5 May 2016 13:15:29 +0200 Subject: [PATCH] Adds GDT initialization. --- prototypes/base/include/gdt.hpp | 170 +++++++++++++++++++++----------- prototypes/base/init.cpp | 3 + prototypes/base/src/gdt.cpp | 56 ++++++++++- 3 files changed, 173 insertions(+), 56 deletions(-) diff --git a/prototypes/base/include/gdt.hpp b/prototypes/base/include/gdt.hpp index a60948d..87dca3a 100644 --- a/prototypes/base/include/gdt.hpp +++ b/prototypes/base/include/gdt.hpp @@ -4,68 +4,127 @@ enum class SegmentAccess : uint8_t { - None = 0, - Accessed = (1 << 0), - - Readable = (1<<1), - Writable = (1<<1), - - Direction = (1<<2), - Conforming = (1<<2), - - Executable = (1 << 3), - Segment = (1 << 4), - - Ring0 = 0, - Ring1 = (1<<5), - Ring2 = (1<<6), - Ring3 = (1<<5) | (1<<6), - - Present = (1 << 7), + None = 0, + Accessed = (1<<0), + Readable = (1<<1), + Writeable = (1<<1), + Direction = (1<<2), + Conforming = (1<<2), + Executable = (1<<3), + Segment = (1<<4), + Ring0 = 0, + Ring1 = (1<<5), + Ring2 = (1<<6), + Ring3 = (1<<5) | (1<<6), + Present = (1<<7), +}; + +enum class SegmentFlags : uint8_t +{ + None = 0, + Available = (1<<0), + LongMode = (1<<1), + Use32Bit = (1<<2), + Use4KSize = (1<<3), }; static inline SegmentAccess operator | (SegmentAccess lhs, SegmentAccess rhs) { - return static_cast(static_cast(lhs) | static_cast(rhs)); + return static_cast(static_cast(lhs) | static_cast(rhs)); } static inline SegmentAccess operator & (SegmentAccess lhs, SegmentAccess rhs) { - return static_cast(static_cast(lhs) & static_cast(rhs)); + return static_cast(static_cast(lhs) & static_cast(rhs)); +} + +static inline bool operator * (SegmentAccess lhs, SegmentAccess rhs) +{ + return (static_cast(lhs) & static_cast(rhs)) != 0; +} + +static inline SegmentFlags operator | (SegmentFlags lhs, SegmentFlags rhs) +{ + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +static inline SegmentFlags operator & (SegmentFlags lhs, SegmentFlags rhs) +{ + return static_cast(static_cast(lhs) & static_cast(rhs)); +} + +static inline bool operator * (SegmentFlags lhs, SegmentFlags rhs) +{ + return (static_cast(lhs) & static_cast(rhs)) != 0; } struct SegmentDescriptor { - uint16_t limit0; - uint16_t base0; - uint8_t base1; - SegmentAccess access; - uint8_t limit1 : 4; - uint8_t flags : 4; - uint8_t base2; - - uint32_t limit() - { - return this->limit0 | (this->limit1 << 16); - } - - void setLimit(uint32_t value) - { - this->limit0 = (value & 0x0FFFF) >> 0; - this->limit1 = (value & 0xFFFFF) >> 16; - } - - uint32_t base() - { - return this->base0 | (this->base1 << 16) | (this->base2 << 24); - } - - void setBase(uint32_t value) - { - this->base0 = (value & 0x0000FFFF) >> 0; - this->base1 = (value & 0x00FF0000) >> 16; - this->base2 = (value & 0xFF000000) >> 24; - } + uint16_t limit0; + uint16_t base0; + uint8_t base1; + SegmentAccess access; + uint8_t limit1 : 4; + uint8_t flags0 : 4; + uint8_t base2; + + SegmentDescriptor() : + limit0(0), base0(0), base1(0), + access(SegmentAccess::None), + limit1(0), flags0(0), base2(0) + { + + } + + SegmentDescriptor( + uint32_t base, + uint32_t length, + SegmentAccess access, + SegmentFlags flags) : + access(access) + { + this->setBase(base); + this->setFlags(flags); + + if(this->flags() * SegmentFlags::Use4KSize) { + this->setLimit(length >> 12); + } else { + this->setLimit(length); + } + } + + void setFlags(SegmentFlags flags) + { + this->flags0 = static_cast(flags) & 0x0F; + } + + SegmentFlags flags() const + { + return static_cast(this->flags0); + } + + uint32_t limit() const + { + return this->limit0 | (this->limit1 << 16); + } + + void setLimit(uint32_t value) + { + this->limit0 = (value & 0x0FFFF) >> 0; + this->limit1 = (value & 0xFFFFF) >> 16; + } + + uint32_t base() const + { + return this->base0 | (this->base1 << 16) | (this->base2 << 24); + } + + void setBase(uint32_t value) + { + this->base0 = (value & 0x0000FFFF) >> 0; + this->base1 = (value & 0x00FF0000) >> 16; + this->base2 = (value & 0xFF000000) >> 24; + } } __attribute__((packed)); static_assert(sizeof(SegmentDescriptor) == 8, "SegmentDescriptor must be 8 bytes large."); @@ -73,11 +132,12 @@ static_assert(sizeof(SegmentDescriptor) == 8, "SegmentDescriptor must be 8 bytes class GDT { public: - static const uint32_t length = 8; + static const uint32_t length = 8; private: - static SegmentDescriptor descriptors[length]; - GDT() = delete; + static SegmentDescriptor descriptors[length]; + GDT() = delete; public: - - static SegmentDescriptor & descriptor(uint32_t index); + static void initialize(); + + static SegmentDescriptor & descriptor(uint32_t index); }; \ No newline at end of file diff --git a/prototypes/base/init.cpp b/prototypes/base/init.cpp index d70a9dd..bd2f6b0 100644 --- a/prototypes/base/init.cpp +++ b/prototypes/base/init.cpp @@ -5,6 +5,7 @@ #include "numeric.hpp" #include "pointer.hpp" #include "multiboot.hpp" +#include "gdt.hpp" #include "compat.h" using namespace multiboot; @@ -24,6 +25,8 @@ extern "C" void init(Structure const & data) << BColor(Color::Blue) << "Hello blue!" << BColor() << "\n" << "Hello default color.\n"; + GDT::initialize(); + Console::main << "bootloader name: " << data.bootLoaderName << "\n" << "command line: " << data.commandline << "\n" diff --git a/prototypes/base/src/gdt.cpp b/prototypes/base/src/gdt.cpp index 099bc03..d5f863b 100644 --- a/prototypes/base/src/gdt.cpp +++ b/prototypes/base/src/gdt.cpp @@ -1,12 +1,66 @@ #include "gdt.hpp" +static SegmentDescriptor invalid; SegmentDescriptor GDT::descriptors[GDT::length]; SegmentDescriptor & GDT::descriptor(uint32_t index) { - static SegmentDescriptor invalid; if(index >= GDT::length) { return invalid; } return GDT::descriptors[index]; +} + +void GDT::initialize() +{ + //Ein Nulldeskriptor (gdt[0] = 0) + GDT::descriptor(0) = SegmentDescriptor(); + + //Ein Codesegment für den Kernel (Present, Ring 0, Executable, 32 Bit; Basis 0, Limit 4 GiB) + GDT::descriptor(1) = SegmentDescriptor( + 0x00000000, + 0xFFFFFFFF, + SegmentAccess::Present | SegmentAccess::Executable | SegmentAccess::Segment | SegmentAccess::Ring0, + SegmentFlags::Use4KSize | SegmentFlags::Use32Bit); + + //Ein Datensegment für den Kernel (Present, Ring 0, Non-Executable, 32 Bit; Basis 0, Limit 4 GiB) + GDT::descriptor(2) = SegmentDescriptor( + 0x00000000, + 0xFFFFFFFF, + SegmentAccess::Present | SegmentAccess::Writeable | SegmentAccess::Segment | SegmentAccess::Ring0, + SegmentFlags::Use4KSize | SegmentFlags::Use32Bit); + + //Ein Codesegment für den Userspace (Present, Ring 3, Executable, 32 Bit; Basis 0, Limit 4 GiB) + GDT::descriptor(3) = SegmentDescriptor( + 0x00000000, + 0xFFFFFFFF, + SegmentAccess::Present | SegmentAccess::Executable | SegmentAccess::Segment | SegmentAccess::Ring3, + SegmentFlags::Use4KSize | SegmentFlags::Use32Bit); + + //Ein Datensegment für den Userspace (Present, Ring 3, Non-Executable, 32 Bit; Basis 0, Limit 4 GiB) + GDT::descriptor(4) = SegmentDescriptor( + 0x00000000, + 0xFFFFFFFF, + SegmentAccess::Present | SegmentAccess::Writeable | SegmentAccess::Segment | SegmentAccess::Ring3, + SegmentFlags::Use4KSize | SegmentFlags::Use32Bit); + + struct + { + uint16_t limit; + void* pointer; + } __attribute__((packed)) gdtp = + { + .limit = GDT::length *sizeof(SegmentDescriptor) - 1, + .pointer = &GDT::descriptors, + }; + asm volatile("lgdt %0" : : "m" (gdtp)); + + asm volatile("mov $0x10, %ax"); + asm volatile("mov %ax, %ds"); + asm volatile("mov %ax, %es"); + asm volatile("mov %ax, %fs"); + asm volatile("mov %ax, %gs"); + asm volatile("mov %ax, %ss"); + asm volatile("ljmp $0x8, $.1"); + asm volatile(".1:"); } \ No newline at end of file