Unreal Mode: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
(Syntax higlighting)
(Played with comments)
Line 23: Line 23:
; partcopy boot.bin 0 200 -f0
; partcopy boot.bin 0 200 -f0


[ORG 0x7c00] ; add to offsets
[ORG 0x7c00] ; add to offsets


start: xor ax, ax ; make it zero
start: xor ax, ax ; make it zero
mov ds, ax ; DS=0
mov ds, ax ; DS=0
mov ss, ax ; stack starts at 0
mov ss, ax ; stack starts at seg 0
mov sp, 0x9c00 ; 200h past code start
mov sp, 0x9c00 ; 200h past code start


cli ; no interrupt
cli ; no interrupts
push ds ; save real mode
push ds ; save real mode


lgdt [gdtinfo] ; load gdt register
lgdt [gdtinfo] ; load gdt register


mov eax, cr0 ; switch to pmode by
mov eax, cr0 ; switch to pmode by
or al,1 ; set pmode bit
or al,1 ; set pmode bit
mov cr0, eax
mov cr0, eax


mov bx, 0x08 ; select descriptor 1
mov bx, 0x08 ; select descriptor 1
mov ds, bx ; 8h = 1000b
mov ds, bx ; 8h = 1000b


and al,0xFE ; back to realmode
and al,0xFE ; back to realmode
mov cr0, eax ; by toggling bit again
mov cr0, eax ; by toggling bit again


pop ds ; get back old segment
pop ds ; get back old segment
sti
sti


mov bx, 0x0f01 ; attrib/char of smiley
mov bx, 0x0f01 ; attrib/char of smiley
mov eax, 0x0b8000 ; note 32 bit offset
mov eax, 0x0b8000 ; note 32 bit offset
mov word [ds:eax], bx
mov word [ds:eax], bx


jmp $ ; loop forever
jmp $ ; loop forever


gdtinfo:
gdtinfo:
Line 58: Line 58:
dd gdt ;start of table
dd gdt ;start of table


gdt dd 0,0 ; entry 0 is always unused
gdt dd 0,0 ; entry 0 is always unused
flatdesc db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0
flatdesc db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0
gdt_end:
gdt_end:


times 510-($-$$) db 0 ; fill sector w/ 0's
times 510-($-$$) db 0 ; fill sector w/ 0's
db 0x55 ; req'd by some BIOSes
db 0x55 ; req'd by some BIOSes
db 0xAA
db 0xAA
</source>
</source>

Revision as of 19:27, 3 June 2009

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 datas 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 conventionnal 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 ...

Of course, unreal mode is kindof useless if you do not have have the A20 Line enabled.

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).

Finally, note that 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         ; 200h past code start

   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