[SOLVED] Adressing entries in 64Bit GDT
Posted: Mon Nov 24, 2014 12:05 pm
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:
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:
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
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:
The Segment Selector contained in one of the Segment Registers provides an index to an entry in the Global Descriptor Table.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).
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;
}
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