How do I enable Unreal Mode? I know that you must go to 32-bit PMODE with A20 enabled and switch back to real mode but I'm not sure how. What method do I use to switch back to real mode and keep 4GB linear memory access? Also, if anyone could explain Unreal Mode a little to me it would be greatly appreciated.
Thanks for your help!
-TripleFault
Big Real/Unreal Mode
Re:Big Real/Unreal Mode
Thanks for the info df! Do you guys know if Unreal Mode is compatible with newer processors and emulators such as Bochs, VMWARE, VirtualPC, etc? (since it is "just a party trick")
Re:Big Real/Unreal Mode
Although originally it was seen by Intel as a bug, they have since acknowledged it, since so many applications used it. So it is now documented, and future processors are obliged to support it.
Re:Big Real/Unreal Mode
I just posted this chunk of code on the OSDev.org message board; I might as well post it here.
This code starts out in real mode and ends up in unreal mode. Code and stack segments are still 16-bit/64KB, but data segments are all 32-bit/4GB.
I just tested this on my laptop and it seems to work fine. I haven't done extensive stress-testing on this or anything, so no warranties. ;D I think it's complete, though, and takes into consideration everything that needs to be considered. You'll need NASM to assemble this.
[pre]
[BITS 16] ; We start in pure real mode.
cli ; Disable interrupts.
mov dx, 0x70 ; Disable NMIs.
in al, dx
or al, 0x80
out dx, al
lgdt [GDT] ; Load the new segment descriptors.
mov eax, cr0 ; Turn on protected mode.
or al, 1
mov cr0, eax
jmp dword 0x08:.1 ; Set CS by jumping to the 32-bit code segment.
[BITS 32] ; Once we've jumped, we're now running 32-bit
; code.
.1: mov eax, dseg-GDT ; Change data-segment limits to 4GB (for all
mov ds, eax ; four data-segment registers).
mov es, eax
mov fs, eax
mov gs, eax
mov eax, ds16-GDT ; Ensure that the stack-segment limit remains
mov ss, eax ; 64KB! (Stack pointer in unreal mode is
; IP -- *not* EIP!)
jmp dword 0x18:.2 ; Ensure that the code-segment limit remains
; 64KB -- jump to the 16-bit code segment.
[BITS 16]
.2: mov eax, cr0 ; Turn off protected mode. Now the CPU will
and al, 0xFE ; interpret all code as 16-bit.
mov cr0, eax
jmp word 0x00:.3 ; Set CS to real-mode segment -- load it with
; zero. (THIS MEANS THAT THIS CODE MUST BE
; IN THE FIRST 64KB OF MEMORY.)
.3: xor ax, ax ; Set all segments to a proper real-mode value
mov ds, ax ; (in this case zero). The unreal-mode limits
mov es, ax ; set for DS, ES, FS, and GS while in protected
mov fs, ax ; mode will not be changed.
mov gs, ax
mov ss, ax
mov dx, 0x70 ; Re-enable NMIs.
in al, dx
and al, 0x7F
out dx, al
sti ; Re-enable interrupts.
[/pre]
And here's the GDT:
[pre]
;-------------------------------------------------------------------------------
; GLOBAL DESCRIPTOR TABLE
;-------------------------------------------------------------------------------
align 8
GDT: dw gdt_limit ; null segment, used to store GDT
dd GDT ; metadata
dw 0
cseg: dd 0x0000FFFF, 0x00CF9800 ; code segment, 32-bit, 0 to 4GB
dseg: dd 0x0000FFFF, 0x00CF9200 ; data segment, 32-bit, 0 to 4GB
cs16: dd 0x0000FFFF, 0x00009800 ; code segment, 16-bit, 0 to 64KB
ds16: dd 0x0000FFFF, 0x00009200 ; data segment, 16-bit, 0 to 64KB
gdt_limit equ $-GDT-1
[/pre]
This code starts out in real mode and ends up in unreal mode. Code and stack segments are still 16-bit/64KB, but data segments are all 32-bit/4GB.
I just tested this on my laptop and it seems to work fine. I haven't done extensive stress-testing on this or anything, so no warranties. ;D I think it's complete, though, and takes into consideration everything that needs to be considered. You'll need NASM to assemble this.
[pre]
[BITS 16] ; We start in pure real mode.
cli ; Disable interrupts.
mov dx, 0x70 ; Disable NMIs.
in al, dx
or al, 0x80
out dx, al
lgdt [GDT] ; Load the new segment descriptors.
mov eax, cr0 ; Turn on protected mode.
or al, 1
mov cr0, eax
jmp dword 0x08:.1 ; Set CS by jumping to the 32-bit code segment.
[BITS 32] ; Once we've jumped, we're now running 32-bit
; code.
.1: mov eax, dseg-GDT ; Change data-segment limits to 4GB (for all
mov ds, eax ; four data-segment registers).
mov es, eax
mov fs, eax
mov gs, eax
mov eax, ds16-GDT ; Ensure that the stack-segment limit remains
mov ss, eax ; 64KB! (Stack pointer in unreal mode is
; IP -- *not* EIP!)
jmp dword 0x18:.2 ; Ensure that the code-segment limit remains
; 64KB -- jump to the 16-bit code segment.
[BITS 16]
.2: mov eax, cr0 ; Turn off protected mode. Now the CPU will
and al, 0xFE ; interpret all code as 16-bit.
mov cr0, eax
jmp word 0x00:.3 ; Set CS to real-mode segment -- load it with
; zero. (THIS MEANS THAT THIS CODE MUST BE
; IN THE FIRST 64KB OF MEMORY.)
.3: xor ax, ax ; Set all segments to a proper real-mode value
mov ds, ax ; (in this case zero). The unreal-mode limits
mov es, ax ; set for DS, ES, FS, and GS while in protected
mov fs, ax ; mode will not be changed.
mov gs, ax
mov ss, ax
mov dx, 0x70 ; Re-enable NMIs.
in al, dx
and al, 0x7F
out dx, al
sti ; Re-enable interrupts.
[/pre]
And here's the GDT:
[pre]
;-------------------------------------------------------------------------------
; GLOBAL DESCRIPTOR TABLE
;-------------------------------------------------------------------------------
align 8
GDT: dw gdt_limit ; null segment, used to store GDT
dd GDT ; metadata
dw 0
cseg: dd 0x0000FFFF, 0x00CF9800 ; code segment, 32-bit, 0 to 4GB
dseg: dd 0x0000FFFF, 0x00CF9200 ; data segment, 32-bit, 0 to 4GB
cs16: dd 0x0000FFFF, 0x00009800 ; code segment, 16-bit, 0 to 64KB
ds16: dd 0x0000FFFF, 0x00009200 ; data segment, 16-bit, 0 to 64KB
gdt_limit equ $-GDT-1
[/pre]