Only one PIT IRQ

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
gsingh2011
Member
Member
Posts: 83
Joined: Tue Feb 03, 2009 11:37 am

Only one PIT IRQ

Post by gsingh2011 »

I just set up IRQs and the PIT, but I only see one IRQ from the PIT. After the IRQ, I see that the IF bit is not set in EFLAGS. Shouldn't iret set the IF bit back to one? I tried adding sti before iret, but that didn't work either. Here's my IRQ code:

Code: Select all

; First parameter is IRQ number, second is IDT entry number
%macro IRQ 2
    global irq%1
    irq%1:
        cli
        push 0
        push %2
        jmp irq_common_stub
%endmacro

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 ; Defined in irq.c

irq_common_stub:
    pusha              ; Push all general purpose registers

    push ds            ; Push all data segment registers
    push es
    push fs
    push gs

    mov ax, 0x10       ; Load the kernel data segment descriptor
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    call irq_handler   ; Handle the IRQ

    pop gs             ; Restore all regs modified in this function
    pop fs
    pop es
    pop ds

    popa
    add esp, 8         ; Cleans up the stack
    iret               ; Return from interrupt
On the screen I see the output from one clock tick, meaning the IRQ happens once. How can I re-enable interrupts after each IRQ?
User avatar
piranha
Member
Member
Posts: 1391
Joined: Thu Dec 21, 2006 7:42 pm
Location: Unknown. Momentum is pretty certain, however.
Contact:

Re: Only one PIT IRQ

Post by piranha »

You need to send an ACK back to the PICs (clicky).

Yes, IRET should re-set the flag back to what it was previously, but you need to tell the PICs that its okay to send interrupts again.
SeaOS: Adding VT-x, networking, and ARM support
dbittman on IRC, @danielbittman on twitter
https://dbittman.github.io
gsingh2011
Member
Member
Posts: 83
Joined: Tue Feb 03, 2009 11:37 am

Re: Only one PIT IRQ

Post by gsingh2011 »

I forgot to post the source for irq_handler(). Is this what you're talking about?

Code: Select all

#define MASTER_PIC_COMMAND_PORT 0x20
#define SLAVE_PIC_COMMAND_PORT  0xA0

void irq_handler(interrupt_stack_frame_t frame) {
    if (frame.interrupt_number > 40) {
        // Reset slave
        outb(SLAVE_PIC_COMMAND_PORT, 0x20);
    }

    // Reset master
    outb(MASTER_PIC_COMMAND_PORT, 0x20);

    if (interrupt_handlers[frame.interrupt_number] != NULL) {
        interrupt_handler *handler = interrupt_handlers[frame.interrupt_number];
        handler(frame);
    }
}
gsingh2011
Member
Member
Posts: 83
Joined: Tue Feb 03, 2009 11:37 am

Re: Only one PIT IRQ

Post by gsingh2011 »

Does anyone have any ideas on how to debug this? Is there any way to query the PIC to see if it's properly reset?
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: Only one PIT IRQ

Post by xenos »

The best way is to use Bochs and to enable debug messages for the PIC. Then it tells you in its log file everything the PIC does, including its reset.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
gsingh2011
Member
Member
Posts: 83
Joined: Tue Feb 03, 2009 11:37 am

Re: Only one PIT IRQ

Post by gsingh2011 »

Thanks for the help. Your response prompted me to see if there was similar functionality in QEMU, and I found that I could type 'info pic' at the QEMU console to get some useful information.

Before the PIT interrupt (IRQ0), IRR = 00 and ISR = 00. After the interrupt IRR = 01 and ISR = 00.

Wikipedia states:
The IRR specifies which interrupts are pending acknowledgement, and is typically a symbolic register which can not be directly accessed. The ISR register specifies which interrupts have been acknowledged, but are still waiting for an End Of Interrupt (EOI).
So what does the fact that ISR still equals 0 mean? That the IRQ hasn't been acknowledged or has been acknowledged and is waiting for an EOI?
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: Only one PIT IRQ

Post by xenos »

The first - it means that the CPU hasn't acknowledged the IRQ yet, i.e., it has not started processing the interrupt. As soon as your IRQ handler starts it will acknowledge the IRQ (this is done automatically, you don't need code for that), after that you should have IRR=0 and ISR=1 (since the IRQ is now "in service"). Finally you need to send EOI, so this will clear the ISR.
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
gsingh2011
Member
Member
Posts: 83
Joined: Tue Feb 03, 2009 11:37 am

Re: Only one PIT IRQ

Post by gsingh2011 »

I noticed that if I add a delay after the reset it actually works fine. For example,

Code: Select all

#define MASTER_PIC_COMMAND_PORT 0x20
#define SLAVE_PIC_COMMAND_PORT  0xA0

void irq_handler(interrupt_stack_frame_t frame) {
    if (frame.interrupt_number > 40) {
        // Reset slave
        outb(SLAVE_PIC_COMMAND_PORT, 0x20);
    }

    // Reset master
    outb(MASTER_PIC_COMMAND_PORT, 0x20);
    int i = 10000000;
    while (i--);

    if (interrupt_handlers[frame.interrupt_number] != NULL) {
        interrupt_handler *handler = interrupt_handlers[frame.interrupt_number];
        handler(frame);
    }
}
Notice the while loop. If I remove that I only see one PIT tick, otherwise I see the PIT continuously ticking. Obviously, this isn't a proper solution to the problem, but it might help diagnose the problem. Any ideas?
Nable
Member
Member
Posts: 453
Joined: Tue Nov 08, 2011 11:35 am

Re: Only one PIT IRQ

Post by Nable »

> 0x20
This is not reset, it's an EOI (end of interrupt [handling]) command. You should send it at the _end_ of the handler.
http://wiki.osdev.org/PIC#End_of_Interrupt
gsingh2011
Member
Member
Posts: 83
Joined: Tue Feb 03, 2009 11:37 am

Re: Only one PIT IRQ

Post by gsingh2011 »

I had already tried that, but it doesn't work. With the while loop (to cause a delay), it works, but again, that's not a solution to the problem.

I've tried to go through different scenarios of how getting interrupts at different states of the IRR and ISR registers could cause problems, but I haven't found anything problematic.
Nable
Member
Member
Posts: 453
Joined: Tue Nov 08, 2011 11:35 am

Re: Only one PIT IRQ

Post by Nable »

> I had already tried that, but it doesn't work.
Could you clarify what do you mean under `that', please? Moving EOI to the end of interrupt handler from it's beginning?

> With the while loop (to cause a delay), it works
It seems to me that with this delay you are waiting until interrupt fires for the second time after the early EOI.
I didn't try debugging full version of your code, so that's just an assumption, sorry.
gsingh2011
Member
Member
Posts: 83
Joined: Tue Feb 03, 2009 11:37 am

Re: Only one PIT IRQ

Post by gsingh2011 »

Yea, I meant move the EOI command to the end of the IRQ handler. In other words (I've changed the command sending interface around a bit, but it does the same thing),

Code: Select all

void irq_handler(interrupt_stack_frame_t frame) {
    ASSERT_INTERRUPTS_DISABLED();

    if (interrupt_handlers[frame.interrupt_number] != NULL) {
        interrupt_handler *handler = interrupt_handlers[frame.interrupt_number];
        handler(frame);
    }

    if (frame.interrupt_number > 40) {
        // Reset slave
        PIC_send_command(&slave, 0x20);
    }

    // Reset master
    PIC_send_command(&master, 0x20);
    int i = 10000000;
    while (i--);
}
When irq_handler starts and right before the EOI is sent, IRR = 0 and ISR = 1. When the EOI is sent, IRR = 0 and ISR = 0. After the while loop delay, IRR = 1 and and ISR = 0. So yes, the while loop essentially waits for the next interrupt before letting the IRQ handler finish. But I don't understand why it doesn't work without this.
gsingh2011
Member
Member
Posts: 83
Joined: Tue Feb 03, 2009 11:37 am

Re: Only one PIT IRQ

Post by gsingh2011 »

I have no idea what to do and I'm completely stuck on this issue. I've pushed all my code here: https://github.com/gsingh93/edos/tree/pic.

Can someone take a look? Important files are irq.c, irq_asm.s, and pit.c. Any help is appreciated.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Only one PIT IRQ

Post by Brendan »

Hi,
gsingh2011 wrote:Can someone take a look? Important files are irq.c, irq_asm.s, and pit.c. Any help is appreciated.
I'd assume that the problem has nothing to do with IRQs, the PIC or the PIT; and that the code simply crashes and/or goes into an infinite loop after initialising things.

I'm also curious about the "return 0;" at the end of "kmain()" - why is it returning at all, and what is it returning to?

As far as I can tell, it returns to the code in "loader.s", which does CLI and then goes into an infinite loop...


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
gsingh2011
Member
Member
Posts: 83
Joined: Tue Feb 03, 2009 11:37 am

Re: Only one PIT IRQ

Post by gsingh2011 »

I'm an idiot. A complete idiot. Thank you for the help. I take it that the reason the delay fixed the issue was there was always an interrupt to service, so the timer_callback was always called, and the code never got a chance to return and halt.
Post Reply