diff --git a/xen/arch/arm/include/asm/vgic.h b/xen/arch/arm/include/asm/vgic.h index 24a4a968c3..31b3d3e5ec 100644 --- a/xen/arch/arm/include/asm/vgic.h +++ b/xen/arch/arm/include/asm/vgic.h @@ -324,6 +324,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..8b1c8eef80 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -107,17 +107,12 @@ static uint64_t vgic_fetch_irouter(struct vgic_irq_rank *rank, /* * Store an IROUTER register in a convenient way and migrate the vIRQ * if necessary. This function only deals with IROUTER32 and onwards. - * - * 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 @@ -673,6 +668,36 @@ write_reserved: return 1; } +/* + * The assumption is that offsets below espi_base are for + * regular SPI, while those at or above are for eSPI. + */ +static inline struct vgic_irq_rank *vgic_common_rank_offset(struct vcpu *v, + unsigned int b, + uint32_t reg, + unsigned int s, + uint32_t spi_base, + uint32_t espi_base) +{ + ASSERT(spi_base < espi_base); + + if ( reg < espi_base ) + return vgic_rank_offset(v, b, reg - spi_base, s); + else + return vgic_ext_rank_offset(v, b, reg - espi_base, s); +} + +static inline uint32_t vgic_get_reg_offset(uint32_t reg, uint32_t spi_base, + uint32_t espi_base) +{ + ASSERT(spi_base < espi_base); + + if ( reg < espi_base ) + return reg - spi_base; + else + return reg - espi_base; +} + static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v, mmio_info_t *info, uint32_t reg, register_t *r) @@ -685,13 +710,17 @@ 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); + rank = vgic_common_rank_offset(v, 1, reg, DABT_WORD, GICD_ISENABLER, + GICD_ISENABLERnE); if ( rank == NULL ) goto read_as_zero; vgic_lock_rank(v, rank, flags); *r = vreg_reg32_extract(rank->ienable, info); @@ -699,8 +728,10 @@ 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); + rank = vgic_common_rank_offset(v, 1, reg, DABT_WORD, GICD_ICENABLER, + GICD_ICENABLERnE); if ( rank == NULL ) goto read_as_zero; vgic_lock_rank(v, rank, flags); *r = vreg_reg32_extract(rank->ienable, info); @@ -710,22 +741,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; + uint32_t ipriorityr, offset; 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); + rank = vgic_common_rank_offset(v, 8, reg, DABT_WORD, GICD_IPRIORITYR, + GICD_IPRIORITYRnE); if ( rank == NULL ) goto read_as_zero; - rank_index = REG_RANK_INDEX(8, reg - GICD_IPRIORITYR, DABT_WORD); + offset = vgic_get_reg_offset(reg, GICD_IPRIORITYR, GICD_IPRIORITYRnE); + rank_index = REG_RANK_INDEX(8, offset, DABT_WORD); vgic_lock_rank(v, rank, flags); ipriorityr = ACCESS_ONCE(rank->ipriorityr[rank_index]); @@ -737,14 +775,17 @@ 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; + uint32_t icfgr, offset; if ( dabt.size != DABT_WORD ) goto bad_width; - rank = vgic_rank_offset(v, 2, reg - GICD_ICFGR, DABT_WORD); + rank = vgic_common_rank_offset(v, 2, reg, DABT_WORD, GICD_ICFGR, + GICD_ICFGRnE); if ( rank == NULL ) goto read_as_zero; + offset = vgic_get_reg_offset(reg, GICD_ICFGR, GICD_ICFGRnE); vgic_lock_rank(v, rank, flags); - icfgr = rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR, DABT_WORD)]; + icfgr = rank->icfg[REG_RANK_INDEX(2, offset, DABT_WORD)]; vgic_unlock_rank(v, rank, flags); *r = vreg_reg32_extract(icfgr, info); @@ -782,12 +823,16 @@ 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); + rank = vgic_common_rank_offset(v, 1, reg, DABT_WORD, GICD_ISENABLER, + GICD_ISENABLERnE); if ( rank == NULL ) goto write_ignore; vgic_lock_rank(v, rank, flags); tr = rank->ienable; @@ -797,8 +842,10 @@ static int __vgic_v3_distr_common_mmio_write(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); + rank = vgic_common_rank_offset(v, 1, reg, DABT_WORD, GICD_ICENABLER, + GICD_ICENABLERnE); if ( rank == NULL ) goto write_ignore; vgic_lock_rank(v, rank, flags); tr = rank->ienable; @@ -808,8 +855,10 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v, 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); + rank = vgic_common_rank_offset(v, 1, reg, DABT_WORD, GICD_ISPENDR, + GICD_ISPENDRnE); if ( rank == NULL ) goto write_ignore; vgic_set_irqs_pending(v, r, rank->index); @@ -817,8 +866,10 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v, 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); + rank = vgic_common_rank_offset(v, 1, reg, DABT_WORD, GICD_ICPENDR, + GICD_ICPENDRnE); if ( rank == NULL ) goto write_ignore; vgic_check_inflight_irqs_pending(v, rank->index, r); @@ -826,28 +877,42 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v, goto write_ignore; case VRANGE32(GICD_ISACTIVER, GICD_ISACTIVERN): + 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%d\n", - v, name, r, reg - GICD_ISACTIVER); + if ( reg < GICD_ISACTIVERnE ) + printk(XENLOG_G_ERR + "%pv: %s: unhandled word write %#"PRIregister" to ISACTIVER%d\n", + v, name, r, reg - GICD_ISACTIVER); + else + 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_ICACTIVER, GICD_ICACTIVERN): - printk(XENLOG_G_ERR - "%pv: %s: unhandled word write %#"PRIregister" to ICACTIVER%d\n", - v, name, r, reg - GICD_ICACTIVER); + case VRANGE32(GICD_ICACTIVERnE, GICD_ICACTIVERnEN): + if ( reg < GICD_ICACTIVERnE ) + printk(XENLOG_G_ERR + "%pv: %s: unhandled word write %#"PRIregister" to ICACTIVER%d\n", + v, name, r, reg - GICD_ICACTIVER); + else + 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); + rank = vgic_common_rank_offset(v, 8, reg, DABT_WORD, GICD_IPRIORITYR, + GICD_IPRIORITYRnE); if ( rank == NULL ) goto write_ignore; + offset = vgic_get_reg_offset(reg, GICD_IPRIORITYR, GICD_IPRIORITYRnE); 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,17 +924,23 @@ 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): + { + uint32_t offset; + /* 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); + rank = vgic_common_rank_offset(v, 2, reg, DABT_WORD, GICD_ICFGR, + GICD_ICFGRnE); if ( rank == NULL ) goto write_ignore; + offset = vgic_get_reg_offset(reg, GICD_ICFGR, GICD_ICFGRnE); vgic_lock_rank(v, rank, flags); - vreg_reg32_update(&rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR, - DABT_WORD)], + vreg_reg32_update(&rank->icfg[REG_RANK_INDEX(2, offset, DABT_WORD)], r, info); vgic_unlock_rank(v, rank, flags); return 1; + } default: printk(XENLOG_G_ERR @@ -1129,6 +1200,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 +1275,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 +1292,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,27 +1308,30 @@ 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; + uint32_t offset; if ( !vgic_reg64_check_access(dabt) ) goto bad_width; - rank = vgic_rank_offset(v, 64, gicd_reg - GICD_IROUTER, - DABT_DOUBLE_WORD); + rank = vgic_common_rank_offset(v, 64, gicd_reg, DABT_DOUBLE_WORD, + GICD_IROUTER, GICD_IROUTERnE); if ( rank == NULL ) goto read_as_zero; + offset = vgic_get_reg_offset(gicd_reg, GICD_IROUTER, GICD_IROUTERnE); vgic_lock_rank(v, rank, flags); - irouter = vgic_fetch_irouter(rank, gicd_reg - GICD_IROUTER); + irouter = vgic_fetch_irouter(rank, offset); vgic_unlock_rank(v, rank, flags); *r = vreg_reg64_extract(irouter, info); return 1; } - - case VRANGE32(0x7FE0, 0xBFFC): + case VRANGE32(0x3700, 0x60FC): + case VRANGE32(0xA004, 0xBFFC): goto read_reserved; case VRANGE32(0xC000, 0xFFCC): @@ -1382,12 +1477,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 +1511,35 @@ 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); + rank = vgic_common_rank_offset(v, 64, gicd_reg, DABT_DOUBLE_WORD, + GICD_IROUTER, GICD_IROUTERnE); if ( rank == NULL ) goto write_ignore; + offset = vgic_get_reg_offset(gicd_reg, GICD_IROUTER, GICD_IROUTERnE); 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); + /* There is 1 vIRQ per IROUTER */ + if ( gicd_reg < GICD_IROUTERnE ) + virq = offset / NR_BYTES_PER_IROUTER; + else + virq = espi_idx_to_intid(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 eb22de6aa6..3ebdf9953f 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -170,6 +170,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; @@ -210,6 +222,16 @@ static unsigned int vgic_num_spi_lines(struct domain *d) return d->arch.vgic.nr_spis; } +/* + * 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)