OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Apr 18, 2024 2:44 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: Triple Fault on PIC IRQ
PostPosted: Sun Nov 18, 2018 2:27 pm 
Offline

Joined: Sun Nov 18, 2018 2:05 pm
Posts: 6
Hi all,

I've been working at this bug for an obscenely long amount of time and I'm completely stumped, so I'd like to submit it here just in case there's any dumb mistakes I've made along the way that have been missed in the blindness of looking over code, the bochs debugger, and objdump a thousand times over.

The main symptom of the bug is a triple fault upon `iret` from the PIC IRQ ISR. The only real leads I have are the code selector being invalid (Bochs yells at me about this), and the GDT dump seems to confirm this, although I don't know what is clobbering it.

Immediately upon entering the ISR, it seems like the Data segment gets clobbered by `pusha`, or at least that's what it appears to be.

The code called by the ISR:
Code:
00100c61 <pitHandler>:
  100c61:       60                      pusha 
  100c62:       fc                      cld   
  100c63:       e8 98 fb ff ff          call   100800 <pit_handler>
  100c68:       61                      popa   
  100c69:       cf                      iret 


The code for pit_handler:
Code:
00100800 <pit_handler>:
  100800:       83 ec 18                sub    $0x18,%esp
  100803:       68 a4 16 10 00          push   $0x1016a4
  100808:       e8 f3 01 00 00          call   100a00 <kprint>
  10080d:       b8 20 00 00 00          mov    $0x20,%eax
  100812:       e6 20                   out    %al,$0x20
  100814:       83 c4 1c                add    $0x1c,%esp
  100817:       c3                      ret   
  100818:       8d b4 26 00 00 00 00    lea    0x0(%esi,%eiz,1),%esi
  10081f:       90                      nop



GDT at `hlt` instruction waiting for interrupts (in my kernel's main function)
Code:
Global Descriptor Table (base=0x00106fe4, limit=24):
GDT[0x00]=??? descriptor hi=0x00400000, lo=0x00000000
GDT[0x01]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
GDT[0x02]=Data segment, base=0x00410010, limit=0x00001741, Read/Write, Expand-down, Accessed


(Note: I'm not sure why the data segment in this case has a weird base and limit - I did some digging to figure out what might be causing this, and I'm not sure if it's expected behaviour, but it doesn't seem to effect the functioning of the kernel at the moment, so I figured it was either a.) normal or b.) innocuous enough to be dealt with later. Please also note that the data segment is absolutely fine [i.e. base=0x0 limit=0xffffffff] after the load and reloading of segments.)


GDT after entering the ISR - (one instruction in, i.e. resting on the `cld` instruction, which makes me think it's the `pusha` instruction?)
Code:
Global Descriptor Table (base=0x00106fe4, limit=24):
GDT[0x00]=??? descriptor hi=0x00400000, lo=0x00000000
GDT[0x01]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Non-Conforming, Accessed, 32-bit
GDT[0x02]=??? descriptor hi=0x00000000, lo=0x00000000


After two more steps (with the debugger resting on the stack pointer subtraction in pit_handler), it gets even worse.
Code:
GDT[0x00]=??? descriptor hi=0x00400000, lo=0x00000000
GDT[0x01]=32-Bit Call Gate target=0x0000:0x0010ffff, DPL=0
GDT[0x02]=??? descriptor hi=0x00000000, lo=0x00000000


This is, to the best of my knowledge, NOT a proper GDT :D

What might I be missing offhand?


Top
 Profile  
 
 Post subject: Re: Triple Fault on PIC IRQ
PostPosted: Sun Nov 18, 2018 2:54 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
Looks like your stack might be overwriting your GDT.

The CPU caches the GDT whenever a segment register is loaded, so it doesn't use the corrupt GDT until the IRET.


Top
 Profile  
 
 Post subject: Re: Triple Fault on PIC IRQ
PostPosted: Sun Nov 18, 2018 2:57 pm 
Offline
Member
Member
User avatar

Joined: Wed Oct 18, 2006 3:45 am
Posts: 9301
Location: On the balcony, where I can actually keep 1½m distance
Quote:
GDT[0x00]=??? descriptor hi=0x00400000, lo=0x00000000
And technically, your GDT is already clobbered before you start :wink:

_________________
"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 ]


Top
 Profile  
 
 Post subject: Re: Triple Fault on PIC IRQ
PostPosted: Sun Nov 18, 2018 3:23 pm 
Offline

Joined: Sun Nov 18, 2018 2:05 pm
Posts: 6
Octocontrabass wrote:
Looks like your stack might be overwriting your GDT.

The CPU caches the GDT whenever a segment register is loaded, so it doesn't use the corrupt GDT until the IRET.


Bingo! Wow, I really should have put that together, but unfortunately my brain just just completely fried. I'll see what I can do to make my stack not kill it, thank you very much!

Combuster wrote:
Quote:
GDT[0x00]=??? descriptor hi=0x00400000, lo=0x00000000
And technically, your GDT is already clobbered before you start :wink:


Is it? I was tying to follow the advice of the wiki to add a null segment at the beginning - I guess that isn't very null though, is it...


Top
 Profile  
 
 Post subject: Re: Triple Fault on PIC IRQ
PostPosted: Sun Nov 18, 2018 3:53 pm 
Offline

Joined: Sun Nov 18, 2018 2:05 pm
Posts: 6
I hope I'm not sounding like a beggar or an idiot here, but I'm not exactly sure what I'd need to do to fix this. I've expanded the stack size multiple times to try to see if it would help push the two a bit away, but the error seems to be sticking around. Perhaps I'm misunderstanding how the linker file is even supposed to function.

Would reserving space in BSS assist with any of this? The GDT seems to be inexorably tied near the stack pointer, and moves whenever I reserve more space. Makes sense if the GDT is being allocated on the BSS, but I'm not sure how or why my stack is clobbering the GDT.

EDIT: Well, something is absolutely wrong. The GDT seems to be allocated on the stack rather than in BSS. I'm immensely confused what I've done to get to this point, honestly.

The stack is between 0x00103030 and 0x00113030. My GDT is apparently allocated at 0x00112fe4, about 0x4C up the stack.


Top
 Profile  
 
 Post subject: Re: Triple Fault on PIC IRQ
PostPosted: Sun Nov 18, 2018 4:17 pm 
Offline
Member
Member

Joined: Tue Mar 04, 2014 5:27 am
Posts: 1108
CalmBit wrote:
EDIT: Well, something is absolutely wrong. The GDT seems to be allocated on the stack rather than in BSS. I'm immensely confused what I've done to get to this point, honestly.

The stack is between 0x00103030 and 0x00113030. My GDT is apparently allocated at 0x00112fe4, about 0x4C up the stack.


Can you show us the code that declares and sets up the GDT and GDTR?


Top
 Profile  
 
 Post subject: Re: Triple Fault on PIC IRQ
PostPosted: Sun Nov 18, 2018 5:25 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 21, 2011 9:47 pm
Posts: 286
Location: Tustin, CA USA
From experience: Is paging enabled? If so, could you have multiple pages mapped to the frame containing the GDT?

_________________
Adam

The name is fitting: Century Hobby OS -- At this rate, it's gonna take me that long!
Read about my mistakes and missteps with this iteration: Journal

"Sometimes things just don't make sense until you figure them out." -- Phil Stahlheber


Top
 Profile  
 
 Post subject: Re: Triple Fault on PIC IRQ
PostPosted: Sun Nov 18, 2018 9:22 pm 
Offline

Joined: Sun Nov 18, 2018 2:05 pm
Posts: 6
alexfru wrote:
CalmBit wrote:
EDIT: Well, something is absolutely wrong. The GDT seems to be allocated on the stack rather than in BSS. I'm immensely confused what I've done to get to this point, honestly.

The stack is between 0x00103030 and 0x00113030. My GDT is apparently allocated at 0x00112fe4, about 0x4C up the stack.


Can you show us the code that declares and sets up the GDT and GDTR?


The main code for assembling the GDT and GDTR looks like this:

(might look familiar - this is a bit of a barebones/tutorial kernel, and although I've tried my best to learn from it and refactor it, sometimes if something "works" you just keep it)

Code:
void encodeGdtEntry(uint8_t *target, GDTEntry source)
{
  if((source.limit > 65536) && ((source.limit & 0xFFF) != 0xFFF))
    {
   kpanic("Source limit over integer limit and not a 0xFFF number");
    }
  else if(source.limit > 65536)
    {
      source.limit = source.limit >> 12;
      target[6] = 0xC0;
    }
  else
    {
      target[6] = 0x40;
    }

  target[0] = source.limit & 0xFF;
  target[1] = (source.limit >> 8) & 0xFF;
  target[6] |= (source.limit >> 16) & 0xF;

  target[2] = source.base & 0xFF;
  target[3] = (source.base >> 8) & 0xFF;
  target[4] = (source.base >> 16) & 0xFF;
  target[7] = (source.base >> 24) & 0xFF;
  target[5] = source.type;
}

void setup_gdt()
{
  GDTEntry gdtEnt[3]= {   {.base=0, .limit=0, .type=0},
         {.base=0, .limit=0xffffffff, .type=0x9A},
         {.base=0, .limit=0xffffffff, .type=0x92} };

  uint8_t gdtTarg[3*8];
  encodeGdtEntry(&gdtTarg[0], gdtEnt[0]);
  encodeGdtEntry(&gdtTarg[8], gdtEnt[1]);
  encodeGdtEntry(&gdtTarg[16], gdtEnt[2]);
  setGdt(gdtTarg, sizeof(gdtTarg));
}


That, in turns, calls this piece of assembly.

Code:
gdtr:
limit: .word 0
base:  .long 0

.globl setGdt
setGdt:
   movl 4(%esp), %eax
   movl %eax, (base)
   movw 8(%esp), %ax
   movw %ax, (gdtr)
   lgdt (gdtr)
   ret

.globl reloadSegments
reloadSegments:
   ljmp $0x08, $reload_CS

reload_CS:
   movw $0x10, %ax
   movw %ax, %ds
   movw %ax, %es
   movw %ax, %fs
   movw %ax, %gs
   movw %ax, %ss
   xchg %bx, %bx
   ret


eryjus wrote:
From experience: Is paging enabled? If so, could you have multiple pages mapped to the frame containing the GDT?


Paging is not enabled, but good thought :)


Top
 Profile  
 
 Post subject: Re: Triple Fault on PIC IRQ
PostPosted: Sun Nov 18, 2018 11:57 pm 
Offline
Member
Member

Joined: Tue Mar 04, 2014 5:27 am
Posts: 1108
So, what storage class does gdtTarg have? Automaic?


Top
 Profile  
 
 Post subject: Re: Triple Fault on PIC IRQ
PostPosted: Mon Nov 19, 2018 12:33 am 
Offline

Joined: Sun Nov 18, 2018 2:05 pm
Posts: 6
alexfru wrote:
So, what storage class does gdtTarg have? Automaic?


Oh boy...this might be just an absolutely giant egg on my face.

For some unknowable, downright awful reason, I assumed that by declaring the array with constants, it would be preserved. Thinking about it again, critically...yeah, it's probably automatic. Whoops.


Top
 Profile  
 
 Post subject: Re: Triple Fault on PIC IRQ
PostPosted: Mon Nov 19, 2018 12:46 am 
Offline

Joined: Sun Nov 18, 2018 2:05 pm
Posts: 6
Thanks to everyone for helping - it has been fixed! The final fix was the following:

The stack was indeed clobbering the GDT - I had accidentally allocated it on the stack as a result of gdtTarg, the main array where my GDT was located, being declared inside of the function. I didn't think about the semantics of this, and the fix was to simply declare it outside of the function in order to allocate it in .bss :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot], Majestic-12 [Bot] and 108 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group