xaizek / tos (License: GPLv3 only) (since 2018-12-07)
This is an alternative version of sources presented as part of Write Your Own OS video tutorial by Viktor Engelmann.
<root> / src / GDT.cpp (e31bf21e34df35d61698b201b20573e6c19e932e) (2,359B) (mode 100644) [raw]
#include "GDT.hpp"

#include <cstdint>

#include <new>

namespace {

union SegmentDescriptor {
    std::uint64_t forceAlignment;
    std::uint8_t data[8];

    SegmentDescriptor(std::uint32_t base, std::uint32_t limit,
                      std::uint8_t type);
    std::uint32_t getBase() const;
    std::uint32_t getLimit() const;
};

}

static SegmentDescriptor GDT[3] = {
    { 0, 0, 0 },
    { 0, 64*1024*1024, 0x9a },
    { 0, 64*1024*1024, 0x92 },
};

GlobalDescriptorTable::GlobalDescriptorTable()
{
    std::uint8_t gdtr[6];
    new(&gdtr[0]) std::uint16_t(sizeof(GDT));
    new(&gdtr[2]) std::uint32_t(reinterpret_cast<std::uint32_t>(&GDT));

    asm volatile("lgdt %0\n"
                 "pushw %2\n"
                 "pushw %2\n"
                 "pushw %2\n"
                 "pushw %2\n"
                 "pushw %2\n"
                 "pushl %1\n"
                 "push $next\n"
                 "retf\n"
                 "next:\n"
                 "popw %%ds\n"
                 "popw %%es\n"
                 "popw %%ss\n"
                 "popw %%gs\n"
                 "popw %%fs\n": : "m"(gdtr), "r"(getCS()), "r"(getDS()));
}

std::uint16_t
GlobalDescriptorTable::getCS() const
{
    return 1 << 3;
}

std::uint16_t
GlobalDescriptorTable::getDS() const
{
    return 2 << 3;
}

SegmentDescriptor::SegmentDescriptor(std::uint32_t base, std::uint32_t limit,
                                     std::uint8_t type)
{
    if (limit < (1 << 20)) {
        data[6] = 0x40;
    } else {
        limit >>= 12;
        data[6] = 0xC0;
    }

    // Encode the limit.
    data[0] = limit & 0xff;
    data[1] = (limit >> 8) & 0xff;
    data[6] |= (limit >> 16) & 0xf;

    // Encode the base.
    data[2] = base & 0xff;
    data[3] = (base >> 8) & 0xff;
    data[4] = (base >> 16) & 0xff;
    data[7] = (base >> 24) & 0xff;

    // Type.
    data[5] = type;
}

std::uint32_t
SegmentDescriptor::getBase() const
{
    std::uint32_t result = data[7];
    result = (result << 8) + data[4];
    result = (result << 8) + data[3];
    result = (result << 8) + data[2];

    return result;
}

std::uint32_t
SegmentDescriptor::getLimit() const
{
    std::uint32_t result = data[6] & 0xf;
    result = (result << 8) + data[1];
    result = (result << 8) + data[0];

    if (data[6] & 0x80) {
        result = (result << 12) | 0xfff;
    }

    return result;
}
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/tos

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/tos

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master