I remapped the PIC and when I send int 0x20, it works. I'm aware that this tutorial has bugs in it, but I was hoping that the code at least works. I have no idea how to debug it, I'm using qemu with the flags -d int,cpu_reset -D qemu2.log, but it says nothing about interrupts nor irqs. Here's my code
interrupt_requests.c
Code: Select all
void IRQ_set_mask(unsigned char IRQline) {
u16int port;
u8int value;
if(IRQline < 8) {
port = PIC1_DATA;
} else {
port = PIC2_DATA;
IRQline -= 8;
}
value = inbyte(port) | (1 << IRQline);
outbyte(port, value);
}
void IRQ_clear_mask(unsigned char IRQline) {
u16int port;
u8int value;
if(IRQline < 8) {
port = PIC1_DATA;
} else {
port = PIC2_DATA;
IRQline -= 8;
}
value = inbyte(port) & ~(1 << IRQline);
outbyte(port, value);
}
Code: Select all
#include <kernel/common.h>
#include <kernel/interrupt_tables.h>
#include <string.h>
extern void idt_flush(u32int);
idt_entry idt_entries[256];
idtr_t idt_ptr;
void init_idt()
{
idt_ptr.limit = sizeof(idt_entry) * 256 -1;
idt_ptr.base = (u32int)&idt_entries;
memset(&idt_entries, 0, sizeof(idt_entry)*256);
idt_set_gate( 0, (u32int)isr0 , 0x08, 0x8E);
idt_set_gate( 1, (u32int)isr1 , 0x08, 0x8E);
idt_set_gate( 2, (u32int)isr2 , 0x08, 0x8E);
idt_set_gate( 3, (u32int)isr3 , 0x08, 0x8E);
idt_set_gate( 4, (u32int)isr4 , 0x08, 0x8E);
idt_set_gate( 5, (u32int)isr5 , 0x08, 0x8E);
idt_set_gate( 6, (u32int)isr6 , 0x08, 0x8E);
idt_set_gate( 7, (u32int)isr7 , 0x08, 0x8E);
idt_set_gate( 8, (u32int)isr8 , 0x08, 0x8E);
idt_set_gate( 9, (u32int)isr9 , 0x08, 0x8E);
idt_set_gate( 10, (u32int)isr10 , 0x08, 0x8E);
idt_set_gate( 11, (u32int)isr11 , 0x08, 0x8E);
idt_set_gate( 12, (u32int)isr12 , 0x08, 0x8E);
idt_set_gate( 13, (u32int)isr13 , 0x08, 0x8E);
idt_set_gate( 14, (u32int)isr14 , 0x08, 0x8E);
idt_set_gate( 15, (u32int)isr15 , 0x08, 0x8E);
idt_set_gate( 16, (u32int)isr16 , 0x08, 0x8E);
idt_set_gate( 17, (u32int)isr17 , 0x08, 0x8E);
idt_set_gate( 18, (u32int)isr18 , 0x08, 0x8E);
idt_set_gate( 19, (u32int)isr19 , 0x08, 0x8E);
idt_set_gate( 20, (u32int)isr20 , 0x08, 0x8E);
idt_set_gate( 21, (u32int)isr21 , 0x08, 0x8E);
idt_set_gate( 22, (u32int)isr22 , 0x08, 0x8E);
idt_set_gate( 23, (u32int)isr23 , 0x08, 0x8E);
idt_set_gate( 24, (u32int)isr24 , 0x08, 0x8E);
idt_set_gate( 25, (u32int)isr25 , 0x08, 0x8E);
idt_set_gate( 26, (u32int)isr26 , 0x08, 0x8E);
idt_set_gate( 27, (u32int)isr27 , 0x08, 0x8E);
idt_set_gate( 28, (u32int)isr28 , 0x08, 0x8E);
idt_set_gate( 29, (u32int)isr29 , 0x08, 0x8E);
idt_set_gate( 30, (u32int)isr30 , 0x08, 0x8E);
idt_set_gate( 31, (u32int)isr31 , 0x08, 0x8E);
outbyte(0x20, 0x11);
outbyte(0xA0, 0x11);
outbyte(0x21, 0x20);
outbyte(0xA1, 0x28);
outbyte(0x21, 0x04);
outbyte(0xA1, 0x02);
outbyte(0x21, 0x01);
outbyte(0xA1, 0x01);
outbyte(0x21, 0x0);
outbyte(0xA1, 0x0);
idt_set_gate(32, (u32int)irq0, 0x08, 0x8E);
idt_set_gate(33, (u32int)irq1, 0x08, 0x8E);
idt_set_gate(34, (u32int)irq2, 0x08, 0x8E);
idt_set_gate(35, (u32int)irq3, 0x08, 0x8E);
idt_set_gate(36, (u32int)irq4, 0x08, 0x8E);
idt_set_gate(37, (u32int)irq5, 0x08, 0x8E);
idt_set_gate(38, (u32int)irq6, 0x08, 0x8E);
idt_set_gate(39, (u32int)irq7, 0x08, 0x8E);
idt_set_gate(40, (u32int)irq8, 0x08, 0x8E);
idt_set_gate(41, (u32int)irq9, 0x08, 0x8E);
idt_set_gate(42, (u32int)irq10, 0x08, 0x8E);
idt_set_gate(43, (u32int)irq11, 0x08, 0x8E);
idt_set_gate(44, (u32int)irq12, 0x08, 0x8E);
idt_set_gate(45, (u32int)irq13, 0x08, 0x8E);
idt_set_gate(46, (u32int)irq14, 0x08, 0x8E);
idt_set_gate(47, (u32int)irq15, 0x08, 0x8E);
idt_flush((u32int)&idt_ptr);
}
void idt_set_gate(u8int index, u32int base, u16int sel, u8int flags)
{
idt_entries[index].isr_low = base & 0xFFFF;
idt_entries[index].isr_high = (base >> 16) & 0xFFFF;
idt_entries[index].kernel_cs = sel;
idt_entries[index].reserved = 0;
// We must uncomment the OR below when we get to using user-mode.
// It sets the interrupt gate's privilege level to 3.
idt_entries[index].attributes = flags /* | 0x60 */;
}
Code: Select all
#include <kernel/common.h>
#include <kernel/irq_handler.h>
isr_t interrupt_handlers[256];
// This gets called from our ASM interrupt handler stub.
void irq_handler(registers_t regs)
{
// Send an EOI (end of interrupt) signal to the PICs.
// If this interrupt involved the slave.
if (regs.int_no >= 40)
{
// Send reset signal to slave.
outbyte(0xA0, 0x20);
}
// Send reset signal to master. (As well as slave, if necessary).
outbyte(0x20, 0x20);
if (interrupt_handlers[regs.int_no] != 0)
{
isr_t handler = interrupt_handlers[regs.int_no];
handler(regs);
}
}
void register_interrupt_handler(u8int n, isr_t handler)
{
interrupt_handlers[n] = handler;
}
Code: Select all
#include <stdio.h>
#include <kernel/descriptor_tables.h>
#include <kernel/interrupt_tables.h>
#include <kernel/tty.h>
#include <kernel/timer.h>
#include <kernel/interrupt_requests.h>
#include <stdint.h>
void kernel_main(void) {
terminal_initialize();
init_descriptor_tables();
init_idt();
IRQ_clear_mask(0);
init_timer(50);
asm volatile ("int $0x20");
}
Code: Select all
#include <kernel/timer.h>
#include <stdio.h>
#include <kernel/irq_handler.h>
#include <kernel/common.h>
u32int tick = 0;
static void timer_callback(registers_t regs)
{
tick++;
printf("Tick: ");
}
void init_timer(u32int frequency)
{
register_interrupt_handler(IRQ0, &timer_callback);
// The value we send to the PIT is the value to divide it's input clock
// (1193180 Hz) by, to get our required frequency. Important to note is
// that the divisor must be small enough to fit into 16-bits.
u32int divisor = 1193180 / frequency;
// Send the command byte.
outbyte(0x43, 0x36);
// Divisor has to be sent byte-wise, so split here into upper/lower bytes.
u8int l = (u8int)(divisor & 0xFF);
u8int h = (u8int)( (divisor>>8) & 0xFF );
// Send the frequency divisor.
outbyte(0x40, l);
outbyte(0x40, h);
}
Code: Select all
.macro IRQ i, j
.global irq\i
irq\i:
cli
push $0
push \j
jmp irq_common_stub
iret
.endm
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 irq_handler
irq_common_stub:
pusha # Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
mov %ds, %ax # Lower 16-bits of eax = ds.
push %eax # save the data segment descriptor
mov $0x10, %ax # load the kernel data segment descriptor
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
call irq_handler
pop %ebx # reload the original data segment descriptor
mov %bx, %ds
mov %bx, %es
mov %bx, %fs
mov %bx, %gs
popa # Pops edi,esi,ebp...
add $8, %esp # Cleans up the pushed error code and pushed ISR number
sti
iret # pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP