The Global Descriptor Table (GDT) usually used to hold segment informations. But GDT can hold things other than segment descriptors, every 8-byte entry in GDT is a descriptor, which can be TSS descriptor, LDT descriptor, Call Gate descriptor. I will introduce segment descriptors in this blog, because the last three descriptors are rarely used in most operating systems. Linux uses a shared TSS and LDT descriptor for every task and imply its own call gates mechanism.
Firstly, GDT can be accessed by a GDT descriptor. This descriptor is not the same as descriptors cited before, it is an assembly structure with a 2-byte size and a 4-byte offset. 2-byte size saves total entries in GDT and 4-byte offset refers to the first entry of GDT. So this means GDT entry can only be set on the first 4G memory.
Each entry of segment descriptor in GDT has a complex structure:
Here are three Base fields refers to the base address of a segment. What "Limit 0:15" means is that the field contains bits 0-15 of the limit value. The base is a 32 bit value cont
aining the linear address where the segment begins. The limit, a 20 bit value, tells the maximum addressable unit (either in 1 byte units, or in pages). Hence, if you choose page granularity (4 KiB) and set the limit value to 0xFFFFF the segment will span the full 4 GiB address space. Here is the structure of the access byte and flags:
The bit fields are:
- Pr: Present bit. This must be 1 for all valid selectors.
- Privl: Privilege, 2 bits. Contains the ring level, 0 = highest (kernel), 3 = lowest (user applications).
- Ex: Executable bit. If 1 code in this segment can be executed, ie. a code selector. If 0 it is a data selector.
- DC: Direction bit/Conforming bit.
- Direction bit for data selectors: Tells the direction. 0 the segment grows up. 1 the segment grows down, ie. the offset has to be greater than the base.
- Conforming bit for code selectors:
- If 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. Theprivl-bits 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 withprivl==0x2, while code in ring 2 and 3 can. Note that the privilege level remains the same, ie. a far-jump form ring 3 to a privl==2-segment remains in ring 3 after the jump.
- If 0 code in this segment can only be executed from the ring set in privl.
- RW: Readable bit/Writable bit.
- Readable bit for code selectors: Whether read access for this segment is allowed. Write access is never allowed for code segments.
- Writable bit for data selectors: Whether write access for this segment is allowed. Read access is always allowed for data segments.
- Ac: Accessed bit. Just set to 0. The CPU sets this to 1 when the segment is accessed.
- Gr: Granularity bit. If 0 the limit is in 1 B blocks (byte granularity), if 1 the limit is in 4 KiB blocks (page granularity).
- Sz: Size bit. If 0 the selector defines 16 bit protected mode. If 1 it defines 32 bit protected mode. You can have both 16 bit and 32 bit selectors at once.
Not shown in the picture is the 'L' bit (bit 21, next to 'Sz') which is used for x86-64 mode. See table 3-1 of the Intel Architecture manual.
Refer to Intel Manual 3.4.5 for more details.
Some materials are cited from http://wiki.osdev.org/Global_Descriptor_Table