I'm working on a general-purpose limited hardware abstraction layer (limited in that it only deals with the processor and core platform components, not peripheral devices) and I'm trying to figure out the easiest and least limiting way to initialize IRQ routing so that whatever is built on top of it can express which IRQs it wants to wait for in a consistent fashion. I've already got what I believe to be an adequate API on the software side, which resembles a select() interface with an additional call for sending EOIs.
What I'm stuck on is getting the APIC architecture to send interrupts to the right places in such a way that I can figure out which device they actually came from. I'm used to dealing with the legacy 8259 PIC, which I used in my last project, so I'm not yet fully acquainted with the whole I/O APIC mess. It seems like there are a lot of methods out there to try and untangle IRQ routing (MP tables, ACPI tables, etc.) but a lot of it is old, and I can't seem to figure out what the "standard" method is nowadays. I really only want to target x86_64 hardware with SMP support, and can deal with dropping support for anything more than 5 years old. The primary purpose of the project is as a didactic tool, and it will be running mostly on virtualized hardware.
What would those of you who have dealt with the I/O APIC recommend in this situation?
General IRQ routing on x86_64
- NickJohnson
- Member
- Posts: 1249
- Joined: Tue Mar 24, 2009 8:11 pm
- Location: Sunnyvale, California
Re: General IRQ routing on x86_64
If you don't want your HAL to deal with devices other than the Core devices, you have almost no way of telling which device is causing an interrupt. Specially so when you allow drivers to specify an IRQ number.
My way of doing it would be: receive IRQ; (I will already know the IRQ number); iterate through a list of drivers waiting for IRQs; find one that is waiting for the IRQ just received; invoke it.
Of course, this is just an example and may or may not (most likely) be efficient or feasible in the real world.
My way of doing it would be: receive IRQ; (I will already know the IRQ number); iterate through a list of drivers waiting for IRQs; find one that is waiting for the IRQ just received; invoke it.
Of course, this is just an example and may or may not (most likely) be efficient or feasible in the real world.
Always give a difficult task to a lazy person. He will find an easy way to do it.
- NickJohnson
- Member
- Posts: 1249
- Joined: Tue Mar 24, 2009 8:11 pm
- Location: Sunnyvale, California
Re: General IRQ routing on x86_64
I already have that part figured out. What I'm stuck on is getting IRQ numbering that can be predictably used by a system running under the HAL, so that the system can predict which devices it is configuring will be connected to which (virtual) IRQ lines the HAL presents.
Re: General IRQ routing on x86_64
In terms of hardware representation resource wise you'll have a combination of IRQs and global system interrupts. Basically IRQs are assumed to map to the first 16 global system interrupts unless there's an entry in the MADT or MP tables overriding the routing (as well as trigger mode). In terms of the APIC and EOIs, I simply have a class of devices described as an interrupt router that supply a range of global system interrupts and describe the EOI method of the device.
The interrupt interface for software interrupts on the processor itself basically consists of an array of function pointers and another array of argument values. When an interrupt is triggered the ISR will call the function with the argument. That argument is stored when the interrupt is initially enabled and routed to the processor(s). For sake of forward compatibility and perhaps better diagnostics you would probably want to store a structure containing a function pointer to an EOI method, a pointer to the interrupt router object itself and whatever other information you feel is necessary.
The interrupt interface for software interrupts on the processor itself basically consists of an array of function pointers and another array of argument values. When an interrupt is triggered the ISR will call the function with the argument. That argument is stored when the interrupt is initially enabled and routed to the processor(s). For sake of forward compatibility and perhaps better diagnostics you would probably want to store a structure containing a function pointer to an EOI method, a pointer to the interrupt router object itself and whatever other information you feel is necessary.
Reserved for OEM use.
Re: General IRQ routing on x86_64
There are several new issues with APIC.
1. You allocate the interrupt vector number from the IDT, rather than having a fixed mapping as between PIC entry and interrupt vector.
2. Some services need several consecutive interrupt vectors (AHCI for instance).
3. Priority is based on the higher bits of the vector number, meaning that the allocation algorithm should have a priority indicator
4. In order to determine PCI IRQ routings, you need ACPI and AML (or detection logic).
5. There is a new (superior) method for interrupts with PCI called MSI, which should be preferred if present.
1. You allocate the interrupt vector number from the IDT, rather than having a fixed mapping as between PIC entry and interrupt vector.
2. Some services need several consecutive interrupt vectors (AHCI for instance).
3. Priority is based on the higher bits of the vector number, meaning that the allocation algorithm should have a priority indicator
4. In order to determine PCI IRQ routings, you need ACPI and AML (or detection logic).
5. There is a new (superior) method for interrupts with PCI called MSI, which should be preferred if present.