another triple fault loading the GDT!

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.
Post Reply
niteice
Member
Member
Posts: 59
Joined: Tue Oct 03, 2006 3:49 pm

another triple fault loading the GDT!

Post by niteice »

For what's probably the 5th thread in the same number of weeks...

I'm restarting my kernel (again) and following JamesM's guide so I can get up to speed quickly. I get a triple fault when I load my new GDT:

Code: Select all

DT_LoadGDT:
	mov		4(%esp),	%eax	// put gdt pointer in eax
	lgdt	(%eax)

	mov		$0x10,	%ax
	mov		%ax,	%ds
	mov		%ax,	%es
	mov		%ax,	%fs
	mov		%ax,	%gs
	mov		%ax,	%ss

	// jump into the new code segment
	ljmp	$0x08,$.flush
.flush:
	ret
to which Bochs tells me:

Code: Select all

00061636687e[CPU0 ] fetch_raw_descriptor: GDT: index (17)2 > limit (0)
00061636687i[CPU0 ] CPU is in protected mode (active)                 
00061636687i[CPU0 ] CS.d_b = 32 bit                                   
00061636687i[CPU0 ] SS.d_b = 32 bit                                   
00061636687i[CPU0 ] EFER   = 0x00000000                               
00061636687i[CPU0 ] | RAX=0000000000100010  RBX=000000000002bdc0
00061636687i[CPU0 ] | RCX=00000000000000ff  RDX=0000000000000002
00061636687i[CPU0 ] | RSP=0000000000109fcc  RBP=0000000000109fe8
00061636687i[CPU0 ] | RSI=000000000002bf2e  RDI=000000000002bf33
00061636687i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00061636687i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00061636687i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00061636687i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00061636687i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af pf cf
00061636687i[CPU0 ] | SEG selector     base    limit G D
00061636687i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00061636687i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 1 1
00061636687i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00061636687i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00061636687i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 1 1
00061636687i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00061636687i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 1 1
00061636687i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00061636687i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00061636687i[CPU0 ] | RIP=0000000000100a77 (0000000000100a77)
00061636687i[CPU0 ] | CR0=0x00000011 CR1=0x0 CR2=0x0000000000000000
00061636687i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00061636687i[CPU0 ] >> mov ds, ax : 8ED8
00061636687e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
I've noticed that whichever order I put the segments in, it will always error on the instruction immediately after mov 0x10, %ax.

My GDT is defined as:

Code: Select all

extern void DT_LoadGDT(uint32_t gdt);

#define NUM_GDT_ENTRIES 3

typedef struct
{
	uint16_t lowLimit;
	uint16_t lowBase;
	uint8_t middleBase;
	uint8_t access;
	uint8_t granularity;
	uint8_t highBase;
} __attribute__((packed)) gdtEntry_t;

static gdtEntry_t gdtEntries[NUM_GDT_ENTRIES];

typedef struct
{
	uint16_t limit;
	uint32_t base;
} __attribute__((packed)) gdt_t;

static gdt_t gdt;

static void gdtSet(int32_t i, uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity)
{
	memset(&gdtEntries, 0, sizeof(gdtEntries) * 5);

	gdtEntries[i].lowBase = base & 0xffff;
	gdtEntries[i].middleBase = (base >> 16) & 0xff;
	gdtEntries[i].highBase = (base >> 24) & 0xff;

	gdtEntries[i].lowLimit = limit & 0xffff;
	gdtEntries[i].granularity = (limit >> 16) & 0xffff;

	gdtEntries[i].granularity |= granularity & 0xf0;
	gdtEntries[i].access = access;
}

gdt.limit = (sizeof(gdtEntry_t) * NUM_GDT_ENTRIES) - 1;
gdt.base = (uint32_t)&gdtEntries;

gdtSet(0, 0, 0, 0, 0);	/* null segment */
gdtSet(1, 0, 0xffffffff, 0x9a, 0xcf);	/* code segment */
gdtSet(2, 0, 0xffffffff, 0x92, 0xcf);	/* data segment */
DT_LoadGDT((uint32_t)&gdt);
Sorry for being repetitive, but it's quite frustrating to be stuck at something that seems so simple.

Thanks for any help.
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: another triple fault loading the GDT!

Post by AJ »

Hi,

Are you sure that ESP+4 contains your GDT pointer? The reason for the triple fault is that the CPU thinks the GDT is zero-sized. I can't tell you whether or not you are accessing the correct parameter in DT_LoadGDT because I'm not familiar with AT&T syntax. If you put a jmp $ just before LGDT, you can check whether eax really does contain a pointer to your GDT information structure.

Also, this may not matter for now, but isn't it more usual to set CS (via the far jump) before loading the data segments? It may also be worth checking the value of DS prior to LGDT, because IIRC, LGDT actually loads from ds:[eax].

Cheers,
Adam
niteice
Member
Member
Posts: 59
Joined: Tue Oct 03, 2006 3:49 pm

Re: another triple fault loading the GDT!

Post by niteice »

The disassembly checks out:

Code: Select all

                DT_LoadGDT((uint32_t)&gdt);
  100564:       b8 58 a0 10 00          mov    $0x10a058,%eax
  100569:       89 04 24                mov    %eax,(%esp)
  10056c:       e8 fb 04 00 00          call   100a6c <DT_LoadGDT>
call pushes eip (4 bytes), so it seems to be the right idea.
niteice
Member
Member
Posts: 59
Joined: Tue Oct 03, 2006 3:49 pm

Re: another triple fault loading the GDT!

Post by niteice »

Alright, I triple fault at either:

Code: Select all

mov		%ax,	%ds
if I put that first or

Code: Select all

jmp	$0x08,$.flush
if I put that first.
System123
Member
Member
Posts: 196
Joined: Mon Jul 07, 2008 1:25 am

Re: another triple fault loading the GDT!

Post by System123 »

I get the same triple faults. I managed to get rid of the mov ds, ax fault by changin it to mov ds, eax.
Gizmic OS
Currently - Busy with FAT12 driver and VFS
niteice
Member
Member
Posts: 59
Joined: Tue Oct 03, 2006 3:49 pm

Re: another triple fault loading the GDT!

Post by niteice »

It assembles to the same code. :|
System123
Member
Member
Posts: 196
Joined: Mon Jul 07, 2008 1:25 am

Re: another triple fault loading the GDT!

Post by System123 »

:S strange because it didn't fault when I did that :S
Gizmic OS
Currently - Busy with FAT12 driver and VFS
niteice
Member
Member
Posts: 59
Joined: Tue Oct 03, 2006 3:49 pm

Re: another triple fault loading the GDT!

Post by niteice »

So I would assume that my GDT is being initialized wrong. There's not really a lot of information on constructing one outside of declaring the raw bytes in an assembly directive though :|
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Re: another triple fault loading the GDT!

Post by AJ »

Hi,
So I would assume that my GDT is being initialized wrong. There's not really a lot of information on constructing one outside of declaring the raw bytes in an assembly directive though
Have a look at the GDT descriptors in the Intel manuals and http://www.sandpile.org/. These are not assembly specific and if you understand the documentation, you should be able to consturct a GDT in the language of your choice.

Cheers,
Adam
niteice
Member
Member
Posts: 59
Joined: Tue Oct 03, 2006 3:49 pm

Re: another triple fault loading the GDT!

Post by niteice »

Alright, I actually managed to load a working GDT! I actually ended up using the one from OpenBSD:

Code: Select all

static gdtEntry_t gdtEntries[NUM_GDT_ENTRIES] =
{
	{ 0, 0, 0, 0, 0, 0 },	// 0: null limit
	{
		0xffff,
		0,
		0,
		31 | 0 | 0x80,
		0xf | 0 | 0x40 | 0x80,
		0
	},
	{
		0xffff,
		0,
		0,
		19 | 0 | 0x80,
		0xf | 0 | 0x40 | 0x80,
		0
	}
};
Perhaps not the best way to do things but it seems to load fine.
Post Reply