Page 1 of 2
Problem loading the GDT
Posted: Sun Nov 25, 2007 3:26 am
by Steve the Pirate
I'm getting a strange problem loading my GDT in my new kernel. When I test it in Virtualbox, it works, but when I test in Bochs, I get an error
Code: Select all
check_cs: attempt to jump to long mode without enabling EFER.LMA !
Does anyone have any idea why this is happening?
Thanks,
-Stephen
Posted: Sun Nov 25, 2007 6:49 am
by jnc100
Are you setting CS.L in your code segment descriptor when you try to jump to protected mode? Its bit 21 of the (edit: 2nd half of the) descriptor (see 3A:3.4.5).
Regards,
John.
Posted: Sun Nov 25, 2007 7:42 pm
by Steve the Pirate
I'm already in protected mode, and I'm trying to set up a flat memory model...
I can't work out why Bochs thinks I'm trying to jump to long mode. Am I jumping to the wrong offset?
Posted: Mon Nov 26, 2007 2:39 am
by AJ
Hi,
Can we see the GDT and the jump instruction, please?
Cheers,
Adam
Posted: Mon Nov 26, 2007 3:49 am
by Steve the Pirate
My most recent attempt is using
JamesM's tutorial code. The same thing still happens.
The only difference is that I'm calling it from C++, instead of from C as in the tutorial.
Here is the jump:
Code: Select all
[GLOBAL gdt_flush] ; Allows the C code to call gdt_flush().
gdt_flush:
mov eax, [esp+4] ; Get the pointer to the GDT, passed as a parameter.
lgdt [eax] ; Load the new GDT pointer
mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment
mov ds, ax ; Load all data segment selectors
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:.flush ; 0x08 is the offset to our code segment: Far jump!
.flush:
ret
Posted: Mon Nov 26, 2007 4:02 am
by Combuster
After debugging I can cause the error in my own kernel when changing a reserved bit in the GDT selector (which MUST be 0 since it is currently redefined as the L bit as jnc100 suggested)
Code: Select all
MOV byte [EDI+1*8+GDT_FLAGS_HI], GDT_LIMIT_HIMASK | GDT_FLAG_PAGES | GDT_FLAG_32BIT ; works
MOV byte [EDI+1*8+GDT_FLAGS_HI], GDT_LIMIT_HIMASK | GDT_FLAG_PAGES | GDT_FLAG_32BIT | 0x20 ; causes panic
Your GDT, please?
Posted: Mon Nov 26, 2007 5:45 am
by Steve the Pirate
I think I fixed it! I am now using this as my set gate (mostly from JamesM's code again)
Code: Select all
void gdt::gate(s32int num, u32int base, u32int limit, u8int access, u8int gran)
{
gdt_entries[num].base_low = (base & 0xFFFF);
gdt_entries[num].base_middle = (base >> 16) & 0xFF;
gdt_entries[num].base_high = (base >> 24) & 0xFF;
gdt_entries[num].limit_low = (limit & 0xFFFF);
gdt_entries[num].granularity = (limit >> 16) & 0xFF;
gdt_entries[num].granularity |= gran & 0xF0;
gdt_entries[num].granularity &= 0xDF; // ADDED - Set CS.L to 0
gdt_entries[num].access = access;
}
My GDT structure is:
Code: Select all
struct gdt_entry_struct
{
u16int limit_low;
u16int base_low;
u8int base_middle;
u8int access;
u8int granularity;
u8int base_high;
} __attribute__((packed));
I commented the line I added, which manually sets L to zero. It seems kind of hackish, and there's probably a better way of doing it, but it works.
Would the original code work on a non-64 bit processor?
Posted: Mon Nov 26, 2007 5:54 am
by Combuster
My guess is that you're passing a value of 0xffffffff into the limit field while it expects 20 significant bits at most.
Posted: Mon Nov 26, 2007 9:11 am
by JamesM
That would be my guess too.
You can probably fix it in a less hacky way by adding:
Code: Select all
limit &= 0xFFFFF; // Limit should only be 20 bits long.
At the start of the function, as an error check.
EDIT: Thanks for bringing this to my attention: I haven't yet tried it on a 64-bit machine (although my own kernel uses the same code and works fine on my 64-bit dev box... hmm)
It seems that error has slipped through from Bran's original code, which my code is based off. Thanks.
Hrmph. Annoying that I didn't notice that. And that bochs ran successfully on my machine (the bochs on my dev box is a x86_64 build, as is qemu). The mattise kernel has the same base code (I just checked
) and it doesn't crash on x64 boxen: I wonder why only you have this problem??
Posted: Mon Nov 26, 2007 9:12 pm
by pcmattman
JamesM wrote:The mattise kernel has the same base code (I just checked
) and it doesn't crash on x64 boxen: I wonder why only you have this problem??
It does work for me as well, which makes this problem really weird.
Perhaps the source of the problem is in his initialization of his GDT?
OP: would you be able to post the code which actually calls gdt::gate? That might help us find the real source of the problem.
Posted: Mon Nov 26, 2007 10:10 pm
by Steve the Pirate
It's pretty much the same as JamesM's code:
Code: Select all
gdt_set_gate(0, 0, 0, 0, 0); // Null segment
set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment
set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment
set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment
set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment
So I gather that I should only have 0xFFFF as the limit?
Posted: Tue Nov 27, 2007 1:45 am
by Combuster
Steve the Pirate wrote:So I gather that I should only have 0xFFFF as the limit?
no, 0xFFFF
F - 20 ones in binary
Posted: Tue Nov 27, 2007 2:43 am
by JamesM
Yeah, it's really strange that this problem has only just appeared... Even Bran's code has it in!
Posted: Tue Nov 27, 2007 2:54 am
by Steve the Pirate
Even weirder is that I downloaded the code from your tutorials, and it doesn't throw that error...
Posted: Tue Nov 27, 2007 4:06 am
by JamesM
Oh? Interesting. So you downloaded my code, compiled and ran it and it ran fine, but yours doesn't? I'll have a closer look.