Unreal mode hates pointers?

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
Jubbens

Unreal mode hates pointers?

Post by Jubbens »

For some reason, I can successfuly move to unreal mode and then display the done message, but when I try to display another message afterwards it reboots! (exception(): 3rd (13) exception with no resolution) I'm sure the problem is elsewhere, so I attatched the full kernel.

Thanks.

Code: Select all

; Move to unreal mode
mov si,msg1
call print
cli
mov al,0xD1
out 0x64,al
mov al,0x03
out 0x60,al
push ds
lgdt [gdtinfo]
mov eax,cr0
inc ax
mov cr0,eax
mov bx,0x08
mov ds,bx
dec ax
mov cr0,eax
pop ds
sti
mov si,done
call print
call br

; Display another message
mov si,msg2
call print

msg1: db "[Kernel] Moving to unreal mode...", 0
msg2: db "This is totally a second message", 0
done: db "Done", 0
AR

Re:Unreal mode hates pointers?

Post by AR »

One problem unrelated appears to be:

Code: Select all

flatdesc db 0xff, 0xff, 0, 0, 0, 10010010b, >01001111b<, 0
It should be 0xCF not 0x4F (Without the highest bit set you will have created a segment that is 0-0xFFFFF, if you want the whole address space then you need to set the granularity bit)

Another is "ORG 0x0000", your GDT Address won't be valid unless the code is loaded at 0 physically which will override the BIOS IVT and crash on the next interrupt.

I can't see anything else really wrong at a glance.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Unreal mode hates pointers?

Post by Candy »

AR wrote: Another is "ORG 0x0000", your GDT Address won't be valid unless the code is loaded at 0 physically which will override the BIOS IVT and crash on the next interrupt.
Pretty darn unlikely. IF you're in real-mode and you overwrite the IVT with the GDT, and an interrupt occurs before you switch, then it's a problem. Who uses the IVT actively in pmode?
AR

Re:Unreal mode hates pointers?

Post by AR »

The code that is not working is operating in Unreal mode, meaning the whole point is that the code is still executing in real mode, which is a problem if the IVT is overwritten.
oswizard

Re:Unreal mode hates pointers?

Post by oswizard »

AR wrote:
Another is "ORG 0x0000", your GDT Address won't be valid unless the code is loaded at 0 physically which will override the BIOS IVT and crash on the next interrupt.

@Candy, Jubbens - what he meant was that the only case in which this code would work would be if it were located at 0 physically. Since it doesn't do that (int 0x10 works to print the message), then it follows that the org directive must be wrong.

The org directive has caused a bit of confusion here before. In short, it specifies the offset (as in seg:offset) of the first byte of the file. If the code is being loaded at, say, 0x0100:0x0000 and the cs, ds, es, etc. are 0x0100, then the org 0x0000 is okay. If the cs, ds, es, etc. are 0x0000 and the code is jumping to 0x1000, then there is a problem.

Even if the org 0x0000 is right, there is another problem: the GDT must be loaded with a linear address (no segments). Right now the GDT is being loaded with an address that is an offset - but the processor expects a full address, without segmentation. Either shift cs left 4 bits and add to the relevant part of the gdtinfo structure at runtime, or change the org statement - make cs, ds, etc. zero and load at a nonzero offset.

Another thing: when switiching to pmode or back to rmode (or unreal mode), I think a jump is required to flush the instruction cache - and to update the CS register! After the first mov cr0, eax, do a jmp 0x08:<label>, where the <label> points to the next instruction. Do the same after the second mov cr0, eax. You will need to create a 16-bit code segment descriptor in your GDT, and ensure that the existing descriptor is a 16-bit data segment - each with a 4GB range.

Also, I would change all segment registers in the brief block of protected mode code. That way, any segment is now 4GB, so if you use stosb etc., which implies using ES:(E)DI, it is "unreal" as well.

Mike
AR

Re:Unreal mode hates pointers?

Post by AR »

You are right that that's what I meant, but no you do not need to jump to flush the cache, flushing is only required for entering protected mode, the whole point of Unreal Mode is that the code segment is still real mode 16bit but you have 32bit data segments, far jumping to a 32bit code segment will change from Unreal to Protected Mode.
Jubbens

Re:Unreal mode hates pointers?

Post by Jubbens »

Changed that descriptor. Thanks for pointing it out before it became a problem.

I'm not sure why I'm over writing the IVT with my GTD. Why would the lgdt instruction load the GDT at the code's location in memory? It does the same thing when I take out the ORG 0x0000. Where can I read up on lgdt?

When I don't try to do anything after jumping into unreal mode and displaying the done message, it works perfectly and sits pretty when it's done. No rebooting. I just find it strange that it would display the done message after jumping into unreal mode, but when I try to display something else afterwards it reboots.
oswizard

Re:Unreal mode hates pointers?

Post by oswizard »

Jubbens wrote: I'm not sure why I'm over writing the IVT with my GTD. Why would the lgdt instruction load the GDT at the code's location in memory? It does the same thing when I take out the ORG 0x0000. Where can I read up on lgdt?
It is not being overwritten. The problem is that the GDT base pointer in the memory passed to lgdt needs to be a linear address (or in real mode, a physical address). Since you are NOT loading the code at physical address 0x00000000 (see my post above), the address is wrong. The org directive tells NASM to add that value to any offset of a label. For instance, if "gdt" is at file offset 0x740, then the address placed in the gdt record is 0x740+org, which will in this case be 0x740. Since (see above) that is NOT where the code is actually loaded, then you must do either one of two things:

1. When you jump to your kernel from the boot sector, jump to 0x0000:{offset} and not {seg}:0x0000 as you are doing now. Then change the org 0x0000 to org {offset} and everything will work.

-- OR --

2. Before executing lgdt, do this:

Code: Select all

xor eax, eax
mov ax, cs
shl eax, 4
add [gdtinfo+2], eax
This will fix up the address so it will be valid.

I am also 90% certain that a jump is required. Otherwise the code that sets up the segment registers would still be in real mode as the code segment and cache are still for real mode. I could be wrong though... if fixing the base address doesn't do it, then try adding the jumps.

Mike
Jubbens

Re:Unreal mode hates pointers?

Post by Jubbens »

Wow...thanks man. I get it now.

Your code to fix the base address did the job.
AR

Re:Unreal mode hates pointers?

Post by AR »

Mike wrote: I am also 90% certain that a jump is required. Otherwise the code that sets up the segment registers would still be in real mode ...
... which is perfectly valid, and the whole point of this exercise (Unreal Mode is usually used for copying a kernel above 1MB whilst the CPU is still executing in Real Mode)
oswizard

Re:Unreal mode hates pointers?

Post by oswizard »

AR: Well, since it works, you must be right! :) I guess it makes sense that it would work...

Anyways, Jubbens, glad to see it works!

Mike
Post Reply