Unreal Mode: Difference between revisions
[unchecked revision] | [unchecked revision] |
mNo edit summary |
Added information on huge unreal mode |
||
Line 15: | Line 15: | ||
When this register given a "selector", a "segment descriptor cache register" is filled with the descriptor values, including the size (or limit). After the switch back to real mode, these values are not modified, regardless of what value is in the 16-bit segment register. So the 64k limit is no longer valid and 32-bit offsets can be used with the real-mode addressing rules (i.e. shift segment 4 bits, then add offset). |
When this register given a "selector", a "segment descriptor cache register" is filled with the descriptor values, including the size (or limit). After the switch back to real mode, these values are not modified, regardless of what value is in the 16-bit segment register. So the 64k limit is no longer valid and 32-bit offsets can be used with the real-mode addressing rules (i.e. shift segment 4 bits, then add offset). |
||
===Big Unreal Mode=== |
|||
⚫ | |||
These will not have affected CS. <br /> |
|||
⚫ | |||
<source lang="asm"> |
<source lang="asm"> |
||
Line 67: | Line 69: | ||
db 0xAA |
db 0xAA |
||
</source> |
</source> |
||
===Huge Unreal Mode=== |
|||
Huge Unreal Mode enables code over 64K. However, it is more difficult to implement as real mode interrupts do not automatically save the high 16 bits of EIP. Initialization is simple though, you just load a 32 bit code segment: |
|||
<source lang="asm"> |
|||
; Assembly example |
|||
; nasmw boot.asm -o boot.bin |
|||
; partcopy boot.bin 0 200 -f0 |
|||
[ORG 0x7c00] ; add to offsets |
|||
start: xor ax, ax ; make it zero |
|||
... ; As before |
|||
mov cr0, eax |
|||
jmp 0x8:pmode |
|||
pmode: |
|||
mov bx, 0x10 ; select descriptor 2, instead of 1 |
|||
mov ds, bx ; 10h = 10000b |
|||
and al,0xFE ; back to realmode |
|||
mov cr0, eax ; by toggling bit again |
|||
jmp 0x0:huge_unreal |
|||
huge_unreal: |
|||
... ;As before |
|||
gdtinfo: |
|||
dw gdt_end - gdt - 1 ;last byte in table |
|||
dd gdt ;start of table |
|||
gdt dd 0,0 ; entry 0 is always unused |
|||
gdt_end: |
|||
flatcode db 0xff, 0xff, 0, 0, 0, 10011010b, 10001111b, 0 |
|||
flatdata db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0 |
|||
times 510-($-$$) db 0 ; fill sector w/ 0's |
|||
db 0x55 ; req'd by some BIOSes |
|||
db 0xAA |
|||
</source> |
|||
WARNING: this may not work on some emulators or some hardware. This is because of direct 32bit PMODE -> (Un)real mode. |
|||
[[Category:X86 CPU]] |
[[Category:X86 CPU]] |
Revision as of 19:36, 12 January 2013
Unreal mode consist of breaking the '64Kb' limit of real mode segments, but still keeping 16 bits instruction and segment*16+offset address formation by tweaking the descriptor caches.
Usage
Unreal mode is recommended in the two following cases :
- you're trying to extend a legacy 16-bits DOS program so that it can deal with larger data and neither vm86, nor xms is suitable for your needs
- you're trying to load something that will run in 32 bits mode and which is larger than 640Kb (so you cannot load it in conventional memory) and you don't want to bother with a disk driver called from pmode yet, and you do not wish to switch between real and protected mode for copying chunks from the conventional memory buffer to the high memory areas ...
You still will not have full access to all physical RAM if you do not have have the A20 Line enabled; all the "odd" 1-megabyte blocks will be unavailable.
Implementation
The reason for doing this is to enable 32-bit offsets in real mode. However, you won't be able to go past 1 meg quite yet.
In protected mode, the bits 3-15 in the segment register are an index into the descriptor table. That's why in this code 0x08 = 1000b gets you the 1 entry.
When this register given a "selector", a "segment descriptor cache register" is filled with the descriptor values, including the size (or limit). After the switch back to real mode, these values are not modified, regardless of what value is in the 16-bit segment register. So the 64k limit is no longer valid and 32-bit offsets can be used with the real-mode addressing rules (i.e. shift segment 4 bits, then add offset).
Big Unreal Mode
These will not have affected CS.
Therefore IP is unaffected by all this, so the code itself is still limited to 64k.
; Assembly example
; nasmw boot.asm -o boot.bin
; partcopy boot.bin 0 200 -f0
[ORG 0x7c00] ; add to offsets
start: xor ax, ax ; make it zero
mov ds, ax ; DS=0
mov ss, ax ; stack starts at seg 0
mov sp, 0x9c00 ; 2000h past code start,
; making the stack 7.5k in size
cli ; no interrupts
push ds ; save real mode
lgdt [gdtinfo] ; load gdt register
mov eax, cr0 ; switch to pmode by
or al,1 ; set pmode bit
mov cr0, eax
mov bx, 0x08 ; select descriptor 1
mov ds, bx ; 8h = 1000b
and al,0xFE ; back to realmode
mov cr0, eax ; by toggling bit again
pop ds ; get back old segment
sti
mov bx, 0x0f01 ; attrib/char of smiley
mov eax, 0x0b8000 ; note 32 bit offset
mov word [ds:eax], bx
jmp $ ; loop forever
gdtinfo:
dw gdt_end - gdt - 1 ;last byte in table
dd gdt ;start of table
gdt dd 0,0 ; entry 0 is always unused
flatdesc db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0
gdt_end:
times 510-($-$$) db 0 ; fill sector w/ 0's
db 0x55 ; req'd by some BIOSes
db 0xAA
Huge Unreal Mode
Huge Unreal Mode enables code over 64K. However, it is more difficult to implement as real mode interrupts do not automatically save the high 16 bits of EIP. Initialization is simple though, you just load a 32 bit code segment:
; Assembly example
; nasmw boot.asm -o boot.bin
; partcopy boot.bin 0 200 -f0
[ORG 0x7c00] ; add to offsets
start: xor ax, ax ; make it zero
... ; As before
mov cr0, eax
jmp 0x8:pmode
pmode:
mov bx, 0x10 ; select descriptor 2, instead of 1
mov ds, bx ; 10h = 10000b
and al,0xFE ; back to realmode
mov cr0, eax ; by toggling bit again
jmp 0x0:huge_unreal
huge_unreal:
... ;As before
gdtinfo:
dw gdt_end - gdt - 1 ;last byte in table
dd gdt ;start of table
gdt dd 0,0 ; entry 0 is always unused
gdt_end:
flatcode db 0xff, 0xff, 0, 0, 0, 10011010b, 10001111b, 0
flatdata db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0
times 510-($-$$) db 0 ; fill sector w/ 0's
db 0x55 ; req'd by some BIOSes
db 0xAA
WARNING: this may not work on some emulators or some hardware. This is because of direct 32bit PMODE -> (Un)real mode.