From 1194140b7fab588b4b9de9aeacbe9672f06c1d8f Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 9 Mar 2021 11:27:41 +0100 Subject: hw/arm/smmuv3: Fix SMMU_CMD_CFGI_STE_RANGE handling If the whole SID range (32b) is invalidated (SMMU_CMD_CFGI_ALL), @end overflows and we fail to handle the command properly. Once this gets fixed, the current code really is awkward in the sense it loops over the whole range instead of removing the currently cached configs through a hash table lookup. Fix both the overflow and the lookup. Signed-off-by: Eric Auger Reviewed-by: Peter Maydell Message-id: 20210309102742.30442-7-eric.auger@redhat.com Signed-off-by: Peter Maydell --- hw/arm/smmu-internal.h | 5 +++++ hw/arm/smmuv3.c | 34 ++++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 14 deletions(-) (limited to 'hw/arm') diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h index 55147f29be..2d75b31953 100644 --- a/hw/arm/smmu-internal.h +++ b/hw/arm/smmu-internal.h @@ -104,4 +104,9 @@ typedef struct SMMUIOTLBPageInvInfo { uint64_t mask; } SMMUIOTLBPageInvInfo; +typedef struct SMMUSIDRange { + uint32_t start; + uint32_t end; +} SMMUSIDRange; + #endif diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index fdd6332ce5..3b87324ce2 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -32,6 +32,7 @@ #include "hw/arm/smmuv3.h" #include "smmuv3-internal.h" +#include "smmu-internal.h" /** * smmuv3_trigger_irq - pulse @irq if enabled and update @@ -895,6 +896,20 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd) } } +static gboolean +smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data) +{ + SMMUDevice *sdev = (SMMUDevice *)key; + uint32_t sid = smmu_get_sid(sdev); + SMMUSIDRange *sid_range = (SMMUSIDRange *)user_data; + + if (sid < sid_range->start || sid > sid_range->end) { + return false; + } + trace_smmuv3_config_cache_inv(sid); + return true; +} + static int smmuv3_cmdq_consume(SMMUv3State *s) { SMMUState *bs = ARM_SMMU(s); @@ -965,27 +980,18 @@ static int smmuv3_cmdq_consume(SMMUv3State *s) } case SMMU_CMD_CFGI_STE_RANGE: /* same as SMMU_CMD_CFGI_ALL */ { - uint32_t start = CMD_SID(&cmd), end, i; + uint32_t start = CMD_SID(&cmd); uint8_t range = CMD_STE_RANGE(&cmd); + uint64_t end = start + (1ULL << (range + 1)) - 1; + SMMUSIDRange sid_range = {start, end}; if (CMD_SSEC(&cmd)) { cmd_error = SMMU_CERROR_ILL; break; } - - end = start + (1 << (range + 1)) - 1; trace_smmuv3_cmdq_cfgi_ste_range(start, end); - - for (i = start; i <= end; i++) { - IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, i); - SMMUDevice *sdev; - - if (!mr) { - continue; - } - sdev = container_of(mr, SMMUDevice, iommu); - smmuv3_flush_config(sdev); - } + g_hash_table_foreach_remove(bs->configs, smmuv3_invalidate_ste, + &sid_range); break; } case SMMU_CMD_CFGI_CD: -- cgit v1.2.3-55-g7522