Page 1 of 1

setting up GDT??

Posted: Wed Jul 11, 2007 8:53 pm
by fei
I'm following up Bran's Kernel Development tutorial (http://www.osdever.net/bkerndev/Docs/gdt.htm). When I failed at seting up GDT. I can't quite understand the far jmp in the code ("jmp 0x08:flush2"). I convert the nasm code to gas ("ljmp $0x80, $flush2"). My kernel just freeze after startup. If I comment out the far jmp, it works fine. Why is called jar jmp? why do I need it? How can I fix the problem?

Thanks in advance!!!

This is the original code

Code: Select all

global _gdt_flush
extern _gp
_gdt_flush:
    lgdt [_gp]
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    jmp 0x08:flush2
flush2:
    ret

This is my code in gas

Code: Select all

.global _gdt_flush
.extern _gdt_p
.type _gdt_flush @function
 _gdt_flush:
 	lgdt (_gdt_p)
 	mov $0x10, %ax
 	mov %ax, %ds
 	mov %ax, %es
 	mov %ax, %fs
 	mov %ax, %gs
 	mov %ax, %ss
	ljmp $0x80, $flush2
flush2:
	ret

Posted: Wed Jul 11, 2007 9:08 pm
by frank
The far jump is necessary to make the processor update the hidden fields for cs.

For anyone to be able to solve your problem we need to know a little bit more information about your kernel.
Are you using grub?
Is your kernel only assembly or is it mixed assembly and C?
Can we see the code that sets up the GDT?

Posted: Wed Jul 11, 2007 9:29 pm
by fei
> Are you using grub?
Yes. I'm using grub

> Is your kernel only assembly or is it mixed assembly and C?
It's mixed assembly and C.

I found out the problem. I changed the _gdt_p.base to tyep "void *' instead of unsigned int. This is the problem. After I changed back to use unsigned int, it works fine.

"void *' and "unsigned int" both have the same size. I tought it's a proper way to use "void *' when dealing with pointers. So, what is the difference between these two types?? I'm a bit confused.

Thanks!

Code: Select all

struct gdt_ptr {
	unsigned short limit;
	unsigned int base;
	//void *base;
}__attribute__((packed));

struct gdt_ptr _gdt_p;

_gdt_p.limit = (sizeof(struct gdt_entry) * 3) - 1;
_gdt_p.base = (unsigned int)(&gdt);

Posted: Wed Jul 11, 2007 9:31 pm
by pcmattman
Of course they have the same size - an address on the x86 in PMode is 32 bits long. Read up on pointers 8)

Posted: Wed Jul 11, 2007 9:39 pm
by earlz
It was probably something to do with pointer addition or something...though you would think they would compile to be the same..

Posted: Wed Jul 11, 2007 9:40 pm
by frank
I'm glad you fixed it. I'm sorry I couldn't be of more help.

Now about the void * versus unsigned int thing:

I looked at the disassembly of accessing two different structs that look just like gdt_ptr. One with void * and one with unsigned int. In the generated assembly there is absolutely no difference between the two. The only thing I could think of is if you were to forget the & in front of gdt when you did it with void *.

Posted: Wed Jul 11, 2007 10:24 pm
by fei
I'm glad you fixed it. I'm sorry I couldn't be of more help.
No worry. Thanks again for your help. "void *" and "unsigned int" ARE the same. I tried to use "void *" again and it just works. Don't remember what was the original code. Sorry for asking a question without carefully thinking it before.