OSDev.org

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

All times are UTC - 6 hours




Post new topic Reply to topic  [ 14 posts ] 
Author Message
 Post subject: GPF after any interrupt gate is called
PostPosted: Wed Jan 08, 2020 8:27 pm 
Offline

Joined: Wed Jan 08, 2020 8:09 pm
Posts: 17
Ok so I've just started coding my OS and it has been fun so far. However I ran into a problem.

Whenever an interrupt fires, be it an exception or an IRQ, a loop of general protection faults is fired after the handler for that interrupt.

I've spent hours debugging already and found a bunch of things that aren't the problem.

-The GDT is set up correctly
-The IDT is also set up correctly
-The PIC is set up correctly
-The timer is masked

So after a while i became frustrated and tried bochs.
Error code: cs_check(0x0010): not a valid code segment!

interrupts.c
Code:
#include "Headers/interrupts.h"

void initializeIDT(const uint16_t selector, const uint8_t exceptionTypeAttr, const uint8_t IRQTypeAttr) {
   for (uint16_t i = 0; i < 256; i++)
      setGateDescriptor(i, (uint32_t*)&_unused, selector, IRQTypeAttr);
   
   setGateDescriptor(0, (uint32_t*)&_exception0, selector, exceptionTypeAttr);
   setGateDescriptor(1, (uint32_t*)&_exception1, selector, exceptionTypeAttr);
   setGateDescriptor(2, (uint32_t*)&_exception2, selector, exceptionTypeAttr);
   setGateDescriptor(3, (uint32_t*)&_exception3, selector, exceptionTypeAttr);
   ...
   

   setGateDescriptor(32, (uint32_t*)&_irq32, selector, IRQTypeAttr);
   setGateDescriptor(33, (uint32_t*)&_irq33, selector, IRQTypeAttr);
   setGateDescriptor(34, (uint32_t*)&_irq34, selector, IRQTypeAttr);
   ...
}

void enableInterrupts() {
   asm volatile ("sti");
}

void disableInterrupts() {
   asm volatile ("cli");
}

void resetPIC(const uint8_t offsetVector) {
   uint8_t PIC1Mask = inb(PORT_NB_PIC_MASTER_DATA);
   uint8_t PIC2Mask = inb(PORT_NB_PIC_SLAVE_DATA);
   //Restart PICs (CW4 needed | cascade mode | edge triggered mode)
   outb(PORT_NB_PIC_MASTER_CMD, 0b00010001);
   outb(PORT_NB_PIC_SLAVE_CMD, 0b00010001);
   //Set vector offset to 32
   outb(PORT_NB_PIC_MASTER_DATA, offsetVector);
   outb(PORT_NB_PIC_SLAVE_DATA, offsetVector + 8);
   //Set up cascade mode
   outb(PORT_NB_PIC_MASTER_DATA, 0x04);
   outb(PORT_NB_PIC_SLAVE_DATA, 0x02);
   //ICW4 (8086 mode)
   outb(PORT_NB_PIC_MASTER_DATA, 0x1);
   outb(PORT_NB_PIC_SLAVE_DATA, 0x1);
   //Clearing masks
   outb(PORT_NB_PIC_MASTER_DATA, PIC1Mask);
   outb(PORT_NB_PIC_SLAVE_DATA, PIC2Mask);
}

void setPICMask(const uint16_t mask) {
   outb(PORT_NB_PIC_MASTER_DATA, (uint8_t)(mask & 0x00FF));
   outb(PORT_NB_PIC_SLAVE_DATA, (uint8_t)(mask >> 8));
}

void resetPICMask() {
   outb(PORT_NB_PIC_MASTER_DATA, 0x0);
   outb(PORT_NB_PIC_SLAVE_DATA, 0x0);
}

uint16_t getPICMask() {
   return ((uint16_t)(inb(PORT_NB_PIC_MASTER_DATA)) |
      ((uint16_t)(inb(PORT_NB_PIC_SLAVE_DATA))) << 8);
}

void sendEOIMasterPIC() {
   outb(PORT_NB_PIC_MASTER_CMD, 0x20);
}

void sendEOISlavePIC() {
   outb(PORT_NB_PIC_SLAVE_CMD, 0x20);
}

void handleIRQ(uint8_t nb) {
   printf(" INTERRUPT:");
   hexDump(&nb, 1);
   if (nb  >= 32 && nb < 40)
      sendEOIMasterPIC();
   else if (nb >= 40 && nb < 48) {
      sendEOISlavePIC();
      sendEOIMasterPIC();
   }
}

void handleException(uint8_t nb) {
   clearScreen();
   printf("EXCEPTION ");
   hexDump(&nb, 1);
   printRegisters();
   printf("          STACK: ");
   hexDump(&nb - 16, 24);
   while (1) {}
}


kernelMain.c
Code:
#include "Headers/types.h"
#include "Headers/debug.h"
#include "Headers/GDT.h"
#include "Headers/IDT.h"
#include "Headers/interrupts.h"

void setUpGDT() {
   setSegmentDescriptor(0, 0, 0, 0, 0);
   setSegmentDescriptor(1, 0, 0xFFFFFFFF, GDT_ACCESS_CODE_SEGMENT, 0b1100);
   setSegmentDescriptor(2, 0, 0xFFFFFFFF, GDT_ACCESS_DATA_SEGMENT, 0b1100);
   loadGDT(3);
}

void setUpInterrupts() {
   setPICMask(0x01);
   resetPIC(0x20);
   initializeIDT(1 * 8, IDT_TYPE_ATTR_TRAP_GATE, IDT_TYPE_ATTR_INT_GATE);
   enableInterrupts();
}

extern void kernelMain(void *multiboot_structure, uint32_t magic) {

   clearScreen();
   
   setUpGDT();

   setUpInterrupts();

   while (1) {
   }
}


interruptStubs.s
Code:
.extern handleIRQ
.extern handleException

.global _exception0
_exception0:
   pushal
   pushl $0
   call handleException
   add $4, %esp
   popal
   iretl

.global _exception1
_exception1:
   pushal
   pushl $1
   call handleException
   add $4, %esp
   popal
   iretl

.global _exception2
_exception2:
   pushal
   pushl $2
   call handleException
   add $4, %esp
   popal
   iretl
...

.global _unused
_unused:
   iretl

.global _irq32
_irq32:
   pushal
   pushl $32
   call handleIRQ
   add $4, %esp
   popal
   iretl

.global _irq33
_irq33:
   pushal
   pushl $33
   call handleIRQ
   add $4, %esp
   popal
   iretl

.global _irq34
_irq34:
   pushal
   pushl $34
   call handleIRQ
   add $4, %esp
   popal
   iretl
...



Thanks in advance for taking the time to help me


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Wed Jan 08, 2020 11:20 pm 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1604
Are you handling exception error codes? Some exceptions (notably #GP and #PF) push an error code to the stack you have to remove before the iret. Otherwise your iret will read garbled data. (See Intel SDM or AMD APM for info on which exceptions those are.)

Other than that I don't see anything obvious. Of course, I would be remiss if I didn't point out that the requested code segment 0x08 and the one error'd by Bochs (0x10) are only one shift apart. Error in setGateDescriptor()?

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Wed Jan 08, 2020 11:30 pm 
Offline

Joined: Wed Jan 08, 2020 8:09 pm
Posts: 17
Thanks for your reply!

I dumped a bunch of IDT entries and the selector is actually 0x8, so no error in setGateDescriptoe(). Btw, the handler for the interrupts causing the GPF gets called, so the selector must be right. Correct me if I'm wrong.

I'll try to add 4 to esp on the right exception handlers.


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Thu Jan 09, 2020 12:58 am 
Offline

Joined: Wed Jan 08, 2020 8:09 pm
Posts: 17
So i put an instruction to add 4 to the stack pointer in the appropriate exception handlers. That way, the error code is taken care of.

It still doesn't work however.


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Thu Jan 09, 2020 10:41 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
What is the value of the CS register before you enable interrupts?


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Thu Jan 09, 2020 11:48 am 
Offline

Joined: Wed Jan 08, 2020 8:09 pm
Posts: 17
Ok so the value of CS before an interrupt gate gets called is 0x10 so that must be the problem.

Now the question is how do i change the value of CS to 0x08?


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Thu Jan 09, 2020 12:17 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
I suggest a far JMP. The correct syntax will depend on where in your code you want to put it.

If you're feeling clever, you might also be interested in a far RET. There are other instructions too.


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Thu Jan 09, 2020 12:20 pm 
Offline

Joined: Wed Jan 08, 2020 8:09 pm
Posts: 17
So what, I just jmpf 0x08:next instruction?


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Thu Jan 09, 2020 12:30 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
Yep.


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Thu Jan 09, 2020 12:45 pm 
Offline

Joined: Wed Jan 08, 2020 8:09 pm
Posts: 17
How do i know what the address of the next instruction is? Can i just save the value of eip and do some basic math?


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Thu Jan 09, 2020 12:46 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
Put a label before the next instruction and use the label. The assembler will fill in the correct address.


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Thu Jan 09, 2020 1:04 pm 
Offline

Joined: Wed Jan 08, 2020 8:09 pm
Posts: 17
Can i do that in inline assembly, cause i think labels aren't accepted?


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Thu Jan 09, 2020 1:30 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5137
Yes. For example:
Code:
asm( "ljmp $0x08, $.Lnext%=\n.Lnext%=:\t" : );


Top
 Profile  
 
 Post subject: Re: GPF after any interrupt gate is called
PostPosted: Thu Jan 09, 2020 1:44 pm 
Offline

Joined: Wed Jan 08, 2020 8:09 pm
Posts: 17
Omg thanks a lot!!!

Now i dont get the GPF anymore.

However I only get one interrupt so the EOI must be incorrectly done.


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 156 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