Per the specification, and as observed in hardware, the SMMUv3 aligns the SMMU_STRTAB_BASE address to the size of the table by masking out the respective least significant bits in the ADDR field.
Apply this masking logic to our smmu_find_ste() lookup function per the specification. ref. ARM IHI 0070C, section 6.3.23. Signed-off-by: Simon Veith <sve...@amazon.de> Cc: Eric Auger <eric.au...@redhat.com> Cc: qemu-devel@nongnu.org Cc: qemu-...@nongnu.org --- Changed in v2: * Now using MAKE_64BIT_MASK() * Eliminated unnecessary branches by using MAX() * Removed unnecessary range check against DMA_ADDR_BITS hw/arm/smmuv3.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 727558b..31ac3ca 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -376,8 +376,9 @@ bad_ste: static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event) { - dma_addr_t addr; + dma_addr_t addr, strtab_base; uint32_t log2size; + int strtab_size_shift; int ret; trace_smmuv3_find_ste(sid, s->features, s->sid_split); @@ -391,10 +392,16 @@ static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, } if (s->features & SMMU_FEATURE_2LVL_STE) { int l1_ste_offset, l2_ste_offset, max_l2_ste, span; - dma_addr_t strtab_base, l1ptr, l2ptr; + dma_addr_t l1ptr, l2ptr; STEDesc l1std; - strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK; + /* + * Align strtab base address to table size. For this purpose, assume it + * is not bounded by SMMU_IDR1_SIDSIZE. + */ + strtab_size_shift = MAX(5, (int)log2size - s->sid_split - 1 + 3); + strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK & + ~MAKE_64BIT_MASK(0, strtab_size_shift); l1_ste_offset = sid >> s->sid_split; l2_ste_offset = sid & ((1 << s->sid_split) - 1); l1ptr = (dma_addr_t)(strtab_base + l1_ste_offset * sizeof(l1std)); @@ -433,7 +440,10 @@ static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, } addr = l2ptr + l2_ste_offset * sizeof(*ste); } else { - addr = (s->strtab_base & SMMU_BASE_ADDR_MASK) + sid * sizeof(*ste); + strtab_size_shift = log2size + 5; + strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK & + ~MAKE_64BIT_MASK(0, strtab_size_shift); + addr = strtab_base + sid * sizeof(*ste); } if (smmu_get_ste(s, addr, ste, event)) { -- 2.7.4