GDT Tutorial: Difference between revisions

m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(7 intermediate revisions by 5 users not shown)
Line 35:
{|class="wikitable" style="display: inline-table;"
|+ 32-bit
! SelectorOffset !! Use !! Content
|-
| 0x0000 || Null Descriptor || <tt>Base = 0<br>Limit = 0x00000000<br>Access Byte = 0x00<br>Flags = 0x0</tt>
Line 47:
| 0x0020 || User Mode Data Segment || <tt>Base = 0<br>Limit = 0xFFFFF<br>Access Byte = 0xF2<br>Flags = 0xC</tt>
|-
| 0x0028 || Task State Segment || <tt>Base = &TSS<br>Limit = sizeof(TSS)-1<br>Access Byte = 0x89<br>Flags = 0x0</tt>
|}
 
{|class="wikitable" style="display: inline-table;"
|+ 64-bit
! SelectorOffset !! Use !! Content
|-
| 0x0000 || Null Descriptor || <tt>Base = 0<br>Limit = 0x00000000<br>Access Byte = 0x00<br>Flags = 0x0</tt>
Line 64:
| 0x0020 || User Mode Data Segment || <tt>Base = 0<br>Limit = 0xFFFFF<br>Access Byte = 0xF2<br>Flags = 0xC</tt>
|-
| 0x0028 || Task State Segment<br>('''[[Global Descriptor Table#Long Mode System Segment Descriptor|64-bit System Segment]]''') || <tt>Base = &TSS<br>Limit = sizeof(TSS)-1<br>Access Byte = 0x89<br>Flags = 0x0</tt>
|}
 
Line 75:
{|class="wikitable" style="display: inline-table;"
|+ Small Kernel
! SelectorOffset !! Use !! Content
|-
| 0x0000 || Null Descriptor || <tt>Base = 0<br>Limit = 0x00000000<br>Access Byte = 0x00<br>Flags = 0x0</tt>
Line 83:
| 0x0010 || Kernel Mode Data Segment || <tt>Base = 0x00800000<br>Limit = 0x003FFFFF<br>Access Byte = 0x92<br>Flags = 0xC</tt>
|-
| 0x0018 || Task State Segment || <tt>Base = &TSS<br>Limit = sizeof(TSS)-1<br>Access Byte = 0x89<br>Flags = 0x0</tt>
|}
 
Line 98:
{|class="wikitable"
|+ GDT
! SelectorOffset !! Use
|-
| Preceding Entries || Null Descriptor<br>Kernel Segments<br>etc.
Line 125:
The above structure of the '''GDT''' doesn't show you how to write entries in the correct format. The actual structure of descriptors is a little messy for backwards compatibility with the 286's '''GDT'''. Base address are split across three different fields and you cannot encode any limit you want.
 
<sourcesyntaxhighlight lang="c">
void encodeGdtEntry(uint8_t *target, struct GDT source)
{
Line 146:
// Encode the flags
target[6] |= (source.flags << 4);
}
</syntaxhighlight>
</source>
 
In order to fill your table, you will want to use this function once for each entry, with <tt>*target</tt> pointing to the logical address of the '''Segment Descriptor''' and <tt>source</tt> being a struct of your design containing the necessary information.
Line 162:
The linear address should here be computed as <tt>segment * 16 + offset</tt>. <tt>GDT</tt> and <tt>GDT_end</tt> are assumed to be symbols in the current data segment.
 
<sourcesyntaxhighlight lang="asm">
gdtr DW 0 ; For limit storage
DD 0 ; For base storage
Line 177:
LGDT [gdtr]
RET
</syntaxhighlight>
</source>
 
==== Protected Mode, Flat Model ====
Line 183:
"Flat" meaning the base of your Data Segment is 0 (regardless of whether '''[[Paging]]''' is enabled). This is the case if your code has just been booted by [[GRUB]], for instance. In the '''[[System V ABI]]''', arguments are passed on reverse order in the stack, so a function that can be called as <tt>setGdt(limit, base)</tt> might look like the following example code.
 
<sourcesyntaxhighlight lang="asm">
gdtr DW 0 ; For limit storage
DD 0 ; For base storage
Line 194:
LGDT [gdtr]
RET
</syntaxhighlight>
</source>
 
==== Protected Mode, Non-Flat Model ====
Line 200:
If your data segment has a non-zero base, you'll have to adjust the instructions of the sequence above to include the ability to add the base offset of your data segment, which should be a known value to you. You can pass it in as an argument and call this function as <tt>setGdt(limit, base, offset)</tt>.
 
<sourcesyntaxhighlight lang="asm">
gdtr DW 0 ; For limit storage
DD 0 ; For base storage
Line 212:
LGDT [gdtr]
RET
</syntaxhighlight>
</source>
 
==== Long Mode ====
Line 218:
In '''[[Long Mode]]''', the length of the '''Base''' field is 8 bytes, rather than 4. As well, the '''[[System V ABI]]''' passes the first two arguments via the '''RDI''' and '''RSI''' registers. Thus, this example code can be called as <tt>setGdt(limit, base)</tt>. As well, only a flat model is possible in long mode, so no considerations have to be made otherwise.
 
<sourcesyntaxhighlight lang="asm">
gdtr DW 0 ; For limit storage
DQ 0 ; For base storage
Line 227:
LGDT [gdtr]
RET
</syntaxhighlight>
</source>
 
=== Reload Segment Registers ===
Line 237:
In this case, reloading '''CS''' is as simple as performing a far jump to the required segment, directly after the jump instruction:
 
<sourcesyntaxhighlight lang="asm">
reloadSegments:
; Reload CS register containing code selector:
Line 250:
MOV SS, AX
RET
</syntaxhighlight>
</source>
 
An explanation of the above code can be found [http://stackoverflow.com/questions/23978486/far-jump-in-gdt-in-bootloader here].
Line 258:
In '''[[Long Mode]]''' the process of changing '''CS''' is not simple as far jumps cannot be used. Using a far return is recommended instead:
 
<sourcesyntaxhighlight lang = "asm">
reloadSegments:
; Reload CS register:
Line 274:
MOV SS, AX
RET
</syntaxhighlight>
</source>
 
== The LDT ==
Line 302:
 
Tool for easily creating GDT entries.
<sourcesyntaxhighlight lang="c">
// Used for creating GDT segment descriptors in 64-bit integer form.
Line 384:
}
</syntaxhighlight>
</source>
 
== See Also ==
Line 398:
[[Category:Tutorials]]
[[Category:X86 CPU]]
[[Category:Memory Segmentation]]