From a0b958f45fade7e43ce748e686369c85b6c3c0d4 Mon Sep 17 00:00:00 2001 From: Ayan Kumar Halder Date: Mon, 6 Jul 2026 15:35:53 +0200 Subject: [PATCH] xen/arm: gic-v3: Introduce CONFIG_GICV3_NR_LRS Add a Kconfig option that lets an integrator hard-code the number of GICv3 List Registers Xen uses. The default (0) keeps reading the count from ICH_VTR_EL2.ListRegs at boot. A non-zero value is validated against the hardware count in gicv3_hyp_init() and replaces gicv3_info.nr_lrs. gicv3_hyp_init() now panics if CONFIG_GICV3_NR_LRS exceeds the hardware count, and zeroes all hardware LRs (once per CPU) as defensive hardening, so any interrupt left in an LR that Xen will not manage cannot be picked up by the GIC. gicv3_ich_read_lr()/gicv3_ich_write_lr() now reject out-of-range indices with an error message, ASSERT_UNREACHABLE() and WARN() instead of silently returning RAZ/WI; reaching this path indicates a bug. Signed-off-by: Ayan Kumar Halder Signed-off-by: Michal Orzel Reviewed-by: Luca Fancellu Reviewed-by: Bertrand Marquis --- xen/arch/arm/Kconfig | 9 ++++++++ xen/arch/arm/gic-v3.c | 50 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index 06289005f4..b9c5c40678 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -145,6 +145,15 @@ config GICV3_ESPI range, from 4096 to 5119. This feature is introduced in GICv3.1 architecture. +config GICV3_NR_LRS + int "Number of GICv3 List Registers used" if EXPERT + depends on GICV3 + range 0 16 + default 0 + help + Controls the number of List registers to be used. + Keep it set to 0 to use a value obtained from a hardware register. + config HAS_ITS bool "GICv3 ITS MSI controller support (UNSUPPORTED)" if UNSUPPORTED depends on GICV3 && !NEW_VGIC && !ARM_32 diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 76b81bfb03..23a4497a30 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -178,6 +178,15 @@ static inline void gicv3_restore_lrs(const struct vcpu *v) static uint64_t gicv3_ich_read_lr(int lr) { + if ( lr < 0 || lr >= gicv3_info.nr_lrs ) + { + gprintk(XENLOG_ERR, "GICv3: LR read index %d out of range (nr_lrs %u)\n", + lr, gicv3_info.nr_lrs); + ASSERT_UNREACHABLE(); + WARN(); + return 0; + } + switch ( lr ) { case 0: return READ_SYSREG_LR(0); @@ -203,6 +212,15 @@ static uint64_t gicv3_ich_read_lr(int lr) static void gicv3_ich_write_lr(int lr, uint64_t val) { + if ( lr < 0 || lr >= gicv3_info.nr_lrs ) + { + gprintk(XENLOG_ERR, "GICv3: LR write index %d out of range (nr_lrs %u)\n", + lr, gicv3_info.nr_lrs); + ASSERT_UNREACHABLE(); + WARN(); + return; + } + switch ( lr ) { case 0: @@ -1043,9 +1061,39 @@ static void gicv3_cpu_disable(void) static void gicv3_hyp_init(void) { register_t vtr; + uint8_t hw_nr_lrs; vtr = READ_SYSREG(ICH_VTR_EL2); - gicv3_info.nr_lrs = (vtr & ICH_VTR_NRLRGS) + 1; + hw_nr_lrs = (vtr & ICH_VTR_NRLRGS) + 1; + + if ( CONFIG_GICV3_NR_LRS && CONFIG_GICV3_NR_LRS > hw_nr_lrs ) + panic("GICv3: CONFIG_GICV3_NR_LRS (%u) exceeds hardware nr_lrs (%u)\n", + CONFIG_GICV3_NR_LRS, hw_nr_lrs); + + gicv3_info.nr_lrs = CONFIG_GICV3_NR_LRS ?: hw_nr_lrs; + + /* Zero all hardware LRs. */ + switch ( hw_nr_lrs ) + { + case 16: WRITE_SYSREG_LR(0, 15); fallthrough; + case 15: WRITE_SYSREG_LR(0, 14); fallthrough; + case 14: WRITE_SYSREG_LR(0, 13); fallthrough; + case 13: WRITE_SYSREG_LR(0, 12); fallthrough; + case 12: WRITE_SYSREG_LR(0, 11); fallthrough; + case 11: WRITE_SYSREG_LR(0, 10); fallthrough; + case 10: WRITE_SYSREG_LR(0, 9); fallthrough; + case 9: WRITE_SYSREG_LR(0, 8); fallthrough; + case 8: WRITE_SYSREG_LR(0, 7); fallthrough; + case 7: WRITE_SYSREG_LR(0, 6); fallthrough; + case 6: WRITE_SYSREG_LR(0, 5); fallthrough; + case 5: WRITE_SYSREG_LR(0, 4); fallthrough; + case 4: WRITE_SYSREG_LR(0, 3); fallthrough; + case 3: WRITE_SYSREG_LR(0, 2); fallthrough; + case 2: WRITE_SYSREG_LR(0, 1); fallthrough; + case 1: WRITE_SYSREG_LR(0, 0); break; + default: BUG(); + } + gicv3.nr_priorities = ((vtr >> ICH_VTR_PRIBITS_SHIFT) & ICH_VTR_PRIBITS_MASK) + 1;