#include "gdt.hpp"
#include "../Helpers/types.hpp"
#include "../Helpers/memory.hpp"

//Constructor
Gdt::Gdt(){

    //Init conventional segment
    this->initGdtDesc(0x0,0x0,0x0,0x0, &m_Descriptors[0]);

    //Init code segment
    this->initGdtDesc(0x0,0xFFFFF,0x9A,0x0D, &m_Descriptors[1]);

    //Init data segment
    this->initGdtDesc(0x0,0xFFFFF,0x92,0x0D, &m_Descriptors[2]);

    //Init stack segment
    this->initGdtDesc(0x00B00000,0x00000500,0x96,0x0D, &m_Descriptors[3]);


    //Init GDT Pointer
    this->m_Pointer.size=4*sizeof(this->m_Descriptors);
    this->m_Pointer.segment=0x00007E00;


}

//Destructor
Gdt::~Gdt(){

}

//Adapt parameter to the gdt descriptor structure
void Gdt::initGdtDesc(u32 base, u32 limit, u8 access, u8 flags, gdtDescriptorStruct *Descriptor){
	Descriptor->limit1 = limit & 0xFFFF;
	Descriptor->base1 = base & 0xFFFF;
	Descriptor->base2 = (base & 0xFF0000) >> 16;
	Descriptor->access = access;
	Descriptor->limit2 = (limit & 0xF0000 ) >> 16;
	Descriptor->flags = flags & 0xFF;
	Descriptor->base3 = (base & 0xFF000000) >> 24;
}

//Copy the gdt into mémory and load it
void Gdt::loadGdt(){
	//Copy Gdt into memory and init registers
	memcpy((u32)m_Descriptors, (u32)m_Pointer.segment, (u32)m_Pointer.size);

    //Put m_Pointer in a var to pass it to assembly code
    int *gdtAdress=(int *)&m_Pointer;

    __asm__("lgdtl (%0);"
            :
            :"r"(gdtAdress)
    );
}