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 --- hw/arm/smmuv3.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index aad4639..2d6c275 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,23 @@ 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 = log2size - s->sid_split - 1 + 3; + if (strtab_size_shift < DMA_ADDR_BITS) { + if (strtab_size_shift < 5) { + strtab_size_shift = 5; + } + strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK & + ~((1ULL << strtab_size_shift) - 1); + } else { + strtab_base = 0; + } 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 +447,14 @@ 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; + if (strtab_size_shift < DMA_ADDR_BITS) { + strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK & + ~((1ULL << strtab_size_shift) - 1); + } else { + strtab_base = 0; + } + addr = strtab_base + sid * sizeof(*ste); } if (smmu_get_ste(s, addr, ste, event)) { -- 2.7.4