x86 Protected Mode: Global Descriptor Table and Segmentation

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:

  1. Initialize GDT with null descriptor
  2. Load GDTR register with LGDT instruction
  3. Disable interrupts (CLI)
  4. Enable A20 address line
  5. Set CR0.PE bit
  6. 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

Tags: x86 protected-mode gdt segmentation assembly

Posted on Thu, 21 May 2026 21:06:38 +0000 by jb489