Skip to content

vGIC: disabling an active HW interrupt orphans it, leaking the physical interrupt #371

Description

@irenebus

Hi, I was running Linux with Bao on my board (an ARMv8-A platform) and using the UART as the serial console. When init started (Run /sbin/init as init process) and the serial driver switched from polling to interrupt mode, the console output stalled — no more UART interrupts were delivered after the first one. After some debugging I
found that the UART interrupt was permanently stuck in Active at the GIC level.

With some debug prints I was able to trace what happens:

The interrupt is disabled while it is Active — that is, already acknowledged via IAR but not yet EOIR. This reconfiguration traps to EL2 and lands in vgic_int_set_field() (vgic.c:685), which does:

  1. vgic_remove_lr() — clears the LR, saves state = ACT.
  2. update_field() — sets enabled = false.
  3. vgic_route() — tries to re-place the interrupt.

But vgic_route() (vgic.c:147) returns immediately:

if ((interrupt->state == INV) || !interrupt->enabled) {
    return;
}

The interrupt is now orphaned: state = ACT, in_lr = false, and not in the spilled queue either.

Later the guest writes EOIR, finding no correspond entry in LRs, so it increments EOICount and fires the LRENP maintenance interrupt. vgic_eoir_highest_spilled_active() scans the spilled queues and still finds nothing — we never put it there. The physical deactivation never happens, and the UART interrupt line is dead.

(Changing the affinity of an active interrupt seems to have a similar issue.)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions