Skip to content

real mode

Mohiuddin Khan Inamdar edited this page Jun 21, 2026 · 3 revisions

← Home

Real Mode

The 16-bit world every x86 starts in — segments, offsets, and a 1 MiB ceiling that MyOS-Simple lives within until it switches to protected mode.

Every x86 CPU, from the original 8086 to the latest 64-bit chip, powers up in real mode. It is a compatibility museum baked into silicon: a 16-bit execution environment that behaves almost exactly like a 1978 Intel 8086. When the BIOS jumps to our boot sector at 0x7C00, this is the environment our code inherits.

What "real mode" means

Real mode is defined by a handful of properties:

  • 16-bit registers. The general-purpose registers AX, BX, CX, DX, the index registers, and the stack pointer are all 16 bits wide. The largest value a single register holds is 0xFFFF (65535).
  • Segment:offset addressing. Memory is reached through a pair of 16-bit values, not a single flat pointer (see below).
  • ~1 MiB of addressable memory. The addressing formula tops out just past one megabyte.
  • No memory protection. Any code can read or write any address. There are no privilege rings, no page faults, no isolation. A stray pointer corrupts whatever it hits.
  • BIOS services are available. Because the IVT is live, software interrupts like int 0x10 and int 0x13 work. These vanish the instant we enter protected mode.

This is why all of MyOS-Simple's boot-time hardware work — clearing the screen, loading the kernel from disk — happens in real mode, before the protected-mode switch.

Segment:offset addressing

The defining feature of real mode is how it forms a physical address. The 8086 had 16-bit registers but a 20-bit address bus — it could point at 64 KiB but wire up to 1 MiB. Intel bridged the gap with segmentation: every memory access combines two 16-bit values.

physical address = (segment << 4) + offset
                 = segment * 16   + offset

The segment register supplies a base, shifted left by 4 bits (multiplied by 16), and the offset is added on top. So the logical address 0x07C0:0x0000 and the logical address 0x0000:0x7C00 both resolve to the same physical byte:

0x07C0 * 16 + 0x0000 = 0x7C00 + 0      = 0x7C00
0x0000 * 16 + 0x7C00 = 0      + 0x7C00 = 0x7C00

This is exactly why MyOS-Simple's bootloader zeroes its segment registers up front:

    ; Set up segments
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x7C00

helloworld-os-c/boot.asm:21-26

With DS = ES = SS = 0, every offset is its own physical address — mov bx, 0x1000 simply means physical 0x1000, with no segment arithmetic to track in your head. The [ORG 0x7C00] directive at the top of each boot file tells the assembler to compute label addresses as if the code lives at offset 0x7C00, which (with a zero DS) matches the physical address the BIOS loaded us to.

💡 Tidbit: Because segment * 16 + offset can be written many ways, the same physical byte has up to 4096 different segment:offset spellings. Two addresses are aliases if they reduce to the same physical value. Real-mode programmers learned to normalise their pointers to avoid surprises.

The 1 MiB ceiling (and a little extra)

The largest address real mode can name comes from maxing out both halves of the formula:

0xFFFF * 16 + 0xFFFF = 0xFFFF0 + 0xFFFF = 0x10FFEF  (~1 MiB + ~64 KiB)

On the original 8086, the address bus was only 20 bits wide, so anything past 0xFFFFF (1 MiB) silently wrapped around to the bottom of memory. The practical ceiling was therefore ~1 MiB.

💡 Tidbit: Real mode's 20-bit reach is a direct consequence of the segment * 16 + offset formula: shifting a 16-bit segment left by 4 and adding a 16-bit offset produces at most a 21-bit sum, but the original bus truncated it to 20 bits — capping classic real mode at ~1 MiB.

⚠️ Caveat: Later CPUs (80286+) had wider address buses, so the wrap no longer happened automatically. The small region just above 1 MiB (0x1000000x10FFEF) became reachable from real mode and is called the High Memory Area (HMA) — but only if the A20 line (address line 20) is enabled. MyOS-Simple does not need the HMA: it loads everything into low memory and switches to protected mode before it would matter.

The memory map in real mode

Here is what low memory looks like while MyOS-Simple's boot sector is running. The full table lives in the memory map reference; the highlights:

Physical address Contents
0x00000 Interrupt Vector Table (IVT) + BIOS data area
0x00500 First freely usable low memory
0x01000 Where the kernel is loaded (stage 2+)
0x07C00 The boot sector (512 bytes, ends in 0xAA55)
0x07E00 Free memory above the boot sector
0xB8000 VGA text-mode framebuffer

The IVT at 0x00000 is what makes BIOS services work: each int N instruction looks up entry N in that table and calls the firmware routine it points to.

The stack in real mode

MyOS-Simple sets SP = 0x7C00 (boot.asm:26). The x86 stack grows downward — each push decrements SP before writing. Starting the stack at 0x7C00 and the code also at 0x7C00 is deliberate: the stack expands into the free memory below the boot sector (0x7BFF, 0x7BFE, …), so it can never collide with the 512 bytes of code sitting at 0x7C00 and above.

⚠️ Caveat: Real mode gives you no stack-overflow protection. If the stack grows far enough down it will eventually run into the IVT/BIOS data at 0x00000 and corrupt it silently. Boot code keeps its stack usage tiny for exactly this reason.

Why leave real mode at all?

Real mode is friendly for booting — the BIOS does the hardware legwork for you — but it is a poor home for a real kernel:

  • Only ~1 MiB of memory is reachable.
  • 16-bit registers make 32-bit arithmetic clumsy.
  • There is no memory protection, so a bug anywhere can corrupt anything.
  • Segment juggling makes large, flat data structures painful.

So from stage 2 onward, the bootloader installs a Global Descriptor Table, flips CR0.PE, and far-jumps into protected mode: flat 32-bit addressing, 4 GiB of reach, and privilege levels. The boot process page walks that transition step by step.

Real mode never fully disappears, though — it is still the only environment in which the convenient BIOS services exist, which is why single-sector stage 1 stays in real mode for its entire life.

See also

Clone this wiki locally