dev-arm: SMMUv3 Table walks using TnSZ
authorGiacomo Travaglini <giacomo.travaglini@arm.com>
Mon, 22 Jul 2019 15:08:26 +0000 (16:08 +0100)
committerGiacomo Travaglini <giacomo.travaglini@arm.com>
Thu, 25 Jul 2019 12:49:12 +0000 (12:49 +0000)
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>
src/dev/arm/smmu_v3_ptops.cc
src/dev/arm/smmu_v3_ptops.hh
src/dev/arm/smmu_v3_transl.cc
src/dev/arm/smmu_v3_transl.hh

index c57c16a3a3076ace449d78e0b9b57d576be87dc4..96d876ea31804c7ff660146671bb8e5eb790aa3b 100644 (file)
@@ -122,7 +122,7 @@ V7LPageTableOps::walkMask(unsigned level) const
 }
 
 unsigned
-V7LPageTableOps::firstLevel() const
+V7LPageTableOps::firstLevel(uint8_t tsz) const
 {
     return 1;
 }
@@ -216,9 +216,13 @@ V8PageTableOps4k::walkMask(unsigned level) const
 }
 
 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 @@ V8PageTableOps16k::walkMask(unsigned level) const
 }
 
 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 @@ V8PageTableOps64k::walkMask(unsigned level) const
 }
 
 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
index 8680541c6dc240f62470d93229c56d392e9dd0bd..244910c0231e1aa76badd06d21dd075c175af457 100644 (file)
@@ -55,7 +55,7 @@ struct PageTableOps
     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 @@ struct V7LPageTableOps : public PageTableOps
     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 @@ struct V8PageTableOps4k : public PageTableOps
     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 @@ struct V8PageTableOps16k : public PageTableOps
     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 @@ struct V8PageTableOps64k : public PageTableOps
     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;
 };
 
index c1a7ed1d305b78fcc0fa000e89d285082518046e..84ca5a7c2a15c43af5bdd6592579f3adf567235e 100644 (file)
@@ -605,10 +605,12 @@ SMMUTranslationProcess::findConfig(Yield &yield,
         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 @@ SMMUTranslationProcess::findConfig(Yield &yield,
         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 @@ SMMUTranslationProcess::translateStage1And2(Yield &yield, Addr addr)
     // 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 @@ SMMUTranslationProcess::translateStage1And2(Yield &yield, Addr addr)
             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 @@ SMMUTranslationProcess::translateStage2(Yield &yield, Addr addr, bool final_tr)
     }
 
     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 @@ SMMUTranslationProcess::translateStage2(Yield &yield, Addr addr, bool final_tr)
                             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);
     }
 
index 6a69460dea5e41af0a1bec9a9cb0a8cba98428be..4da35d72d7b5db00bf7754fab1e2780734d3449d 100644 (file)
@@ -73,6 +73,8 @@ class SMMUTranslationProcess : public SMMUProcess
         uint16_t vmid;
         uint8_t stage1TranslGranule;
         uint8_t stage2TranslGranule;
+        uint8_t t0sz;
+        uint8_t s2t0sz;
     };
 
     enum FaultType