Every programmer familiar with the x86 architecture understands the difference between real and protected address mode of the processor. It is well known that the real mode is compatible with Intel’s old 16-bit 8088/8086 CPUs, while protected mode was a new feature introduced in the Intel 80286 and extended to 32-bit in the 80386. The 80386 further muddled things by introducing the Virtual-8086 mode (V86 mode) that was something of both.
Not every programmer knows exactly what the difference is between real and protected mode on processors that support both. Intel’s documentation, frankly, does its best to obscure and confuse the issue (a situation not unfamiliar to readers of Intel’s processor documentation) without actually lying outright. Intel suggests that real mode implies 16-bit segments with 64KB limits, 8086 style addressing, limited instruction set, no paging, no privilege levels, and no memory protection.
The truth is a little more complicated. Reading between the lines of Intel’s manuals, one catches a glimpse of it. Reading AMD’s processor manuals, one finds some of the less obvious details spelled out. It is difficult to say whether Intel failed to clearly document the inner workings of real mode out of pure laziness or if the motivation was not pinning down “unimportant” details so that the implementation could be changed in the future.
Processor evolution helped to obscure matters some more. With the 286, the programmer could not switch from protected mode back to real mode (not even using the undocumented LOADALL instruction). After reset, the CPU always started in real mode, and the processor took care of setting everything up. Starting with the 386, switching from protected back to real mode was possible without a processor reset.
Intel’s 386/486 documentation provides clues in two areas: The description of switching from protected to real mode, and instruction timings. A look at the instruction timings reveals which instructions actually behave differently in real vs. protected mode. There are basically only two categories—segment register loads and port I/O. The latter is actually not obvious; one might expect real mode port I/O to execute about as quickly as protected mode instructions running with the highest privilege (ring 0), but real mode in fact executes slightly slower. Segment register loads are easy to explain—because there is no need to load a descriptor from the LDT/GDT, real mode segment register loads execute faster (segment register stores, on the other hand, take the same amount of cycles regardless of mode). On the other hand, control transfer instructions (CALL, RET, JMP), show no difference in execution speed in comparable cases. The INT instruction and its variants is behaves differently, in part because it implicitly involves segment register loads.
The Intel reference manual chapters describing mode switching contain more hints. “After entering protected mode, the segment registers continue to hold the contents they had in real address mode. Software should reload all the segment registers.” Perhaps the two modes aren’t so radically different? The checklist for switching from protected back to real mode is even more revealing. Paging must be manually turned off. Segment registers must be explicitly loaded with descriptor values approximating real mode. The IDTR must be programmed to point to low memory. Why all this hassle? Isn’t real mode supposed to be 8086 compatible? Shouldn’t clearing the PE bit in the CR0 control register take care of everything?
The clear answer may be found in AMD manuals in the description of real-mode segment register loading: “The POP and MOV instructions can be used to load a (possibly) new segment selector into one of the segment registers. When this occurs, the selector is updated and the selector base is set to selector * 16. The segment limit and segment attributes are unchanged, but are normally 64K (the maximum allowable limit) and read/write data, respectively”.
There is no real mode. There is a special variant of protected mode which handles segment register loads differently and has a few other minor differences. The segmentation and memory protection hardware works in real mode just as well as it does in protected mode. That’s why accessing memory past the 64KB limit causes a general protection fault (#GP). That’s why the segment registers need to be loaded with appropriate descriptors before switching back to real mode.
Clever programmers of course long ago asked the question of what happens when that isn’t done. The answer is so-called unreal mode—a real mode in the sense of running with PE=0, but with segment limits other (larger) than 64KB. That way, physical memory beyond 1MB can be accessed from real mode, even while running a real-mode operating system which can handle hardware interrupts etc. It is even possible (though perhaps not useful) to use paging together with real mode.
The V86 mode is then a hybrid of real and protected mode. Segment register loads work exactly the same as in real mode. However, the processor runs at privilege level 3, therefore I/O and other privileged instructions behave differently (in that respect, V86 mode is the same as unprivileged protected mode). The V86 mode is typically used in conjunction with paging, which translates linear addresses to physical addresses. The generation of linear addresses is the same in real and V86 modes, and emulates the 8086. This is accomplished simply by updating the hidden segment base registers in a special way when running in real and V86 modes, as described in the AMD documentation.
In many situations, it is better to think of real mode as slightly modified protected mode rather than a wholly different processor mode. The processor behaves largely the same, and compatibility with the 8086 is achieved primarily by preloading the hidden descriptor registers with carefully chosen values. The segmentation and memory protection features of the CPU are no different between real and protected mode.
Small inaccuracy, you write : ” With the 286, the programmer could not switch from protected mode back to real mode (short of using the undocumented LOADALL instruction).” – I assure you, I was very familiar with the 26 loadall and iapx286 in general, including undocumented and/or falsely documented aspects : loadall cannot go back to real mode (i.e, reset the PE bit) any more than LMSW. Once PE=1, it sticks until the “-reset” line is asserted.
Thanks for the correction. Most LOADALL descriptions simply say that the instruction loads the entire processor state, and only sometimes the fine print mentions that it can’t be used to switch to real mode on a 286. Of course on 286s, LOADALL was typically used to avoid switching to protected mode altogether.
“There is no real mode. There is a special variant of protected mode which handles segment register loads differently and has a few other minor differences. ”
Actually, there is a real mode, but the PE bit changes less than people often think, the biggest being how interrupts work.