Hi,
arabasso wrote:If I use APIC, I have to "abandon" PIC 8259?
In theory, it is possible to use both at the same time. In practice there's no reason to use both at the same time as all IRQs that are connected to the PIC chips are also connected to the IO APIC anyway, and it just causes unnecessary confusion.
arabasso wrote:There are master and slave IRQ or not?
IRQs are just IRQs. There's a master and slave PIC because a single PIC chip only has 8 inputs and that wasn't enough so IBM added a second PIC chip. There isn't a master and slave I/O APIC. Usually there's only one I/O APIC with 24 inputs and that's enough inputs for everything. However, especially for servers, it's entirely possible to have multiple I/O APICs (e.g. one of the computers I have here has two I/O APICs where each has 16 inputs, and I've seen datasheets for large servers with four I/O APICs). When there are multiple I/O APICs they are all independent - none are "master" and none are "slaves".
arabasso wrote:I have to remap the master and slave IRQs as PIC?
You'd mask all IRQs in the PIC so they can't occur, and use the I/O APICs instead. However, it is still technically possible for the PIC chips to generate spurious IRQs (which can't be masked or prevented in the PIC); so just in case you'd still need to remap the PICs even though you aren't using them, and have spurious IRQ handlers for the PICs. In theory it may be possible to prevent the PICs from sending any signal to the CPU (by breaking the connection between the master PIC's "INTR" line and the CPU) but there's at least 3 different ways this signal can be connected to the CPU (directly to a local APIC input, via. an I/O APIC input, or via. a special gate in the chipset) and it's a lot easier not to bother (and more fun to collect statistics, so the administrator can find out how many spurious IRQs from the PIC chips have occurred, as a high number of spurious IRQs might indicate noisy signals and motherboard problems).
arabasso wrote:And last (not so important) in an MP environment, where there is a LAPIC for each processor, I have to install an interrupt handler for all CPUs? And when an interrupt occurs, the LAPIC are "minimally smart" and directs the interrupt to handler in the CPU only (it would be chaos if should call the same handler for all CPUs
), or I have to program this feature?
For IRQs from the IO APIC/s, you have to program the IO APIC to tell it which CPU/s each IRQ should be sent to, and the IRQ can be sent to a specific CPU or broadcast to multiple CPUs. For the local APIC there's several sources of interrupts - interrupts that were sent by software on other CPUs (called Inter-Processor Interrupts, or IPIs), the local APIC's inputs (which are typically only used for NMI and maybe the connection from the PIC chips to the CPUs), plus some internal interrupt sources - the local APIC timer's IRQ, the thermal status IRQ, the error IRQ, etc. All interrupts from the local APIC go to the CPU connected to that local APIC (you shouldn't try to broadcast something like the local APIC timer's IRQ to several CPUs, for e.g.).
In all of these cases (IPIs, I/O APIC and local APICs), for normal interrupts (e.g. not including things like NMI) software determines which interrupt vector (in the IDT) should be used for that interrupt; and there's a priority mechanism that depends on the interrupt vector. The CPU itself also has a "current priority level" that works in conjunction with the interrupt vector priorities (and has nothing to do with anything else, like current privilege level/CPL). Receiving an interrupt causes the CPU's priority to be raised to the priority of that interrupt, where lower priority interrupts are temporarily blocked. This means you'll probably want things like IPIs and the local APIC timer to use higher priority interrupt vectors and things like the floppy controller (and spurious IRQs) to use lower priority interrupt vectors (so that the local APIC timer and IPIs can interrupt the floppy controller's interrupt handler, but the floppy controller's IRQ can't interrupt the IPI handlers or local APIC timer's interrupt handler). The end result is that you want to dynamically assign interrupt vectors to different things depending on what type of device is connected to it - for e.g. if IO APIC input #12 is an ethernet controller then you might assign a higher priority interrupt vector to it, and if IO APIC input #12 is a sound card you might want to assign a lower priority interrupt vector to it instead.
Software can also change a CPUs current priority (where the CPU's priority is the priority software set or the priority of the interrupt currently being handled, whichever is higher). This means that (for just one example) you could have a very high priority "real time" process, and when the scheduler gives this process CPU time it could adjust the CPU's priority to prevent low priority IRQs from interrupting while the very high priority "real time" process is running.
Also, for IRQs from an I/O APIC, you can use a special "send to lowest priority CPU" mode. In this case, if one CPU is running a very high priority "real time" process, another CPU is handling a high priority interrupt and a third CPU is doing nothing, then hardware can automatically send the IRQ to the CPU that is doing nothing.
Normally, you only need one IDT that's shared by all CPUs, where all IDT entries can be used by any CPU/s. In this case, for IRQs (from the IO APIC) the IO APIC's configuration determines which CPU/s actually receive the IRQ and some CPUs may not use some of the IDT entries. For example, if you tell the IO APIC to always send an IRQ to CPU #2, then CPU #1 never receives that IRQ and therefore doesn't actually use the IDT entry for that IRQ.
For massive systems, it might (in theory) be beneficial to be "clever". For example, you could arrange CPUs in groups and have a slightly different IDT for each group. In this case, you could configure the IO APIC so that one IRQ is sent to CPUs in the first group as interrupt 0x33, and a completely different IRQ is sent to a different group of CPUs as interrupt 0x33. The IDT for the first group of CPUs would use interrupt 0x33 for one IRQ handler and the IDT for the second group of CPUs would use interrupt 0x33 for a completely different IRQ handler. That way you can have more than 256 IRQs even though there's only 256 IDT entries (and reduce the chance of needing IRQ sharing, and maybe use interrupt priorities more efficiently).
Cheers,
Brendan