The IRS provides a set of registers to allow software to read and write the configuration of a VPE. IRS_VPE_SELR selects the VPE to operate on, IRS_VPE_STATUSR indicates whether that selection was successful, and other registers like IRS_VPE_DBR will then provide access to the config for the selected VPE.
Implement IRS_VPE_SELR and IRS_VPE_STATUSR, for the "select a VPE" part of this mechanism. Signed-off-by: Peter Maydell <[email protected]> --- hw/intc/arm_gicv5.c | 111 +++++++++++++++++++++++++++++ hw/intc/arm_gicv5_common.c | 6 ++ hw/intc/trace-events | 1 + include/hw/intc/arm_gicv5_common.h | 2 + 4 files changed, 120 insertions(+) diff --git a/hw/intc/arm_gicv5.c b/hw/intc/arm_gicv5.c index e762c058a98..455242596bc 100644 --- a/hw/intc/arm_gicv5.c +++ b/hw/intc/arm_gicv5.c @@ -116,6 +116,24 @@ static void VMTE_free(void *data) g_free(vmte); } +static VPE *vpe_for_vpeid(VMTE *vmte, uint32_t vpeid) +{ + /* + * Return the VPE struct for the specified VPEID for this VM, or + * NULL if there is no such valid VPE. + */ + VPE *vpe; + + if (!vmte || vpeid >= (1 << vmte->vpe_id_bits)) { + return NULL; + } + vpe = &vmte->vpet[vpeid]; + if (!vpe->valid) { + return NULL; + } + return vpe; +} + static bool gicv5_domain_has_virt(GICv5Common *cs, GICv5Domain domain) { /* @@ -1949,6 +1967,56 @@ txfail: vmid, vpeid, vpete_addr); } +static VPE *vpe_from_selr(GICv5 *s, GICv5Domain domain) +{ + /* + * Return the VPE for the VM/VPE indicated by the current value of + * IRS_VPE_SELR, or NULL if none. + */ + GICv5Common *cs = ARM_GICV5_COMMON(s); + GICv5VMTConfig *cfg = &s->vmt_config[domain]; + uint32_t vmid, vpeid; + VMTE *vmte; + + if (FIELD_EX64(cs->irs_vpe_selr[domain], IRS_VPE_SELR, S) == 0) { + return NULL; + } + + vmid = FIELD_EX64(cs->irs_vpe_selr[domain], IRS_VPE_SELR, VM_ID); + vpeid = FIELD_EX64(cs->irs_vpe_selr[domain], IRS_VPE_SELR, VPE_ID); + + if (!cfg->valid || vmid >= (1 << cfg->vm_id_bits)) { + return NULL; + } + + vmte = g_hash_table_lookup(cfg->vm_cache, GINT_TO_POINTER(vmid)); + return vpe_for_vpeid(vmte, vpeid); +} + +static void irs_vpe_selr_write(GICv5 *s, GICv5Domain domain, uint64_t value) +{ + GICv5Common *cs = ARM_GICV5_COMMON(s); + uint32_t status = R_IRS_VPE_STATUSR_IDLE_MASK; + VPE *vpe; + + /* RES0 if we don't have virt */ + if (!gicv5_domain_has_virt(cs, domain)) { + return; + } + + cs->irs_vpe_selr[domain] = value; + + vpe = vpe_from_selr(s, domain); + if (vpe) { + /* We successfully selected a valid VPE */ + status |= R_IRS_VPE_STATUSR_V_MASK; + } + + trace_gicv5_irs_vpe_selr_write(domain_name[domain], value, status); + + cs->irs_vpe_statusr[domain] = status; +} + static void spi_sample(GICv5SPIState *spi) { /* @@ -2168,6 +2236,30 @@ static bool config_readl(GICv5 *s, GICv5Domain domain, hwaddr offset, *data = 0; } return true; + case A_IRS_VPE_SELR: + if (gicv5_domain_has_virt(cs, domain)) { + *data = extract64(cs->irs_vpe_selr[domain], 0, 32); + } else { + /* RAZ/WI if no virt */ + *data = 0; + } + return true; + case A_IRS_VPE_SELR + 4: + if (gicv5_domain_has_virt(cs, domain)) { + *data = extract64(cs->irs_vpe_selr[domain], 32, 32); + } else { + /* RAZ/WI if no virt */ + *data = 0; + } + return true; + case A_IRS_VPE_STATUSR: + if (gicv5_domain_has_virt(cs, domain)) { + *data = cs->irs_vpe_statusr[domain]; + } else { + /* RAZ/WI if no virt */ + *data = 0; + } + return true; case A_IRS_SPI_STATUSR: /* * QEMU writes to IRS_SPI_{CFGR,DOMAINR,SELR,VMR} take effect @@ -2334,6 +2426,14 @@ static bool config_writel(GICv5 *s, GICv5Domain domain, hwaddr offset, irs_vmap_vper_write(s, domain, deposit64(cs->irs_vmap_vper[domain], 32, 32, data)); return true; + case A_IRS_VPE_SELR: + irs_vpe_selr_write(s, domain, + deposit64(cs->irs_vpe_selr[domain], 0, 32, data)); + return true; + case A_IRS_VPE_SELR + 4: + irs_vpe_selr_write(s, domain, + deposit64(cs->irs_vpe_selr[domain], 32, 32, data)); + return true; case A_IRS_SPI_SELR: cs->irs_spi_selr[domain] = data; return true; @@ -2466,6 +2566,14 @@ static bool config_readll(GICv5 *s, GICv5Domain domain, hwaddr offset, *data = 0; } return true; + case A_IRS_VPE_SELR: + if (gicv5_domain_has_virt(cs, domain)) { + *data = cs->irs_vpe_selr[domain]; + } else { + /* RAZ/WI if no virt */ + *data = 0; + } + return true; } return false; @@ -2496,6 +2604,9 @@ static bool config_writell(GICv5 *s, GICv5Domain domain, hwaddr offset, case A_IRS_VMAP_VPER: irs_vmap_vper_write(s, domain, data); return true; + case A_IRS_VPE_SELR: + irs_vpe_selr_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 6e0e2295fde..553598e3178 100644 --- a/hw/intc/arm_gicv5_common.c +++ b/hw/intc/arm_gicv5_common.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "hw/intc/arm_gicv5_common.h" #include "hw/intc/arm_gicv5_stream.h" +#include "hw/intc/arm_gicv5_regs.h" #include "hw/core/qdev-properties.h" #include "qapi/error.h" #include "trace.h" @@ -113,6 +114,11 @@ static void gicv5_common_reset_hold(Object *obj, ResetType type) memset(cs->irs_vmap_vistr, 0, sizeof(cs->irs_vmap_vistr)); memset(cs->irs_vmap_l2_vistr, 0, sizeof(cs->irs_vmap_l2_vistr)); memset(cs->irs_vmap_vper, 0, sizeof(cs->irs_vmap_vper)); + memset(cs->irs_vpe_selr, 0, sizeof(cs->irs_vpe_selr)); + + for (int i = 0; i < NUM_GICV5_DOMAINS; i++) { + cs->irs_vpe_statusr[i] = R_IRS_VPE_STATUSR_IDLE_MASK; + } } } diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 79381c109b7..edfbf7d7157 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -253,6 +253,7 @@ gicv5_cache_vmte(const char *domain, uint32_t vmid) "GICv5 IRS %s VM ID %u valid gicv5_irs_vmap_vistr_write(const char *domain, uint32_t vmid, const char *type, const char *what) "GICv5 IRS %s VM ID %u %s IST now %s" gicv5_initialize_vpet(const char *domain, uint32_t vmid, uint32_t vpeid, bool valid) "GICv5 IRS %s VM ID %u VPE %u starts as valid %d" gicv5_irs_vmap_vper_write(const char *domain, uint32_t vmid, uint32_t vpeid) "GICv5 IRS %s VM ID %u VPE %u now made valid" +gicv5_irs_vpe_selr_write(const char *domain, uint64_t selr, uint32_t status) "GICv5 IRS %s IRS_VPE_SELR written 0x%" PRIx64 " IRS_VPE_STATUSR now 0x%x" # arm_gicv5_common.c gicv5_common_realize(uint32_t irsid, uint32_t num_cpus, uint32_t spi_base, uint32_t spi_irs_range, uint32_t spi_range) "GICv5 IRS realized: IRS ID %u, %u CPUs, SPI base %u, SPI IRS range %u, SPI range %u" diff --git a/include/hw/intc/arm_gicv5_common.h b/include/hw/intc/arm_gicv5_common.h index c8574f66a63..5823a7f78a0 100644 --- a/include/hw/intc/arm_gicv5_common.h +++ b/include/hw/intc/arm_gicv5_common.h @@ -96,6 +96,8 @@ struct GICv5Common { uint64_t irs_vmap_vistr[NUM_GICV5_DOMAINS]; uint64_t irs_vmap_l2_vistr[NUM_GICV5_DOMAINS]; uint64_t irs_vmap_vper[NUM_GICV5_DOMAINS]; + uint64_t irs_vpe_selr[NUM_GICV5_DOMAINS]; + uint32_t irs_vpe_statusr[NUM_GICV5_DOMAINS]; /* * Pointer to an array of state information for the SPIs. Array -- 2.43.0
