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
{
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<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)
{
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
{
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<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));
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);
};

View file

@ -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"

View file

@ -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, 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:");
}