dev-arm: SMMUv3 Table walks using TnSZ

TnSZ is needed when selecting the starting level of a table
walk, since it directly affects the number of IA bits.
This has been implemented by adding T0SZ and S2T0SZ to the
translation context.
T1SZ is not used at the moment since the current model doesn't
support TTB1.

Change-Id: I75663475c4dc01e5986cd93f8deafcdf7b1ece82
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Michiel Van Tol <michiel.vantol@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/19630
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/dev/arm/smmu_v3_ptops.cc b/src/dev/arm/smmu_v3_ptops.cc
index c57c16a..96d876e 100644
--- a/src/dev/arm/smmu_v3_ptops.cc
+++ b/src/dev/arm/smmu_v3_ptops.cc
@@ -122,7 +122,7 @@
 }
 
 unsigned
-V7LPageTableOps::firstLevel() const
+V7LPageTableOps::firstLevel(uint8_t tsz) const
 {
     return 1;
 }
@@ -216,9 +216,13 @@
 }
 
 unsigned
-V8PageTableOps4k::firstLevel() const
+V8PageTableOps4k::firstLevel(uint8_t tsz) const
 {
-    return 0;
+    if (tsz >= 16 && tsz <= 24) return 0;
+    if (tsz >= 25 && tsz <= 33) return 1;
+    if (tsz >= 34 && tsz <= 39) return 2;
+
+    panic("Unsupported TnSZ: %d\n", tsz);
 }
 
 unsigned
@@ -312,9 +316,14 @@
 }
 
 unsigned
-V8PageTableOps16k::firstLevel() const
+V8PageTableOps16k::firstLevel(uint8_t tsz) const
 {
-    return 0;
+    if (tsz == 16) return 0;
+    if (tsz >= 17 && tsz <= 27) return 1;
+    if (tsz >= 28 && tsz <= 38) return 2;
+    if (tsz == 39) return 3;
+
+    panic("Unsupported TnSZ: %d\n", tsz);
 }
 
 unsigned
@@ -400,9 +409,13 @@
 }
 
 unsigned
-V8PageTableOps64k::firstLevel() const
+V8PageTableOps64k::firstLevel(uint8_t tsz) const
 {
-    return 1;
+    if (tsz >= 12 && tsz <= 21) return 1;
+    if (tsz >= 22 && tsz <= 34) return 2;
+    if (tsz >= 35 && tsz <= 39) return 3;
+
+    panic("Unsupported TnSZ: %d\n", tsz);
 }
 
 unsigned
diff --git a/src/dev/arm/smmu_v3_ptops.hh b/src/dev/arm/smmu_v3_ptops.hh
index 8680541..244910c 100644
--- a/src/dev/arm/smmu_v3_ptops.hh
+++ b/src/dev/arm/smmu_v3_ptops.hh
@@ -55,7 +55,7 @@
     virtual Addr index(Addr va, unsigned level) const = 0;
     virtual Addr pageMask(pte_t pte, unsigned level) const = 0;
     virtual Addr walkMask(unsigned level) const = 0;
-    virtual unsigned firstLevel() const = 0;
+    virtual unsigned firstLevel(uint8_t tsz) const = 0;
     virtual unsigned lastLevel() const = 0;
 };
 
@@ -68,7 +68,7 @@
     Addr index(Addr va, unsigned level) const override;
     Addr pageMask(pte_t pte, unsigned level) const override;
     Addr walkMask(unsigned level) const override;
-    unsigned firstLevel() const override;
+    unsigned firstLevel(uint8_t tsz) const override;
     unsigned lastLevel() const override;
 };
 
@@ -81,7 +81,7 @@
     Addr index(Addr va, unsigned level) const override;
     Addr pageMask(pte_t pte, unsigned level) const override;
     Addr walkMask(unsigned level) const override;
-    unsigned firstLevel() const override;
+    unsigned firstLevel(uint8_t tsz) const override;
     unsigned lastLevel() const override;
 };
 
@@ -94,7 +94,7 @@
     Addr index(Addr va, unsigned level) const override;
     Addr pageMask(pte_t pte, unsigned level) const override;
     Addr walkMask(unsigned level) const override;
-    unsigned firstLevel() const override;
+    unsigned firstLevel(uint8_t tsz) const override;
     unsigned lastLevel() const override;
 };
 
@@ -107,7 +107,7 @@
     Addr index(Addr va, unsigned level) const override;
     Addr pageMask(pte_t pte, unsigned level) const override;
     Addr walkMask(unsigned level) const override;
-    unsigned firstLevel() const override;
+    unsigned firstLevel(uint8_t tsz) const override;
     unsigned lastLevel() const override;
 };
 
diff --git a/src/dev/arm/smmu_v3_transl.cc b/src/dev/arm/smmu_v3_transl.cc
index c1a7ed1..84ca5a7 100644
--- a/src/dev/arm/smmu_v3_transl.cc
+++ b/src/dev/arm/smmu_v3_transl.cc
@@ -605,10 +605,12 @@
         tc.httb = ste.dw3.s2ttb << STE_S2TTB_SHIFT;
         tc.vmid = ste.dw2.s2vmid;
         tc.stage2TranslGranule = ste.dw2.s2tg;
+        tc.s2t0sz = ste.dw2.s2t0sz;
     } else {
         tc.httb = 0xdeadbeef;
         tc.vmid = 0;
         tc.stage2TranslGranule = TRANS_GRANULE_INVALID;
+        tc.s2t0sz = 0;
     }
 
 
@@ -621,11 +623,13 @@
         tc.ttb1 = cd.dw2.ttb1 << CD_TTB_SHIFT;
         tc.asid = cd.dw0.asid;
         tc.stage1TranslGranule = cd.dw0.tg0;
+        tc.t0sz = cd.dw0.t0sz;
     } else {
         tc.ttb0 = 0xcafebabe;
         tc.ttb1 = 0xcafed00d;
         tc.asid = 0;
         tc.stage1TranslGranule = TRANS_GRANULE_INVALID;
+        tc.t0sz = 0;
     }
 
     return true;
@@ -875,7 +879,7 @@
     // Level here is actually (level+1) so we can count down
     // to 0 using unsigned int.
     for (level = pt_ops->lastLevel() + 1;
-        level > pt_ops->firstLevel();
+        level > pt_ops->firstLevel(context.t0sz);
         level--)
     {
         walkCacheLookup(yield, walk_ep, addr,
@@ -908,7 +912,8 @@
             table_addr = s2tr.addr;
         }
 
-        tr = walkStage1And2(yield, addr, pt_ops, pt_ops->firstLevel(),
+        tr = walkStage1And2(yield, addr, pt_ops,
+                            pt_ops->firstLevel(context.t0sz),
                             table_addr);
     }
 
@@ -949,13 +954,13 @@
     }
 
     const WalkCache::Entry *walk_ep = NULL;
-    unsigned level = pt_ops->firstLevel();
+    unsigned level = pt_ops->firstLevel(context.s2t0sz);
 
     if (final_tr || smmu.walkCacheNonfinalEnable) {
         // Level here is actually (level+1) so we can count down
         // to 0 using unsigned int.
         for (level = pt_ops->lastLevel() + 1;
-            level > pt_ops->firstLevel();
+            level > pt_ops->firstLevel(context.s2t0sz);
             level--)
         {
             walkCacheLookup(yield, walk_ep, addr,
@@ -981,7 +986,8 @@
                             level + 1, walk_ep->pa);
         }
     } else {
-        tr = walkStage2(yield, addr, final_tr, pt_ops, pt_ops->firstLevel(),
+        tr = walkStage2(yield, addr, final_tr, pt_ops,
+                        pt_ops->firstLevel(context.s2t0sz),
                         context.httb);
     }
 
diff --git a/src/dev/arm/smmu_v3_transl.hh b/src/dev/arm/smmu_v3_transl.hh
index 6a69460..4da35d7 100644
--- a/src/dev/arm/smmu_v3_transl.hh
+++ b/src/dev/arm/smmu_v3_transl.hh
@@ -73,6 +73,8 @@
         uint16_t vmid;
         uint8_t stage1TranslGranule;
         uint8_t stage2TranslGranule;
+        uint8_t t0sz;
+        uint8_t s2t0sz;
     };
 
     enum FaultType