Global Descriptor Table Issues

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.
cjhawley
Posts: 7
Joined: Tue Jan 19, 2010 3:32 pm

Global Descriptor Table Issues

Post by cjhawley »

Hi,

I have been holding back to ask this question for about a week trying to figure out what is going on by my self, but, no luck.

I am following the JamesM tutorial on kernels and have gotten stuck at flushing the old GDT loaded by grub out and replacing it with my new one.
This is not working however and I do not know why.

Code: Select all

gdt_flush2:
	
	lgdt [gdt_ptr_struct] //get the structure from C
	mov ax, 0x10 //offset to data
	mov ds, ax //load segment selector
	mov es, ax //load segment selector
	mov fs, ax //load segment selector
	mov gs, ax //load segment selector
	mov ss, ax //load segment selector
	jmp 0x08:flush2 //will cause cs to be loaded as well
flush2:
	ret //back to C
I have tried returning to my C code at different places to see where things are going wrong and it is right after mov ax, 0x10 and before mov ds, ax.
Any help would be appreciated.

Here is a bochs dump:

Code: Select all

00209657525i[CPU0 ] CS.d_b = 16 bit
00209657525i[CPU0 ] SS.d_b = 16 bit
00209657525i[CPU0 ] EFER   = 0x00000000
00209657525i[CPU0 ] | RAX=0000000000000000  RBX=0000000000000000
00209657525i[CPU0 ] | RCX=000000000009e080  RDX=0000000000000014
00209657525i[CPU0 ] | RSP=000000000000ff98  RBP=000000000000ffb0
00209657525i[CPU0 ] | RSI=00000000000e472c  RDI=000000000000ffac
00209657525i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00209657525i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00209657525i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00209657525i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00209657525i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df IF tf SF zf AF PF CF
00209657525i[CPU0 ] | SEG selector     base    limit G D
00209657525i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00209657525i[CPU0 ] |  CS:f000( 0004| 0|  0) 000f0000 0000ffff 0 0
00209657525i[CPU0 ] |  DS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00209657525i[CPU0 ] |  SS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00209657525i[CPU0 ] |  ES:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00209657525i[CPU0 ] |  FS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00209657525i[CPU0 ] |  GS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00209657525i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00209657525i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00209657525i[CPU0 ] | RIP=000000000000fea6 (000000000000fea6)
00209657525i[CPU0 ] | CR0=0x60000010 CR2=0x0000000000000000
00209657525i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00209657525i[CPU0 ] 0x000000000000fea6>> push eax : 6650
User avatar
thepowersgang
Member
Member
Posts: 734
Joined: Tue Dec 25, 2007 6:03 am
Libera.chat IRC: thePowersGang
Location: Perth, Western Australia
Contact:

Re: Global Descriptor Table Issues

Post by thepowersgang »

Well, instead of doing a ret, I would suggest using the bochs magic breakpoint (xchg bx,bx)
Either that, or explicitly setting one in the debugger.

Also, are you actually in protected mode when you are running this code? The bochs register dump seems to say that the current segment values have a limit of 16K (also cs.d_b should be 32-bit in PMode)
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
cjhawley
Posts: 7
Joined: Tue Jan 19, 2010 3:32 pm

Re: Global Descriptor Table Issues

Post by cjhawley »

Yes, I am in protected mode. I have been pretty much following along with the tutorial, but with that being said, I have been spending a good deal of time creating standard functions (Sort of my reason to go into OS Dev...Lame reason, I know).
User avatar
thepowersgang
Member
Member
Posts: 734
Joined: Tue Dec 25, 2007 6:03 am
Libera.chat IRC: thePowersGang
Location: Perth, Western Australia
Contact:

Re: Global Descriptor Table Issues

Post by thepowersgang »

so, why is that bochs dump saying you're in real mode (heck 66 50 == push AX in PMode)
Could you make sure that the dump is from the correct place, and I also suggest putting in some magic breaks and then single-stepping until it crashes.
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Global Descriptor Table Issues

Post by neon »

His bochs log is probably right after a triple fault. cs:eip seems to indicate its in the BIOS. cr0.pm bit is 0 so its a clear indication that you are in real mode at the time you took the bochs log. Please repost it.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
cjhawley
Posts: 7
Joined: Tue Jan 19, 2010 3:32 pm

Re: Global Descriptor Table Issues

Post by cjhawley »

Apologies,

Code: Select all

Booting from 0000:7c00
00051033458i[BIOS ] int13_harddisk: function 41, unmapped device for ELDL=80
00051038235i[BIOS ] int13_harddisk: function 08, unmapped device for ELDL=80
00051042888i[BIOS ] *** int 15h function AX=00c0, BX=0000 not yet supported!
00056846830e[CPU0 ] load_seg_reg(DS, 0x0010): invalid segment
00056846830e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00056846830e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00056846830i[CPU0 ] CPU is in protected mode (active)
00056846830i[CPU0 ] CS.d_b = 32 bit
00056846830i[CPU0 ] SS.d_b = 32 bit
00056846830i[CPU0 ] EFER   = 0x00000000
00056846830i[CPU0 ] | RAX=0000000000000010  RBX=000000000002d000
00056846830i[CPU0 ] | RCX=0000000000000002  RDX=00000000000003d5
00056846830i[CPU0 ] | RSP=0000000000067e7c  RBP=0000000000067ea8
00056846830i[CPU0 ] | RSI=0000000000053c99  RDI=0000000000053c9a
00056846830i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00056846830i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00056846830i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00056846830i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00056846830i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf ZF af PF cf
00056846830i[CPU0 ] | SEG selector     base    limit G D
00056846830i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00056846830i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00056846830i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00056846830i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00056846830i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00056846830i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00056846830i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00056846830i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00056846830i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00056846830i[CPU0 ] | RIP=000000000010002b (000000000010002b)
00056846830i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000
00056846830i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00056846830i[CPU0 ] 0x000000000010002b>> mov ds, ax : 8ED8
00056846830e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
EDIT: nasm 2.05.01, ld 2.20, gcc 4.41
User avatar
thepowersgang
Member
Member
Posts: 734
Joined: Tue Dec 25, 2007 6:03 am
Libera.chat IRC: thePowersGang
Location: Perth, Western Australia
Contact:

Re: Global Descriptor Table Issues

Post by thepowersgang »

Ok, break into the debugger just after the LGDT and do "info gdt" and show us the result.
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
cjhawley
Posts: 7
Joined: Tue Jan 19, 2010 3:32 pm

Re: Global Descriptor Table Issues

Post by cjhawley »

I use GDB to debug with qemu (more simple I think) and I do not have the option 'info gdt' but here is a register dump:

Code: Select all

eax            0xe	14
ecx            0x2	2
edx            0x3d5	981
ebx            0x2d000	184320
esp            0x67e7c	0x67e7c
ebp            0x67ea8	0x67ea8
esi            0x53cb1	343217
edi            0x53cb2	343218
eip            0x100020	0x100020 <gdt_flush2>
eflags         0x46	[ PF ZF ]
cs             0x8	8
ss             0x10	16
ds             0x10	16
es             0x10	16
fs             0x10	16
gs             0x10	16
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Global Descriptor Table Issues

Post by neon »

The value of GDTR might give us some info. If I was to guess id suspect that either the GDT is invalid or gdt_ptr_struct points to an invalid structure or invalid address. You can find out if its pointing to your GDTR structure by debugging. Else posting your structures and more code might help.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
cjhawley
Posts: 7
Joined: Tue Jan 19, 2010 3:32 pm

Re: Global Descriptor Table Issues

Post by cjhawley »

Code: Select all

typedef struct gdt_entry gdt_entry;
struct gdt_entry {
	unsigned short low_limit;
	unsigned short low_base;
	unsigned char middle_base;
	unsigned char high_base;
	unsigned char access;
	unsigned char gran;
}__attribute__((packed));

typedef struct gdt_ptr gdt_ptr;
struct gdt_ptr {
	unsigned short limit;
	unsigned int base;
}__attribute__((packed));

gdt_entry gdt_struct[3];
gdt_ptr gdt_ptr_struct;

Code: Select all

gdt_set_gate(0,0,0,0,0);
	gdt_set_gate(1,0,0,0,0);
	gdt_set_gate(2,0,0,0,0);

	gdt_ptr_struct.limit = (sizeof(gdt_entry) * 3) - 1;
	gdt_ptr_struct.base = &gdt_struct;

	
	gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
	gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
As you can see I really am just following the tutorial.
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Global Descriptor Table Issues

Post by neon »

Use Bochs and do what was suggested earlier. With Bochs debugger, break right after the ldgt and do info gdt 0 4 and post the results here.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
cjhawley
Posts: 7
Joined: Tue Jan 19, 2010 3:32 pm

Re: Global Descriptor Table Issues

Post by cjhawley »

Here it is:

Code: Select all

Global Descriptor Table (base=0x00000000, limit=65535):
GDT[0x00]=Code segment, base=0xf053f000, limit=0x0000ff53, Execute/Read, Conforming, Accessed, 16-bit
GDT[0x01]=Code segment, base=0xf053f000, limit=0x0000ff53, Execute/Read, Conforming, Accessed, 16-bit
GDT[0x02]=Code segment, base=0xf053f000, limit=0x0000ff53, Execute/Read, Conforming, Accessed, 16-bit
GDT[0x03]=Code segment, base=0xf053f000, limit=0x0000ff53, Execute/Read, Conforming, Accessed, 16-bit
GDT[0x04]=32-Bit TSS (Available) at 0xf087f000, length 0x0fea5
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Global Descriptor Table Issues

Post by Brendan »

Hi,
cjhawley wrote:

Code: Select all

Global Descriptor Table (base=0x00000000, limit=65535):
GDT[0x00]=Code segment, base=0xf053f000, limit=0x0000ff53, Execute/Read, Conforming, Accessed, 16-bit
GDT[0x01]=Code segment, base=0xf053f000, limit=0x0000ff53, Execute/Read, Conforming, Accessed, 16-bit
GDT[0x02]=Code segment, base=0xf053f000, limit=0x0000ff53, Execute/Read, Conforming, Accessed, 16-bit
GDT[0x03]=Code segment, base=0xf053f000, limit=0x0000ff53, Execute/Read, Conforming, Accessed, 16-bit
GDT[0x04]=32-Bit TSS (Available) at 0xf087f000, length 0x0fea5
The CPU thinks that the GDT is at 0x00000000, and the descriptor entries look like they contain values left over from the real mode IVT. Either the GDT isn't at 0x00000000 (and your "gdt_ptr" is wrong), or the GDT is meant to be at 0x00000000 but you forgot to copy or create the GDT at this address.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
computafreak
Member
Member
Posts: 76
Joined: Sun Dec 14, 2008 1:53 pm

Re: Global Descriptor Table Issues

Post by computafreak »

Are you passing a pointer to the GDT? If you're just passing the GDT itself, LGDT will load the null descriptor as if it's an address. My assembly stub does pretty much the same as yours and I call it like so:

Code: Select all

loadGDT(&gdtPointer)
cjhawley
Posts: 7
Joined: Tue Jan 19, 2010 3:32 pm

Re: Global Descriptor Table Issues

Post by cjhawley »

Yes, that is how I am calling it now.

Code: Select all

gdt_flush2((unsigned int)&gdt_ptr_struct);
I changed my asm code to grab the parameter.
I also moved my instantiation of my pointer and my gdt structure into the gdt C file instead of keeping them in my header file.
It now crashes at the mov ss, ax

Huh, cool.
Post Reply