x86 memory segmentation

Dealing with larger addresses and more memory was thus comparably slower, as that capability was somewhat grafted-on in the Intel 8086.

In both real and protected modes, the system uses 16-bit segment registers to derive the actual memory address.

The Intel 80386, introduced in 1985, adds two additional segment registers, FS and GS, with no specific uses defined by the hardware.

Because there is no protection or privilege limitation in real mode, it is still entirely up to the program to coordinate and keep within the bounds of any segments.

This derived directly from the hardware design of the Intel 8086 (and, subsequently, the closely related 8088), which had exactly 20 address pins.

The use of this feature by programmers led to the Gate A20 compatibility issues in later CPU generations, Intel 286 and above, where the linear address space was expanded past 20 bits.

The root of the problem is that no appropriate address-arithmetic instructions suitable for flat addressing of the entire memory range are available.

[citation needed] Flat addressing is possible by applying multiple instructions, which however leads to slower programs.

For example, in the tiny model CS=DS=SS, that is the program's code, data, and stack are all contained within a single 64 KB segment.

The 80286's protected mode extends the processor's address space to 224 bytes (16 megabytes), but not by adjusting the shift value.

This method was commonly used on Windows 3.x applications to produce a flat memory space, although as the OS itself was still 16-bit, API calls could not be made with 32-bit instructions.

Machines following the rising IBM PC/AT standard could feign a reset to the CPU via the standardised keyboard controller, but this was significantly sluggish.

That selector consists of a 2-bit Requested Privilege Level (RPL), a 1-bit Table Indicator (TI), and a 13-bit index.

Otherwise, the processor adds the 24-bit segment base, specified in descriptor, to the offset, creating a linear physical address.

A 386 CPU can be put back into real mode by clearing a bit in the CR0 control register, however this is a privileged operation in order to enforce security and robustness.

By way of comparison, a 286 could only be returned to real mode by forcing a processor reset, e.g. by a triple fault or using external hardware.

Four of the segment registers, CS, SS, DS, and ES, are forced to base address 0, and the limit to 264.

Unlike the global descriptor table mechanism used by legacy modes, the base address of these segments is stored in a model-specific register.

For instance, the Linux kernel sets up only 4 general purpose segments: Since the base is set to 0 in all cases and the limit 4 GiB, the segmentation unit does not affect the addresses the program issues before they arrive at the paging unit.

This is because the current privilege level (CPL) of the processor is stored in the lower 2 bits of the CS register.

The only ways to raise the processor privilege level (and reload CS) are through the lcall (far call) and int (interrupt) instructions.

[6] Of course, in real mode, there are no privilege levels; all programs have absolute unchecked access to all of memory and all CPU instructions.

Three segments in real mode memory (click on image to enlarge). There is an overlap between segment 2 and segment 3; the bytes in the turquoise area can be used from both segment selectors. If however the program code dealing with segment 2 never uses offsets large enough to reach 0x77D0, then it can be thought of as a shorter, non-overlapping, and at most 30,672-byte segment.
Three segments in protected mode memory (click on image to enlarge), with the local descriptor table .