Hi Volodymyr,

Thank you for your review and RB.
Unfortunately, the code contains an error related to offset calculation 
for GICD_IROUTERnE, which was observed by Oleksandr. I will fix it in 
V6, along with the formatting issues you discovered. I apologize for that.

On 29.08.25 23:12, Volodymyr Babchuk wrote:
> Hi Leonid,
> 
> Leonid Komarianskyi <leonid_komarians...@epam.com> writes:
> 
>> Implemented support for GICv3.1 extended SPI registers for vGICv3,
>> allowing the emulation of eSPI-specific behavior for guest domains.
>> The implementation includes read and write emulation for eSPI-related
>> registers (e.g., GICD_ISENABLERnE, GICD_IROUTERnE, and others),
>> following a similar approach to the handling of regular SPIs.
>>
>> The eSPI registers, previously located in reserved address ranges,
>> are now adjusted to support MMIO read and write operations correctly
>> when CONFIG_GICV3_ESPI is enabled.
>>
>> The availability of eSPIs and the number of emulated extended SPIs
>> for guest domains is reported by setting the appropriate bits in the
>> GICD_TYPER register, based on the number of eSPIs requested by the
>> domain and supported by the hardware. In cases where the configuration
>> option is disabled, the hardware does not support eSPIs, or the domain
>> does not request such interrupts, the functionality remains unchanged.
>>
>> Signed-off-by: Leonid Komarianskyi <leonid_komarians...@epam.com>
> 
> I have a couple of comments about coding style, but apart from that it
> looks really good. With these issues fixed:
> 
> Reviewed-by: Volodymyr Babchuk <volodymyr_babc...@epam.com>
> 
>>
>> ---
>> Changes in V5:
>> - since eSPI-specific defines and macros are now available even when the
>>    appropriate config is disabled, this allows us to remove many
>>    #ifdef guards and reuse the existing code for regular SPIs for eSPIs as
>>    well, as eSPIs are processed similarly. This improves code readability
>>    and consolidates the register ranges for SPIs and eSPIs in a single
>>    place, simplifying future changes or fixes for SPIs and their
>>    counterparts from the extended range
>> - moved vgic_ext_rank_offset() from
>>    [08/12] xen/arm: vgic: add resource management for extended SPIs
>>    as the function was unused before this patch
>> - added stub implementation of vgic_ext_rank_offset() when 
>> CONFIG_GICV3_ESPI=n
>> - removed unnecessary defines for reserved ranges, which were introduced in
>>    V4 to reduce the number of #ifdefs. The issue is now resolved by
>>    allowing the use of SPI-specific offsets and reworking the logic
>>
>> Changes in V4:
>> - added missing RAZ and write ignore eSPI-specific registers ranges:
>>    GICD_NSACRnE and GICD_IGRPMODRnE
>> - changed previously reserved range to cover GICD_NSACRnE and
>>    GICD_IGRPMODRnE
>> - introduced GICD_RESERVED_RANGE<n>_START/END defines to remove
>>    hardcoded values and reduce the number of ifdefs
>> - fixed reserved ranges with eSPI option enabled: added missing range
>>    0x0F30-0x0F7C
>> - updated the logic for domains that do not support eSPI, but Xen is
>>    compiled with the eSPI option. Now, prior to other MMIO checks, we
>>    verify whether eSPI is available for the domain or not. If not, it
>>    behaves as it does currently - RAZ and WI
>> - fixed print for GICD_ICACTIVERnE
>> - fixed new lines formatting for switch-case
>>
>> Changes in V3:
>> - changed vgic_store_irouter parameters - instead of offset virq is
>>    used, to remove the additional bool espi parameter and simplify
>>    checks. Also, adjusted parameters for regular SPI. Since the offset
>>    parameter was used only for calculating virq number and then reused for
>>    finding rank offset, it will not affect functionality.
>> - fixed formatting for goto lables - added newlines after condition
>> - fixed logs for GICD_ISACTIVERnE and GICD_ICACTIVERnE handlers
>> - removed #ifdefs in 2 places where they were adjacent and could be merged
>>
>> Changes in V2:
>> - add missing rank index conversion for pending and inflight irqs
>> ---
>>   xen/arch/arm/include/asm/vgic.h |   4 +
>>   xen/arch/arm/vgic-v3.c          | 198 ++++++++++++++++++++++++++------
>>   xen/arch/arm/vgic.c             |  23 ++++
>>   3 files changed, 192 insertions(+), 33 deletions(-)
>>
>> diff --git a/xen/arch/arm/include/asm/vgic.h 
>> b/xen/arch/arm/include/asm/vgic.h
>> index 3aa22114ba..103bc3c74b 100644
>> --- a/xen/arch/arm/include/asm/vgic.h
>> +++ b/xen/arch/arm/include/asm/vgic.h
>> @@ -314,6 +314,10 @@ extern struct vgic_irq_rank *vgic_rank_offset(struct 
>> vcpu *v,
>>                                                 unsigned int b,
>>                                                 unsigned int n,
>>                                                 unsigned int s);
>> +extern struct vgic_irq_rank *vgic_ext_rank_offset(struct vcpu *v,
>> +                                                  unsigned int b,
>> +                                                  unsigned int n,
>> +                                                  unsigned int s);
>>   extern struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int 
>> irq);
>>   extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, unsigned int n);
>>   extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, unsigned int n);
>> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
>> index 4369c55177..b5d766c98f 100644
>> --- a/xen/arch/arm/vgic-v3.c
>> +++ b/xen/arch/arm/vgic-v3.c
>> @@ -111,13 +111,10 @@ static uint64_t vgic_fetch_irouter(struct 
>> vgic_irq_rank *rank,
>>    * Note the offset will be aligned to the appropriate boundary.
>>    */
>>   static void vgic_store_irouter(struct domain *d, struct vgic_irq_rank 
>> *rank,
>> -                               unsigned int offset, uint64_t irouter)
>> +                               unsigned int virq, uint64_t irouter)
>>   {
>>       struct vcpu *new_vcpu, *old_vcpu;
>> -    unsigned int virq;
>> -
>> -    /* There is 1 vIRQ per IROUTER */
>> -    virq = offset / NR_BYTES_PER_IROUTER;
>> +    unsigned int offset;
>>   
>>       /*
>>        * The IROUTER0-31, used for SGIs/PPIs, are reserved and should
>> @@ -685,13 +682,20 @@ static int __vgic_v3_distr_common_mmio_read(const char 
>> *name, struct vcpu *v,
>>       {
>>       case VRANGE32(GICD_IGROUPR, GICD_IGROUPRN):
>>       case VRANGE32(GICD_IGRPMODR, GICD_IGRPMODRN):
>> +    case VRANGE32(GICD_IGROUPRnE, GICD_IGROUPRnEN):
>> +    case VRANGE32(GICD_IGRPMODRnE, GICD_IGRPMODRnEN):
>>           /* We do not implement security extensions for guests, read zero */
>>           if ( dabt.size != DABT_WORD ) goto bad_width;
>>           goto read_as_zero;
>>   
>>       case VRANGE32(GICD_ISENABLER, GICD_ISENABLERN):
>> +    case VRANGE32(GICD_ISENABLERnE, GICD_ISENABLERnEN):
>>           if ( dabt.size != DABT_WORD ) goto bad_width;
>> -        rank = vgic_rank_offset(v, 1, reg - GICD_ISENABLER, DABT_WORD);
>> +        if ( reg >= GICD_ISENABLERnE )
>> +            rank = vgic_ext_rank_offset(v, 1, reg - GICD_ISENABLERnE,
>> +                                        DABT_WORD);
>> +        else
>> +            rank = vgic_rank_offset(v, 1, reg - GICD_ISENABLER, DABT_WORD);
>>           if ( rank == NULL ) goto read_as_zero;
>>           vgic_lock_rank(v, rank, flags);
>>           *r = vreg_reg32_extract(rank->ienable, info);
>> @@ -699,8 +703,13 @@ static int __vgic_v3_distr_common_mmio_read(const char 
>> *name, struct vcpu *v,
>>           return 1;
>>   
>>       case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
>> +    case VRANGE32(GICD_ICENABLERnE, GICD_ICENABLERnEN):
>>           if ( dabt.size != DABT_WORD ) goto bad_width;
>> -        rank = vgic_rank_offset(v, 1, reg - GICD_ICENABLER, DABT_WORD);
>> +        if ( reg >= GICD_ICENABLERnE )
>> +            rank = vgic_ext_rank_offset(v, 1, reg - GICD_ICENABLERnE,
>> +                                        DABT_WORD);
>> +        else
>> +            rank = vgic_rank_offset(v, 1, reg - GICD_ICENABLER, DABT_WORD);
>>           if ( rank == NULL ) goto read_as_zero;
>>           vgic_lock_rank(v, rank, flags);
>>           *r = vreg_reg32_extract(rank->ienable, info);
>> @@ -710,20 +719,29 @@ static int __vgic_v3_distr_common_mmio_read(const char 
>> *name, struct vcpu *v,
>>       /* Read the pending status of an IRQ via GICD/GICR is not supported */
>>       case VRANGE32(GICD_ISPENDR, GICD_ISPENDRN):
>>       case VRANGE32(GICD_ICPENDR, GICD_ICPENDRN):
>> +    case VRANGE32(GICD_ISPENDRnE, GICD_ISPENDRnEN):
>> +    case VRANGE32(GICD_ICPENDRnE, GICD_ICPENDRnEN):
>>           goto read_as_zero;
>>   
>>       /* Read the active status of an IRQ via GICD/GICR is not supported */
>>       case VRANGE32(GICD_ISACTIVER, GICD_ISACTIVERN):
>>       case VRANGE32(GICD_ICACTIVER, GICD_ICACTIVERN):
>> +    case VRANGE32(GICD_ISACTIVERnE, GICD_ISACTIVERnEN):
>> +    case VRANGE32(GICD_ICACTIVERnE, GICD_ICACTIVERnEN):
>>           goto read_as_zero;
>>   
>>       case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
>> +    case VRANGE32(GICD_IPRIORITYRnE, GICD_IPRIORITYRnEN):
>>       {
>>           uint32_t ipriorityr;
>>           uint8_t rank_index;
>>   
>>           if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto 
>> bad_width;
>> -        rank = vgic_rank_offset(v, 8, reg - GICD_IPRIORITYR, DABT_WORD);
>> +        if ( reg >= GICD_IPRIORITYRnE )
>> +            rank = vgic_ext_rank_offset(v, 8, reg - GICD_IPRIORITYRnE,
>> +                                        DABT_WORD);
>> +        else
>> +            rank = vgic_rank_offset(v, 8, reg - GICD_IPRIORITYR, DABT_WORD);
>>           if ( rank == NULL ) goto read_as_zero;
>>           rank_index = REG_RANK_INDEX(8, reg - GICD_IPRIORITYR, DABT_WORD);
>>   
>> @@ -737,11 +755,15 @@ static int __vgic_v3_distr_common_mmio_read(const char 
>> *name, struct vcpu *v,
>>       }
>>   
>>       case VRANGE32(GICD_ICFGR, GICD_ICFGRN):
>> +    case VRANGE32(GICD_ICFGRnE, GICD_ICFGRnEN):
>>       {
>>           uint32_t icfgr;
>>   
>>           if ( dabt.size != DABT_WORD ) goto bad_width;
>> -        rank = vgic_rank_offset(v, 2, reg - GICD_ICFGR, DABT_WORD);
>> +        if ( reg >= GICD_ICFGRnE )
>> +            rank = vgic_ext_rank_offset(v, 2, reg - GICD_ICFGRnE, 
>> DABT_WORD);
>> +        else
>> +            rank = vgic_rank_offset(v, 2, reg - GICD_ICFGR, DABT_WORD);
>>           if ( rank == NULL ) goto read_as_zero;
>>           vgic_lock_rank(v, rank, flags);
>>           icfgr = rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR, DABT_WORD)];
>> @@ -782,46 +804,81 @@ static int __vgic_v3_distr_common_mmio_write(const 
>> char *name, struct vcpu *v,
>>       {
>>       case VRANGE32(GICD_IGROUPR, GICD_IGROUPRN):
>>       case VRANGE32(GICD_IGRPMODR, GICD_IGRPMODRN):
>> +    case VRANGE32(GICD_IGROUPRnE, GICD_IGROUPRnEN):
>> +    case VRANGE32(GICD_IGRPMODRnE, GICD_IGRPMODRnEN):
>>           /* We do not implement security extensions for guests, write 
>> ignore */
>>           goto write_ignore_32;
>>   
>>       case VRANGE32(GICD_ISENABLER, GICD_ISENABLERN):
>> +    case VRANGE32(GICD_ISENABLERnE, GICD_ISENABLERnEN):
>>           if ( dabt.size != DABT_WORD ) goto bad_width;
>> -        rank = vgic_rank_offset(v, 1, reg - GICD_ISENABLER, DABT_WORD);
>> +        if ( reg >= GICD_ISENABLERnE )
>> +            rank = vgic_ext_rank_offset(v, 1, reg - GICD_ISENABLERnE,
>> +                                        DABT_WORD);
>> +        else
>> +            rank = vgic_rank_offset(v, 1, reg - GICD_ISENABLER, DABT_WORD);
>>           if ( rank == NULL ) goto write_ignore;
>>           vgic_lock_rank(v, rank, flags);
>>           tr = rank->ienable;
>>           vreg_reg32_setbits(&rank->ienable, r, info);
>> -        vgic_enable_irqs(v, (rank->ienable) & (~tr), rank->index);
>> +        if ( reg >= GICD_ISENABLERnE )
>> +            vgic_enable_irqs(v, (rank->ienable) & (~tr),
>> +                             EXT_RANK_IDX2NUM(rank->index));
>> +        else
>> +            vgic_enable_irqs(v, (rank->ienable) & (~tr), rank->index);
>>           vgic_unlock_rank(v, rank, flags);
>>           return 1;
>>   
>>       case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
>> +    case VRANGE32(GICD_ICENABLERnE, GICD_ICENABLERnEN):
>>           if ( dabt.size != DABT_WORD ) goto bad_width;
>> -        rank = vgic_rank_offset(v, 1, reg - GICD_ICENABLER, DABT_WORD);
>> +        if ( reg >= GICD_ICENABLERnE )
>> +            rank = vgic_ext_rank_offset(v, 1, reg - GICD_ICENABLERnE,
>> +                                        DABT_WORD);
>> +        else
>> +            rank = vgic_rank_offset(v, 1, reg - GICD_ICENABLER, DABT_WORD);
>>           if ( rank == NULL ) goto write_ignore;
>>           vgic_lock_rank(v, rank, flags);
>>           tr = rank->ienable;
>>           vreg_reg32_clearbits(&rank->ienable, r, info);
>> -        vgic_disable_irqs(v, (~rank->ienable) & tr, rank->index);
>> +        if ( reg >= GICD_ICENABLERnE )
>> +            vgic_disable_irqs(v, (~rank->ienable) & tr,
>> +                              EXT_RANK_IDX2NUM(rank->index));
>> +        else
>> +            vgic_disable_irqs(v, (~rank->ienable) & tr, rank->index);
>>           vgic_unlock_rank(v, rank, flags);
>>           return 1;
>>   
>>       case VRANGE32(GICD_ISPENDR, GICD_ISPENDRN):
>> +    case VRANGE32(GICD_ISPENDRnE, GICD_ISPENDRnEN):
>>           if ( dabt.size != DABT_WORD ) goto bad_width;
>> -        rank = vgic_rank_offset(v, 1, reg - GICD_ISPENDR, DABT_WORD);
>> +        if ( reg >= GICD_ISPENDRnE )
>> +            rank = vgic_ext_rank_offset(v, 1, reg - GICD_ISPENDRnE, 
>> DABT_WORD);
>> +        else
>> +            rank = vgic_rank_offset(v, 1, reg - GICD_ISPENDR, DABT_WORD);
>>           if ( rank == NULL ) goto write_ignore;
>>   
>> -        vgic_set_irqs_pending(v, r, rank->index);
>> +        if ( reg >= GICD_ISPENDRnE )
>> +            vgic_set_irqs_pending(v, r, EXT_RANK_IDX2NUM(rank->index));
>> +        else
>> +            vgic_set_irqs_pending(v, r, rank->index);
>>   
>>           return 1;
>>   
>>       case VRANGE32(GICD_ICPENDR, GICD_ICPENDRN):
>> +    case VRANGE32(GICD_ICPENDRnE, GICD_ICPENDRnEN):
>>           if ( dabt.size != DABT_WORD ) goto bad_width;
>> -        rank = vgic_rank_offset(v, 1, reg - GICD_ICPENDR, DABT_WORD);
>> +        if ( reg >= GICD_ICPENDRnE )
>> +            rank = vgic_ext_rank_offset(v, 1, reg - GICD_ICPENDRnE, 
>> DABT_WORD);
>> +        else
>> +            rank = vgic_rank_offset(v, 1, reg - GICD_ICPENDR, DABT_WORD);
>>           if ( rank == NULL ) goto write_ignore;
>>   
>> -        vgic_check_inflight_irqs_pending(v, rank->index, r);
>> +        if ( reg >= GICD_ICPENDRnE )
>> +            vgic_check_inflight_irqs_pending(v,
>> +                                             EXT_RANK_IDX2NUM(rank->index), 
>> r);
>> +        else
>> +            vgic_check_inflight_irqs_pending(v, rank->index, r);
>>   
>>           goto write_ignore;
>>   
>> @@ -838,16 +895,38 @@ static int __vgic_v3_distr_common_mmio_write(const 
>> char *name, struct vcpu *v,
>>                  v, name, r, reg - GICD_ICACTIVER);
>>           goto write_ignore_32;
>>   
>> +    case VRANGE32(GICD_ISACTIVERnE, GICD_ISACTIVERnEN):
>> +        if ( dabt.size != DABT_WORD )
>> +            goto bad_width;
>> +        printk(XENLOG_G_ERR
>> +               "%pv: %s: unhandled word write %#"PRIregister" to 
>> ISACTIVER%dE\n",
>> +               v, name, r, reg - GICD_ISACTIVERnE);
>> +        return 0;
>> +
>> +    case VRANGE32(GICD_ICACTIVERnE, GICD_ICACTIVERnEN):
>> +        printk(XENLOG_G_ERR
>> +               "%pv: %s: unhandled word write %#"PRIregister" to 
>> ICACTIVER%dE\n",
>> +               v, name, r, reg - GICD_ICACTIVERnE);
>> +        goto write_ignore_32;
>> +
>>       case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
>> +    case VRANGE32(GICD_IPRIORITYRnE, GICD_IPRIORITYRnEN):
>>       {
>> -        uint32_t *ipriorityr, priority;
>> +        uint32_t *ipriorityr, priority, offset;
>>   
>>           if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto 
>> bad_width;
>> -        rank = vgic_rank_offset(v, 8, reg - GICD_IPRIORITYR, DABT_WORD);
>> +        if ( reg >= GICD_IPRIORITYRnE ) {
> 
> Brace should go on new line
> 
>> +            offset = reg - GICD_IPRIORITYRnE;
>> +            rank = vgic_ext_rank_offset(v, 8, offset, DABT_WORD);
>> +        }
>> +        else
>> +        {
>> +            offset = reg - GICD_IPRIORITYR;
>> +            rank = vgic_rank_offset(v, 8, offset, DABT_WORD);
>> +        }
>>           if ( rank == NULL ) goto write_ignore;
>>           vgic_lock_rank(v, rank, flags);
>> -        ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8, reg - 
>> GICD_IPRIORITYR,
>> -                                                      DABT_WORD)];
>> +        ipriorityr = &rank->ipriorityr[REG_RANK_INDEX(8, offset, 
>> DABT_WORD)];
>>           priority = ACCESS_ONCE(*ipriorityr);
>>           vreg_reg32_update(&priority, r, info);
>>           ACCESS_ONCE(*ipriorityr) = priority;
>> @@ -859,10 +938,14 @@ static int __vgic_v3_distr_common_mmio_write(const 
>> char *name, struct vcpu *v,
>>           goto write_ignore_32;
>>   
>>       case VRANGE32(GICD_ICFGR + 4, GICD_ICFGRN): /* PPI + SPIs */
>> +    case VRANGE32(GICD_ICFGRnE, GICD_ICFGRnEN):
>>           /* ICFGR1 for PPI's, which is implementation defined
>>              if ICFGR1 is programmable or not. We chose to program */
>>           if ( dabt.size != DABT_WORD ) goto bad_width;
>> -        rank = vgic_rank_offset(v, 2, reg - GICD_ICFGR, DABT_WORD);
>> +        if ( reg >= GICD_ICFGRnE )
>> +            rank = vgic_ext_rank_offset(v, 2, reg - GICD_ICFGRnE, 
>> DABT_WORD);
>> +        else
>> +            rank = vgic_rank_offset(v, 2, reg - GICD_ICFGR, DABT_WORD);
>>           if ( rank == NULL ) goto write_ignore;
>>           vgic_lock_rank(v, rank, flags);
>>           vreg_reg32_update(&rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR,
>> @@ -1129,6 +1212,16 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, 
>> mmio_info_t *info,
>>               typer |= GICD_TYPE_LPIS;
>>   
>>           typer |= (v->domain->arch.vgic.intid_bits - 1) << 
>> GICD_TYPE_ID_BITS_SHIFT;
>> +#ifdef CONFIG_GICV3_ESPI
>> +        if ( v->domain->arch.vgic.nr_espis > 0 )
>> +        {
>> +            /* Set eSPI support bit for the domain */
>> +            typer |= GICD_TYPER_ESPI;
>> +            /* Set ESPI range bits */
>> +            typer |= (DIV_ROUND_UP(v->domain->arch.vgic.nr_espis, 32) - 1)
>> +                       << GICD_TYPER_ESPI_RANGE_SHIFT;
>> +        }
>> +#endif
>>   
>>           *r = vreg_reg32_extract(typer, info);
>>   
>> @@ -1194,6 +1287,16 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, 
>> mmio_info_t *info,
>>       case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
>>       case VRANGE32(GICD_ICFGR, GICD_ICFGRN):
>>       case VRANGE32(GICD_IGRPMODR, GICD_IGRPMODRN):
>> +    case VRANGE32(GICD_IGROUPRnE, GICD_IGROUPRnEN):
>> +    case VRANGE32(GICD_ISENABLERnE, GICD_ISENABLERnEN):
>> +    case VRANGE32(GICD_ICENABLERnE, GICD_ICENABLERnEN):
>> +    case VRANGE32(GICD_ISPENDRnE, GICD_ISPENDRnEN):
>> +    case VRANGE32(GICD_ICPENDRnE, GICD_ICPENDRnEN):
>> +    case VRANGE32(GICD_ISACTIVERnE, GICD_ISACTIVERnEN):
>> +    case VRANGE32(GICD_ICACTIVERnE, GICD_ICACTIVERnEN):
>> +    case VRANGE32(GICD_IPRIORITYRnE, GICD_IPRIORITYRnEN):
>> +    case VRANGE32(GICD_ICFGRnE, GICD_ICFGRnEN):
>> +    case VRANGE32(GICD_IGRPMODRnE, GICD_IGRPMODRnEN):
>>           /*
>>            * Above all register are common with GICR and GICD
>>            * Manage in common
>> @@ -1201,6 +1304,7 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, 
>> mmio_info_t *info,
>>           return __vgic_v3_distr_common_mmio_read("vGICD", v, info, 
>> gicd_reg, r);
>>   
>>       case VRANGE32(GICD_NSACR, GICD_NSACRN):
>> +    case VRANGE32(GICD_NSACRnE, GICD_NSACRnEN):
>>           /* We do not implement security extensions for guests, read zero */
>>           goto read_as_zero_32;
>>   
>> @@ -1216,16 +1320,21 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, 
>> mmio_info_t *info,
>>           /* Replaced with GICR_ISPENDR0. So ignore write */
>>           goto read_as_zero_32;
>>   
>> -    case VRANGE32(0x0F30, 0x60FC):
>> +    case VRANGE32(0x0F30, 0x0FFC):
>>           goto read_reserved;
>>   
>>       case VRANGE64(GICD_IROUTER32, GICD_IROUTER1019):
>> +    case VRANGE64(GICD_IROUTERnE, GICD_IROUTERnEN):
>>       {
>>           uint64_t irouter;
>>   
>>           if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
>> -        rank = vgic_rank_offset(v, 64, gicd_reg - GICD_IROUTER,
>> -                                DABT_DOUBLE_WORD);
>> +        if ( gicd_reg >= GICD_IROUTERnE )
>> +            rank = vgic_ext_rank_offset(v, 64, gicd_reg - GICD_IROUTERnE,
>> +                                        DABT_DOUBLE_WORD);
>> +        else
>> +            rank = vgic_rank_offset(v, 64, gicd_reg - GICD_IROUTER,
>> +                                    DABT_DOUBLE_WORD);
>>           if ( rank == NULL ) goto read_as_zero;
>>           vgic_lock_rank(v, rank, flags);
>>           irouter = vgic_fetch_irouter(rank, gicd_reg - GICD_IROUTER);
>> @@ -1235,8 +1344,8 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, 
>> mmio_info_t *info,
>>   
>>           return 1;
>>       }
>> -
>> -    case VRANGE32(0x7FE0, 0xBFFC):
>> +    case VRANGE32(0x3700, 0x60FC):
>> +    case VRANGE32(0xA004, 0xBFFC):
>>           goto read_reserved;
>>   
>>       case VRANGE32(0xC000, 0xFFCC):
>> @@ -1382,12 +1491,23 @@ static int vgic_v3_distr_mmio_write(struct vcpu *v, 
>> mmio_info_t *info,
>>       case VRANGE32(GICD_IPRIORITYR, GICD_IPRIORITYRN):
>>       case VRANGE32(GICD_ICFGR, GICD_ICFGRN):
>>       case VRANGE32(GICD_IGRPMODR, GICD_IGRPMODRN):
>> +    case VRANGE32(GICD_IGROUPRnE, GICD_IGROUPRnEN):
>> +    case VRANGE32(GICD_ISENABLERnE, GICD_ISENABLERnEN):
>> +    case VRANGE32(GICD_ICENABLERnE, GICD_ICENABLERnEN):
>> +    case VRANGE32(GICD_ISPENDRnE, GICD_ISPENDRnEN):
>> +    case VRANGE32(GICD_ICPENDRnE, GICD_ICPENDRnEN):
>> +    case VRANGE32(GICD_ISACTIVERnE, GICD_ISACTIVERnEN):
>> +    case VRANGE32(GICD_ICACTIVERnE, GICD_ICACTIVERnEN):
>> +    case VRANGE32(GICD_IPRIORITYRnE, GICD_IPRIORITYRnEN):
>> +    case VRANGE32(GICD_ICFGRnE, GICD_ICFGRnEN):
>> +    case VRANGE32(GICD_IGRPMODRnE, GICD_IGRPMODRnEN):
>>           /* Above registers are common with GICR and GICD
>>            * Manage in common */
>>           return __vgic_v3_distr_common_mmio_write("vGICD", v, info,
>>                                                    gicd_reg, r);
>>   
>>       case VRANGE32(GICD_NSACR, GICD_NSACRN):
>> +    case VRANGE32(GICD_NSACRnE, GICD_NSACRnEN):
>>           /* We do not implement security extensions for guests, write 
>> ignore */
>>           goto write_ignore_32;
>>   
>> @@ -1405,26 +1525,38 @@ static int vgic_v3_distr_mmio_write(struct vcpu *v, 
>> mmio_info_t *info,
>>           if ( dabt.size != DABT_WORD ) goto bad_width;
>>           return 0;
>>   
>> -    case VRANGE32(0x0F30, 0x60FC):
>> +    case VRANGE32(0x0F30, 0x0FFC):
>>           goto write_reserved;
>>   
>>       case VRANGE64(GICD_IROUTER32, GICD_IROUTER1019):
>> +    case VRANGE64(GICD_IROUTERnE, GICD_IROUTERnEN):
>>       {
>>           uint64_t irouter;
>> +        unsigned int offset, virq;
>>   
>>           if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
>> -        rank = vgic_rank_offset(v, 64, gicd_reg - GICD_IROUTER,
>> -                                DABT_DOUBLE_WORD);
>> +        if ( gicd_reg >= GICD_IROUTERnE ) {
> 
> Braces should go into separate line
> 
>> +            offset = gicd_reg - GICD_IROUTERnE;
>> +            rank = vgic_ext_rank_offset(v, 64, offset, DABT_DOUBLE_WORD);
>> +        } else {
> 
> ... so "else" also should be on a separate line
> 
>> +            offset = gicd_reg - GICD_IROUTER;
>> +            rank = vgic_rank_offset(v, 64, offset, DABT_DOUBLE_WORD);
>> +        }
>>           if ( rank == NULL ) goto write_ignore;
>>           vgic_lock_rank(v, rank, flags);
>> -        irouter = vgic_fetch_irouter(rank, gicd_reg - GICD_IROUTER);
>> +        irouter = vgic_fetch_irouter(rank, offset);
>>           vreg_reg64_update(&irouter, r, info);
>> -        vgic_store_irouter(v->domain, rank, gicd_reg - GICD_IROUTER, 
>> irouter);
>> +        if ( gicd_reg >= GICD_IROUTERnE )
>> +            virq = ESPI_IDX2INTID(offset / NR_BYTES_PER_IROUTER);
>> +        else
>> +            virq = offset / NR_BYTES_PER_IROUTER;
>> +        vgic_store_irouter(v->domain, rank, virq, irouter);
>>           vgic_unlock_rank(v, rank, flags);
>>           return 1;
>>       }
>>   
>> -    case VRANGE32(0x7FE0, 0xBFFC):
>> +    case VRANGE32(0x3700, 0x60FC):
>> +    case VRANGE32(0xA004, 0xBFFC):
>>           goto write_reserved;
>>   
>>       case VRANGE32(0xC000, 0xFFCC):
>> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
>> index c9b9528c66..27ffdf316c 100644
>> --- a/xen/arch/arm/vgic.c
>> +++ b/xen/arch/arm/vgic.c
>> @@ -193,6 +193,18 @@ int domain_vgic_register(struct domain *d, unsigned int 
>> *mmio_count)
>>   }
>>   
>>   #ifdef CONFIG_GICV3_ESPI
>> +/*
>> + * The function behavior is the same as for regular SPIs (vgic_rank_offset),
>> + * but it operates with extended SPI ranks.
>> + */
>> +struct vgic_irq_rank *vgic_ext_rank_offset(struct vcpu *v, unsigned int b,
>> +                                           unsigned int n, unsigned int s)
>> +{
>> +    unsigned int rank = REG_RANK_NR(b, (n >> s));
>> +
>> +    return vgic_get_rank(v, rank + EXT_RANK_MIN);
>> +}
>> +
>>   static unsigned int vgic_num_spi_lines(struct domain *d)
>>   {
>>       return d->arch.vgic.nr_spis + d->arch.vgic.nr_espis;
>> @@ -241,6 +253,17 @@ struct pending_irq *espi_to_pending(struct domain *d, 
>> unsigned int irq)
>>   {
>>       return NULL;
>>   }
>> +
>> +/*
>> + * It is expected that, in the case of CONFIG_GICV3_ESPI=n, the function 
>> will
>> + * return NULL. In this scenario, mmio_read/mmio_write will be treated as
>> + * RAZ/WI, as expected.
>> + */
>> +struct vgic_irq_rank *vgic_ext_rank_offset(struct vcpu *v, unsigned int b,
>> +                                           unsigned int n, unsigned int s)
>> +{
>> +    return NULL;
>> +}
>>   #endif
>>   
>>   static unsigned int vgic_num_alloc_irqs(struct domain *d)
> 

Best regards,
Leonid

Reply via email to