When your brand new computer boots, it’s still using the old 16bit mode, called “real mode”. One of the first things done by an operating system is to switch to protected mode, which enables 32-bit memory access.
The GDT (Global Descriptor Table) is represented as an array of descriptors. Each entry describes a memory segment.
The DPL field describes the privilege level at which the segment is accessible. Usually the kernel runs at privilege level 0, and the userland at privilege level 3.
The Granularity indicates if the limit is interpreted as a byte number (the flag is cleared) or if it’s interpreted as a number of pages (a page is 4KB length).
The first segment is the null segment, it has the same goal as the NULL pointer in C. The GDT entry should be filled with zero.
The TYPE field should be filled with:
Once you filled your GDT, you must inform the processor about it. This is done
gdtr register which can be changed with the
The segmentation, set with the GDT, can be used with the segmentation registers:
cswhich is the code selector,
eipis relative to this segment
dswhich is the data selector, data read and write are relative to this segment.
sswhich is the stack selector,
espis relative to this segment
gsare additional data segments available for the system programmer.
The format is the following:
The segments can only be changed when the RPL and the CPL (which is contained in
cs register) are smaller than the DPL of the requested segment.
Switching to protected mode
The first thing to do is to load a GDT into the
gdtr register with the
instruction. Next, you should set the PE (Protection Enable) bit in the
Since you can’t modify
cr0, you should use a temporary register:
movl $0x12, %cr0 /* It _won't_ assemble */ movl $0x12, %eax movl %eax, %cr0 /* OK */
Lastly, you should reload all the segment selectors with good values. Like
cr0, all the selectors except
cs should be set with a temporary register.
cs is special, you can only alter it with an intersegment jump (
with an intersegment return (
pushl $0x42 /* push %cs on the stack */ pushl $1f /* push %eip on the stack */ lret /* far return */ 1: /* After the lret you will get here, with cs set to 0x42 */