I can't get my interrupt code to work. What am I missing?
Posted: Fri Aug 31, 2007 12:48 pm
I've read the manual numerous times as well as tons of tutorials and forum posts on the matter.
I think I must have some typo or glitch in my logic because this code is driving me nuts.
The problem is that as soon as I enable interrupts, I get a ton of these errors:
Eventually it'll triple fault and reset itself. I'm doing this all in Bochs by the way.
Could someone with a fresh set of eyes take a look at my code and let me know if you spot something weird?
My ISRs are defined like so:
Here is my isr_common_stub which each ISR jumps to:
Each ISR calls my fault_handler, which is written in C code. Right now it doesn't do anything. It justs loops infinitely:
First, I remap the IRQs:
Then, I install the IDT:
Here's what my idt_entry_set_values function looks like:
And here's my struct IDT:
I think I must have some typo or glitch in my logic because this code is driving me nuts.
The problem is that as soon as I enable interrupts, I get a ton of these errors:
Code: Select all
00001193930i[CPU0 ] BxError: instruction with opcode=0xff
00001193930i[CPU0 ] mod was c0, nnn was 7, rm was 7
00001193930i[CPU0 ] WARNING: Encountered an unknown instruction (signalling illegal instruction)
Could someone with a fresh set of eyes take a look at my code and let me know if you spot something weird?
My ISRs are defined like so:
Code: Select all
...
isr9:
cli
push $0
push $9
jmp isr_common_stub
isr10:
cli
push $10
jmp isr_common_stub
...
Code: Select all
isr_common_stub:
pusha
pushw %ds # Push all user segment selectors
pushw %es
pushw %fs
pushw %gs
movw $0x10, %ax # User kernel data segment selector
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movl %esp, %eax # Push the address of ESP as a parameter so that the
pushl %eax # Fault handler function can access the REG structure
movl fault_handler, %eax
call %eax # Call the fault handler
popl %eax
popw %gs
popw %fs
popw %es
popw %ds
popa
addl $8, %esp # Cleans up pushed error code and Interrupt number
iret # CPU will pop off CS, EIP, EFLAGS, SS, and ESP automatically
Code: Select all
void fault_handler(struct REGS *r)
{
for(;;);
}
First, I remap the IRQs:
Code: Select all
outb(0x20, 0x11);
outb(0xA0, 0x11);
outb(0x21, 0x20);
outb(0xA1, 0x28);
outb(0x21, 0x04);
outb(0xA1, 0x02);
outb(0x21, 0x01);
outb(0xA1, 0x01);
outb(0x21, 0x0);
outb(0xA1, 0x0);
Code: Select all
struct IDT * idt_dest = IDT_ADDR; // IDT starts at this address
struct IDT_PTR idtr = {0x1000, IDT_ADDR}; // lidt will load this structure
// Selector, Offset, Flags, IDT
idt_entry_set_values(0x08, (unsigned)isr0, 0x8E, idt_dest++);
...
idt_entry_set_values(0x08, (unsigned)isr31, 0x8E, idt_dest++);
idt_entry_set_values(0x08, (unsigned)irq0, 0x8E, idt_dest++);
...
idt_entry_set_values(0x08, (unsigned)irq15, 0x8E, idt_dest);
__asm__ ("lidt (%0)\n\t":: "r" (&idtr))
__asm__ __volatile__ ("sti\n\t");
Code: Select all
void idt_entry_set_values(unsigned short selector, unsigned int offset, unsigned char flags, struct IDT* e)
{
e->selector = selector;
e->offset_low = (offset & 0xFFFF);
e->offset_high = (offset >> 16) & 0xFFFF;
e->always0 = 0;
e->flags = flags;
}
Code: Select all
struct IDT
{
unsigned short offset_low;
unsigned short selector; // Selects GDT descriptor
unsigned char always0; // Always set this to zero
unsigned char flags;
unsigned short offset_high;
} __attribute__((packed));