Page 1 of 1

Cannot change GDT while in protected mode

Posted: Wed Mar 19, 2014 9:55 pm
by fkpama
Hi all, first post on the forum.

I should start by saying that I'm a newbie in OS programming! So forgive me if my question sounds stupid.

Until now, I managed to install grub2 on a hard disk and make him load my kernel. I'm now playing a little with this tutorial. I know it's for real mode programming, but I wanted to adapt it to the environment that we're in when given control by grub and somehow I'm stuck for 3/4 days now on the GDT's step.

When I debug with qemu, I see that my kernel freeze when I'm trying to change the DS register. as I understand things, I believe the DS register was not used until accessing data in other segment, even in protected mode (please feel free to correct me if I'm wrong). So I was hoping that my code, following the one on the tutorial, would smoothly work. But, as some of you may have understand since I'm sure I'm making a dumb mistake, It's not working.

Can someone help me here please? Did I missed something?

Thanks for your time guys

Re: Cannot change GDT while in protected mode

Posted: Wed Mar 19, 2014 10:00 pm
by thepowersgang
First off, bran's tutorial is actually a protected mode tutorial (an old one, with many very bad quirks).

Without seeing what code you're compiling, I can't really tell much about why your code is crashing. But I'd suggest running your code under bochs with the debugger enabled instead of using qemu at this stage. (You'll want to compile bochs with --enable-debugger if using linux, or use bochsdbg.exe if on windows)

Re: Cannot change GDT while in protected mode

Posted: Wed Mar 19, 2014 10:33 pm
by fkpama
Hi thepowersgang, thanks for your quick support. The code is pretty much exactly what's in the tutorial.

Here it is :

File asm.S :

Code: Select all

.global gdt_flush
gdt_flush:
lgdt	gp
	mov	$0x10, %ax
	mov	%ax, %ds
	mov	%ax, %es
	mov	%ax, %fs
	mov	%ax, %gs
	mov	%ax, %ss
	ljmp	$0x08, $flush2
        ret
Here's how I call it :

Code: Select all

typedef
        struct s_gdt
        {
                WORD limit_low;
                WORD base_low;
                BYTE base_middle;
                BYTE access;
                BYTE granularity;
                BYTE base_high; 
        } PACKED
        GDT_ENTRY;

typedef
        struct s_gdt_ptr
        {
                WORD limit;
                DWORD base;
        } PACKED
        GDT_PTR;

GDT_ENTRY gdt[3];
GDT_PTR gp;

extern void gdt_flush();

void gdt_set_gate(int num, DWORD base, DWORD limit, BYTE access, BYTE gran)
{
        gdt[num].base_low = (base & 0xFFFF);
        gdt[num].base_middle = ( base >> 16 ) & 0xFF;
        gdt[num].base_high = ( base >> 24 ) & 0xFF;

        gdt[num].limit_low = ( limit & 0xFFFF );
        gdt[num].granularity = (( limit >> 16 ) & 0x0F);

        gdt[num].granularity |= (gran & 0xF0);
        gdt[num].access = access;
}

void gdt_install()
{
        gp.limit = (sizeof(GDT_PTR) * 3) - 1;
        gp.base = (DWORD)&gdt;

        gdt_set_gate(0,0,0,0,0);
        gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
        gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);

        gdt_flush((DWORD)&gp);
}
In the kernel_main I just call gdt_install(). WORD, BYTE, DWORD just expands to 'unsigned short', 'unsigned char' and 'unsigned int', respectively.

I'll give a try with the bochs debugger as you suggested.

Thanks for your help.

Re: Cannot change GDT while in protected mode

Posted: Wed Mar 19, 2014 10:51 pm
by Bender
Hi,
This may be incorrect. (I am not familiar with GAS Syntax so beware!)

Code: Select all

lgdt   gp
Should be:

Code: Select all

lgdt [gp]
Basically the difference is that X will pass the address of X, however [X] will get the value. (Hope what I am saying is sane)
EDIT: Does it even compile? Where exactly is flush2?
According to the tutorial:

Code: Select all

global _gdt_flush     ; Allows the C code to link to this
extern _gp            ; Says that '_gp' is in another file
_gdt_flush:
    lgdt [_gp]        ; Load the GDT with our '_gp' which is a special pointer
    mov ax, 0x10      ; 0x10 is the offset in the GDT to our data segment
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    jmp 0x08:flush2   ; 0x08 is the offset to our code segment: Far jump!
flush2:
    ret 
BTW I haven't looked at your other code.
-Bender

Re: Cannot change GDT while in protected mode

Posted: Wed Mar 19, 2014 11:10 pm
by fkpama
Hi Bender,

I'm really sorry about that, I forgot to mention that I'm using gas (AT&T) syntax so I give the memory location with that statement.

about flush2, I didn't put it in this code :oops: . I must have deleted it by mistake (it's been 4 days you know :twisted: ) but I saw the registers that QEMU (multi boot) gave me and it was already pointing to the right offset and, I didn't have the chance to worry about that yet, I don't even pass the 2nd line :/

Re: Cannot change GDT while in protected mode

Posted: Wed Mar 19, 2014 11:13 pm
by Bender
Hi,
Well then do what thePowersGang suggested, test it on Bochs with debugging enabled, and post what you get.
-Bender