aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Pavlu <petr.pavlu@suse.com>2022-01-13 16:19:16 +0100
committerPeter Maydell <peter.maydell@linaro.org>2022-01-20 11:47:52 +0000
commit5e66daec9ef0cd0107ba30225e23224c66ed24f3 (patch)
tree498f0d424eccf642a9240619f00433ffdcadddaa
parenta66a24585fae7036dc2f358c9addd1630be5c50c (diff)
hw/intc/arm_gic: Allow reset of the running priority
When running Linux on a machine with GICv2, the kernel can crash while processing an interrupt and can subsequently start a kdump kernel from the active interrupt handler. In such a case, the crashed kernel might not gracefully signal the end of interrupt to the GICv2 hardware. The kdump kernel will however try to reset the GIC state on startup to get the controller into a sane state, in particular the kernel writes ones to GICD_ICACTIVERn and wipes out GICC_APRn to make sure that no interrupt is active. The patch adds a logic to recalculate the running priority when GICC_APRn/GICC_NSAPRn is written which makes sure that the mentioned reset works with the GICv2 emulation in QEMU too and the kdump kernel starts receiving interrupts. The described scenario can be reproduced on an AArch64 QEMU virt machine with a kdump-enabled Linux system by using the softdog module. The kdump kernel will hang at some point because QEMU still thinks the running priority is that of the timer interrupt and asserts no new interrupts to the system: $ modprobe softdog soft_margin=10 soft_panic=1 $ cat > /dev/watchdog [Press Enter to start the watchdog, wait for its timeout and observe that the kdump kernel hangs on startup.] Signed-off-by: Petr Pavlu <petr.pavlu@suse.com> Message-id: 20220113151916.17978-3-ppavlu@suse.cz Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--hw/intc/arm_gic.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 0cd9ceca8d..492b2421ab 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -1736,6 +1736,7 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
} else {
s->apr[regno][cpu] = value;
}
+ s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu);
break;
}
case 0xe0: case 0xe4: case 0xe8: case 0xec:
@@ -1752,6 +1753,7 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
return MEMTX_OK;
}
s->nsapr[regno][cpu] = value;
+ s->running_priority[cpu] = gic_get_prio_from_apr_bits(s, cpu);
break;
}
case 0x1000: