All Articles

Notes on x86 CPU Memory Protection Mechanisms (GDT and LDT)

This page has been machine-translated from the original page.

While reading UNIX source code, I became curious about the process of transitioning to protected mode during boot, so I’ve compiled my findings.

I’ve tried to ensure technical accuracy, but if there are any errors, I would appreciate your feedback.

This article targets Intel’s x86 CPU.

Table of Contents

Real Mode and Protected Mode

Real Mode

Real mode in x86 CPUs is an operating mode for Intel 8086 CPU compatibility.

For x86, it is the initial operating mode at boot, and the BIOS also operates in real mode.

Due to Intel 8086 CPU compatibility, real mode restricts all register address lengths to 16 bits.

Reference: Real Mode - Wikipedia

When referencing memory addresses, segment register values are used to access a 20-bit address space.

Additionally, by enabling the A20 Line, a 21-bit address space can be used.

Real mode does not have hardware-based memory protection or virtual memory, which exist in protected mode described later.

Reference: Real Mode - OSDev Wiki

Protected Mode

Protected mode is an operating mode in x86 CPUs where the memory space is extended to 32 bits and memory and I/O protection becomes possible.

Hierarchical privilege management (ring protection) and memory protection between tasks are possible.

Reference: Protected Mode - Wikipedia

Reference: Protected Mode - OSDev Wiki

As mentioned earlier, since the BIOS operates in real mode on x86 CPUs, BIOS interrupts cannot be used after transitioning to protected mode.

The mechanism of memory protection in protected mode is described later.

Memory Protection in Protected Mode

In protected mode, it is necessary to define the memory regions that a program can reference. This applies to kernel programs as well.

First, x86 CPUs handle programs and data in units of contiguous memory regions called segments.

Segment units come in two sizes: 64KB or 4GB.

In memory protection in protected mode, the starting point and size of a memory region, as well as the read/write/execute permissions for that memory region, are called segment descriptors and are managed by descriptor tables.

When a program references memory in protected mode, the DS register does not directly point to a memory address value.

Instead, the DS register references the descriptor table to obtain segment information.

This mechanism makes it essential to rewrite the descriptor table for a program to reference arbitrary memory regions.

However, since the descriptor table cannot be rewritten by programs, as a result, programs cannot reference memory regions other than those predetermined, achieving memory protection.

Reference: How Windows Works

Reference: ASCII.jp: Understanding Windows Memory Management from x86 Mechanisms (1/4)

About Descriptor Tables

There are two types of descriptor tables: GDT (Global Descriptor Table) and LDT (Local Descriptor Table).

GDT (Global Descriptor Table)

The GDT is a descriptor table that is typically defined only once per system.

The GDT manages multiple LDTs.

x86 CPUs have a register called GDTR for pointing to the starting address of the GDT.

Reference: Global Descriptor Table - Wikipedia

Reference: Global Descriptor Table - OSDev Wiki

LDT (Local Descriptor Table)

LDTs are descriptor tables created for each program.

In x86 CPUs, programs cannot access regions other than those defined in descriptor tables.

Therefore, by having the OS manage non-conflicting descriptor tables for each program, it is possible to prevent each program from referencing other programs’ memory regions, achieving memory protection.

Similar to GDTR, x86 CPUs have a register called LDTR for specifying the starting address of the currently used LDT.

When a program tries to set a value in a segment register, the CPU references LDTR to obtain the address the program is trying to access and verifies access permission.

Summary

To organize the flow during program execution on x86 CPUs: first, when a program transitions to an execution state, the CPU identifies the index of the target program’s LDT from the GDT referenced via GDTR and stores it in LDTR.

When a program requests a reference to a specific segment, the CPU references the LDT from LDTR to obtain the reference address and verify reference permission.

Through this series of processes, programs cannot reference memory regions other than those predefined, achieving memory protection.

References