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