[SOLVED] Adressing entries in 64Bit GDT

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
ratz
Posts: 2
Joined: Mon Nov 24, 2014 11:00 am

[SOLVED] Adressing entries in 64Bit GDT

Post by ratz »

Hi Folks,

i have a question regarding the correct adressing of entries in the Global Descriptor Table (GDT) in 64Bit Long Mode!

The Intel Software Developers Manual Vol. 3 Chapter 3.5.2 states the following:
In IA-32e mode, a segment descriptor table can contain up to 8192 (2^13 ) 8-byte descriptors. An entry in the segment descriptor table can be 8 bytes. System descriptors are expanded to 16 bytes (occupying the space of two entries).
The Segment Selector contained in one of the Segment Registers provides an index to an entry in the Global Descriptor Table.
If i want to calculate the real offset to my entry in the GDT i have to multiply the index with the size of an entry.
As seen in the quote from the manual, entries can be either 8 or 16 Bytes long!
How can i calculate the correct offset, if the sizes of the GDT-Entries vary?

In my project i am trying to read the contents of the Task-State-Segment Descriptor in the GDT and tried the following:

Code: Select all

typedef union
{
    struct
    {
        uint8_t RPL : 2;            // Requested Privilege Level
        bool TI : 1;                // TI = 0: GDT, TI = 1: LDT
        uint16_t index : 13;        // Index into the GDT or LDT
    } bf;                           // bf stands for bit-fields

    uint16_t val;                   // used to avoid typecasting issues
} __attribute__((packed)) selector_t; //Segment Selector type

typedef union
{
    struct
    {
        uint16_t segment_limit : 16;
        uint16_t base_lo : 16;
        uint8_t base_mid : 8;
        uint8_t type : 4;
        bool : 1;               // Fixed_0
        uint8_t DPL : 2;        // Descriptor Privilege Level
        bool P : 1;             // Present
        uint8_t limit : 4;      // Segment Limit
        bool AVL : 1;           // Available to System Programmers
        uint8_t : 2;            // Fixed_0
        bool G : 1;             // Granularity
        uint8_t base_hi : 8;
        #ifdef __x86_64__
        uint32_t base_ext : 32;
        uint8_t : 8;            // Reserved
        uint8_t : 5;            // Fixed_0
        uint32_t : 19;          // Reserved
        #endif
    } bf;

    #ifdef __i386__
    uint32_t hi;
    uint32_t lo;
    #endif
    #ifdef __x86_64__
    uint64_t hi;
    uint64_t lo;
    #endif
} __attribute__((packed)) tss_descriptor_t; // Task-State-Segment Descriptor

typedef union
{
    struct
    {
        uint16_t limit_lo : 16;
        uint16_t base_lo : 16;
        uint8_t  base_mid : 8;
        uint8_t  access : 8;
        uint8_t  granularity : 8;
        uint8_t  base_hi : 8;
        #ifdef __x86_64__
        uint32_t base_ext : 32;
        uint8_t : 8;            // Reserved
        uint8_t : 5;            // Fixed_0
        uint32_t : 19;          // Reserved
        #endif
    } bf;

    #ifdef __i386__
    uint32_t hi;
    uint32_t lo;
    #endif
    #ifdef __x86_64__
    uint64_t hi;
    uint64_t lo;
    #endif
} __attribute__((packed)) gdt_entry_t;


typedef struct
{
    uint16_t limit;     // Table Limit, The size of the gdt minus one (the last valid address in the table).
    #ifdef __i386__
    uint32_t base;      // Linear Base Address, The address of the first gdt_entry_t struct.
    #endif
    #ifdef __x86_64__
    uint64_t base;      // Linear Base Address in 64bit Mode, The address of the first gdt_entry_t struct.
    #endif
} __attribute__((packed)) dtr_t; //descriptor table register (for IDTR and GDTR)


####FUNCTIONS####
dtr_t *GetIDTR(void)
{
    dtr_t *lpIDTR = (dtr_t *)kmalloc(sizeof(dtr_t), GFP_KERNEL);
    if(!lpIDTR) return NULL;

    asm volatile(
        ".intel_syntax noprefix;"
        #ifdef __i386__
        "sidt [ebx];"
        #endif
        #ifdef __x86_64__
        "sidt [rbx];"
        #endif
        ".att_syntax prefix;"
        : :"b"(lpIDTR)
    );

    return lpIDTR;
}

selector_t GetTaskRegister(void)
{
    selector_t tr;

    asm volatile(
        ".intel_syntax noprefix;"
        "str ax;"
        ".att_syntax prefix;"
        : "=a"(tr.val)
    );

    return tr;
}

gdt_entry_t *GetGDTEntry(selector_t sr)
{
    uint32_t offset = 0;
    dtr_t *lpGDTR = GetGDTR();
    gdt_entry_t *ptr_descriptor = NULL;

    offset = sr.bf.selector * sizeof(gdt_entry_t);
    ptr_descriptor = (void *)lpGDTR->base+offset;
    kfree(lpGDTR);

    return ptr_descriptor;
}

tss_descriptor_t GetTSSDescriptor(void)
{
	sr_t sr = GetTaskRegister();
	gdt_entry_t *ptr_tss_descriptor = GetGDTEntry(sr);
	tss_descriptor_t tss;

	tss.lo = ptr_tss_descriptor->lo;
	tss.hi = ptr_tss_descriptor->hi;

	return tss;
}
In the function GetGDTEntry() i try to calculate the offset, but i dont know which size to use, because the entries can vary in their size :/
What would be the proper way to get the correct offset to an entry?
Is there a universal solution that works for Legacy-Mode (32Bit) and Long-Mode (64Bit and Compatibility-Mode)?
And what is the size of the NULL-Descriptor in the GDT in Legacy-Mode (32Bit) and Long-Mode (64Bit and Compatibility-Mode)?

Thank you for your help!

ratz
Last edited by ratz on Mon Nov 24, 2014 12:56 pm, edited 1 time in total.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Adressing entries in 64Bit GDT

Post by Combuster »

Double-sized entries count as two entries. The offset is always the entry number times eight. The processor isn't smart enough to read every entry in the GDT in order to find where the nth entire descriptor is located.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
ratz
Posts: 2
Joined: Mon Nov 24, 2014 11:00 am

Re: Adressing entries in 64Bit GDT

Post by ratz »

That was the perfect answer,

thank you very much :)
Post Reply