diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index b2da886adc..589c033eda 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -481,10 +481,12 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info, case VRANGE32(GICD_ICPENDR, GICD_ICPENDRN): if ( dabt.size != DABT_WORD ) goto bad_width; - printk(XENLOG_G_ERR - "%pv: vGICD: unhandled word write %#"PRIregister" to ICPENDR%d\n", - v, r, gicd_reg - GICD_ICPENDR); - return 0; + rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ICPENDR, DABT_WORD); + if ( rank == NULL ) goto write_ignore; + + vgic_check_inflight_irqs_pending(v->domain, v, rank->index, r); + + goto write_ignore; case VRANGE32(GICD_ISACTIVER, GICD_ISACTIVERN): if ( dabt.size != DABT_WORD ) goto bad_width; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index cb5a70c42e..65bb7991a6 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -817,10 +817,12 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v, case VRANGE32(GICD_ICPENDR, GICD_ICPENDRN): if ( dabt.size != DABT_WORD ) goto bad_width; - printk(XENLOG_G_ERR - "%pv: %s: unhandled word write %#"PRIregister" to ICPENDR%d\n", - v, name, r, reg - GICD_ICPENDR); - return 0; + rank = vgic_rank_offset(v, 1, reg - GICD_ICPENDR, DABT_WORD); + if ( rank == NULL ) goto write_ignore; + + vgic_check_inflight_irqs_pending(v->domain, v, rank->index, r); + + goto write_ignore; case VRANGE32(GICD_ISACTIVER, GICD_ISACTIVERN): if ( dabt.size != DABT_WORD ) goto bad_width; @@ -986,11 +988,8 @@ static int vgic_v3_rdistr_sgi_mmio_write(struct vcpu *v, mmio_info_t *info, info, gicr_reg, r); case VREG32(GICR_ICPENDR0): - if ( dabt.size != DABT_WORD ) goto bad_width; - printk(XENLOG_G_ERR - "%pv: vGICR: SGI: unhandled word write %#"PRIregister" to ICPENDR0\n", - v, r); - return 0; + return __vgic_v3_distr_common_mmio_write("vGICR: SGI", v, + info, gicr_reg, r); case VREG32(GICR_IGRPMODR0): /* We do not implement security extensions for guests, write ignore */ diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 8f9400a519..83386cf3d5 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -726,6 +726,34 @@ unsigned int vgic_max_vcpus(unsigned int domctl_vgic_version) } } +void vgic_check_inflight_irqs_pending(struct domain *d, struct vcpu *v, + unsigned int rank, uint32_t r) +{ + const unsigned long mask = r; + unsigned int i; + + for_each_set_bit( i, &mask, 32 ) + { + struct pending_irq *p; + struct vcpu *v_target; + unsigned long flags; + unsigned int irq = i + 32 * rank; + + v_target = vgic_get_target_vcpu(v, irq); + + spin_lock_irqsave(&v_target->arch.vgic.lock, flags); + + p = irq_to_pending(v_target, irq); + + if ( p && !list_empty(&p->inflight) ) + printk(XENLOG_G_WARNING + "%pv trying to clear pending interrupt %u.\n", + v, irq); + + spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags); + } +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index 62c2ae538d..e69a59063a 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -298,6 +298,8 @@ extern bool vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int virq, const struct sgi_target *target); extern bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq); +extern void vgic_check_inflight_irqs_pending(struct domain *d, struct vcpu *v, + unsigned int rank, uint32_t r); #endif /* !CONFIG_NEW_VGIC */