Add virtual=true support to gicv5_set_pending(). This is similar to the handling for set_priority and friends, except that the Pending state is the one change a cpuif can make to an interrupt that doesn't require a VPE for the VM to be resident on it. Instead gicv5_set_pending() is passed the VM ID to operate on.
Signed-off-by: Peter Maydell <[email protected]> --- hw/intc/arm_gicv5.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index 1bb649cf4f1..c07122fe6e4 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -643,6 +643,7 @@ static const GICv5ISTConfig *ist_for_vint(GICv5 *s, DEF_SET_FIELD_FOR_IST(priority, uint8_t, PRIORITY) DEF_SET_FIELD_FOR_IST(enabled, bool, ENABLE) DEF_SET_FIELD_FOR_IST(handling, bool, HM) +DEF_SET_FIELD_FOR_IST(pending, bool, PENDING) void gicv5_set_priority(GICv5Common *cs, uint32_t id, uint8_t priority, GICv5Domain domain, GICv5IntType type, bool virtual, @@ -761,8 +762,30 @@ void gicv5_set_pending(GICv5Common *cs, uint32_t id, bool pending, trace_gicv5_set_pending(domain_name[domain], inttype_name(type), virtual, vm, id, pending); if (virtual) { - qemu_log_mask(LOG_GUEST_ERROR, "gicv5_set_pending: tried to set " - "pending state of a virtual interrupt\n"); + /* + * SetPending is the one operation on an interrupt that a cpuif + * can do without having a VPE for the VM resident. Instead it + * passes us the VM ID to operate on, and we must look up the + * IST to use that way rather than with ist_for_vint(). + */ + GICv5VMTConfig *vmcfg = &s->vmt_config[domain]; + const GICv5ISTConfig *cfg; + VMTE *vmte; + + if (!gicv5_domain_has_virt(cs, domain) || !vmcfg->valid) { + return; + } + + vmte = g_hash_table_lookup(vmcfg->vm_cache, GINT_TO_POINTER(vm)); + if (!vmte) { + return; + } + + cfg = type == GICV5_LPI ? &vmte->lpi_ist : &vmte->spi_ist; + if (!set_pending_for_ist(cs, cfg, id, pending, &iaffid)) { + return; + } + irs_recalc_vhppi(s, vmte, iaffid); return; } @@ -770,15 +793,10 @@ void gicv5_set_pending(GICv5Common *cs, uint32_t id, bool pending, case GICV5_LPI: { const GICv5ISTConfig *cfg = &s->phys_lpi_config[domain]; - L2_ISTE_Handle h; - uint32_t *l2_iste_p = get_l2_iste(cs, cfg, id, &h); - if (!l2_iste_p) { + if (!set_pending_for_ist(cs, cfg, id, pending, &iaffid)) { return; } - *l2_iste_p = FIELD_DP32(*l2_iste_p, L2_ISTE, PENDING, pending); - iaffid = FIELD_EX32(*l2_iste_p, L2_ISTE, IAFFID); - put_l2_iste(cs, cfg, &h); break; } case GICV5_SPI: -- 2.43.0
