Interupt Problem

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
voidlogic
Posts: 8
Joined: Thu Feb 28, 2008 2:43 pm

Interupt Problem

Post by voidlogic »

Hey everyone,

I'm having a problem with interrupts. I have enabled interrupts (sti), initialized, remapped and unmasked the PIC, yet my interrupt handlers will not fire. If I call asm("int $0"); my divide by zero handler fires, and if I call asm("int $33"); my general interrupt handler fires and it calls the keyboard routine. But simply pressing keys does not work.

Here is my PIC configuration:

Code: Select all

    //tell PICs they are cascaded    
    outportb(0x20, 0x11);  
    outportb(0xA0, 0x11);
    //normally IRQs 0 to 7 are mapped to entries 8 to 15.
    //This does not work in protected mode, because IDT entry 8 is a
    //double fault. Without remapping, every time IRQ 0 fires (timer),
    //you would get a double fault exception
   // We send commands to the PICs [aka i8259s] in order
    //to make IRQ 0 through 15 be remapped to IDT entries to 32 through 47
    outportb(0x21, 0x20); 
    outportb(0xA1, 0x28);
    //set IRQ2 as connection to PIC slave
    outportb(0x21, 0x04);
    outportb(0xA1, 0x02);
    //unmask all interrupts
    outportb(0x21, 0x01);
    outportb(0xA1, 0x01);
    outportb(0x21, 0x0);
    outportb(0xA1, 0x0);
Any ideas or tips would be very helpful.
The below is included in case it is helpful.

Code: Select all

void irqHandler(regs *state)
{
    system.console<<endl<<"IRQ "<<state->intNum<<" fired."<<endl;
    void (*handler)(regs *state);
    handler = (void (*)(regs*))handlerIdt->irqHandlers[state->intNum - 32];
    if (handler)
        handler(state);
    //if an irq then we need to send an EOI to the slave PIC
    if (state->intNum >= 40)
        outportb(0xA0, 0x20);
    //Always send EOI to master PIC
    outportb(0x20, 0x20);
}

irqCommonStub:
    pusha
    push ds
    push es
    push fs
    push gs
    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp
    push eax
    mov eax, _Z10irqHandlerP4regs
    call eax
    pop eax
    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret                       

irq0:
    cli
    push byte 0
    push byte 32
    jmp irqCommonStub

irq1:
    cli
    push byte 0
    push byte 33
    jmp irqCommonStub

Any ideas would be great :D
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Post by 01000101 »

Just a thought, you might want to try re-enabling interrupts after one is handled... try putting a 'sti' at the end of the general ISR stub.
voidlogic
Posts: 8
Joined: Thu Feb 28, 2008 2:43 pm

RE: add sti

Post by voidlogic »

I can try that, though I don't think it will matter, iret is also an implict sti if I remember correctly. Thanks for the idea :)
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Post by 01000101 »

=) sry if it doesn't work.
all my IDT/ISR coding is in C, so I have to use it at the end.
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

But simply pressing keys does not work.
You have to ensure that the keyboard's buffer is empty. If it's full, no IRQs will fire. A better test would be to see if the PIT fires properly (IRQ 0).
voidlogic
Posts: 8
Joined: Thu Feb 28, 2008 2:43 pm

Post by voidlogic »

You have to ensure that the keyboard's buffer is empty. If it's full, no IRQs will fire. A better test would be to see if the PIT fires properly (IRQ 0).
I agree, a timer would be a better test, I will try that. I am a bit confused about the keyboard buffer you mention. In my last OS I read a scancode from a port- no buffer (I wasn't aware of any buffer besides my own). Is this buffer in hardware? Where can I find out more about it (primarily, how to clear it). I tried googling, but didn't come up with much. Now I'm digging through my Intel manuals. Let me know if you have any tips. Thanks
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

voidlogic wrote:
You have to ensure that the keyboard's buffer is empty. If it's full, no IRQs will fire. A better test would be to see if the PIT fires properly (IRQ 0).
I agree, a timer would be a better test, I will try that. I am a bit confused about the keyboard buffer you mention. In my last OS I read a scancode from a port- no buffer (I wasn't aware of any buffer besides my own). Is this buffer in hardware? Where can I find out more about it (primarily, how to clear it). I tried googling, but didn't come up with much. Now I'm digging through my Intel manuals. Let me know if you have any tips. Thanks
Yes, there is a buffer in hardware. It stores the scancodes generated until you read them (inb(0x60)). You should do a simple loop first:

Code: Select all

while(inb(0x64)&1)
  inb(0x60);
This will read from the keyboard controller until there is no data left. Then you should recieve an interrupt when more is available.
voidlogic
Posts: 8
Joined: Thu Feb 28, 2008 2:43 pm

Still not working :(

Post by voidlogic »

Well, I tried clearing the keyboard buffer to no avail. Then I realized ints are not firing at all becuase my general interrupt handler should be saying the timer is firing, even if it doesn't have a handler to call for the timer....

Below is my enable/disable int functions and a copy of my general interrupt handler (see my first post for more detail).
Any ideas would be great, I am stumped. :(

Code: Select all

inline void enableInterrupts()
{
    __asm__ __volatile__ ("sti");
}

inline void disableInterrupts()
{
    __asm__ __volatile__ ("cli");
}

void irqHandler(regs *state)
{
    system.console<<endl<<"IRQ "<<state->intNum<<" fired."<<endl;
    void (*handler)(regs *state);
    handler = (void (*)(regs*))handlerIdt->irqHandlers[state->intNum - 32];
    if (handler)
        handler(state);
    //if an irq then we need to send an EOI to the slave PIC
    if (state->intNum >= 40)
        outportb(0xA0, 0x20);
    //Always send EOI to master PIC
    outportb(0x20, 0x20);
}
voidlogic
Posts: 8
Joined: Thu Feb 28, 2008 2:43 pm

I'm really sorry

Post by voidlogic »

I'm an idiot :idea: . I need to apologize to everyone who has been so helpful.
I was working in my kernel class and I hadn't looked at my main.cpp in a long time. What I didn't realize that I had accidentally commented out while(true); along with comments. It actually all works fine, interrupts where not firing because execution had been halted. Thanks again for the help and patience. :wink:
Post Reply