Re: [PATCH v3] xen/arm: gic-v3: Introduce CONFIG_GICV3_NR_LRS

Bertrand Marquis <[email protected]> Wed, 29 Jul 2026 07:33:12 +0000
Newsgroups gmane.comp.emulators.xen.devel
Message-ID <[email protected]>
Hi,

> On 6 Jul 2026, at 15:35, Ayan Kumar Halder <[email protected]> wrote:
> 
> Add a Kconfig option that lets an integrator hard-code the number of
> GICv3 Link 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 <[email protected]>
> Signed-off-by: Michal Orzel <[email protected]>

With the typo Link/List registers fixed:

Reviewed-by: Bertrand Marquis <[email protected]>

Cheers
Bertrand

> ---
> Changes in 
> v3:
> - Validate CONFIG_GICV3_NR_LRS against the hardware count in
>  gicv3_hyp_init() and panic if it exceeds it (Julien, Luca).
> - Allow an integrator to select fewer LRs than the hardware supports;
>  gicv3_info.nr_lrs is replaced with the clamped value (Julien).
> - Zero all hardware LRs in gicv3_hyp_init() as defensive hardening.
> - Replace the silent RAZ/WI out-of-range path in gicv3_ich_read_lr()/
>  gicv3_ich_write_lr() with gprintk() + ASSERT_UNREACHABLE() + WARN()
>  (Julien).
> - Renamed the Kconfig from LRS to NR_LRS (Julien).
> - The link-time dead-code-elimination guard is split out into a
>  separate follow-up patch.
> 
> v2:
> - s/lrs/LRS.
> - Implement RAZ/WI instead of panic.
> 
> 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 5fa89fcb24..798bc8e9b2 100644
> --- a/xen/arch/arm/Kconfig
> +++ b/xen/arch/arm/Kconfig
> @@ -143,6 +143,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 Link Registers used" if EXPERT
> + depends on GICV3
> + range 0 16
> + default 0
> + help
> +  Controls the number of Link 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 acdac22953..46ab0b6329 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:
> @@ -1041,9 +1059,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;
> 
> -- 
> 2.25.1
>