Big Real/Unreal Mode

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

Big Real/Unreal Mode

Post by Neo »

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!
-Neo
Only Human
Xenos

RE:Big Real/Unreal Mode

Post by Xenos »

The trick is to set up a GDT with 4GB segments and load them when you are in PMode. The segment registers have a visible part containing the segment selector and an invisible part containing linear base address, limit, access rights etc. The invisible part is updated when a new segment selector is loaded. This way you can load them with 4GB segments and go back to real mode, keeping the segment register values. (Make sure not to load segment registers after going back.)

Well, switching to PMode and back is essentially toggling the PE bit (bit 0) in CR0. To enable PMode, set this bit and make a far jump to a 32bit address. Load DS-GS with some selectors. To go back to real mode, clear this bit and make another far jump to a 16bit real mode address. Make sure to disable interrupts during this procedure since they are handled differently in PMode.
Karig

RE:Big Real/Unreal Mode

Post by Karig »

Just to clarify something: Xenos said "Load DS-GS". Don't bother with loading CS or SS. In real (or unreal) mode, you're using IP (not EIP) as the pointer to the next instruction, so you can't have code segments greater than 64KB. Also, you're using SP (not ESP) as the pointer to the top of your stack, so you can't have stack segments greater than 64KB. But you CAN use the 32-bit registers to load and store data pretty much anywhere in memory.
TripleFault

RE:Big Real/Unreal Mode

Post by TripleFault »

Wow!  Thanks for clarifying that.  I thought that you could use 4GB total for DS and CS but I was wrong.  You just saved me from making a big mistake. :)
~ TripleFault !)
mindvnas

RE:Big Real/Unreal Mode

Post by mindvnas »

also note that unreal mode will be lost, when segment regs are reloaded. so if you call a routine that pushes ds/pops ds then you cant use ds: anymore to access the 4G. most routines including ms-dos, wont use fs: or gs:
correct me if im wrong...
carbonBased

RE:Big Real/Unreal Mode

Post by carbonBased »

Indeed.  Dos can't use fs and gs, else it wouldn't run on older hardware that didn't support them.

If the original poster is intending on writing an OS for use in unreal mode, I think they should seriously reconsider.  Any stray app can [in]voluntarily reload a segment register and toast your memory setup.  Not to mention a whole slew of other problems (16-bit ip, mostly).

The 16-bit IP issue _can_ be resolved... the solution certainly isn't pretty.  If would involve intermittantly switching back into pmode, updating the CS descriptors base pointer, and jumping back to real-mode, which is _way_ to much effort (recalculating ip's, desciding when to perform these (slow) switches, and how to encorporate this switching code into a functional application...)

Straight PMode's a much better choice, and affords protection schemes which you wouldn't have in unreal mode.

Cheers,
Jeff
Karig

RE:Big Real/Unreal Mode

Post by Karig »

It depends on what you're doing. If you want to build a 16-bit toy OS, so you can take advantage of BIOS services and a 4GB data space at the same time, unreal mode would probably be fine.

I'm considering using unreal mode in my own toy OS to let me use the BIOS to load large files (i.e., one megabyte and larger) into the space above the one-megabyte mark. (Obviously I'd have to load X sectors at a time into a buffer in conventional memory and then copy them into high memory using 32-bit instructions, but it'd save me from switching back and forth between real mode and protected mode just to load a single file.)

If you intend to write a **REAL** OS, then of course you'd find another way to do it. :-)
Guest

RE:Big Real/Unreal Mode

Post by Guest »

>also note that unreal mode will be lost, when segment regs are reloaded

not true. the limit portion of the segment descriptor caches is not affected if you reload the segment register in (un)real mode
Karig

RE:Big Real/Unreal Mode (sample code here)

Post by Karig »

If you get stuck, you can cheat and borrow my code. :) It seems to work fine -- I just tried it on my laptop -- but I haven't used it more than once. It SHOULD work, and it looks right to me, but I don't promise that it's flawless. :) But I felt like sharing. You'll need NASM to compile this as is.

<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>
Xenos

RE:Big Real/Unreal Mode (sample code here)

Post by Xenos »

This code assumes a GDT with a 32Bit code segment at 0x08, a 16Bit Code segment at 0x18 and (not obvious) some data segment. Perhaps you could post your GDT? It would clarify that thing.
Karig

RE:Big Real/Unreal Mode (sample code here)

Post by Karig »

Oops, yes, I forgot that. Here it is:

;-------------------------------------------------------------------------------
; GLOBAL DESCRIPTOR TABLE
;-------------------------------------------------------------------------------

align 8

GDT: dw gdt_limit  ; null segment, used to store GDT metadata
dd GDT
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
Post Reply