Page 1 of 1

IRQs doesn't work

Posted: Fri Nov 17, 2023 12:05 pm
by husaral
So I tried to write a basic PIT timer but the interrupt doesn't get called. When I call the handler manually by int command it does work but it doesn't do anything automatically. I am sure my main function never returns as I have set a infinite loop. (I have set up the GDT, IDT and PIC and exceptions does work)

The files:

irq.s :

Code: Select all

.section .text
.align 4

.macro IRQ index byte
	.global _irq\index
	.type _irq\index, @function
	_irq\index:
		pushl $0
		pushl $\byte
		jmp isr_wrapper
.endm

.macro ISR index
	.global _isr\index
	.type _isr\index, @function
	_isr\index:
		pushl $0
		pushl $\index
		jmp isr_wrapper
.endm

.macro ISR_ERR index
	.global _isr\index
	.type _isr\index, @function
	_isr\index:
		pushl $\index
		jmp isr_wrapper
.endm

ISR 0
ISR 1
ISR 2
ISR 3
ISR 4
ISR 5
ISR 6
ISR 7
ISR_ERR 8
ISR 9
ISR_ERR 10
ISR_ERR 11
ISR_ERR 12
ISR_ERR 13
ISR_ERR 14
ISR 15
ISR 16
ISR 17
ISR 18
ISR 19
ISR 20
ISR 21
ISR 22
ISR 23
ISR 24
ISR 25
ISR 26
ISR 27
ISR 28
ISR 29
ISR 30
ISR 31
IRQ 0, 32
IRQ 1, 33
IRQ 2, 34
IRQ 3, 35
IRQ 4, 36
IRQ 5, 37
IRQ 6, 38
IRQ 7, 39
IRQ 8, 40
IRQ 9, 41
IRQ 10, 42
IRQ 11, 43
IRQ 12, 44
IRQ 13, 45
IRQ 14, 46
IRQ 15, 47

.extern isr_handler
.type isr_handler, @function

.global isr_wrapper
isr_wrapper:
	pushal

	push %esp
	cld

	call isr_handler

	add $4, %esp
	popal
	add $8, %esp
	iretl
idt.c :

Code: Select all

#include <stdint.h>
#include <arch/x86/idt.h>
#include <arch/x86/regs.h>
#include <arch/x86/pic.h>
#include <sys/kprint.h>

struct InterruptDescriptor {
	uint16_t offset_low; //Offset bits 0 to 15
	uint16_t selector; //A code segment selector in GDT or LDT
	uint8_t zero; //Just a gap, always set to zero
	uint8_t type_attributes; //Gate type, DPL and present bit fields
	uint16_t offset_high; //Offset bits 16 to 31
} __attribute__((packed));

struct IDTPointer{
	uint16_t limit;
	void* base;
} __attribute__((packed));

static struct IDTPointer idt_pointer;
struct InterruptDescriptor idt[256];
static void (*irq_handler_table[16]) (void);

void idt_set_gate(uint8_t num, void* handler, uint16_t selector, uint8_t type_attributes){
	idt[num].offset_low = (uint32_t) handler & 0xFFFF;
	idt[num].selector = selector;
	idt[num].type_attributes = type_attributes;
	idt[num].offset_high = ((uint32_t)handler >> 16) & 0xFFFF;
}

void irq_set_handler(uint8_t irq, void* handler){
	irq_handler_table[irq] = handler;
}

void initialize_idt(void){
	idt_pointer.limit = sizeof(idt);
	idt_pointer.base = &idt;

	void* isr_handlers[] = {_isr0, _isr1, _isr2, _isr3, _isr4, _isr5,
	_isr6, _isr7, _isr8, _isr9, _isr10, _isr11, _isr12, _isr13, _isr14, _isr15, _isr16,
	_isr17, _isr18, _isr19, _isr20, _isr21, _isr22, _isr23, _isr24, _isr25, _isr26, _isr27,
	_isr28, _isr29, _isr30, _isr31};

	for(int i = 0; i < 32; ++i){
		idt_set_gate(i, isr_handlers[i], 0x08, 0x8E);
	}

	void* irq_handlers[] = {_irq0, _irq1, _irq2, _irq3, _irq4, _irq5, _irq6, _irq7, _irq8, _irq9,
	_irq10, _irq11, _irq12, _irq13, _irq14, _irq15};

	for(int i = 0; i < 16; ++i){
		idt_set_gate(i + 32, irq_handlers[i], 0x08, 0x8E); //There are 32 entries before the first IRQ entry
	}

	//Load the new IDT
	asm volatile ("lidt %0" :: "m"(idt_pointer));
}

static void _exception(char* message, struct x86Registers* regs){
	kprintf(message);
	kprintf("EAX : 0x%x EBX : 0x%x ECX : 0x%x EDX : 0x%x\n", regs->eax, regs->ebx, regs->ecx, regs->edx);
	kprintf("ESP : 0x%x EBP : 0x%x ESI : 0x%x EDI : 0x%x\n", regs->esp, regs->ebp, regs->esi, regs->edi);
	kprintf("EIP : 0x%x CS : 0x%x EFLAGS : 0x%x SS : 0x%x\n", regs->eip, regs->cs, regs->eflags, regs->ss);
	asm volatile("hlt");
}

static void _handle_irq(struct x86Registers* regs, int irq){
	irq_handler_table[irq]();
	acknowledge_irq(irq);
}

struct x86Registers* isr_handler(struct x86Registers* regs){
	switch (regs->interrupt_no){
		case 0: _exception("Division by zero\n", regs); break;
		case 3: _exception("Breakpoint\n", regs); break;
		case 4: _exception("Overflow\n", regs); break;
		case 5: _exception("Range exceeded\n", regs); break;
		case 6: _exception("Invalid opcode\n", regs); break;
		case 7: _exception("Device not available\n", regs); break;
		case 8: _exception("Double fault\n", regs); break;
		case 32: _handle_irq(regs, 0); break;
		case 33: _handle_irq(regs, 1); break;
		case 34: _handle_irq(regs, 2); break;
		case 35: _handle_irq(regs, 3); break;
		case 36: _handle_irq(regs, 4); break;
		case 37: _handle_irq(regs, 5); break;
		case 38: _handle_irq(regs, 6); break;
		case 39: _handle_irq(regs, 7); break;
		case 40: _handle_irq(regs, 8); break;
		case 41: _handle_irq(regs, 9); break;
		case 42: _handle_irq(regs, 10); break;
		case 43: _handle_irq(regs, 11); break;
		case 44: _handle_irq(regs, 12); break;
		case 45: _handle_irq(regs, 13); break;
		case 46: _handle_irq(regs, 14); break;
		case 47: _handle_irq(regs, 15); break;
		default: kprintf("Interrupt!"); break;
	}

	return regs;
}

pic.c :

Code: Select all

#include <stdint.h>
#include <arch/x86/ports.h>

#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1

void remap_pic(uint32_t offset1, uint32_t offset2){
    uint8_t p1, p2;

    p1 = inb(PIC1_DATA);
    p2 = inb(PIC2_DATA);

    outb(PIC1_COMMAND, 0x11);
    iowait();
    outb(PIC2_COMMAND, 0x11);
    iowait();

    outb(PIC1_DATA, offset1);
    iowait();
    outb(PIC2_DATA, offset2);
    iowait();

    outb(PIC1_DATA, 4);
    iowait();
    outb(PIC2_DATA, 2);
    iowait();

    outb(PIC1_DATA, 0x01);
    iowait();
    outb(PIC2_DATA, 0x01);
    iowait();

    outb(PIC1_DATA, p1);
    outb(PIC2_DATA, p2);
}

void unmask_irq(uint8_t irq){
        uint16_t port = PIC1_DATA;
        uint8_t value;

        if(irq >= 8){
            port = PIC2_DATA;
            irq -= 8;
        }

        value = inb(port) & ~(1 << irq);
        outb(port, value);
}

void acknowledge_irq(uint8_t irq_no){
    if (irq_no >= 8)
        outb(PIC2_COMMAND, 0x20);

    outb(PIC1_COMMAND, 0x20);
}

pit.c :

Code: Select all

#include <stdint.h>
#include <arch/x86/idt.h>
#include <arch/x86/regs.h>
#include <arch/x86/pic.h>
#include <arch/x86/ports.h>
#include <sys/kprint.h>

void pit_handler(void){
    kprintf("PIT\n");
    acknowledge_irq(0);
}

void initialize_pit(void) {
    irq_set_handler(0, pit_handler);
    unmask_irq(0);

    long divisor = 1193180 / 100;
    outb(0x43, 0x36);
    outb(0x40, divisor & 0xFF);
    outb(0x40, (divisor >> 8) & 0xFF);

}
Thanks for any help.

Re: IRQs doesn't work

Posted: Tue Feb 13, 2024 12:15 pm
by Octocontrabass
I know it's been a while, but... did you use STI to enable interrupts?