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) -- WBR, Volodymyr