GDT Tutorial: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
→‎How to Set Up The GDT: Changed code examples and added code for long mode and non-flat protected mode. Feel free to check my work.
Line 123:
=== Filling the Table ===
 
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. Plus, here and there, you have flags that you need to set up properly if you want things to work.
 
<source lang="c">
/**
* \param target A pointer to the 8-byte GDT entry
* \param source An arbitrary structure describing the GDT entry
*/
void encodeGdtEntry(uint8_t *target, struct GDT source)
{
Line 160 ⟶ 156:
=== Telling the CPU Where the Table Is ===
 
Some assembly example is required here. While you could use [[inline assembly]], the memory packing expected by <tt>the '''LGDT</tt>''' and <tt>'''LIDT</tt>''' instructions makes it much easier to write a small assembly routine instead. As said above, you'll use <tt>'''LGDT</tt>''' instruction to load the base address and the limit of the GDT. Since the base address should be a linear address, you'll need a bit of tweaking depending of your current [[MMU]] setup.
 
==== From Real Mode ====
 
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.
Line 183 ⟶ 179:
</source>
 
==== FromProtected FlatMode, ProtectedFlat ModeModel ====
 
"Flat" meaning the base of your dataData segmentSegment is 0 (regardless of whether paging'''[[Paging]]''' is on or offenabled). This is the case if you'reyour code has just been booted by [[GRUB]], for instance. YouIn shouldthe '''[[System V ABI]]''', arguments are passed on reverse order in the stack, so a function that can callbe thiscalled as <tt>setGdt(GDTlimit, sizeof(GDT)base)</tt> might look like the following example code.
 
<source lang="asm">
Line 192 ⟶ 188:
 
setGdt:
MOV EAXAX, [esp + 4]
MOV [gdtr], AX
MOV EAX, [ESP + 8]
MOV [gdtr + 2], EAX
MOVLGDT AX, [ESP + 8gdtr]
DEC AXRET
</source>
 
==== Protected Mode, Non-Flat Model ====
 
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>.
 
<source lang="asm">
gdtr DW 0 ; For limit storage
DD 0 ; For base storage
 
setGdt:
MOV AX, [esp + 4]
MOV [gdtr], AX
MOV EAX, [ESP + 8]
ADD EAX, [ESP + 12]
MOV [gdtr + 2], EAX
LGDT [gdtr]
RET
</source>
 
==== From Non-Flat ProtectedLong Mode ====
 
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.
If your data segment has a non-zero base (e.g. you're using a [[Higher Half Kernel]] during the segmentation trick), you'll have to "<tt>ADD EAX, base_of_your_data_segment_which_you_should_know</tt>" between the "<tt>MOV EAX, ...</tt>" and the "<tt>MOV ..., EAX</tt>" instructions of the sequence above.
 
<source lang="asm">
gdtr DW 0 ; For limit storage
DQ 0 ; For base storage
 
setGdt:
MOV [gdtr], DI
MOV [gdtr+2], RSI
LGDT [gdtr]
RET
</source>
 
=== Reload Segment Registers ===
 
Whatever you do with the '''GDT''' has no effect on the CPU until you load selectorsnew '''Segment Selectors''' into segment'''Segment Registers'''. For most of these registers, the process is as simple as using '''MOV''' instructions, but changing the '''CS''' register requires code resembling a jump or call to elsewhere, as this is the only way its value is meant to be changed.
 
==== Protected Mode ====
 
In this case, reloading '''CS''' is as simple as performing a far jump to the required segment, directly after the jump instruction:
 
<source lang="asm">