The IRS_VMAP_L2_VISTR allows the guest to make an L2 entry in the VM's VLPI or VSPI IST valid; it is the equivalent of what IRS_MAP_L2_ISTR does for the physical LPI IST.
Signed-off-by: Peter Maydell <[email protected]> --- hw/intc/arm_gicv5.c | 76 ++++++++++++++++++++++++++++++ hw/intc/arm_gicv5_common.c | 1 + include/hw/intc/arm_gicv5_common.h | 1 + 3 files changed, 78 insertions(+) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index 3fac52012b1..4f74236c62b 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -1792,6 +1792,46 @@ txfail: vmid, vmte->vmte_addr); } +static void irs_vmap_l2_vistr_write(GICv5 *s, GICv5Domain domain, + uint64_t value) +{ + GICv5Common *cs = ARM_GICV5_COMMON(s); + GICv5VMTConfig *cfg = &s->vmt_config[domain]; + uint32_t vmid = FIELD_EX64(value, IRS_VMAP_L2_VISTR, VM_ID); + bool m = FIELD_EX64(value, IRS_VMAP_L2_VISTR, M); + uint32_t intid = FIELD_EX64(value, IRS_VMAP_L2_VISTR, ID); + GICv5IntType type = FIELD_EX64(value, IRS_VMAP_VISTR, TYPE); + VMTE *vmte; + GICv5ISTConfig *vist; + + if (!gicv5_domain_has_virt(cs, domain) || !cfg->valid) { + /* Whole register RAZ/WI if no virt or no VM table */ + return; + } + + /* M bit is WO/UNKNOWN; write the other fields */ + cs->irs_vmap_l2_vistr[domain] = value & ~R_IRS_VMAP_L2_VISTR_M_MASK; + + /* + * M = 0 and bad VMID must be ignored; invalid TYPE is + * UNPREDICTABLE, and we choose to ignore + */ + if (!m || vmid >= (1 << cfg->vm_id_bits) || + (type != GICV5_LPI && type != GICV5_SPI)) { + return; + } + + vmte = g_hash_table_lookup(cfg->vm_cache, GINT_TO_POINTER(vmid)); + if (!vmte) { + /* VM is not valid */ + return; + } + + vist = type == GICV5_LPI ? &vmte->lpi_ist : &vmte->spi_ist; + + map_l2_istr(cs, vist, intid); +} + static void spi_sample(GICv5SPIState *spi) { /* @@ -1979,6 +2019,22 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset, *data = 0; } return true; + case A_IRS_VMAP_L2_VISTR: + if (gicv5_domain_has_virt(cs, domain) && s->vmt_config[domain].valid) { + *data = extract64(cs->irs_vmap_l2_vistr[domain], 0, 32); + } else { + /* RAZ/WI if no virt or no VM table */ + *data = 0; + } + return true; + case A_IRS_VMAP_L2_VISTR + 4: + if (gicv5_domain_has_virt(cs, domain) && s->vmt_config[domain].valid) { + *data = extract64(cs->irs_vmap_l2_vistr[domain], 32, 32); + } else { + /* RAZ/WI if no virt or no VM table */ + *data = 0; + } + return true; case A_IRS_SPI_STATUSR: /* * QEMU writes to IRS_SPI_{CFGR,DOMAINR,SELR,VMR} take effect @@ -2128,6 +2184,15 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset, deposit64(cs->irs_vmap_vistr[domain], 32, 32, data)); return true; + case A_IRS_VMAP_L2_VISTR: + irs_vmap_l2_vistr_write(s, domain, + deposit64(cs->irs_vmap_vistr[domain], 0, 32, data)); + return true; + case A_IRS_VMAP_L2_VISTR + 4: + irs_vmap_l2_vistr_write(s, domain, + deposit64(cs->irs_vmap_vistr[domain], + 32, 32, data)); + return true; case A_IRS_SPI_SELR: cs->irs_spi_selr[domain] = data; return true; @@ -2244,6 +2309,14 @@ static bool config_readll(GICv5 *s, GICv5Domain domain, hwaddr offset, *data = 0; } return true; + case A_IRS_VMAP_L2_VISTR: + if (gicv5_domain_has_virt(cs, domain) && s->vmt_config[domain].valid) { + *data = cs->irs_vmap_l2_vistr[domain]; + } else { + /* RAZ/WI if no virt or no VM table */ + *data = 0; + } + return true; } return false; @@ -2268,6 +2341,9 @@ static bool config_writell(GICv5 *s, GICv5Domain domain, hwaddr offset, case A_IRS_VMAP_VISTR: irs_vmap_vistr_write(s, domain, data); return true; + case A_IRS_VMAP_L2_VISTR: + irs_vmap_l2_vistr_write(s, domain, data); + return true; } return false; diff --git a/hw/intc/arm_gicv5_common.c b/hw/intc/arm_gicv5_common.c index 181171e000b..b52dba3d3b4 100644 --- a/hw/intc/arm_gicv5_common.c +++ b/hw/intc/arm_gicv5_common.c @@ -111,6 +111,7 @@ static void gicv5_common_reset_hold(Object *obj, ResetType type) memset(cs->irs_vmap_l2_vmtr, 0, sizeof(cs->irs_vmap_l2_vmtr)); memset(cs->irs_vmap_vmr, 0, sizeof(cs->irs_vmap_vmr)); memset(cs->irs_vmap_vistr, 0, sizeof(cs->irs_vmap_vistr)); + memset(cs->irs_vmap_l2_vistr, 0, sizeof(cs->irs_vmap_l2_vistr)); } } diff --git a/include/hw/intc/arm_gicv5_common.h b/include/hw/intc/arm_gicv5_common.h index 19e13693de9..8103f14ba44 100644 --- a/include/hw/intc/arm_gicv5_common.h +++ b/include/hw/intc/arm_gicv5_common.h @@ -94,6 +94,7 @@ struct GICv5Common { uint64_t irs_vmap_l2_vmtr[NUM_GICV5_DOMAINS]; uint64_t irs_vmap_vmr[NUM_GICV5_DOMAINS]; uint64_t irs_vmap_vistr[NUM_GICV5_DOMAINS]; + uint64_t irs_vmap_l2_vistr[NUM_GICV5_DOMAINS]; /* * Pointer to an array of state information for the SPIs. Array -- 2.43.0
