Unreal mode
Unreal mode
Hi! I'm trying to support the unreal mode in my bootloader. Is there a way to use the old segment:offest notation up to the first megabyte and the physical for the upper addresses?
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: Unreal mode
That sounded rather clueless. What do you want with *supporting* unreal mode? Is your OS based on Unreal Mode?trying to support the unreal mode
That aside, please search the wiki first: Descriptor Cache & Unreal Mode
- Love4Boobies
- Member
- Posts: 2111
- Joined: Fri Mar 07, 2008 5:36 pm
- Location: Bucharest, Romania
Re: Unreal mode
Do you know exactly what unreal mode is? Why do you want these "notations"?Karlosoft wrote:Hi! I'm trying to support the unreal mode in my bootloader. Is there a way to use the old segment:offest notation up to the first megabyte and the physical for the upper addresses?
"Computers in the future may weigh no more than 1.5 tons.", Popular Mechanics (1949)
[ Project UDI ]
[ Project UDI ]
Re: Unreal mode
Hello,
You do not "support" unreal mode because there is no such mode. Unreal mode is not a processor mode but rather a "trick" (One I personally dont recommend, but its there.) Also, a bootloader should not "support" a mode, its only job, by its definition, is to get the system running. The system software can then provide support for the real processor modes: its primary mode (probably protected mode), real and/or v86 tasks, etc.
You do not "support" unreal mode because there is no such mode. Unreal mode is not a processor mode but rather a "trick" (One I personally dont recommend, but its there.) Also, a bootloader should not "support" a mode, its only job, by its definition, is to get the system running. The system software can then provide support for the real processor modes: its primary mode (probably protected mode), real and/or v86 tasks, etc.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Re: Unreal mode
My bootloader loads files in the first mega and I want to copy them above it.
I've read that with the unreal mode I can use up to 4 gb so I need to switch the processor in this real mode to copy them.
I've read that with the unreal mode I can use up to 4 gb so I need to switch the processor in this real mode to copy them.
Re: Unreal mode
well
i have done exactly that. it is quite simple.
load a new GDT, and only change es.
for example:
lgdt [temp_gdt]
mov axs,0x08
mov es,ax
and then you can acess all 4 GB of the memory. example :
mov edi,0xff000000
mov eax,0x12345678
mov [es:edi],eax
.
if you dont "change" the limit for the segment ( es) then you will get a protection fault ( if i remember correct). However you may not change ds, as that causes a lot of trouble.
the reason why this works is that the cpu keeps a copy of the old GDT ( for ds and the rest), so changing ds will affect that "copy" and thereby causing unknown errors( i do not remember the error at this time)
.
so to sum this up:
create a temperory new GDT for, with the limit as 4 GB, and full access. then load that new GDT, and change the the wanted segment ( however not DS, Nor a "jmp 0x08:where" because we do not want to enter 32 bit mode, only change the limit for the specific segment)
and that is all the "magic"
KMt dk
i have done exactly that. it is quite simple.
load a new GDT, and only change es.
for example:
lgdt [temp_gdt]
mov axs,0x08
mov es,ax
and then you can acess all 4 GB of the memory. example :
mov edi,0xff000000
mov eax,0x12345678
mov [es:edi],eax
.
if you dont "change" the limit for the segment ( es) then you will get a protection fault ( if i remember correct). However you may not change ds, as that causes a lot of trouble.
the reason why this works is that the cpu keeps a copy of the old GDT ( for ds and the rest), so changing ds will affect that "copy" and thereby causing unknown errors( i do not remember the error at this time)
.
so to sum this up:
create a temperory new GDT for, with the limit as 4 GB, and full access. then load that new GDT, and change the the wanted segment ( however not DS, Nor a "jmp 0x08:where" because we do not want to enter 32 bit mode, only change the limit for the specific segment)
and that is all the "magic"
KMt dk
well, what to say, to much to do in too little space.
when it goes up hill, increase work, when it goes straight, test yourself but when going down, slow down.
when it goes up hill, increase work, when it goes straight, test yourself but when going down, slow down.
Re: Unreal mode
Not entirely true. There are other methods. Unreal mode is one of the easier methods though.Karlosoft wrote:My bootloader loads files in the first mega and I want to copy them above it.
I've read that with the unreal mode I can use up to 4 gb so I need to switch the processor in this real mode to copy them.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Re: Unreal mode
Thank you kmtdk
However what are these other ways Neon?
However what are these other ways Neon?
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
Re: Unreal mode
Just plain protected mode? I do that as well...
Re: Unreal mode
When I wrote my own bootloader, I used the unreal mode first. But it didn't work on my computer, so I implemented reading from floppy in real mode, switching to protected mode, copying to high memory, switching back to real mode, reading again and so on. That has worked, so I don't suggest using unreal mode at all, because I'm pretty sure it doesn't work on my computer (and hence maybe on other CPUs, too).
Re: Unreal mode
You can just load the sector via the BIOS in real mode and copy the sector to its protected mode address in protected mode. Tis what I do anyways in mine except it switches between modes for each sector. A little slow but works well for my design.
You can also just stick with protected mode as Combuster said.
You can also just stick with protected mode as Combuster said.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Re: Unreal mode
lots of needless attacks going on in the beginning part of this thread...
http://files.osdev.org/mirrors/geezer/j ... gments.htm
(hint: that was a poker reference; I'm suggesting that this page is vastly superior to the one he mentioned.)
Also, unreal mode is quite standard (if not officially documented), present on all 32-bit cpu's.
The cpu keeps its copy of the values in its internal registers; not in memory (aka not anywhere that would depend on ds or that would be messed up by changing it).
(now to actually ANSWER the op's question!)
Short version of unreal mode:
The cpu stores internally for each segment a base, limit, and security bits and uses this stored copy (not the gdt) for all memory accesses. This copy is updated only when writing to the segment registers, never in-between. The only difference between real and protected mode is what happens when a seg.reg. is written to:
In real mode: set the base to (value<<4), and leave the limit/others unchanged.
In protected mode: load/change all of them from the gdt in memory.
Also note that switching on/off protected mode in CR0 leaves these values completely unaltered.
The limit is set to ffff by default; but according to the above, you can set PE, load all regs w/a segment whose limit is ffffffff and whose base is anything (specified in the gdt), unset PE, restore the old value of the segment register (which changes only the base, not the newly set limit), and use the segment (including reading/writing to the seg.regs. and using segment:offset) exactly like real mode segments, but with the ability to access all memory.
Some sample code (untested) for switching to unreal mode, using the method in the above paragraph:
For example, in unreal mode, the following are both valid and produce identical results in edx:
So to answer your question,
Accessing memory by physical address just means doing a segment:offset after setting the segment register to 0.
Note that in unreal mode, you need the "a32" prefix with any [segment:offset] access where offset is bigger than ffff. The assembler might insert this automatically (in the case of using a 32-bit register in the address like "mov reg,[eax]") or it might insist on making you do it manually (like nasm, in the case of "mov reg,[32-bit number]" or the "rep movsd"-type instructions). This is fairly annoying, but can be worked around (use "a32 mov reg,[32-bit number]" or "a32 rep movsd").
Programs originally compiled/intended for real mode (including bios) will still continue to function in unreal mode by the old segment:offset of offset less than ffff, they just won't know they can use a32/access higher memory.
If you know that the bios is the only 16-bit code you will ever want to call, another way would be to make a "call bios interrupt" function that switches back to 16-bit mode for you, and just call that from 32-bit mode (rather than trying to make a separate 16-bit function for every bios function you want to use.)
He knows what real and unreal modes are, and listed a specific way he wants to use them. Apart from not knowing how to do this (which was his entire question and the purpose for this thread), what exactly was "clueless" about it?Combuster wrote: That sounded rather clueless.
The benefits of unreal mode are quite well known; access to the 32-bit address space while simultaneously being able to call bios and real mode programs.Combuster wrote: What do you want with *supporting* unreal mode?
Irrelevant; all we need to know is that he plans on using it at some point.Combuster wrote: Is your OS based on Unreal Mode?
I'll see your wiki-based page, and raise you this one:Combuster wrote: That aside, please search the wiki first: Descriptor Cache
http://files.osdev.org/mirrors/geezer/j ... gments.htm
(hint: that was a poker reference; I'm suggesting that this page is vastly superior to the one he mentioned.)
The code on that page is rather crippled; it only sets one of the segment registers, and it is integrated into/mixed in with the test code (rather than being a separate function which can be copied standalone into a real mode program).Combuster wrote: Unreal Mode
Ok? Its purpose/advantage is [I stated this above in response to Combuster.] As long as it fulfills these goals, what does it matter whether it is technically a "mode" or not?Neon wrote: You do not "support" unreal mode because there is no such mode. Unreal mode is not a processor mode but rather a "trick"
Also, unreal mode is quite standard (if not officially documented), present on all 32-bit cpu's.
Any particular reason you're against it?Neon wrote: (One I personally dont recommend, but its there.)
I mentioned the abilities of unreal mode above; all of them can be used (and are even necessary!) by the bootloader to do its job. Again, I don't see why you're against unreal mode being used by bootloaders.Neon wrote: Also, a bootloader should not "support" a mode, its only job, by its definition, is to get the system running.
System software can do whatever it wants, and so can the bootloader (while it's still running).Neon wrote: The system software can then provide support for the real processor modes: its primary mode (probably protected mode), real and/or v86 tasks, etc.
Huh??kmtdk wrote: However you may not change ds, as that causes a lot of trouble.
[...]
so changing ds will affect that "copy" and thereby causing unknown errors( i do not remember the error at this time)
The cpu keeps its copy of the values in its internal registers; not in memory (aka not anywhere that would depend on ds or that would be messed up by changing it).
(now to actually ANSWER the op's question!)
Short version of unreal mode:
The cpu stores internally for each segment a base, limit, and security bits and uses this stored copy (not the gdt) for all memory accesses. This copy is updated only when writing to the segment registers, never in-between. The only difference between real and protected mode is what happens when a seg.reg. is written to:
In real mode: set the base to (value<<4), and leave the limit/others unchanged.
In protected mode: load/change all of them from the gdt in memory.
Also note that switching on/off protected mode in CR0 leaves these values completely unaltered.
The limit is set to ffff by default; but according to the above, you can set PE, load all regs w/a segment whose limit is ffffffff and whose base is anything (specified in the gdt), unset PE, restore the old value of the segment register (which changes only the base, not the newly set limit), and use the segment (including reading/writing to the seg.regs. and using segment:offset) exactly like real mode segments, but with the ability to access all memory.
Some sample code (untested) for switching to unreal mode, using the method in the above paragraph:
Code: Select all
; call this function from real mode to
enter_unreal_mode:
; save the interrupt flag state
pushfd
; save the segment bases, since
; they get overwritten by the
; switch to unreal mode
push ds
push es
push fs
push gs
; interrupts can save/restore segment
; registers. The PE bit changes the
; meaning of writing to a segment register,
; i.e. allowing this to happen would result
; in the restored data meaning something
; different than the saved data.
cli
; set PE bit
mov eax,cr0
or al,1
mov cr0,eax
; change the segment limit, while
; keeping all other atrributes the same.
; Note: this overwrites the base address.
lgdt[cs:.gdt]
mov ax,8
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
; don't bother with cs or ss, since
; push/pop/call/jmp in real mode is
; limited to a 16-bit sp/ip
; done here, back to (altered) real mode
mov eax,cr0
and al,0xfe
mov cr0,eax
; restore the stuff that was saved
pop gs
pop fs
pop es
pop ds
popfd
ret
.gdt:
dw .end-.gdt-1
dd gdt
dw 0
dq 0x008f92000000ffff ;unreal mode data
.end:
Code: Select all
;one way:
mov ax,0
mov ds,ax
mov eax,0x200000
mov edx,[eax]
;another way to get the same address:
mov ax,0x1000
mov ds,ax
mov eax,0x1f0000
mov edx,[eax]
In unreal mode, both segment:offset and physical can be used for any address (not just the 1st meg), since the offset can now be 32 bits.Karlosoft wrote:Is there a way to use the old segment:offest notation up to the first megabyte and the physical for the upper addresses?
Accessing memory by physical address just means doing a segment:offset after setting the segment register to 0.
Note that in unreal mode, you need the "a32" prefix with any [segment:offset] access where offset is bigger than ffff. The assembler might insert this automatically (in the case of using a 32-bit register in the address like "mov reg,[eax]") or it might insist on making you do it manually (like nasm, in the case of "mov reg,[32-bit number]" or the "rep movsd"-type instructions). This is fairly annoying, but can be worked around (use "a32 mov reg,[32-bit number]" or "a32 rep movsd").
Programs originally compiled/intended for real mode (including bios) will still continue to function in unreal mode by the old segment:offset of offset less than ffff, they just won't know they can use a32/access higher memory.
You could run your code in 32-bit pmode, and then switch back to unreal mode to call the bios. (disabling interrupts in pmode would probably be the easiest way to get this to work.) It is more complicated to set up, but it means you don't have to deal with the 16-bit stack/ip limitation.Karlosoft wrote:what are these other ways
If you know that the bios is the only 16-bit code you will ever want to call, another way would be to make a "call bios interrupt" function that switches back to 16-bit mode for you, and just call that from 32-bit mode (rather than trying to make a separate 16-bit function for every bios function you want to use.)
Would like to see your code; unreal mode not working on some cpu's would be a pretty big deal...XanClic wrote:I don't suggest using unreal mode at all, because I'm pretty sure it doesn't work on my computer (and hence maybe on other CPUs, too).
Re: Unreal mode
OK, I take everything back.
I still found that old piece of code but it was only the "switch" version (switching from real to protected mode and back). That worked as expected. Then I changed that code to do everything in unreal mode and... It still worked. So it was the usual stuff, just a bug made by me and not an unusual CPU behaviour. Though I don't have the original code to locate that bug.
Luckily I did not write "I know it won't work" but "I'm pretty sure".
I'm really sorry.
I still found that old piece of code but it was only the "switch" version (switching from real to protected mode and back). That worked as expected. Then I changed that code to do everything in unreal mode and... It still worked. So it was the usual stuff, just a bug made by me and not an unusual CPU behaviour. Though I don't have the original code to locate that bug.
Luckily I did not write "I know it won't work" but "I'm pretty sure".
I'm really sorry.
Re: Unreal mode
Hello,
Yes - its a hack; nonstandard. I dont care how supported it is - it can break at any time. Just because there is an easy way to do something, doesnt make it a good way.qqq wrote:Any particular reason you're against it?
As posted earlier, there are ways that you can load files in a bootloader > 1 MB. ie, mine loads files > 3GB without unreal mode using the BIOS and protected mode. You can even stick with protected mode all together.qqq wrote:I mentioned the abilities of unreal mode above; all of them can be used (and are even necessary!) by the bootloader to do its job. Again, I don't see why you're against unreal mode being used by bootloaders.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
-
- Member
- Posts: 170
- Joined: Wed Jul 18, 2007 5:51 am
Re: Unreal mode
Unreal mode IS documented by Intel and AMD. They just call it SMM mode. BIOSes rely on it to operate. SMM was officially implemented with the 386. Unreal mode is simply the OS taking advantage of the 4gb limit in the same way the BIOS does under SMM mode.neon wrote:Hello,
Yes - its a hack; nonstandard. I dont care how supported it is - it can break at any time. Just because there is an easy way to do something, doesnt make it a good way.qqq wrote:Any particular reason you're against it?
As posted earlier, there are ways that you can load files in a bootloader > 1 MB. ie, mine loads files > 3GB without unreal mode using the BIOS and protected mode. You can even stick with protected mode all together.qqq wrote:I mentioned the abilities of unreal mode above; all of them can be used (and are even necessary!) by the bootloader to do its job. Again, I don't see why you're against unreal mode being used by bootloaders.
There is no reason for Intel or AMD to remove unreal mode as it costs them nothing.
If you want a "perfect" processor that is clearly documented with no quirks then don't work with x86.
Using unreal mode is perfectly acceptable.