IOAPIC Interrupt correctly set, but code is never run

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
ATXcs1372
Member
Member
Posts: 30
Joined: Wed Jun 01, 2011 7:14 pm

IOAPIC Interrupt correctly set, but code is never run

Post by ATXcs1372 »

I am running this under bochs, so let me walk you through this:

Initial Problem:
I'm trying to get the APIC Timer to fire vector 0x20 (32) of the IDT. I have correctly set the timer as bochs is giving repeated

Code: Select all

00024807285d[APIC0] local apic timer(periodic) triggered int
messages. The problem though lies in the fact the code for that vector is never run and thus the EOI message is never sent and the previous message is followed by

Code: Select all

00024832885d[APIC0] triggered vector 0x20 not accepted
but only on the second time the interrupt is triggered, making the EOI problem pretty apparent.


Double Checks:
Correct code location is placed into vector 0x20 as I can call the location as a form a pointer function and it works (until the iretq).

Code: Select all

IDT[0x20]=64-Bit Interrupt Gate target=0x0018:0000000000201040, DPL=0
Correctly installed IOAPIC INTIN0 to vector 0x20

Code: Select all

00018381615d[IOAP ] IOAPIC: now entry[0] is dest=00, masked=0, trig_mode=0, remote_irr=0, polarity=0, delivery_status=0, dest_mode=0, delivery_mode=0, vector=20
The code to be called is

Code: Select all

localAPICTimerISR:
    push    rax
    mov     al, '6'
    mov     [0x000B809C], al
    mov     al, '0'
    mov     [0x000B809E], al
    
    mov     rax, QWORD [0x5000]                        ; stored location of local APIC for BSP
    add     rax, 0xB0
    mov     DWORD [rax], 0                                  ; set EOI

    pop     rax
    iretq
Final:
Initially I worried about the plain "vector=20" from the IOAPIC message, but even installing at vector #20 the code did not run.
There is nothing printed to the screen (the two 0xB8000 locations).
The ISR is installed to the IDT long before the timer is set up.

Am I missing something obvious?
User avatar
brain
Member
Member
Posts: 234
Joined: Thu Nov 05, 2009 5:04 pm
Location: UK
Contact:

Re: IOAPIC Interrupt correctly set, but code is never run

Post by brain »

Check the trigger mode and polarity of the ioapic Interrupt redirection, I had similar problems at first and my code was zeroing the ioapic register...
Rudster816
Member
Member
Posts: 141
Joined: Thu Jun 17, 2010 2:36 am

Re: IOAPIC Interrupt correctly set, but code is never run

Post by Rudster816 »

You need to set a color for the characters printed :wink:
ATXcs1372
Member
Member
Posts: 30
Joined: Wed Jun 01, 2011 7:14 pm

Re: IOAPIC Interrupt correctly set, but code is never run

Post by ATXcs1372 »

brain wrote:Check the trigger mode and polarity of the ioapic Interrupt redirection, I had similar problems at first and my code was zeroing the ioapic register...
AFAIK it should be a fixed interrupt (dest mode = 0) with active high (polarity = 0) and edge triggered (trigger mode = 0) which matches what bochs is telling me...
ATXcs1372
Member
Member
Posts: 30
Joined: Wed Jun 01, 2011 7:14 pm

Re: IOAPIC Interrupt correctly set, but code is never run

Post by ATXcs1372 »

Rudster816 wrote:You need to set a color for the characters printed :wink:
While technically yes I should write the attribute byte for those, they've already been written from previous debug info at those two locations.
Regardless, no matter what function I make the vector point to, it isn't executed.
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: IOAPIC Interrupt correctly set, but code is never run

Post by xenos »

I'm a bit confused. The local APIC timer interrupt is not directed through the IOAPIC, it is generated in the local APIC. If you direct IRQ0 through the IOAPIC to the same interrupt vector 0x20, you point the PIT timer interrupt to the same interrupt vector. If you wish to use only the local APIC timer, there is no need to fiddle around with the IOAPIC at all. The only thing you need to set is the local APIC's LVT.

BTW, the message generated by Bochs ("triggered vector 0x20 not accepted") indicates that the corresponding bit of the IRR is set when the interrupt arrives, and so the interrupt is discarded, which may be caused by not correctly sending an EOI. However, this still doesn't explain why your interrupt handler doesn't get called (because otherwise it would print something to the screen and send an EOI).

Could you provide the code you use to setup the local APIC timer and LVT?
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
ATXcs1372
Member
Member
Posts: 30
Joined: Wed Jun 01, 2011 7:14 pm

Re: IOAPIC Interrupt correctly set, but code is never run

Post by ATXcs1372 »

XenOS wrote:I'm a bit confused. The local APIC timer interrupt is not directed through the IOAPIC, it is generated in the local APIC. If you direct IRQ0 through the IOAPIC to the same interrupt vector 0x20, you point the PIT timer interrupt to the same interrupt vector. If you wish to use only the local APIC timer, there is no need to fiddle around with the IOAPIC at all. The only thing you need to set is the local APIC's LVT.

Could you provide the code you use to setup the local APIC timer and LVT?
You're right, I was misunderstanding the way the timer, APIC, and LVT worked together. I also had to change it to vector 0x21 due to the PIT interrupt I forgot I set :/

However, the vector in the LVT entry for the timer should be the vector for the IVT correct?

Here's how I setup the timer:

Code: Select all

void initializeAPICTimer(uint8_t vector)
{
    uint64_t apic = *((uint64_t *)0x5000);     ; local APIC location stored at 0x5000 by bootloader, is verified by kernel
    
    *((uint32_t *)(apic + APIC_SPUR))      |= 0x000001FF;
    *((uint32_t *)(apic + APIC_DFR))        = 0xFFFFFFFF;
    *((uint32_t *)(apic + APIC_TPR))        = 0x00000000;
    *((uint32_t *)(apic + APIC_TDCR))       = 0x00000003;
    *((uint32_t *)(apic + APIC_TMRLVTR))    = 0x00020000 | vector;
    *((uint32_t *)(apic + APIC_TICR))       = 0x00000640;
}
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: IOAPIC Interrupt correctly set, but code is never run

Post by Brendan »

Hi,
ATXcs1372 wrote:However, the vector in the LVT entry for the timer should be the vector for the IVT correct?
Yes.

Also note that the vector also determines interrupt priority. I'd be tempted to use a vector with a high number so that the local APIC timer has a higher priority than normal interrupts (and giving the local APIC's "spurious interrupt" a low number).
ATXcs1372 wrote:Here's how I setup the timer:
That looks correct to me, except you probably should use "volatile" (so that the C compiler doesn't decide that because the values written aren't used anywhere else the writes can be ignored/discarded). For example, maybe "volatile void *apic = *((void **)0x5000);".

For debugging, don't forget that you can read things like the local APIC timer's current count (should be decreasing or zero afterwards) and both the IRR and ISR (to see if the local APIC tried to send any IRQs that you missed).


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.
ATXcs1372
Member
Member
Posts: 30
Joined: Wed Jun 01, 2011 7:14 pm

Re: IOAPIC Interrupt correctly set, but code is never run

Post by ATXcs1372 »

Brendan wrote: That looks correct to me, except you probably should use "volatile" (so that the C compiler doesn't decide that because the values written aren't used anywhere else the writes can be ignored/discarded). For example, maybe "volatile void *apic = *((void **)0x5000);".
Raising the task priority nor the volatile attributes fixed the issue. I even moved the interrupt into a different priority block in the IVT.
At the moment there aren't any other interrupts called so priority or a long-running interrupt shouldnt be the issue.

Executing the following code does run the interrupt as expected, but while the timer is trying to call it the code just isn't running...

Code: Select all

asm volatile("int $0x21");
Post Reply