Adds GDT initialization.

This commit is contained in:
Felix Queißner 2016-05-05 13:15:29 +02:00
parent 8e247ba638
commit 4e21175e8e
3 changed files with 173 additions and 56 deletions

View file

@ -4,68 +4,127 @@
enum class SegmentAccess : uint8_t enum class SegmentAccess : uint8_t
{ {
None = 0, None = 0,
Accessed = (1 << 0), Accessed = (1<<0),
Readable = (1<<1),
Readable = (1<<1), Writeable = (1<<1),
Writable = (1<<1), Direction = (1<<2),
Conforming = (1<<2),
Direction = (1<<2), Executable = (1<<3),
Conforming = (1<<2), Segment = (1<<4),
Ring0 = 0,
Executable = (1 << 3), Ring1 = (1<<5),
Segment = (1 << 4), Ring2 = (1<<6),
Ring3 = (1<<5) | (1<<6),
Ring0 = 0, Present = (1<<7),
Ring1 = (1<<5), };
Ring2 = (1<<6),
Ring3 = (1<<5) | (1<<6), enum class SegmentFlags : uint8_t
{
Present = (1 << 7), None = 0,
Available = (1<<0),
LongMode = (1<<1),
Use32Bit = (1<<2),
Use4KSize = (1<<3),
}; };
static inline SegmentAccess operator | (SegmentAccess lhs, SegmentAccess rhs) static inline SegmentAccess operator | (SegmentAccess lhs, SegmentAccess rhs)
{ {
return static_cast<SegmentAccess>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs)); return static_cast<SegmentAccess>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
} }
static inline SegmentAccess operator & (SegmentAccess lhs, SegmentAccess rhs) static inline SegmentAccess operator & (SegmentAccess lhs, SegmentAccess rhs)
{ {
return static_cast<SegmentAccess>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs)); return static_cast<SegmentAccess>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs));
}
static inline bool operator * (SegmentAccess lhs, SegmentAccess rhs)
{
return (static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs)) != 0;
}
static inline SegmentFlags operator | (SegmentFlags lhs, SegmentFlags rhs)
{
return static_cast<SegmentFlags>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
}
static inline SegmentFlags operator & (SegmentFlags lhs, SegmentFlags rhs)
{
return static_cast<SegmentFlags>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs));
}
static inline bool operator * (SegmentFlags lhs, SegmentFlags rhs)
{
return (static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs)) != 0;
} }
struct SegmentDescriptor struct SegmentDescriptor
{ {
uint16_t limit0; uint16_t limit0;
uint16_t base0; uint16_t base0;
uint8_t base1; uint8_t base1;
SegmentAccess access; SegmentAccess access;
uint8_t limit1 : 4; uint8_t limit1 : 4;
uint8_t flags : 4; uint8_t flags0 : 4;
uint8_t base2; uint8_t base2;
uint32_t limit() SegmentDescriptor() :
{ limit0(0), base0(0), base1(0),
return this->limit0 | (this->limit1 << 16); access(SegmentAccess::None),
} limit1(0), flags0(0), base2(0)
{
void setLimit(uint32_t value)
{ }
this->limit0 = (value & 0x0FFFF) >> 0;
this->limit1 = (value & 0xFFFFF) >> 16; SegmentDescriptor(
} uint32_t base,
uint32_t length,
uint32_t base() SegmentAccess access,
{ SegmentFlags flags) :
return this->base0 | (this->base1 << 16) | (this->base2 << 24); access(access)
} {
this->setBase(base);
void setBase(uint32_t value) this->setFlags(flags);
{
this->base0 = (value & 0x0000FFFF) >> 0; if(this->flags() * SegmentFlags::Use4KSize) {
this->base1 = (value & 0x00FF0000) >> 16; this->setLimit(length >> 12);
this->base2 = (value & 0xFF000000) >> 24; } else {
} this->setLimit(length);
}
}
void setFlags(SegmentFlags flags)
{
this->flags0 = static_cast<uint8_t>(flags) & 0x0F;
}
SegmentFlags flags() const
{
return static_cast<SegmentFlags>(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)); } __attribute__((packed));
static_assert(sizeof(SegmentDescriptor) == 8, "SegmentDescriptor must be 8 bytes large."); 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 class GDT
{ {
public: public:
static const uint32_t length = 8; static const uint32_t length = 8;
private: private:
static SegmentDescriptor descriptors[length]; static SegmentDescriptor descriptors[length];
GDT() = delete; GDT() = delete;
public: public:
static void initialize();
static SegmentDescriptor & descriptor(uint32_t index);
static SegmentDescriptor & descriptor(uint32_t index);
}; };

View file

@ -5,6 +5,7 @@
#include "numeric.hpp" #include "numeric.hpp"
#include "pointer.hpp" #include "pointer.hpp"
#include "multiboot.hpp" #include "multiboot.hpp"
#include "gdt.hpp"
#include "compat.h" #include "compat.h"
using namespace multiboot; using namespace multiboot;
@ -24,6 +25,8 @@ extern "C" void init(Structure const & data)
<< BColor(Color::Blue) << "Hello blue!" << BColor() << "\n" << BColor(Color::Blue) << "Hello blue!" << BColor() << "\n"
<< "Hello default color.\n"; << "Hello default color.\n";
GDT::initialize();
Console::main Console::main
<< "bootloader name: " << data.bootLoaderName << "\n" << "bootloader name: " << data.bootLoaderName << "\n"
<< "command line: " << data.commandline << "\n" << "command line: " << data.commandline << "\n"

View file

@ -1,12 +1,66 @@
#include "gdt.hpp" #include "gdt.hpp"
static SegmentDescriptor invalid;
SegmentDescriptor GDT::descriptors[GDT::length]; SegmentDescriptor GDT::descriptors[GDT::length];
SegmentDescriptor & GDT::descriptor(uint32_t index) SegmentDescriptor & GDT::descriptor(uint32_t index)
{ {
static SegmentDescriptor invalid;
if(index >= GDT::length) { if(index >= GDT::length) {
return invalid; return invalid;
} }
return GDT::descriptors[index]; 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, 32Bit; Basis 0, Limit 4GiB)
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, 32Bit; Basis 0, Limit 4GiB)
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, 32Bit; Basis 0, Limit 4GiB)
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, 32Bit; Basis 0, Limit 4GiB)
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:");
} }