Skip to content

Commit

Permalink
gdt: add a table abstraction.
Browse files Browse the repository at this point in the history
The Global Descriptor Table is abstracted by a class that manages its properties
(alignment, maximum size, etc.). This representation aims to be extended and
specified to implement the real kernel GDT. Tests are done in Arch library
tests.
  • Loading branch information
ddejean committed Mar 7, 2014
1 parent 64fde65 commit 63119c0
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 0 deletions.
49 changes: 49 additions & 0 deletions kernel/Arch/Gdt.cpp
@@ -0,0 +1,49 @@
/*
* Gdt.cpp
*
* Copyright (C) 2014 Simple Object Kernel project
* by Damien Dejean <dam.dejean@gmail.com>
*
* GDT representation implementation.
* It aims to ease GDT manipulation avioding common errors with CPU
* configuration.
*/

#include <string.h>
#include "Gdt.h"

#define GDT_ALIGN_MASK 0x7

Gdt::Gdt(RawSegmentDescriptor *rawGdt, uint32_t count)
{
assert(rawGdt != NULL);
assert(count > 1); /* At least one NULL entry */
assert(count <= GDT_MAX_COUNT);
assert(((uint32_t)rawGdt & 0x7) == 0u);

mRawGdt = rawGdt;
mCount = count;
}

uint32_t Gdt::getBaseAddress(void)
{
return (uint32_t)mRawGdt;
}

uint16_t Gdt::getLimit(void)
{
/*
* Limit definition as given by Intel Developer's Manual, Volume 3a, section
* 3.5.1.
*/
return mCount * sizeof(*mRawGdt) - 1;
}

void Gdt::insert(uint32_t index, SegmentDescriptor *desc)
{
assert(index < GDT_MAX_COUNT);
assert(desc != NULL);
assert(mRawGdt != NULL);

mRawGdt[index] = desc->toRawSegmentDescriptor();
}
60 changes: 60 additions & 0 deletions kernel/Arch/Gdt.h
@@ -0,0 +1,60 @@
/*
* Gdt.h
*
* Copyright (C) 2014 Simple Object Kernel project
* by Damien Dejean <dam.dejean@gmail.com>
*
* Intel's x86 Global Descriptor table representation.
*/

#ifndef _GDT_H_
#define _GDT_H_

#include <assert.h>
#include <stdint.h>
#include "SegmentDescriptor.h"

/* @see Intel Software Developer's Manual, Volume 3A, 3.5.1 */
#define GDT_MAX_COUNT 8192

class Gdt {
private:
uint32_t mCount;
RawSegmentDescriptor *mRawGdt;

public:
/**
* Initialize a Global Descriptor Table representation.
* Protected to ensure this class is extended.
* @param rawGdt a reference on the raw GDT table.
* @param count number of available GDT entries.
*
* @pre rawGdt != NULL
* rawGdt is aligned on 8 byte boundary
* 1 < count <= GDT_MAX_COUNT
*/
Gdt(RawSegmentDescriptor *rawGdt, uint32_t count);

/**
* GDT linear base address as expected by the CPU.
* @return the linear address of the raw GDT, aligned on 8 byte boundary.
* @see Intel Developer's Manual Volume 3a, section 3.5.1.
*/
uint32_t getBaseAddress(void);

/**
* GDT limit.
* @return the limit, ie the GDT size, a multiple of 8 bytes minus 1.
* @see Intel Developer's Manual Volume 3a, section 3.5.1.
*/
uint16_t getLimit(void);

/**
* Inserts a descriptor in teh GDT at the specified index.
* @param index insertion index in the table.
* @param desc the descriptor to insert.
*/
void insert(uint32_t index, SegmentDescriptor *desc);
};

#endif /* _GDT_H_ */
61 changes: 61 additions & 0 deletions kernel/Arch/tests/TestGdt.cpp
@@ -0,0 +1,61 @@
#include <stdlib.h>
#include <string.h>
#include "TestGdt.h"
#include "Arch/Gdt.h"


#define TEST_GDT_COUNT 8

/* A raw gdt for test purposes */
static RawSegmentDescriptor testGdt[TEST_GDT_COUNT]
__attribute__((aligned(8)));

/* The test GDT instance */
static Gdt *gdt;

void TestGdt::setUp(void)
{
gdt = new Gdt(testGdt, TEST_GDT_COUNT);
}

void TestGdt::tearDown(void)
{
delete gdt;
gdt = NULL;
memset(testGdt, 0, sizeof(testGdt));
}

void TestGdt::testBaseAddress(void)
{
TS_ASSERT((gdt->getBaseAddress() & 0x7u) == 0u);
}

void TestGdt::testLimit(void)
{
TS_ASSERT_EQUALS(gdt->getLimit(), sizeof(testGdt) - 1);
}

void TestGdt::testInsert(void)
{
SegmentDescriptor *nullDesc, *codeDesc, *dataDesc;

nullDesc = SegmentDescriptor::aNullSegmentDescriptor();
codeDesc = SegmentDescriptor::aCodeSegmentDescriptor();
dataDesc = SegmentDescriptor::aDataSegmentDescriptor();

gdt->insert(0, nullDesc);
gdt->insert(1, codeDesc);
gdt->insert(2, dataDesc);
gdt->insert(3, codeDesc);
gdt->insert(4, dataDesc);

TS_ASSERT_EQUALS(testGdt[0], nullDesc->toRawSegmentDescriptor());
TS_ASSERT_EQUALS(testGdt[1], codeDesc->toRawSegmentDescriptor());
TS_ASSERT_EQUALS(testGdt[2], dataDesc->toRawSegmentDescriptor());
TS_ASSERT_EQUALS(testGdt[3], codeDesc->toRawSegmentDescriptor());
TS_ASSERT_EQUALS(testGdt[4], dataDesc->toRawSegmentDescriptor());

delete nullDesc;
delete codeDesc;
delete dataDesc;
}
16 changes: 16 additions & 0 deletions kernel/Arch/tests/TestGdt.h
@@ -0,0 +1,16 @@
#ifndef _TESTGDT_H_
#define _TESTGDT_H_

#include "CxxTest/TestSuite.h"

class TestGdt: public CxxTest::TestSuite {
public:
void setUp(void);
void tearDown(void);

void testBaseAddress(void);
void testLimit(void);
void testInsert(void);
};

#endif /* _TESTGDT_H_ */

0 comments on commit 63119c0

Please sign in to comment.