Yep. The microcode in real mode segment loading (as shown in the post) does not set the limit to 64KB. That is why returning to real mode with a large value like 4GB in limit gives you "unreal mode".
wasn't this basically the consensus among numerical analysts like 20 years ago? i remeber reading similar arguments in goldberg's paper and various game dev forums circa 2005, so genuinely curious what keeps making this idea feel "new" to each generation of programmers who rediscovers it
Again a very interesting look at how this chip works internally!
I've decoded the entry point PLA of the 80286 (not the actual microcode though). It also has separate entries for real and protected mode, but only for segment loads from a general purpose register, HLT, and for those opcodes that aren't allowed in real mode like ARPL.
Loading a segment register from memory on the 286 uses the same microcode in both modes, as does everything else that would certainly have to act differently, like jump/call far. That was a bit surprising, since it would have to decide at run time which mode it's in. Is this the same on the 386?
Tested on my 286 machine what happens when opcodes are decoded while in real mode but executed after PE is set: Segment load from memory works (using protected mode semantics), whereas the load from register only changes the visible selector and nothing else. The base in the descriptor cache keeps whatever was set there before -- I assume on the 386, SBRM would update the base the same way it does in real mode in that situation, because it's also used for V86 mode there. Illegal-in-real-mode instructions trap, but do so correctly using the protected mode IDT.
Also seems like executing three pre-decoded instructions without a jump after setting PE causes a triple fault for some reason.
Nice findings. For segment loads from memory, the entry point is actually shared between real and protected mode on the 386. The microcode branches later based on PE and does the extra descriptor work only in protected mode. So maybe it's done similarly on the 286.
The decode vs. execution behavior is more interesting. From both Intel docs and my own core, PE is effectively checked in both stages independently, but decode happens ahead of execution (prefetch queue). So if an instruction is decoded in real mode, it’ll still follow the real-mode path even if PE is set before it executes.
That’s exactly why Intel requires a jump right after setting PE — it flushes the prefetch queue and forces re-decode in protected mode. As the 80386 System Software Writer’s Guide (Ch. 6.1) puts it: "Instructions in the queue were fetched and decoded while the processor was in real mode; executing them after switching to protected mode can be erroneous."
6 comments
[ 5.0 ms ] story [ 26.2 ms ] threadHow hard would it be for Mr Github to add rss/atom feeds, I wonder?
I've decoded the entry point PLA of the 80286 (not the actual microcode though). It also has separate entries for real and protected mode, but only for segment loads from a general purpose register, HLT, and for those opcodes that aren't allowed in real mode like ARPL.
Loading a segment register from memory on the 286 uses the same microcode in both modes, as does everything else that would certainly have to act differently, like jump/call far. That was a bit surprising, since it would have to decide at run time which mode it's in. Is this the same on the 386?
Tested on my 286 machine what happens when opcodes are decoded while in real mode but executed after PE is set: Segment load from memory works (using protected mode semantics), whereas the load from register only changes the visible selector and nothing else. The base in the descriptor cache keeps whatever was set there before -- I assume on the 386, SBRM would update the base the same way it does in real mode in that situation, because it's also used for V86 mode there. Illegal-in-real-mode instructions trap, but do so correctly using the protected mode IDT.
Also seems like executing three pre-decoded instructions without a jump after setting PE causes a triple fault for some reason.
The decode vs. execution behavior is more interesting. From both Intel docs and my own core, PE is effectively checked in both stages independently, but decode happens ahead of execution (prefetch queue). So if an instruction is decoded in real mode, it’ll still follow the real-mode path even if PE is set before it executes.
That’s exactly why Intel requires a jump right after setting PE — it flushes the prefetch queue and forces re-decode in protected mode. As the 80386 System Software Writer’s Guide (Ch. 6.1) puts it: "Instructions in the queue were fetched and decoded while the processor was in real mode; executing them after switching to protected mode can be erroneous."