This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

GICv3: Purpose of EOIcount in ICH_HCR_EL2 and LRENPIE maintenance interrupt

My initial understanding was that with LRENPIE set, any EOI coming from the guest on IRQs that are not in any LRs, will result in a maintenance interrupt and the hypervisor can check which IRQ was deactivated.

Upon taking a closer look though, I can't understand how this can be done. Since such an event will cause an asynchronous exception and not a data abort (like a regular trap), you cannot use the ESR to get the register number that the guest used for the EOI/DIR. The manual only mentions EOIcount, but that's just a counter of how many EOIs occured without a relevant LR.

So my question is, how can you tell which IRQ the guest EOIed, by using the LRENPIE maintenance interrupt and without trapping all EOI guest accesses?

Parents Reply Children
  • The thing to remember is that interrupt priority restricts what order the interrupts can be taken in.  To be ack’ed an interrupt must be higher priority than the current Running Priority, and by ack’ing the interrupt the Running Priority increases.  Therefore, a high priority interrupt can pre-empt a low priority interrupt, but not the other way round.

    Note: In GIC lower numeric values are higher priority.

    Let’s have an example for a PE with 2 List Registers (2 only because it’ll be quicker to write out). 

    The hypervisor has two virtual interrupts to present:

    • A: pri 0x8
    • B: pri 0x7

    It sets up two List Registers, enters the guest, the guest reads the IAR and gets.. B.  Because generally the GIC will give you the higher priority interrupt if it has a choice.

    Now this means we won’t see your scenario.  When we ack’ed B, the Running Priority became 0x7.  Interrupt A is lower priority (numerically higher) and therefore cannot pre-empt.  It won’t be signalled, or returned by a read of IAR, until software does the priority drop/write to EOIR.

    To get the interesting scenario the interrupts have to arrive one at a time. 

    • T0: Initially the Hypervisor only knows about Int A.  It sets up the List Register, the Guest takes the interrupt and acks it, the virtual running priority is now 0x8.
    • T1: Int B becomes available.  The Hypervisor sets up a second List Register, the Guest takes the interrupt and acks it, the virtual running priority is now 0x7.
    • T2: Int C (pri=x06) becomes available.  All the List Registers are full, so the Hypervisor spills Int A and uses the slot for Int C.  The Guest takes the interrupt and acks it, the virtual running priority is now 0x6.
    • T3:  Int D (pri=0x5) becomes available.  Again, all the List Registers are full, the Hypervisor spill Int B and uses the slot for Int D.  The Guest takes the interrupt and acks it.

    So, at this point there are four active virtual interrupts, two in the List Registers (C & D) and two spilled (A & B).  There are also four active virtual priorities, giving an overall virtual running priority of 0x5.

    Now the Guest will start writing to EOIR.  We’ll assume the guest follows the correct order and EOICount is initially 0. 

    • T4: The Guest writes EOIR with Int D.  This hits in the List Register, which gets updated.  EOICoint remains at 0.
    • T5: The Guest writes EOIR with Int C.  This hits in the List Register, which gets updated.  EOICoint remains at 0.
    • T6: The Guest writes EOIR with Int B.  This misses in the List Register.  Meaning that EOICount is incremented and becomes 1.
    • T7: Something causes entry to the hypervisor.

    The hypervisor wants to get a picture of the over status of the virtual GIC.  It knows which interrupts it presented (A, B, C and D) and what the priorities of those interrupts were.  Because it knows the priorities, it knows the possible orders the interrupts could have nested.  It also knows if these were ack’ed by the guest (either from when it spilled the List Registers or by looking at the List Registers now).  

    Question: Which, if any, interrupts are Active?  And how does the Hypervisor know this?

    For C and D, this is easy.  The Hypervisor just needs to look at the List Registers, both of which have been set to Inactivate by the guest’s writes to EOIR.

    The hypervisor also sees that the EOICount is 1 – so one of the spiled interrupts also been EOIR’ed.  But which one?

    That’s where priority comes in.  The answer has to be that Int B was EOIR’ed, leaving Int A as the only still Active interrupt.  It has to be this way because of the priorities of Int A and B.  Int B could have pre-empted Int A, but not the other way round.  So if the Guest is sticking to the rules, it must have Ack’ed A before B, and must therefore have EOIR’d B before A.

  • Thanks Martin, that was very detailed and clear.