GDT troubles ...again

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.
mmiikkee12
Member
Member
Posts: 38
Joined: Sat Jun 03, 2006 11:00 pm

GDT troubles ...again

Post by mmiikkee12 »

OK, so I realized a few mistakes with my past projects and decided to start on a new one, being careful not to make any of those mistakes again. I got some basic printf stuff working, but the GDT is still giving me problems. Bochs gives me some errors about valid bits and interrupts:
00017461598e[CPU0 ] load_seg_reg(DS): valid bit cleared
00017461598e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00017461598e[CPU0 ] interrupt(): gate descriptor is not valid sys seg
00017461598i[CPU0 ] protected mode
00017461598i[CPU0 ] CS.d_b = 32 bit
00017461598i[CPU0 ] SS.d_b = 32 bit
00017461598i[CPU0 ] | EAX=00000010 EBX=00103004 ECX=00000002 EDX=00000002
00017461598i[CPU0 ] | ESP=0010afac EBP=0010afd8 ESI=000247d8 EDI=00030658
00017461598i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00017461598i[CPU0 ] | SEG selector base limit G D
00017461598i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00017461598i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00017461598i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00017461598i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00017461598i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00017461598i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00017461598i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00017461598i[CPU0 ] | EIP=00100066 (00100066)
00017461598i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00017461598i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00017461598i[CPU0 ] >> mov ds, ax : 8ED8
00017461598e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting


So I wrote a quick function to dump a segment descriptor, and came up with:
Segment 0: base 00000000, limit 00000000, accessed 0, writable 0, direction 0, exec 0, sys 1, dpl 0, present 1, bitness 1, granularity 1.
Raw: 00 00 00 00 00 90 c0 00
Segment 1: base 00000000, limit 000fffff, accessed 0, writable 1 [this is my code segment so I think this is "conforming" or something instead, but my dump function doesn't know the difference.], direction 0, exec 1, sys 1, dpl 0, present 1, bitness 1, granularity 1.
Raw: ff ff 00 00 00 9a cf 00
Segment 2: base 00000000, limit 000fffff, accessed 0, writable 1, direction 0, exec 0, sys 1, dpl 0, present 1, bitness 1, granularity 1.
Raw: ff ff 00 00 00 92 cf 00

Anything obvious I'm missing here? I don't see a bit called "valid" in the manual, is that referring to something else? (present is set on all of them.)

Thanks.
Pyrofan1
Member
Member
Posts: 234
Joined: Sun Apr 29, 2007 1:13 am

Post by Pyrofan1 »

from what i can tell, you're causing a GPF by writing invalid entries to the GDT.
mmiikkee12
Member
Member
Posts: 38
Joined: Sat Jun 03, 2006 11:00 pm

Post by mmiikkee12 »

What's invalid about them though? I even printed out the contents to be sure. Is my structure in the wrong order or something?

Code: Select all

   typedef struct __attribute__((packed))
   {
      uint_16 limit_low;
      uint_32 base_low:24;
      uint_8 accessed:1;
      uint_8 writable:1;
      uint_8 direction:1;
      uint_8 exec:1;
      uint_8 sys:1;
      uint_8 dpl:2;
      uint_8 present:1;
      uint_8 limit_high:4;
      uint_8 unused:2;
      uint_8 thirty_two_bit:1;
      uint_8 granularity:1;
      uint_8 base_high;
   } entry_t;
   
   typedef struct __attribute__((packed))
   {
      uint_32 base;
      uint_32 limit;
   } gdtr_t;
mmiikkee12
Member
Member
Posts: 38
Joined: Sat Jun 03, 2006 11:00 pm

Post by mmiikkee12 »

Poke. ("Bump" is such a cliche...)

I also noticed that in QEMU most of the time it will just lock up after selecting my OS in GRUB. Is this a related problem?
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

Maybe you should try setting a breakpoint in bochs to the location just where the problem starts and try examining the GDT.

Code: Select all

info gdt 0 5
mmiikkee12
Member
Member
Posts: 38
Joined: Sat Jun 03, 2006 11:00 pm

Post by mmiikkee12 »

My GDT is only 3 entries long. Anyway, I could only get Bochs to enter the debugger *after* the CPU reset, so the GDT and all registers were reset also.

Looking around on the forums, I found http://www.osdev.org/phpBB2/viewtopic.php?t=14542&postdays=0&postorder=asc&highlight=fetchrawdescriptor&start=0
This suggested that I was supposed to make cs the first segment I reloaded instead of the last. But this:

Code: Select all

extern gdtr
global gdt_flush
gdt_flush:
   mov eax, [esp+4]
   lgdt [eax]
   jmp 0x08:.finish_reload
.finish_reload:
   mov eax, 0x10
   mov ds, eax
   mov es, eax
   mov fs, eax
   mov gs, eax
   mov ss, eax
   ret

also didn't work:
00017057497e[CPU0 ] jump_protected: call gate.p == 0
00017057497e[CPU0 ] fetch_raw_descriptor: GDT: index (f007)1e00 > limit (b020)


Taking another hint from that post I checked the versions of my toolchain, all stable afaik:
[mike@thiscomputer ~]$ nasm -v
NASM version 0.98.39 compiled on Mar 1 2005
[mike@thiscomputer ~]$ g++ -v
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ../configure --prefix=/usr --enable-shared --enable-languages=c,c++,objc --enable-threads=posix --enable-__cxa_atexit --disable-multilib --libdir=/usr/lib --libexecdir=/usr/lib --enable-clocale=gnu --disable-libstdcxx-pch --with-tune=generic
Thread model: posix
gcc version 4.2.1
[mike@thiscomputer ~]$ ld -v
GNU ld version 2.17.50.0.18 20070731
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

Okay the following method may not be supported on your particular BOCHs version but this is how I would do it. With a thing known as Magic Breakpoints. All you have to do is put a xchg bx, bx where you want to debugger to stop at and edit the config file to say magic_break: enabled=1 somewhere in it.

The other way would be to use

Code: Select all

mov ecx, 0
breakpoint:
cmp ecx, 0
    je breakpoint


and jump to the debugger when it locks up and type set ecx = 1 and then continue from there.
mmiikkee12
Member
Member
Posts: 38
Joined: Sat Jun 03, 2006 11:00 pm

Post by mmiikkee12 »

00022852647i[CPU0 ] [22852647] Stopped on MAGIC BREAKPOINT

Nice, it works. Gotta love black magic (although I suppose it could be another color if I decided to change my Konsole background.)

I put one here:

Code: Select all

gdt_flush:
   mov eax, [esp+4]
   lgdt [eax]
   xchg bx, bx
   jmp 0x08:.finish_reload
.finish_reload:

and got this:
<bochs:4> info gdt 0 2
Global Descriptor Table (base=0x00170010, limit=45088):
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x01]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x02]=??? descriptor hi=0x00000000, lo=0x00000000


So something is corrupting GDTR. (I know a 3-entry GDT is less than 45008 bytes.) The limit is also wrong (last symbol in objdump -S ends at 0x101aea)

-----

OK, just realized I had gdtr_t not only in the wrong order, but I made both base and limit uint_32's. So, now:

Code: Select all

   typedef struct __attribute__((packed))
   {
      uint_16 limit_low;
      uint_32 base_low:24;
      uint_8 type:4;
      uint_8 system:1;
      uint_8 dpl:2;
      uint_8 present:1;
      uint_8 limit_high:4;
      uint_8 unused:2;
      uint_8 bitness:1;
      uint_8 granularity:1;
      uint_8 base_high;
   } entry_t;
   
   typedef struct __attribute__((packed))
   {
      uint_16 limit;
      uint_32 base;
   } gdtr_t;


And running this produces:
00021334899i[CPU0 ] [21334899] Stopped on MAGIC BREAKPOINT
(0) Magic breakpoint
Next at t=21334899
(0) [0x00100064] 0008:00100064 (unk. ctxt): jmp far 0008:0010006b ; ea6b0010000800
<bochs:2> info gdt 0 2
Global Descriptor Table (base=0x00000017, limit=45088):
GDT[0x00]=Data segment, linearaddr=00f000ff, limit=f53f0 * 4Kbytes, Read/Write, Accessed
GDT[0x01]=16-Bit Trap Gate target=0x00fe:0x00e9a5f0, DPL=0
GDT[0x02]=Data segment, linearaddr=00f000ff, limit=f53f0 * 4Kbytes, Read/Write, Accessed


I was planning on waiting until I have all my current code working before importing it into a SVN repo. Should I do that now so you can see my code?
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

Are you sure you are filling the structure out? The data doesn't even seem to change when you change to size of the structure. Also can you post the function that is supposed to fill out the GDTR structure?
mmiikkee12
Member
Member
Posts: 38
Joined: Sat Jun 03, 2006 11:00 pm

Post by mmiikkee12 »

I had this:

Code: Select all

   entry_t gdt[3];
extern "C" gdtr_t gdtr = { (uint_32)&gdt[0], sizeof(gdt) - 1 };

(These are global variables btw, not declared in a function.)

But I started wondering why I had it declared as extern "C", removed that, and got this:
<bochs:3> info gdt 0 2
Global Descriptor Table (base=0x00000017, limit=45088):
GDT[0x00]=Data segment, linearaddr=00f000ff, limit=f53f0 * 4Kbytes, Read/Write, Accessed
GDT[0x01]=16-Bit Trap Gate target=0x00fe:0x00e9a5f0, DPL=0
GDT[0x02]=Data segment, linearaddr=00f000ff, limit=f53f0 * 4Kbytes, Read/Write, Accessed
<bochs:4> c
00018291036e[CPU0 ] jump_protected: gate type 7 unsupported
00018291036i[CPU0 ] protected mode
00018291036i[CPU0 ] CS.d_b = 32 bit
00018291036i[CPU0 ] SS.d_b = 32 bit
00018291036i[CPU0 ] | EAX=00103008 EBX=00103008 ECX=00000000 EDX=000003d5
00018291036i[CPU0 ] | ESP=0010afac EBP=0010afd8 ESI=000247d8 EDI=00030658
00018291036i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00018291036i[CPU0 ] | SEG selector base limit G D
00018291036i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00018291036i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00018291036i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00018291036i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00018291036i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00018291036i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00018291036i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00018291036i[CPU0 ] | EIP=00100064 (00100064)
00018291036i[CPU0 ] | CR0=0x00000011 CR1=0 CR2=0x00000000
00018291036i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00018291036i[CPU0 ] >> jmp far 0008:0010006b : EA6B0010000800
00018291036e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00018291036i[SYS ] bx_pc_system_c::Reset(SOFTWARE) called
00018291036i[APIC0] local apic in CPU 0 initializing
00018291036e[CPU0 ] CPU_LOOP bx_guard.interrupt_requested=1
Next at t=18291036
(0) [0x00100064] 0008:100064 (unk. ctxt): jmp far 0008:0010006b ; ea6b0010000800


Gate type 7? Um... why is it doing anything involving gates?
frank
Member
Member
Posts: 729
Joined: Sat Dec 30, 2006 2:31 pm
Location: East Coast, USA

Post by frank »

I don't know this will help but try filling it out in a function.

Code: Select all

void Init_GDTR( void )
{
   gdtr.limit = sizeof( gdt );
   gdtr.base = &gdt[0];

}


Well all of the errors are because either the GDTR is filled out incorrectly (just look at the base and limit in the bochs output) or the pointer that is passed to flush_gdt is incorrect.
mmiikkee12
Member
Member
Posts: 38
Joined: Sat Jun 03, 2006 11:00 pm

Post by mmiikkee12 »

Still the gate type 7 message.

I'm going to take a short (couple of hours) break from OSDev for a few hours to do some web coding (for my OS's website of course :-), but please feel free to try to tell me wtf is going on :-)
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven
Contact:

Post by Candy »

mmiikkee12 wrote:I was planning on waiting until I have all my current code working before importing it into a SVN repo. Should I do that now so you can see my code?


It's advisable to check into a svn / cvs / something repo ASAP after you get one more feature working. You wouldn't be the first to have the just-not-working product remove half its source.
User avatar
AndrewAPrice
Member
Member
Posts: 2294
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post by AndrewAPrice »

mmiikkee12 wrote:Poke.


I would have used pop. But then that'd mean all other threads after this would be deleted.
My OS is Perception.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven
Contact:

Post by Candy »

MessiahAndrw wrote:
mmiikkee12 wrote:Poke.


I would have used pop. But then that'd mean all other threads after this would be deleted.


It's not a weasel. Use push.
Post Reply