GDT and Segmentation Mechanism
At boot, x86 CPUs operate in real mode using segmented addressing: segment register × 16 + offset register yields physical addresses. This legacy approach lacks security features and modern multitasking support.
In protected mode, all 32 address lines become active, enabling 4GB physical addressing. Memory segmentation persists for compatibility, with segment metadata stored in the Global Descriptor Table (GDT). Each GDT entry is a descriptor defining segment properties, while segment selectors in registers point to specific descriptors.
Descriptor Structure
Each 8-byte descriptor contains:
- 32-bit base address
- 20-bit limit determining segment size (byte or 4KB granularity)
- Attribute flags including:
- Type (code/data/stack)
- Descriptor Privilege Level (DPL)
- Present flag
- Granularity bit
- Default operation size (16/32-bit)
Actual segment boundary = (Descriptor limit + 1) × granularity - 1
Segment Selector
16-bit selectors contain:
- 13-bit index into GDT/LDT
- TI flag (0=GDT, 1=LDT)
- 2-bit Requested Privilege Level (RPL)
Transitioning to Protected Mode
Key steps:
- Initialize GDT with null descriptor
- Load GDTR register with LGDT instruction
- Disable interrupts (CLI)
- Enable A20 address line
- Set CR0.PE bit
- Far jump to protected mode code segmant
Descriptor Construction Macro
%macro SegmentDescriptor 3
dw %2 & 0xFFFF ; Limit low
dw %1 & 0xFFFF ; Base low
db (%1 >> 16) & 0xFF ; Base mid
dw ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; Flags + limit high
db (%1 >> 24) & 0xFF ; Base high
%endmacro
Protected Mode Entry Example
%include "pm_const.inc"
org 0x100
jmp start
section .gdt
gdt_start:
SegmentDescriptor 0, 0, 0
SegmentDescriptor 0, code32_len-1, CODE_FLAGS
SegmentDescriptor 0xB8000, 0xFFFF, VIDEO_FLAGS
gdt_ptr:
dw gdt_size - 1
dd gdt_start
selector_code32 equ 1 * 8
selector_video equ 2 * 8
section .real
bits 16
start:
; Initialize segment registers
mov ax, cs
mov ds, ax
; ... (other initialization)
; Load GDT
lgdt [gdt_ptr]
; Disable interrupts
cli
; Enable A20
in al, 0x92
or al, 2
out 0x92, al
; Set protection enable
mov eax, cr0
or eax, 1
mov cr0, eax
; Jump to 32-bit code
jmp selector_code32:0
section .prot
bits 32
protected_start:
mov ax, selector_video
mov gs, ax
mov edi, (80*11+79)*2
mov ah, 0x0C
mov al, 'P'
mov [gs:edi], ax
jmp $
code32_len equ $ - protected_start
Instruction Differencse
Behavior varies between modes:
- 8-bit operands: Real mode extends to 16 bits, protected mode extends to 32 bits
- 16/32-bit operands: Direct push/pop in both modes