GDT 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.
FusT
Member
Member
Posts: 91
Joined: Wed Sep 19, 2012 3:43 am
Location: The Netherlands

GDT issues

Post by FusT »

Hi everyone,

I know this is somewhat of a noob question but it's been driving me insane for a day and can't seem to firgure out what the problem is.
I'm trying to load my GDT but it crashes while updating the segment registers (SS to be specific).
Also, when examining the bochs output something strange cought my eye: The base and limit are both at 0xffffffff? Hmm. that can't be right....

The GDT structs (gdt.h):

Code: Select all

struct gdt_entry {
        uint16_t limit_low;
        uint16_t base_low;
        uint8_t base_middle;
        uint8_t access;
        uint8_t flags;
        uint8_t base_high;
} __attribute__ ((packed));
typedef struct gdt_entry gdt_entry_t;

struct gdt_ptr {
        uint16_t limit;
        uint32_t base;
} __attribute__ ((packed));
typedef struct gdt_ptr gdt_ptr_t;
gdt.c:

Code: Select all

#include "gdt.h"
extern void gdt_flush(uint32_t);

static void gdt_set_gate(int32_t, uint32_t, uint32_t, uint8_t, uint8_t);

gdt_entry_t gdt_entries[5];
gdt_ptr_t gdt;

void init_gdt()
{
        gdt.limit = (sizeof(gdt_entry_t) * 5) - 1;
        gdt.base = (uint32_t)&gdt_entries;

        gdt_set_gate(0, 0, 0, 0, 0);
        gdt_set_gate(1, 0x40000000, 0xFFFFFFFF, 0x9A, 0xCF);
        gdt_set_gate(2, 0x40000000, 0xFFFFFFFF, 0x92, 0xCF);
        gdt_set_gate(3, 0x40000000, 0xFFFFFFFF, 0xFA, 0xCF);
        gdt_set_gate(4, 0x40000000, 0xFFFFFFFF, 0xF2, 0xCF);

        gdt_flush((uint32_t)&gdt);
}

static void gdt_set_gate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
{
        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].flags = (limit >> 16) & 0x0F;

        gdt_entries[num].flags |= flags & 0xF0;
        gdt_entries[num].access = access;
}
the relevant code from interrupts.s:

Code: Select all

[GLOBAL gdt_flush]
gdt_flush:
        mov eax, [esp+4]
        lgdt [eax]

        mov ax, 0x10
        mov ds, ax
        mov es, ax
        mov fs, ax
        mov gs, ax
        mov ss, ax         ; Crashes here
        jmp 0x08:.flush2

.flush2:
        ret
And the relevant part from bochsout.txt:

Code: Select all

00670455802p[CPU0 ] >>PANIC<< exception(): 3rd (13) exception with no resolution
00670455802i[CPU0 ] CPU is in protected mode (active)
00670455802i[CPU0 ] CS.d_b = 32 bit
00670455802i[CPU0 ] SS.d_b = 32 bit
00670455802i[CPU0 ] EFER   = 0x00000000
00670455802i[CPU0 ] | RAX=0000000000100010  RBX=000000000002d000
00670455802i[CPU0 ] | RCX=0000000000000004  RDX=0000000000102f90
00670455802i[CPU0 ] | RSP=0000000000067e60  RBP=0000000000067e8c
00670455802i[CPU0 ] | RSI=0000000000053c9d  RDI=0000000000053c9e
00670455802i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00670455802i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00670455802i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00670455802i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00670455802i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00670455802i[CPU0 ] | SEG selector     base    limit G D
00670455802i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00670455802i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00670455802i[CPU0 ] |  DS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00670455802i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00670455802i[CPU0 ] |  ES:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00670455802i[CPU0 ] |  FS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00670455802i[CPU0 ] |  GS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00670455802i[CPU0 ] |  MSR_FS_BASE:00000000ffffffff
00670455802i[CPU0 ] |  MSR_GS_BASE:00000000ffffffff
00670455802i[CPU0 ] | RIP=00000000001007cb (00000000001007cb)
00670455802i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000
00670455802i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00670455802i[CPU0 ] 0x00000000001007cb>> mov ss, ax : 8ED0
00670455802i[CMOS ] Last time is 1405492339 (Wed Jul 16 08:32:19 2014)
00670455802i[     ] restoring default signal behavior
00670455802i[CTRL ] quit_sim called with exit code 1
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GDT issues

Post by Combuster »

And the relevant part from bochsout.txt:
I'm missing the preceding 3-4 lines
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
FusT
Member
Member
Posts: 91
Joined: Wed Sep 19, 2012 3:43 am
Location: The Netherlands

Re: GDT issues

Post by FusT »

Now that you mention it, something else caught my eye (guess I was overlooking it). Bouchsout contains two dumps.
Here's the preceding few lines:

Code: Select all

00670455802e[CPU0 ] load_seg_reg(SS): not writable data segment
00670455802e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00670455802e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00670455802i[CPU0 ] CPU is in protected mode (active)
00670455802i[CPU0 ] CS.d_b = 32 bit
00670455802i[CPU0 ] SS.d_b = 32 bit
00670455802i[CPU0 ] EFER   = 0x00000000
00670455802i[CPU0 ] | RAX=0000000000100010  RBX=000000000002d000
00670455802i[CPU0 ] | RCX=0000000000000004  RDX=0000000000102f90
00670455802i[CPU0 ] | RSP=0000000000067e60  RBP=0000000000067e8c
00670455802i[CPU0 ] | RSI=0000000000053c9d  RDI=0000000000053c9e
00670455802i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00670455802i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00670455802i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00670455802i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00670455802i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00670455802i[CPU0 ] | SEG selector     base    limit G D
00670455802i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00670455802i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00670455802i[CPU0 ] |  DS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00670455802i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00670455802i[CPU0 ] |  ES:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00670455802i[CPU0 ] |  FS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00670455802i[CPU0 ] |  GS:0010( 0002| 0|  0) ffffffff ffffffff 1 1
00670455802i[CPU0 ] |  MSR_FS_BASE:00000000ffffffff
00670455802i[CPU0 ] |  MSR_GS_BASE:00000000ffffffff
00670455802i[CPU0 ] | RIP=00000000001007cb (00000000001007cb)
00670455802i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000
00670455802i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00670455802i[CPU0 ] 0x00000000001007cb>> mov ss, ax : 8ED0
Hmm. That indeed gives some more information, still not entirely sure what it means though.

Edit: Actually, I know exactly what it means but i'm not sure what's causing it...
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GDT issues

Post by Combuster »

I suspect you're using the GDT trick, and you're giving the CPU the virtual GDT address rather than the physical one.

And in bochs, non-present physical memory gives all ones.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: GDT issues

Post by Waszka »

What does

Code: Select all

info gdt
in bochs show you?
FusT
Member
Member
Posts: 91
Joined: Wed Sep 19, 2012 3:43 am
Location: The Netherlands

Re: GDT issues

Post by FusT »

Took a while as Ubuntu does not have bochs internal debugger by default, but here it is:
Output of info gdt:

Code: Select all

Global Descriptor Table (base=0x00009108, limit=39):
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x0000fff0
GDT[0x01]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
GDT[0x02]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
GDT[0x03]=Code segment, base=0x00000000, limit=0x0000ffff, Execute/Read, Conforming, Accessed, 16-bit
GDT[0x04]=Data segment, base=0x00000000, limit=0x0000ffff, Read/Write, Accessed
Oh and @combuster: Nope, not using the GDT trick. I'm booting directly from GRUB.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: GDT issues

Post by jnc100 »

Is that the output of 'info gdt' _after_ lgdt? I ask because its base address is 0x9108 whereas your code is executing above the 1 MiB mark making me think it is your bootloaders gdt rather that that set up in your kernel.

Regards,
John.
FusT
Member
Member
Posts: 91
Joined: Wed Sep 19, 2012 3:43 am
Location: The Netherlands

Re: GDT issues

Post by FusT »

Ah, you're right. I set the breakpoint wrong, my bad.
When I break right at the line that causes the triple fault i get this from info gdt:
Global Descriptor Table (base=0x2f600000, limit=59):
bx_dbg_read_linear: physical memory read error (phy=0x00002f600000, lin=0x2f600000)
error: GDTR+8*0 points to invalid linear address 0x2f600000
bx_dbg_read_linear: physical memory read error (phy=0x00002f600008, lin=0x2f600008)
error: GDTR+8*1 points to invalid linear address 0x2f600000
bx_dbg_read_linear: physical memory read error (phy=0x00002f600010, lin=0x2f600010)
error: GDTR+8*2 points to invalid linear address 0x2f600000
bx_dbg_read_linear: physical memory read error (phy=0x00002f600018, lin=0x2f600018)
error: GDTR+8*3 points to invalid linear address 0x2f600000
bx_dbg_read_linear: physical memory read error (phy=0x00002f600020, lin=0x2f600020)
error: GDTR+8*4 points to invalid linear address 0x2f600000
bx_dbg_read_linear: physical memory read error (phy=0x00002f600028, lin=0x2f600028)
error: GDTR+8*5 points to invalid linear address 0x2f600000
bx_dbg_read_linear: physical memory read error (phy=0x00002f600030, lin=0x2f600030)
error: GDTR+8*6 points to invalid linear address 0x2f600000
You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'
Guess this is pretty noob but I'm a bit lost atm. :roll:
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GDT issues

Post by Combuster »

Well since you have a working debugger now, try to find the source of

Code: Select all

base=0x2f600000
It's taken from your GDTR structure by LGDT. You might even find that 00 00 60 2f somewhere in your binary with other tools.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
Waszka
Member
Member
Posts: 38
Joined: Tue Apr 22, 2014 11:30 am
Location: Poland

Re: GDT issues

Post by Waszka »

Just to be sure: do you use cross-compiler? I had similar problems with IDT because of not using one.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: GDT issues

Post by jnc100 »

So lgdt is being given a bogus address for your GDT (0x2f600000). You can check the actual address of the 'gdt_entries' structures by running nm on your binary. If they are different then I'd imagine the problem lies with your assembler code expecting the SysV ABI i386 calling convention whereas your compiler is not honouring this.

Regards,
John.
FusT
Member
Member
Posts: 91
Joined: Wed Sep 19, 2012 3:43 am
Location: The Netherlands

Re: GDT issues

Post by FusT »

@Waszka: Yes, i'm sure i'm using a cross compiler. I followed JamesM's tutorial using the very same compiler (built using the wiki) and decided it was time to stop copy-pasting and roll my own kernel.
@John: Thanks for the tip!
I'll post the results of nm as i have no clue what exactly is going wrong and how to fix it.

Code: Select all

$ nm kernel.bin | grep gdt_entries
00102f60 B gdt_entries
This seems to suggest that highest byte (or 2 bytes, if you're counting zeros) of the address being passed to lgdt is missing. Strange, as the JamesM tutorials use almost the exact same code and seem to run fine.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: GDT issues

Post by jnc100 »

Your compiler seems to be not acknowledging the packed attribute. It is loading the address of gdt_entries to the 4th through 7th bytes of gdt_ptr_t (rather than 2nd through 5th), and in addition it seems to think each gdt_entry_t is 12 bytes long (as evidenced by the GDTR limit being 59 rather than 39).

Exactly which cross compiler are you using, and how are you calling it?

Regards,
John.
FusT
Member
Member
Posts: 91
Joined: Wed Sep 19, 2012 3:43 am
Location: The Netherlands

Re: GDT issues

Post by FusT »

Ok, that makes sense. The though that is was an alignment issue did cross my mind.
I use the cross-compiler built using the wiki: http://wiki.osdev.org/GCC_Cross-Compiler
It's GCC version i586-elf-gcc (GCC) 4.8.2
It's called from a Makefile, this is the relevant section:

Code: Select all

INCLUDES = ./include

CC      = i586-elf-gcc
CFLAGS  = -Wall -Wextra -nostdlib -fno-builtin -nostartfiles -nodefaultlibs -I $(INCLUDES)
LD      = i586-elf-ld


OBJFILES = idt.o gdt.o asm/interrupts.o video/video.o string.o boot.o kernel.o

all: kernel.img

.s.o:
        nasm -f elf -o $@ $<

.c.o:
        $(CC) $(CFLAGS) -o $@ -c $<

kernel.bin: $(OBJFILES)
        $(LD) -T linker.ld -o $@ $^
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: GDT issues

Post by jnc100 »

This is indeed odd as that should work. Could you post a disassembly of the init_gdt function produced by i586-elf-objdump -drS gdt.o?

Regards,
John.
Post Reply