Yet another forum user with IDT 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.
Post Reply
User avatar
Maddie
Posts: 13
Joined: Tue Aug 10, 2021 4:22 pm
Libera.chat IRC: maddie

Yet another forum user with IDT issues

Post by Maddie »

As the title says, I'm having trouble with interrupts. QEMU triple faults whenever I enable them. I have a higher half 64-bit kernel with Limine as the bootloader. here is the relevant code:

Code: Select all

#include "../drivers/ports.h"
#include "stdint.h"


struct IDT_entry{
		uint16_t offset_lowerbits;
		uint16_t selector;
		uint8_t ist;
		uint8_t type_attr;
		uint16_t offset_higherbits;
		uint32_t offset_highestbits;
		uint32_t zero;
} __attribute__((packed));

struct IDTR{
	uint16_t	limit;
	uint64_t	base;
} __attribute__((packed));

struct IDT_entry IDT[256];
struct IDTR idtr;


void load_idt(struct IDTR idt_ptr) {
                __asm__ volatile(
                        "lidt %0"
                        :
                        : "m" (idt_ptr)
                );
}

void sti() {
    __asm__ volatile("sti;");
}

void fillentry(uint8_t i, uint64_t address) {
        IDT[i].offset_lowerbits = (uint16_t) address;
        IDT[i].selector = 0x08;
        IDT[i].ist = 0;
        IDT[i].type_attr = 0x8E;
        IDT[i].offset_higherbits = (uint16_t)(address >> 16);
        IDT[i].offset_highestbits = (uint32_t)(address >> 32);
        IDT[i].zero = 0;
}


void picremap() {
        byteout(0x20, 0x11);
        byteout(0xA0, 0x11);
        byteout(0x21, 0x20);
        byteout(0xA1, 40);
        byteout(0x21, 0x04);
        byteout(0xA1, 0x02);
        byteout(0x21, 0x01);
        byteout(0xA1, 0x01);
        byteout(0x21, 0x0);
        byteout(0xA1, 0x0);
}

void idt_install() {
        extern uint64_t irq0();
        extern uint64_t irq1();
        extern uint64_t irq2();
        extern uint64_t irq3();
        extern uint64_t irq4();
        extern uint64_t irq5();
        extern uint64_t irq6();
        extern uint64_t irq7();
        extern uint64_t irq8();
        extern uint64_t irq9();
        extern uint64_t irq10();
        extern uint64_t irq11();
        extern uint64_t irq12();
        extern uint64_t irq13();
        extern uint64_t irq14();
        extern uint64_t irq15();

        picremap();

        fillentry(0, (uint64_t)irq0);
        fillentry(1, (uint64_t)irq1);
        fillentry(2, (uint64_t)irq2);
        fillentry(3, (uint64_t)irq3);
        fillentry(4, (uint64_t)irq4);
        fillentry(5, (uint64_t)irq5);
        fillentry(6, (uint64_t)irq6);
        fillentry(7, (uint64_t)irq7);
        fillentry(8, (uint64_t)irq8);
        fillentry(9, (uint64_t)irq9);
        fillentry(10, (uint64_t)irq10);
        fillentry(11, (uint64_t)irq11);
        fillentry(12, (uint64_t)irq11);
        fillentry(13, (uint64_t)irq12);
        fillentry(14, (uint64_t)irq13);
        fillentry(15, (uint64_t)irq14);

        idtr.limit = sizeof(struct IDT_entry) * 256 - 1;
        idtr.base = (uint64_t)IDT;

        initgdt();

	load_idt(idtr);
        sti();

}

If it helps, I've verified through GDB that the address in the IDT register indeed matches the address of IDT (my table).

Thanks in advance for your help.
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Yet another forum user with IDT issues

Post by Octocontrabass »

Maddie wrote:QEMU
You can add "-d int" and "-no-reboot" to your QEMU command line to get register dumps and other status information that can help you figure out what's causing a triple fault. I don't think it works with hardware acceleration, though.
Maddie wrote:

Code: Select all

        byteout(0x21, 0x20);
        byteout(0xA1, 40);

Code: Select all

        fillentry(0, (uint64_t)irq0);
        [...]
        fillentry(15, (uint64_t)irq14);
You're programming the interrupt controllers to map the ISA IRQs to interrupt vectors 0x20 through 0x2F (32 through 47) but you're installing your IRQ handlers at interrupt vectors 0x00 through 0x0F (0 through 15).
User avatar
Maddie
Posts: 13
Joined: Tue Aug 10, 2021 4:22 pm
Libera.chat IRC: maddie

Re: Yet another forum user with IDT issues

Post by Maddie »

Octocontrabass wrote:
Maddie wrote:QEMU
You can add "-d int" and "-no-reboot" to your QEMU command line to get register dumps and other status information that can help you figure out what's causing a triple fault. I don't think it works with hardware acceleration, though.
Maddie wrote:

Code: Select all

        byteout(0x21, 0x20);
        byteout(0xA1, 40);

Code: Select all

        fillentry(0, (uint64_t)irq0);
        [...]
        fillentry(15, (uint64_t)irq14);
You're programming the interrupt controllers to map the ISA IRQs to interrupt vectors 0x20 through 0x2F (32 through 47) but you're installing your IRQ handlers at interrupt vectors 0x00 through 0x0F (0 through 15).
*placeholder, still tinkering with the code...*
Last edited by Maddie on Tue Aug 10, 2021 6:33 pm, edited 1 time in total.
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Yet another forum user with IDT issues

Post by Octocontrabass »

Huh? No, the PIC mapping is correct: interrupt vectors 0x00 through 0x1F are reserved for exceptions, so you don't want to remap the PIC to use those vectors for IRQs.
User avatar
Maddie
Posts: 13
Joined: Tue Aug 10, 2021 4:22 pm
Libera.chat IRC: maddie

Re: Yet another forum user with IDT issues

Post by Maddie »

You're right, my mistake. I spoke too soon...
User avatar
Maddie
Posts: 13
Joined: Tue Aug 10, 2021 4:22 pm
Libera.chat IRC: maddie

Re: Yet another forum user with IDT issues

Post by Maddie »

Okay, so I've set the ISA IRQs to vectors 32 through 47, but now I'm getting a general protection fault, which is odd...
QEMU gives me this:

Code: Select all

check_exception old: 0xffffffff new 0xd
     1: v=0d e=ff50 i=0 cpl=0 IP=0008:ffffffff80202924 pc=ffffffff80202924 SP=0010:ffffffff80208108 env->regs[R_EAX]=ffff800007c4a000


User avatar
Maddie
Posts: 13
Joined: Tue Aug 10, 2021 4:22 pm
Libera.chat IRC: maddie

Re: Yet another forum user with IDT issues

Post by Maddie »

I think I found the problem: I used IRET instead of IRETQ. Sneaky.

"In your interrupt handler routines, remember to use IRETQ instead of IRET, as nasm won't translate that for you. Many 64bit IDT related problems on the forum are caused by that missing 'Q'. Don't let this happen to you."
Post Reply