[RFC v5 08/28] hw/arm/smmu-common: Key configuration cache on SMMUDevice and SEC_SID
Tao Tang <[email protected]>
| Newsgroups | org.nongnu.qemu-devel,org.nongnu.qemu-arm |
|---|---|
| Message-ID | <[email protected]> |
Adapt the configuration cache to distinguish entries decoded through different SEC_SID-selected programming interfaces by introducing a composite SMMUConfigKey. The key combines SMMUDevice with SEC_SID, preventing Secure and Non-secure configuration entries from aliasing in the cache and leaving the key extensible for a future Realm SEC_SID namespace. The cache lookup, insertion, and invalidation mechanisms are updated to use this new keying infrastructure. Signed-off-by: Tao Tang <[email protected]> Reviewed-by: Eric Auger <[email protected]> Reviewed-by: Pierrick Bouvier <[email protected]> Link: https://lore.kernel.org/qemu-devel/[email protected]/ --- hw/arm/smmu-common.c | 45 ++++++++++++++++++++++++++++++++++-- hw/arm/smmuv3.c | 12 ++++++---- include/hw/arm/smmu-common.h | 7 ++++++ 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 89e1e2826d4..63c36329a98 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -30,6 +30,26 @@ #include "hw/arm/smmu-common.h" #include "smmu-internal.h" +/* Configuration Cache Management */ +static guint smmu_config_key_hash(gconstpointer key) +{ + const SMMUConfigKey *k = key; + return g_direct_hash(k->sdev) ^ (guint)k->sec_sid; +} + +static gboolean smmu_config_key_equal(gconstpointer a, gconstpointer b) +{ + const SMMUConfigKey *ka = a; + const SMMUConfigKey *kb = b; + return ka->sdev == kb->sdev && ka->sec_sid == kb->sec_sid; +} + +SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID sec_sid) +{ + SMMUConfigKey key = {.sdev = sdev, .sec_sid = sec_sid}; + return key; +} + ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid) { switch (sec_sid) { @@ -265,7 +285,8 @@ static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value, static gboolean smmu_hash_remove_by_sid_range(gpointer key, gpointer value, gpointer user_data) { - SMMUDevice *sdev = (SMMUDevice *)key; + SMMUConfigKey *config_key = (SMMUConfigKey *)key; + SMMUDevice *sdev = config_key->sdev; uint32_t sid = smmu_get_sid(sdev); SMMUSIDRange *sid_range = (SMMUSIDRange *)user_data; @@ -283,6 +304,24 @@ void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range) &sid_range); } +static gboolean smmu_hash_remove_by_sdev(gpointer key, gpointer value, + gpointer user_data) +{ + SMMUConfigKey *config_key = (SMMUConfigKey *)key; + SMMUDevice *target = (SMMUDevice *)user_data; + + if (config_key->sdev != target) { + return false; + } + trace_smmu_config_cache_inv(smmu_get_sid(target)); + return true; +} + +void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev) +{ + g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sdev, sdev); +} + void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova, uint8_t tg, uint64_t num_pages, uint8_t ttl) { @@ -979,7 +1018,9 @@ static void smmu_base_realize(DeviceState *dev, Error **errp) error_propagate(errp, local_err); return; } - s->configs = g_hash_table_new_full(NULL, NULL, NULL, g_free); + s->configs = g_hash_table_new_full(smmu_config_key_hash, + smmu_config_key_equal, + g_free, g_free); s->iotlb = g_hash_table_new_full(smmu_iotlb_key_hash, smmu_iotlb_key_equal, g_free, g_free); s->smmu_pcibus_by_busptr = g_hash_table_new(NULL, NULL); diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 3ff2f498a3b..a01175cc672 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -952,7 +952,7 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg, * * The configuration cache contains data resulting from both STE and CD * decoding under the form of an SMMUTransCfg struct. The hash table is indexed - * by the SMMUDevice handle. + * by a composite key of the SMMUDevice and the sec_sid. */ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event, SMMUSecSID sec_sid) @@ -960,8 +960,9 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event, SMMUv3State *s = sdev->smmu; SMMUState *bc = &s->smmu_state; SMMUTransCfg *cfg; + SMMUConfigKey lookup_key = smmu_get_config_key(sdev, sec_sid); - cfg = g_hash_table_lookup(bc->configs, sdev); + cfg = g_hash_table_lookup(bc->configs, &lookup_key); if (cfg) { sdev->cfg_cache_hits++; trace_smmuv3_config_cache_hit(smmu_get_sid(sdev), @@ -977,7 +978,9 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event, cfg = g_new0(SMMUTransCfg, 1); if (!smmuv3_decode_config(&sdev->iommu, cfg, event, sec_sid)) { - g_hash_table_insert(bc->configs, sdev, cfg); + SMMUConfigKey *persistent_key = g_new(SMMUConfigKey, 1); + *persistent_key = lookup_key; + g_hash_table_insert(bc->configs, persistent_key, cfg); } else { g_free(cfg); cfg = NULL; @@ -991,8 +994,7 @@ static void smmuv3_flush_config(SMMUDevice *sdev) SMMUv3State *s = sdev->smmu; SMMUState *bc = &s->smmu_state; - trace_smmu_config_cache_inv(smmu_get_sid(sdev)); - g_hash_table_remove(bc->configs, sdev); + smmu_configs_inv_sdev(bc, sdev); } /* Do translation with TLB lookup. */ diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h index a31ffcf6e71..bd83648b14c 100644 --- a/include/hw/arm/smmu-common.h +++ b/include/hw/arm/smmu-common.h @@ -153,6 +153,11 @@ typedef struct SMMUIOTLBKey { uint8_t level; } SMMUIOTLBKey; +typedef struct SMMUConfigKey { + SMMUDevice *sdev; + SMMUSecSID sec_sid; +} SMMUConfigKey; + typedef struct SMMUSIDRange { uint32_t start; uint32_t end; @@ -247,6 +252,7 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg, void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *entry); SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova, uint8_t tg, uint8_t level); +SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID sec_sid); void smmu_iotlb_inv_all(SMMUState *s); void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid); void smmu_iotlb_inv_vmid(SMMUState *s, int vmid); @@ -256,6 +262,7 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova, void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg, uint64_t num_pages, uint8_t ttl); void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range); +void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev); /* Unmap the range of all the notifiers registered to any IOMMU mr */ void smmu_inv_notifiers_all(SMMUState *s); -- 2.34.1