Page 1 of 2

HOWTO: Setting up Unreal Mode...

Posted: Sat Jun 30, 2007 3:23 pm
by JJeronimo
If anyone here needs help setting up unreal mode, here is the basic idea:
(It's in FASM syntax)

Code: Select all

start:
call enter_unreal_mode

mov	[gs:0x100000], dword 0xdeadbeef	;Now, this won't cause a GPF...

jmp $



enter_unreal_mode:
		cli

		push	dword gdt+0x10000
		push	word  gdt.limit
		movzx	esp, sp
		lgdt	[esp]

		mov	eax, cr0
		or	eax, 1
		mov	cr0, eax

		mov	ax, 8
		mov	gs, ax		;Add here any other registers with which you want to access over 1MB

		mov	eax, cr0
		and	eax, not 1
		mov	cr0, eax

		xor	ax, ax
		mov	gs, ax

		add	sp, 6

		sti

		ret


macro gdt_entry base,limit,flags  {
	dw	limit and 0xFFFF
	dw	base  and 0xFFFF
	db	(base shr 16)  and 0xFF
	db	flags
	db	((limit shr 16) and 0xF) or 0xC0
	db	(base shr 24)  and 0xFF
}


gdt:
	dd 0,0						;NULL entry

	gdt_entry   0x00000000, 0xFFFFF, 10010010b	;Ring 0, data, expand-up, r/w

	.limit = $-gdt-1
JJ

Posted: Sun Jul 01, 2007 5:43 pm
by Ninjarider
for some reason all that stuff confuses me. how do you come up with the data for the gdt

Posted: Sun Jul 01, 2007 6:37 pm
by mathematician
Ninjarider wrote:for some reason all that stuff confuses me. how do you come up with the data for the gdt
You need to go to either AMD or Intel's website and download their manuals for the x86 family of processors. In the meantime you could try:

http://www.osdever.net/tutorials/brunma ... ial_02.php

Posted: Sun Jul 01, 2007 7:03 pm
by Kevin McGuire
Ninjarider wrote:for some reason all that stuff confuses me. how do you come up with the data for the gdt
This might confuse you more, but then again it could help as it is what I learned from (not the Intel manuals).
http://www.osdever.net/tutorials/descriptors.php

Posted: Sun Jul 01, 2007 7:40 pm
by Ninjarider
i have the intel manuals on my computer. my computer does not have internet so i look up things at work when i can. i dont have adobe on my computer. can't download it either. they wont let me at work. im currently digging through the intel manuals. i think this is something the wife is going to have to read and translate everything for me.

good time for a break. those manuals are making my brain hurt.

Posted: Sun Jul 01, 2007 9:04 pm
by JJeronimo
Ninjarider wrote:for some reason all that stuff confuses me. how do you come up with the data for the gdt
I don't understand your question. The macro gdt_entry declares a GDT entry based on parameters' data, then there is the limit symbol that is the maximum byte displacement inside the GDT, and there is also the NULL GDT descriptor, that is all zeros.

Then there is the lgdt instruction that loads the GDT CPU Register based on a structure that the previous 2 instructions (not counting the movzx, which is only issued because there is no addressing mode which uses SP) had built on the stack.

Finally, the processor is switched to protected mode, the segment selectors which we plan to use to access memory over 1MB are loaded, and we switch back to (un)real mode, not forgetting to reload the segment registers with standard RM values after it.

The objective of all this was setting the segment limit of the Internal Descriptor Caches to 4GB. If we wanted to do the same thing for SS or CS, we had to make sure that the D/B descriptor field was 16-bit, or otherwise the operating mode would not be compatible with the BIOS and we would triple fault on the first interrupt...

JJ

Posted: Sun Jul 01, 2007 9:19 pm
by Ninjarider
something that confuses me
the segment selectors which we plan to use to access memory over 1MB are loaded
how do you go about adding registers to be able to access over the 1 meg limit. does the value of gs determine which registers can access the full 4 gig?
macro gdt_entry base,limit,flags {
dw limit and 0xFFFF
dw base and 0xFFFF
db (base shr 16) and 0xFF
db flags
db ((limit shr 16) and 0xF) or 0xC0
db (base shr 24) and 0xFF
the above confuses me because in asm, or atleast masm, i dont think thats possible. that and what does all that mean. were do you get it?

i dont want to copy some code into my kernal and say that it just works, dont know how but it does. I would like to know that when i want to i can change any available settings.

Posted: Mon Jul 02, 2007 7:45 am
by JAAman
when you can, get hard-copies of the intel manuals (they will send them to you free of charge including shipping), its much easier to read than the PDF versions
how do you go about adding registers to be able to access over the 1 meg limit. does the value of gs determine which registers can access the full 4 gig?
no, gs is just a segment register just like the other segment registers, it is the GDT that tells the CPU which segments can access what
the above confuses me because in asm, or atleast masm, i dont think thats possible. that and what does all that mean. were do you get it?
that comes from the intel manuals, 3A:3.4.5, there is a nice description and figure 3-8 shows exactly what the structure looks like, and that section includes a complete description of each field

basically you have:
the base -- which defines where the segment should start in linear memory
the limit -- which defines how long the segment is
the type -- which defines what the segment is used for
the flags -- which define what permissions the segment has and who is allowed to use them (and whether the segment is loaded in memory at the time)

the earlier parts of 3A:3.4 give more information as to how the segments are used, and how they are loaded into the segment registers

i dont want to copy some code into my kernal and say that it just works, dont know how but it does. I would like to know that when i want to i can change any available settings.
thats a very good attitude, all i can say is the intel manuals are you best friend in learning about the CPU -- and they are usually quite readable

once you get it, it is quite simple really, i suggest that you spend some more time in 3A:3.4 (most OSs use the flat model, similar to what is discribed in 3A:3.2.1, except you need 2 segments per supported ring -- normally 2 rings, 4 segments)

Posted: Mon Jul 02, 2007 9:09 am
by JJeronimo
JAAman wrote:when you can, get hard-copies of the intel manuals (they will send them to you free of charge including shipping), its much easier to read than the PDF versions
Everywhere or only in the USA?
And does AMD do the following? I'm more used to the AMD manuals than the Intel ones...

JJ

Posted: Mon Jul 02, 2007 9:36 am
by JJeronimo
Ninjarider wrote:something that confuses me
the segment selectors which we plan to use to access memory over 1MB are loaded
how do you go about adding registers to be able to access over the 1 meg limit. does the value of gs determine which registers can access the full 4 gig?
No. You need to load the descriptor in the segment registers with which you want to access the entire 4GB. For example, if you wanted to use all the segment registers (in order to be able to place the stack and to execute code above 1MB as well), you would need to do:

Code: Select all

mov ax, 1 shl 3
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax

;Then, you still need to jump to protected mode code, using a code descriptor...
(but in this case, make sure that the descriptors have 16-bits default address size... The one I declared above didn't have, but as I didn't load ss nor cs, it wasn't important...)

The following are the correct 16-bit descriptors:

Code: Select all

macro gdt_entry base,limit,flags  {
   dw   limit and 0xFFFF
   dw   base  and 0xFFFF
   db   (base shr 16)  and 0xFF
   db   flags
   db   ((limit shr 16) and 0xF) or 0x80
   db   (base shr 24)  and 0xFF
} 

;(...)

gdt_entry   0x00000000, 0xFFFFF, 10010010b   ;Ring 0, data, expand-up, r/w, 16-bit PM
gdt_entry   0x00000000, 0xFFFFF, 10011010b   ;Ring 0, code, expand-up, r/x, 16-bit PM
Then, undo everything when to clear back the PE bit.

Better thinking, I don't understand why someone would want to place code above 1MB in unreal mode, because the good thing about unreal mode is being able to call the BIOS and use 32-bit offsets as well, but if you put your code above 1MB you won't be able to call the BIOS, cause it wouldn't be able to return to your program... Unless you wrap the BIOS calls with some code that is under 1MB, which is a possibility...
macro gdt_entry base,limit,flags {
dw limit and 0xFFFF
dw base and 0xFFFF
db (base shr 16) and 0xFF
db flags
db ((limit shr 16) and 0xF) or 0xC0
db (base shr 24) and 0xFF
}
the above confuses me because in asm, or atleast masm, i dont think thats possible. that and what does all that mean. were do you get it?
Don't you know how to declare data in ASM?
* dw declares a word
* db declares a byte

Now, that, is a macro that declares the GDT descriptor, in the place where you invoke it, based on the macro parameters, which are packed in the way the processor understands them.
The macro is in FASM syntax, which is a bit strange from the point of view of the average NASM user...
i don't want to copy some code into my kernel and say that it just works, don't know how but it does. I would like to know that when i want to i can change any available settings.
Good attitude.

JJ

Posted: Mon Jul 02, 2007 9:36 am
by JAAman
Everywhere or only in the USA?
And does AMD do the following? I'm more used to the AMD manuals than the Intel ones...
everywhere in the world, afaik

AMD sometimes does also, though im not as familiar with their policies, and their manuals and order pages are much more confusing and harder to find

i have both (although my AMD copies are quite old -- revision 3.07 -september 2002, my intel copies are revision 19US), personally i find the intel manuals much easier to read, and much easier to find the information (section numbers in the intel manuals are also much easier for referring to -- the section numbers dont change between revisions, while page numbers do, and AMD (in my copies anyway) use page numbers, making it much harder to refer to in different revisions -- which is why i always mention the intel section numbers when im talking about it online, as page numbers would be different for people with different revisions)

Posted: Mon Jul 02, 2007 11:43 am
by hailstorm
I don't believe ninjarider understands what is happening exactly when you execute this small program... :)

The way how the intel processors (and it's "clones") work regarding protected mode techniques is as follows:
Although the segmentregisters contain 16 bit values, behind the scenes, more information is stored.
The data that is stored is most likely to be the base address of a segment, its limit and some properties or flags. When the processor starts in real mode, the base is set 0 and the limit to 0xffff (65536).
So, that is how intel keeps it segment limit in real mode in later IA32 processors. It is very easy to understand I think, that the limit can be adjusted pretty easily. So that is what the code does.
- Set up a valid gdt.
- Enter protected mode
- Load a datasegment using a selector with a limit > 0xffff
Using granularity=1 and limit = 0xfffff you get the full span of memory,
4 GB!
- Return to real mode.
And there you have it; the compatibility limit is gone and you have full access of the whole memory bus.
Don't forget to enable the A20 line; this addressline is blocked because of these compatibility issues...

I hope it's clear. :D

Posted: Mon Jul 02, 2007 12:33 pm
by JJeronimo
JAAman wrote:personally i find the intel manuals much easier to read, and much easier to find the information
Now, better thinking, the AMD manuals are not very well organized...
But I don't know how the intel are organized... The topics are very connected with each other so it's a bit difficult to coherently organize this type of documentation...

JJ

Posted: Mon Jul 02, 2007 12:36 pm
by JJeronimo
hailstorm wrote:I hope it's clear. :D
At least looks better than my explanation!

JJ

Posted: Mon Jul 02, 2007 12:49 pm
by Ninjarider
the part that i dont understand about the macro is well first off its a macro. havn't bothered to understand how they work. the part mostly that i do not understand about your macro is this
db {label} and {some number} or {another number}
i know that you can declare a variable using constants, or immediates. what i dont understand is your using a label for another variable thats not in your code.

from what i've been reading im slowly understanding stuff. main thing that confused me was the use of the word segment. i could not tell if they were talking about the segment registers or the memory segment as a whole.

another question i have is the granularity (g).
if im not mistaken the g is 1 bit and is either on or off. if g is set is the max mem 4gigs and if its not is the max 1 gig. or did just just not understand what they were saying at all.