Global Descriptor Table
The Global Descriptor Table (GDT) is a binary data structure specific to the IA32 and x86-64 architectures. It contains entries telling the CPU about memory segments. A similar Interrupt Descriptor Table exists containing task and interrupt descriptors. Read the GDT Tutorial.
The GDT is pointed to by the value in the GDTR register. This is loaded using the LGDT assembly instruction, whose argument is a pointer to a GDT Descriptor structure:
- Size: The size of the table in bytes subtracted by 1. This subtraction occurs because the maximum value of Size is 65535, while the GDT can be up to 65536 bytes in length (8192 entries). Further, no GDT can have a size of 0 bytes.
- Offset: The linear address of the GDT (not the physical address, paging applies).
Note that the amount of data loaded by LGDT differs in 32-bit and 64-bit modes, the offset is 4 bytes long in 32-bit mode and 8 bytes long in 64-bit mode.
For more information, see Section 2.4.1: Global Descriptor Table Register (GDTR) and Figure 2-6: Memory Management Registers of the Intel Software Developer Manual, Volume 3-A.
The table contains Segment Descriptor entries which are 8 bytes long. Each entry has a complex structure:
What "Limit 0:15" means is that the field contains bits 0-15 of the Limit value.
- Base: A 32-bit value containing the linear address where the segment begins.
- Limit: A 20-bit value, tells the maximum addressable unit, either in 1 byte units, or in 4KiB pages. Hence, if you choose page granularity and set the Limit value to 0xFFFFF the segment will span the full 4 GiB address space in 32-bit mode.
In 64-bit mode, the Base and Limit values are ignored, each descriptor covers the entire linear address space regardless of what they are set to.
The Access Byte and Flags are laid out as follows:
- Pr: Present bit. Allows an entry to refer to a valid segment. Must be set (1) for any valid segment.
- Privl: Descriptor privilege level field. Contains the ring level of the segment. 0 = highest privilege (kernel), 3 = lowest privilege (user applications).
- S: Descriptor type bit. If clear (0) the descriptor defines a system segment (eg. a Task State Segment). If set (1) it defines a code or data segment.
- Ex: Executable bit. If clear (0) the descriptor defines a data segment. If set (1) it defines a code segment which can be executed from.
- DC: Direction bit/Conforming bit.
- For data selectors: Direction bit. If clear (0) the segment grows up. If set (1) the segment grows down, ie. the Offset has to be greater than the Limit.
- For code selectors: Conforming bit.
- If clear (0) code in this segment can only be executed from the ring set in Privl.
- If set (1) code in this segment can be executed from an equal or lower privilege level. For example, code in ring 3 can far-jump to conforming code in a ring 2 segment. The Privl field represent the highest privilege level that is allowed to execute the segment. For example, code in ring 0 cannot far-jump to a conforming code segment where Privl is 2, while code in ring 2 and 3 can. Note that the privilege level remains the same, ie. a far-jump from ring 3 to a segment with a Privl of 2 remains in ring 3 after the jump.
- RW: Readable bit/Writable bit.
- For code segments: Readable bit. If clear (0), read access for this segment is not allowed. If set (1) read access is allowed. Write access is never allowed for code segments.
- For data segments: Writeable bit. If clear (0), write access for this segment is not allowed. If set (1) write access is allowed. Read access is always allowed for data segments.
- Ac: Accessed bit. Best left clear (0), the CPU will set it when the segment is accessed.
- Gr: Granularity flag, indicates the size the Limit value is scaled by. If clear (0), the Limit is in 1 Byte blocks (byte granularity). If set (1), the Limit is in 4 KiB blocks (page granularity).
- Sz: Size flag. If clear (0), the descriptor defines a 16-bit protected mode segment. If set (1) it defines a 32-bit protected mode segment. A GDT can have both 16-bit and 32-bit selectors at once.
- L: Long-mode code flag. If set (1), the descriptor defines a 64-bit code segment. When set, Sz should always be clear. For any other type of segment (other code types or any data segment), it should be clear (0).
- The diagram currently does not reflect its position, it is bit-53 of the overall descriptor or one bit to the right of the Sz bit in this diagram.
For more information, see Section 3.4.5: Segment Descriptors and Figure 3-8: Segment Descriptor of the Intel Software Developer Manual, Volume 3-A.
- GDT Tutorial
- Getting to Ring 3
- http://www.osdever.net/tutorials/view/the-world-of-protected-mode - how to set up GDT in assembler