summaryrefslogtreecommitdiffstats
path: root/hw/arm/smmuv3.c
diff options
context:
space:
mode:
authorEric Auger2021-03-09 11:27:41 +0100
committerPeter Maydell2021-03-12 13:40:10 +0100
commit1194140b7fab588b4b9de9aeacbe9672f06c1d8f (patch)
treeb8ab57842d22616864670958097cf6f003300510 /hw/arm/smmuv3.c
parenthw/arm/smmuv3: Enforce invalidation on a power of two range (diff)
downloadqemu-1194140b7fab588b4b9de9aeacbe9672f06c1d8f.tar.gz
qemu-1194140b7fab588b4b9de9aeacbe9672f06c1d8f.tar.xz
qemu-1194140b7fab588b4b9de9aeacbe9672f06c1d8f.zip
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 <eric.auger@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 20210309102742.30442-7-eric.auger@redhat.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/arm/smmuv3.c')
-rw-r--r--hw/arm/smmuv3.c34
1 files changed, 20 insertions, 14 deletions
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: