GPF after any interrupt gate is called

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
aphexia
Posts: 17
Joined: Wed Jan 08, 2020 8:09 pm
Libera.chat IRC: aphexia

GPF after any interrupt gate is called

Post by aphexia »

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: Select all

#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: Select all

#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: Select all

.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
nullplan
Member
Member
Posts: 1910
Joined: Wed Aug 30, 2017 8:24 am

Re: GPF after any interrupt gate is called

Post by nullplan »

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!
aphexia
Posts: 17
Joined: Wed Jan 08, 2020 8:09 pm
Libera.chat IRC: aphexia

Re: GPF after any interrupt gate is called

Post by aphexia »

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.
aphexia
Posts: 17
Joined: Wed Jan 08, 2020 8:09 pm
Libera.chat IRC: aphexia

Re: GPF after any interrupt gate is called

Post by aphexia »

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.
Octocontrabass
Member
Member
Posts: 5882
Joined: Mon Mar 25, 2013 7:01 pm

Re: GPF after any interrupt gate is called

Post by Octocontrabass »

What is the value of the CS register before you enable interrupts?
aphexia
Posts: 17
Joined: Wed Jan 08, 2020 8:09 pm
Libera.chat IRC: aphexia

Re: GPF after any interrupt gate is called

Post by aphexia »

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?
Octocontrabass
Member
Member
Posts: 5882
Joined: Mon Mar 25, 2013 7:01 pm

Re: GPF after any interrupt gate is called

Post by Octocontrabass »

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.
aphexia
Posts: 17
Joined: Wed Jan 08, 2020 8:09 pm
Libera.chat IRC: aphexia

Re: GPF after any interrupt gate is called

Post by aphexia »

So what, I just jmpf 0x08:next instruction?
Octocontrabass
Member
Member
Posts: 5882
Joined: Mon Mar 25, 2013 7:01 pm

Re: GPF after any interrupt gate is called

Post by Octocontrabass »

Yep.
aphexia
Posts: 17
Joined: Wed Jan 08, 2020 8:09 pm
Libera.chat IRC: aphexia

Re: GPF after any interrupt gate is called

Post by aphexia »

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?
Octocontrabass
Member
Member
Posts: 5882
Joined: Mon Mar 25, 2013 7:01 pm

Re: GPF after any interrupt gate is called

Post by Octocontrabass »

Put a label before the next instruction and use the label. The assembler will fill in the correct address.
aphexia
Posts: 17
Joined: Wed Jan 08, 2020 8:09 pm
Libera.chat IRC: aphexia

Re: GPF after any interrupt gate is called

Post by aphexia »

Can i do that in inline assembly, cause i think labels aren't accepted?
Octocontrabass
Member
Member
Posts: 5882
Joined: Mon Mar 25, 2013 7:01 pm

Re: GPF after any interrupt gate is called

Post by Octocontrabass »

Yes. For example:

Code: Select all

asm( "ljmp $0x08, $.Lnext%=\n.Lnext%=:\t" : );
aphexia
Posts: 17
Joined: Wed Jan 08, 2020 8:09 pm
Libera.chat IRC: aphexia

Re: GPF after any interrupt gate is called

Post by aphexia »

Omg thanks a lot!!!

Now i dont get the GPF anymore.

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