assemblyx86portirq

Handling x86 IRQs from secondary PIC: EOI order important?


I recently added a part to an application of mine which is meant to allow it to operate with an IRQ belonging to the secondary PIC. In particular, the interrupt handler needs to signal an End Of Interrupt condition to both PICs then instead of only the primary one. This is my code:

  push cs
  pop ds
  mov al, 20h   ; acknowledge interrupt
  cmp byte [serial_use_irqmask + 1], 0
  je @F
  out 0A0h, al  ; to secondary PIC
@@:
  out 20h, al   ; to primary PIC

Now, while adding this part I considered whether to signal the EOI to the secondary PIC first, or to the primary PIC. Searching for that did not yield any statements either way. However, I found that some examples seem to choose the order I ended up implementing; that is the secondary PIC first, then the primary.

My question is, does this matter at all? Is there an actual reason to prefer either order?

Examples of secondary PIC first

bootlib interrupt handlers:

                movb $0x20, %al # end of interrupt command
                outb %al, $0xA0 # PIC2 command port
                outb %al, $0x20 # PIC1 command port

osdev.org wiki's article on Interrupts:

mov al, 20h
out A0h, al
out 20h, al

Pure64 interrupt handlers:

        mov al, 0x20        ; Acknowledge the IRQ
        out 0xA0, al
        out 0x20, al

Dos64-stub interrupt handlers:

Irq0007_1:
    mov al,20h
    out 20h,al
    pop rax
swint:
    iretq
;--- IRQs 8-F
Irq080F:
    push rax
    mov al,20h
    out 0A0h,al
    jmp Irq0007_1

Example of primary PIC first

Example in the German Wikipedia article "Softwarebremse" ("Bremse" means "Brake"):

   mov al, 20h
   out 020h, al
   out 0a0h, al
   sti

Solution

  • I don't think it matters.
    The 8259A datasheet doesn't shed any more light, only stating (twice):

    An EOI command must be issued twice: once for the master and once for the corresponding slave.

    No order is stated explicitly.

    Sending the EOI to the slave first still won't allow any IRQ from the slave (until the EOI to the master), because the master won't serve any of the slave requests. When the master receives the EOI, all IRQs will be allowed.

    Sending the EOI to the master first will allow new master IRQs but no slave IRQs, until the slave receives the EOI too.

    So sending the EOI to the slave first won't change the "interruptability" of the system while the master is still waiting for its EOI.
    This allows finer control of the moment the system is ready to accept lower-priority interrupts. Assuming the IF flag is set before iret.


    As far as the PICs are concerned, there is no technical requirement to use a specific order.

    I don't think there a difference in the risk of losing slave IRQs: The PIC will set the IRR bit immediately upon the assertion of the relative IRQ pin but the ISR bit is set only after receiving the ACK from the CPU (and the IRR bit is cleared).
    The IRR-ISR pair form a mini-queue, with the IRR buffering a request while an interrupt is still being served.
    When the slave receives the EOI first and the master doesn't, it's the master that prevents the slave from setting the ISR and clearing the IRR by not issuing an interrupt request to the CPU. When the master receives the EOI first and the slave doesn't, it's the slave itself that won't issue an interrupt request.
    In any case, the IRR is never cleared and only one IRQ request can be buffered.

    Sending the EOI to the master first may unlock its (high-priority) IRQs earlier but we are talking about the timing of a few instructions.
    Again assuming the IF flag is set before iret.

    I don't see any reason to prefer any of the two ordering.