Wiki sample of the Unreal Mode problem
Posted: Fri Jun 08, 2012 12:33 am
Hello!
I'm trying to program FRM (Flat Real Mode, or sometimes they say "Unreal Mode") in my bootloader to boot my kernel above the first megabyte. I know this topic has discussed many times and I've read some of the related topics and theory.
But I'm confused by the example in the wiki article: http://wiki.osdev.org/Unreal_Mode.
Since:
1) Intel Developer's Manual for 80386 10.3 Switching to Protected Mode says: "Immediately after setting the PE flag, the initialization code must flush the processor's instruction prefetch queue by executing a JMP instruction." But there is no FAR JMP in the wiki code.
I think doing FAR JMP immediately right after we have set PE bit in CR0 is needed since the CS value is not valid selector and we must fix it. But all works fine in the wiki sample. Why?
2) In the wiki article I've read: "Finally, note that IP is unaffected by all this, so the code itself is still limited to 64k." OK, I couldn't understand why and started to look for explanation.
My thoughts:
CPU 80386 and above in real mode also pays attention to some fields of the shadow part of segment registers: limit and granularity, size (16-bit or 32-bit). The last is very
important. You can load the shadow part of a segment register only in protected mode. In real mode they are already initialized by: limit=0xFFFF, byte granularity, 16-bit. The trick is that CPU in real mode and protected mode works the same way: CPU checks all addresses to fit into the segment range (segment size = limit * granularity, but segment base in real mode is in the segment register itself and in the protected mode - in the shadow part of the segment register) and determines operand size from the segment size (which is in the shadow part).
So, in protected mode I can load to the shadow part of segments registers this values:
limit=0xFFFFF, page granularity, 32-bit size. And then I switch CPU to the real mode and can use 32-bit offsets to load data (commands that work with 32-bit operands in 16-bit segment has prefix, so the program become larger). If I've not change shadow part of the CS to 16-bit I can also use 32-bit code (32-bit offsets). All will be OK before the moment I enable interrupts or invoke BIOS function, since BIOS interrupt handlers and functions are 16-bit they will crash. Obvious, that I need real mode for the BIOS functions, so I must leave CS 16-bit.
If CS is 32-bit I can't use BIOS functions but 4GB memory is available for me in real mode. Nowdays this feature is not useful, but 80386, 80486, Pentium works faster in real mode than in protected mode.
All this ideas I have found at http://board.flatassembler.net/topic.php?t=135
and http://board.flatassembler.net/topic.php?t=11940. There a difference
between Flat Real Mode and Unreal Mode is explained.
P.S: In 16-bit mode I can not use "jmp <32-bit offset>". Stupid question: Why does the prefix 0x66 (?) not work? Or why doesn't call <32-bit offset> push into the stack EIP instead of IP?
What do I misunderstand?
I'm trying to program FRM (Flat Real Mode, or sometimes they say "Unreal Mode") in my bootloader to boot my kernel above the first megabyte. I know this topic has discussed many times and I've read some of the related topics and theory.
But I'm confused by the example in the wiki article: http://wiki.osdev.org/Unreal_Mode.
Since:
1) Intel Developer's Manual for 80386 10.3 Switching to Protected Mode says: "Immediately after setting the PE flag, the initialization code must flush the processor's instruction prefetch queue by executing a JMP instruction." But there is no FAR JMP in the wiki code.
I think doing FAR JMP immediately right after we have set PE bit in CR0 is needed since the CS value is not valid selector and we must fix it. But all works fine in the wiki sample. Why?
2) In the wiki article I've read: "Finally, note that IP is unaffected by all this, so the code itself is still limited to 64k." OK, I couldn't understand why and started to look for explanation.
My thoughts:
CPU 80386 and above in real mode also pays attention to some fields of the shadow part of segment registers: limit and granularity, size (16-bit or 32-bit). The last is very
important. You can load the shadow part of a segment register only in protected mode. In real mode they are already initialized by: limit=0xFFFF, byte granularity, 16-bit. The trick is that CPU in real mode and protected mode works the same way: CPU checks all addresses to fit into the segment range (segment size = limit * granularity, but segment base in real mode is in the segment register itself and in the protected mode - in the shadow part of the segment register) and determines operand size from the segment size (which is in the shadow part).
So, in protected mode I can load to the shadow part of segments registers this values:
limit=0xFFFFF, page granularity, 32-bit size. And then I switch CPU to the real mode and can use 32-bit offsets to load data (commands that work with 32-bit operands in 16-bit segment has prefix, so the program become larger). If I've not change shadow part of the CS to 16-bit I can also use 32-bit code (32-bit offsets). All will be OK before the moment I enable interrupts or invoke BIOS function, since BIOS interrupt handlers and functions are 16-bit they will crash. Obvious, that I need real mode for the BIOS functions, so I must leave CS 16-bit.
If CS is 32-bit I can't use BIOS functions but 4GB memory is available for me in real mode. Nowdays this feature is not useful, but 80386, 80486, Pentium works faster in real mode than in protected mode.
All this ideas I have found at http://board.flatassembler.net/topic.php?t=135
and http://board.flatassembler.net/topic.php?t=11940. There a difference
between Flat Real Mode and Unreal Mode is explained.
P.S: In 16-bit mode I can not use "jmp <32-bit offset>". Stupid question: Why does the prefix 0x66 (?) not work? Or why doesn't call <32-bit offset> push into the stack EIP instead of IP?
What do I misunderstand?