Can't enable IRQs with I/O APIC

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
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Can't enable IRQs with I/O APIC

Post by BrightLight »

I have SMP support in my kernel now, and it boots up to 16 CPUs perfectly fine.
But I have an issue trying to enable IRQs. I set up 24 IRQs in the I/O APIC registers 0x10 - 0x3F, and I'm perfectly sure I'm doing that correctly. I put the interrupt number in the lowest 8 bits and set bits 56-63 to the CPU number I want to receive the interrupt.
Then, I set up the PIT and install its IRQ handler. In Bochs and QEMU, the IRQ is received once. However, in QEMU if I emulate more than 2 CPUs it doesn't get called at all. On my laptop (4 CPUs), it is also never received.
Can someone point out what I'm doing wrong? Do I need to do something with the local APIC? Do I need to enable the I/O APIC somehow?
P.S.: Is there an alternative for EOI on the I/O APIC?
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Can't enable IRQs with I/O APIC

Post by Brendan »

Hi,
omarrx024 wrote:I have SMP support in my kernel now, and it boots up to 16 CPUs perfectly fine.
But I have an issue trying to enable IRQs. I set up 24 IRQs in the I/O APIC registers 0x10 - 0x3F, and I'm perfectly sure I'm doing that correctly. I put the interrupt number in the lowest 8 bits and set bits 56-63 to the CPU number I want to receive the interrupt.
Then, I set up the PIT and install its IRQ handler. In Bochs and QEMU, the IRQ is received once. However, in QEMU if I emulate more than 2 CPUs it doesn't get called at all. On my laptop (4 CPUs), it is also never received.
Can someone point out what I'm doing wrong? Do I need to do something with the local APIC? Do I need to enable the I/O APIC somehow?
P.S.: Is there an alternative for EOI on the I/O APIC?
You'd need to (in order):
  • Parse ACPI 's "MADT/APIC" table to figure out how legacy ISA IRQs are connected to IO APIC inputs (and fall back to Intel's "MultiProcessor Specification" tables if there is no ACPI).
  • Mask all IRQs (not the "cascade" line) in the PIC chips
  • Mask everything in all IO APICs. You can "pre-setup" each IO APIC input while doing this. Note: there can be more than one IO APIC - e.g. a pair of IO APICs with 16 inputs each, or a set of four IO APICs, or....
  • Create (or make sure you already have) an IDT with interrupt vectors for the local APIC's spurious IRQ, the master PIC's spurious IRQ and the slave PIC's spurious IRQ.
  • For each CPU (in any order):
    • Set the local APIC's "Task Priority Register" to zero
    • Setup the local APIC's "Spurious Interrupt Vector Register" (give it a vector for the spurious IRQ, and enable the local APIC)
    • (Optional maybe) setup the local APIC's "Destination Format Register" for flat mode
    • (Optional maybe) setup the local APIC's "Logical Destination Register"
    • Do whatever ACPI and/or MP spec tables told you to do (if anything) with the local APIC's "LINT0" and "LINT1" interrupts
  • If ACPI and/or MP spec tables told you there's an IMCR, diddle the IMCR to switch from "PIC mode" to "IO APIC mode" (see MP spec for details)
Once that's done; when you initialise a device (e.g. PIT chip), after doing any resetting and/or self-testing you'd want to install a suitable interrupt handler for it in the IDT, and after that unmask its IRQ in the IO APIC (and not in any PIC chip).

Finally; when an interrupt does occur (excluding any of the spurious IRQs) you have to send an EOI to the local APIC's "EOI Register" (and not to any PIC chip).


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.
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: Can't enable IRQs with I/O APIC

Post by BrightLight »

Brendan wrote:Parse ACPI 's "MADT/APIC" table to figure out how legacy ISA IRQs are connected to IO APIC inputs (and fall back to Intel's "MultiProcessor Specification" tables if there is no ACPI).
Does this mean I use APIC table entry type 2 (interrupt source override)?
Brendan wrote:Set the local APIC's "Task Priority Register" to zero
What is the register offset?
Thanks in advance!
P.S.: How do I send EOI?
Last edited by BrightLight on Thu Jan 07, 2016 5:14 am, edited 1 time in total.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Can't enable IRQs with I/O APIC

Post by Brendan »

Hi,
omarrx024 wrote:
Brendan wrote:Parse ACPI 's "MADT/APIC" table to figure out how legacy ISA IRQs are connected to IO APIC inputs (and fall back to Intel's "MultiProcessor Specification" tables if there is no ACPI).
Does this mean I use APIC table entry type 2 (interrupt source override)?
Yes.

For ACPI, the general idea is that you start by assuming there's a 1:1 mapping between ISA IRQs and IO APIC inputs (e.g. "IO APIC input #0 = ISA IRQ0; IO APIC input #1 = ISA IRQ1; ...; IO APIC input #15 = ISA IRQ15", but skipping "ISA IRQ 2" because it doesn't exist).

Then the "interrupt source override" structures (in ACPI's MADT/APIC table) tells you how that assumed/original 1:1 mapping needs to be changed. Typically you'll have one for ACPI's SCI and one for "ISA IRQ0", but different computers are different.
omarrx024 wrote:
Brendan wrote:Set the local APIC's "Task Priority Register" to zero
What is the register offset?
I don't remember these details (I just look them up in Intel's manual when I need to); but if you want me to guess, "offset 0x340" sounds like it might be close to me.. ;)


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.
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: Can't enable IRQs with I/O APIC

Post by BrightLight »

Thanks a lot! I've got the IRQs working on Bochs, QEMU and real hardware.
But I still have one problem: the IRQ is only received once. When I try to send an EOI to the local APIC register 0xA0, Bochs console log says:

Code: Select all

00028654781i[APIC0 ] warning: write to read-only APIC register 0xa0
How do I send EOI?
EDIT: I've figured how to send EOI from the Intel manuals and inter-processor IRQs are working like a charm. Thanks again!
You know your OS is advanced when you stop using the Intel programming guide as a reference.
digo_rp
Member
Member
Posts: 233
Joined: Sun Jun 05, 2005 11:00 pm

Re: Can't enable IRQs with I/O APIC

Post by digo_rp »

to send EOI

ApicWrite(0xB0, 0);

:D
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: Can't enable IRQs with I/O APIC

Post by BrightLight »

digo_rp wrote:to send EOI

ApicWrite(0xB0, 0);

:D
Thanks, but I've already figured this out from Intel's manual. :)
You know your OS is advanced when you stop using the Intel programming guide as a reference.
Post Reply