Page 1 of 1
GDT limitations
Posted: Sat Aug 15, 2009 1:09 pm
by brodeur235
When I load my kernel to an address above 1 word, I get this from bochs:
Code: Select all
[CPU0 ] prefetch: EIP [00010000] > CS.limit [0000ffff]
I know what this means. I know that bochs is right, the highest limit I can give to a code segment in the GDT is a 1 word limit (0xffff), which as you can see is prohibiting me from jumping to my kernel. I also know that it is very possible to load a kernel in the higher up address space. How do ya'll do it? My GDT is typical and probably unimportant, but here it is for inclusiveness:
Code: Select all
gdt_entries:
; null entry
db 00000000b
db 00000000b
db 00000000b
db 00000000b
db 00000000b
db 00000000b
db 00000000b
db 00000000b
; code segment descriptor: OFFSET = 0x0008
db 11111111b
db 11111111b
db 00000000b
db 00000000b
db 00000000b
db 10011010b
db 11001111b
db 00000000b
; data segment descriptor: OFFSET = 0x0010
db 11111111b
db 11111111b
db 00000000b
db 00000000b
db 00000000b
db 10010010b
db 11001111b
db 00000000b
gdt_descriptor:
; table size (2 bytes)
dw (gdt_descriptor - gdt_entries - 1)
; table offset (4 bytes)
dd (gdt_entries+0x7C00)
Help appreciated,
Brodeur235
Re: GDT limitations
Posted: Sat Aug 15, 2009 1:27 pm
by neon
Setting bit 55 of a GDT entry [granularity] multiplies the GDT limit by 4k (0xffff*4k=0xFFFF000). The bit looks set in your GDT, so I dont think that is the problem.
I assume that the A20 gate has already been set?
Re: GDT limitations
Posted: Sat Aug 15, 2009 1:42 pm
by ru2aqare
neon wrote:Setting bit 55 of a GDT entry [granularity] multiplies the GDT limit by 4k (0xffff*4k=0xFFFF000). The bit looks set in your GDT, so I dont think that is the problem.
Did you reload your segment registers after loading the GDTR? Segment register cs: via a far jump, other segment registers directly? The descriptors are correct.
Re: GDT limitations
Posted: Sat Aug 15, 2009 2:50 pm
by brodeur235
@neon
I assume that the A20 gate has already been set?
Yup. However, even if I hadn't this should still work. The A20 line enables addressing over 1Mb (0x100000), whereas I'm only trying to load a small (4 Kb) kernel at 0x10000.
@ru2aqare
Did you reload your segment registers after loading the GDTR? Segment register cs: via a far jump, other segment registers directly?
"via a far jump" is the problem. It won't let me far jump above the one word level. What I do, in order is this: Load the GDTR, far jump to my kernel (which only works if the kernel is below the 1 word level), and then reload all the segment registers immediately.
Here is my bootloader's main, which gives you an overview of what it does and in what order is does it:
Code: Select all
[BITS 16]
bl_main:
; disable interrupts
cli
; setup stack
xor ax,ax
mov ss,ax
mov esp,0x00007C00
; setup data
xor ax,ax
mov ds,ax
; load kernel
call kernel_loader
; load gdt
lgdt [ BLOC( gdt_descriptor ) ]
; enter pmode
mov eax,cr0
or eax,1
mov cr0,eax
; enable a20 line
call a20_enable
; jmp to protected mode
jmp DWORD 0x08:KERNEL_OFFSET
Interrupts are not enabled unitl much farther along in the kernel after setting up ISRs and remapping IRQs.
Thanks for the replys and help still appreciated,
Brodeur235
EDIT: BLOC( ) is just a macro that adds 0x7C00 to the specified label parameter.
Re: GDT limitations
Posted: Sat Aug 15, 2009 3:28 pm
by neon
Yup. However, even if I hadn't this should still work. The A20 line enables addressing over 1Mb (0x100000), whereas I'm only trying to load a small (4 Kb) kernel at 0x10000.
Ah, k, didnt know that. You mentioned in your first post that with the GDT code limit to 0xffff [which is incorrect] it prevents you from 'jumping to your kernel' so I was suspecting that you were loading your kernel above that.
I suppose my next question is: what does you jmp instruction supposed to do? Is it supposed to execute your kernel? That particular message doesnt say anything about segment registers being incorrect nor the GDT. [Bochs would give a different error for that.]
Re: GDT limitations
Posted: Sat Aug 15, 2009 4:21 pm
by Combuster
the highest limit I can give to a code segment in the GDT is a 1 word limit (0xffff)
Even 0xffff
f, more than one word. And with the granularity bit you can make 00xfffff fff - fffff(limit) fff(added by setting the G bit)
Re: GDT limitations
Posted: Sat Aug 15, 2009 5:52 pm
by brodeur235
Firstly, bochs is TELLING me that:
Code: Select all
[CPU0 ] prefetch: EIP [00010000] > CS.limit [0000ffff]
My code segment limit IS 0xffff.
I went to my GDT and was reminded that there is only room to set a limit to 1 word, max. So, I naturally assumed that because I set the code segment limit to < 1 word in the GDT, that that's what was restricting me from jumping to my kernel. However, you tell me that if I have the granularity bit set ( and it is set... you've all seen my GDT ), that that extends the code segment limit... Okay, great! Bochs disagrees. I have the granularity bit set and yet I still get the prefetch error.
Other things:
Ah, k, didnt know that. You mentioned in your first post that with the GDT code limit to 0xffff [which is incorrect] it prevents you from 'jumping to your kernel' so I was suspecting that you were loading your kernel above that.
Okay, I don't think I've been very clear... The A20 line enables addressing over the 1Mb line: 0x100000 (that's a 1 with 5 zeros). Something else, (I suspect my GDT) is limiting my code segment range to BELOW one word: 0x10000 (a 1 with 4 zeros, so 0xffff and under is okay). I know that this "something else" factor is limiting me because of the prefetch message I get from Bochs. I actually >am< loading my kernel above 0xffff, but that's still below the A20 line, which is at 0x100000, not 0x10000.
0x1000000 (A20 limitation) > 0x10000 (kernel load location) > 0xffff (code segment limit)
I'm loading the kernel in that area on purpose, to test one thing at a time. Once I get the code segment limit to cooperate, then I'll test the A20 line.
Also:
Even 0xfffff, more than one word. And with the granularity bit you can make 00xfffff fff - fffff(limit) fff(added by setting the G bit)
I'm not fully understanding what you're saying here, but if the gist of it is that by setting the granularity bit, I can extend my code segment range, I have to remind you that the granularity bit IS set, yet Bochs is still throwing a complaint at me...
Again, thanks for the help/replies guys,
Brodeur235
Re: GDT limitations
Posted: Sat Aug 15, 2009 6:06 pm
by ru2aqare
I'm not very sure about this, but the problem may be...
Code: Select all
; load gdt
lgdt [ BLOC( gdt_descriptor ) ]
; enter pmode
mov eax,cr0
or eax,1
mov cr0,eax
Aren't you supposed to flush/reload the segment registers here? Since you don't do that, the hidden portions of the segment registers remain untouched, and the real-mode 64K segment limit remains in effect. Which probably causes a GPF when you try to jump outside of the 64K range later on.
Re: GDT limitations
Posted: Sat Aug 15, 2009 6:37 pm
by neon
Aren't you supposed to flush/reload the segment registers here?
I think you should but are not required to. ie, in my real system, I have the enabling pmode function as a completely separate function - thus it gets called and returns back to the calling function to enable protected mode. The flushing/reloading segment regs are later after the function call.
Okay, I don't think I've been very clear... The A20 line enables addressing over the 1Mb line: 0x100000 (that's a 1 with 5 zeros).
You were clear the first time, no need to reiterate. Do keep in mind, however: The way you enable the 20th address line may not work on all platforms [although enabling it via keyboard controller command port seems to be pretty common.]
I actually >am< loading my kernel above 0xffff, but that's still below the A20 line, which is at 0x100000, not 0x10000.
That is fine.
We have verified that the GDT itself is correct. It also seems like it is being loaded correctly as well [if it didnt, you would get a different error.] I suspect that the problem is something else. It may be easier for us to understand the problem if you post the full register dump and error message bochs gives.
Re: GDT limitations
Posted: Sat Aug 15, 2009 6:56 pm
by Firestryke31
Does kernel_loader modify ds? That's one thing I might look into. A quick fix/check is to add a "push ds \ pop ds" guard around the call and if it works then you've found the problem.
Re: GDT limitations
Posted: Sat Aug 15, 2009 9:10 pm
by brodeur235
The kernel loader does not modify ds, but I tested the push and pop to check for results, andnothing appeared to change.
As for the actual error, Bochsout.txt starts up as normal. Here is the prologue to the problem:
Code: Select all
00470331662i[BIOS ] Booting from 0000:7c00
00470466714e[CPU0 ] prefetch: EIP [00010000] > CS.limit [0000ffff]
00470470101i[CPU0 ] BOUND_GdMa: fails bounds test
00470483184e[DMA ] io write to address 00000000, len=2
00470483208e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
00470485748e[DMA ] io write to address 00000000, len=2
00470500379e[CPU0 ] prefetch: EIP [00010000] > CS.limit [0000ffff]
00470530737e[CPU0 ] prefetch: EIP [00010010] > CS.limit [0000ffff]
00470561087e[CPU0 ] prefetch: EIP [00010000] > CS.limit [0000ffff]
00470591437e[CPU0 ] prefetch: EIP [00010000] > CS.limit [0000ffff]
The prefetch error continues until I turn of the emulators power. Here is what bochs looks like:
I hope this helps solve the problem..
Brodeur235
Re: GDT limitations
Posted: Sun Aug 16, 2009 8:21 am
by neon
Hm, I was actually looking for a register dump. Bochs dumps it in the bochs crash log after you power it off.
Re: GDT limitations
Posted: Sun Aug 16, 2009 8:34 am
by ru2aqare
Code: Select all
00470331662i[BIOS ] Booting from 0000:7c00
00470466714e[CPU0 ] prefetch: EIP [00010000] > CS.limit [0000ffff]
00470470101i[CPU0 ] BOUND_GdMa: fails bounds test
Are you using the 'bound' instruction? If not, this might indicate that some code jumps into a random location in memory, or the stack is corrupted and control is transfered to a random location.
Code: Select all
00470500379e[CPU0 ] prefetch: EIP [00010000] > CS.limit [0000ffff]
00470530737e[CPU0 ] prefetch: EIP [00010010] > CS.limit [0000ffff]
00470561087e[CPU0 ] prefetch: EIP [00010000] > CS.limit [0000ffff]
00470591437e[CPU0 ] prefetch: EIP [00010000] > CS.limit [0000ffff]
Also if you take the differences of the timestamps of the successive error messages, you get a constant 30350, which leads me to believe that some code is looping forever in a random segment in memory. Once it crosses the 64K segment limit, it wraps around to zero and continues, but Bochs logs the error nonetheless.
Re: GDT limitations
Posted: Tue Aug 18, 2009 2:01 am
by Craze Frog
I still think the segment registers aren't set properly. Why don't you show us the code where you load the gdt and the new segment registers?
Re: GDT limitations
Posted: Wed Aug 19, 2009 4:34 am
by Combuster
I had a fresh look over the code, and this struck me as really odd.
Code: Select all
mov eax,cr0
or eax,1
mov cr0,eax
call a20_enable
Why are you calling a20_enable in "limbo mode"?