misc: Replaced master/slave terminology
[gem5.git] / src / arch / arm / table_walker.hh
index 4753fe6a045b34b4872f2f9300584b319d94a555..8f4aaefd3ad344b9a5718ce1c63e27d13b438b64 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013 ARM Limited
+ * Copyright (c) 2010-2016, 2019 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -33,9 +33,6 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- *          Giacomo Gabrielli
  */
 
 #ifndef __ARCH_ARM_TABLE_WALKER_HH__
 
 #include <list>
 
+#include "arch/arm/faults.hh"
 #include "arch/arm/miscregs.hh"
 #include "arch/arm/system.hh"
 #include "arch/arm/tlb.hh"
-#include "dev/dma_device.hh"
-#include "mem/mem_object.hh"
 #include "mem/request.hh"
 #include "params/ArmTableWalker.hh"
+#include "sim/clocked_object.hh"
 #include "sim/eventq.hh"
-#include "sim/fault_fwd.hh"
 
 class ThreadContext;
 
+class DmaPort;
+
 namespace ArmISA {
 class Translation;
 class TLB;
 class Stage2MMU;
 
-class TableWalker : public MemObject
+class TableWalker : public ClockedObject
 {
   public:
     class WalkerState;
 
     class DescriptorBase {
       public:
+        DescriptorBase() : lookupLevel(L0) {}
+
         /** Current lookup level for this descriptor */
         LookupLevel lookupLevel;
 
@@ -107,7 +107,7 @@ class TableWalker : public MemObject
         bool _dirty;
 
         /** Default ctor */
-        L1Descriptor()
+        L1Descriptor() : data(0), _dirty(false)
         {
             lookupLevel = L1;
         }
@@ -229,7 +229,7 @@ class TableWalker : public MemObject
          */
         bool secure(bool have_security, WalkerState *currState) const
         {
-            if (have_security) {
+            if (have_security && currState->secureLookup) {
                 if (type() == PageTable)
                     return !bits(data, 3);
                 else
@@ -251,12 +251,13 @@ class TableWalker : public MemObject
         bool _dirty;
 
         /** Default ctor */
-        L2Descriptor()
+        L2Descriptor() : data(0), l1Parent(nullptr), _dirty(false)
         {
             lookupLevel = L2;
         }
 
-        L2Descriptor(L1Descriptor &parent) : l1Parent(&parent)
+        L2Descriptor(L1Descriptor &parent) : data(0), l1Parent(&parent),
+                                             _dirty(false)
         {
             lookupLevel = L2;
         }
@@ -362,6 +363,14 @@ class TableWalker : public MemObject
 
     };
 
+    // Granule sizes for AArch64 long descriptors
+    enum GrainSize {
+        Grain4KB  = 12,
+        Grain16KB = 14,
+        Grain64KB = 16,
+        ReservedGrain = 0
+    };
+
     /** Long-descriptor format (LPAE) */
     class LongDescriptor : public DescriptorBase {
       public:
@@ -373,6 +382,8 @@ class TableWalker : public MemObject
             Page
         };
 
+        LongDescriptor() : data(0), _dirty(false) {}
+
         /** The raw bits of the entry */
         uint64_t data;
 
@@ -409,11 +420,8 @@ class TableWalker : public MemObject
         /** True if the current lookup is performed in AArch64 state */
         bool aarch64;
 
-        /** True if the granule size is 64 KB (AArch64 only) */
-        bool largeGrain;
-
         /** Width of the granule size in bits */
-        int grainSize;
+        GrainSize grainSize;
 
         /** Return the descriptor type */
         EntryType type() const
@@ -421,8 +429,8 @@ class TableWalker : public MemObject
             switch (bits(data, 1, 0)) {
               case 0x1:
                 // In AArch64 blocks are not allowed at L0 for the 4 KB granule
-                // and at L1 for the 64 KB granule
-                if (largeGrain)
+                // and at L1 for 16/64 KB granules
+                if (grainSize > Grain4KB)
                     return lookupLevel == L2 ? Block : Invalid;
                 return lookupLevel == L0 || lookupLevel == L3 ? Invalid : Block;
               case 0x3:
@@ -435,15 +443,29 @@ class TableWalker : public MemObject
         /** Return the bit width of the page/block offset */
         uint8_t offsetBits() const
         {
-            assert(type() == Block || type() == Page);
-            if (largeGrain) {
-                if (type() == Block)
-                    return 29 /* 512 MB */;
-                return 16 /* 64 KB */;  // type() == Page
+            if (type() == Block) {
+                switch (grainSize) {
+                    case Grain4KB:
+                        return lookupLevel == L1 ? 30 /* 1 GB */
+                                                 : 21 /* 2 MB */;
+                    case Grain16KB:
+                        return 25  /* 32 MB */;
+                    case Grain64KB:
+                        return 29 /* 512 MB */;
+                    default:
+                        panic("Invalid AArch64 VM granule size\n");
+                }
+            } else if (type() == Page) {
+                switch (grainSize) {
+                    case Grain4KB:
+                    case Grain16KB:
+                    case Grain64KB:
+                        return grainSize; /* enum -> uint okay */
+                    default:
+                        panic("Invalid AArch64 VM granule size\n");
+                }
             } else {
-                if (type() == Block)
-                    return lookupLevel == L1 ? 30 /* 1 GB */ : 21 /* 2 MB */;
-                return 12 /* 4 KB */;  // type() == Page
+                panic("AArch64 page table entry must be block or page\n");
             }
         }
 
@@ -707,8 +729,11 @@ class TableWalker : public MemObject
         /** Cached copy of the cpsr as it existed when translation began */
         CPSR cpsr;
 
-        /** Cached copy of the ttbcr as it existed when translation began. */
-        TTBCR ttbcr;
+        /** Cached copy of ttbcr/tcr as it existed when translation began */
+        union {
+            TTBCR ttbcr; // AArch32 translations
+            TCR tcr;     // AArch64 translations
+        };
 
         /** Cached copy of the htcr as it existed when translation began. */
         HTCR htcr;
@@ -728,6 +753,9 @@ class TableWalker : public MemObject
         /** If the access comes from the secure state. */
         bool isSecure;
 
+        /** True if table walks are uncacheable (for table descriptors) */
+        bool isUncacheable;
+
         /** Helper variables used to implement hierarchical access permissions
          * when the long-desc. format is used (LPAE only) */
         bool secureLookup;
@@ -736,14 +764,12 @@ class TableWalker : public MemObject
         bool xnTable;
         bool pxnTable;
 
+        /** Hierarchical access permission disable */
+        bool hpd;
+
         /** Flag indicating if a second stage of lookup is required */
         bool stage2Req;
 
-        /** Indicates whether the translation has been passed onto the second
-         *  stage mmu, and no more work is required from the first stage.
-         */
-        bool doingStage2;
-
         /** A pointer to the stage 2 translation that's in progress */
         TLB::Translation *stage2Tran;
 
@@ -772,6 +798,12 @@ class TableWalker : public MemObject
 
         TableWalker *tableWalker;
 
+        /** Timestamp for calculating elapsed time in service (for stats) */
+        Tick startTime;
+
+        /** Page entries walked during service (for stats) */
+        unsigned levels;
+
         void doL1Descriptor();
         void doL2Descriptor();
 
@@ -784,37 +816,6 @@ class TableWalker : public MemObject
 
   protected:
 
-    /**
-     * A snooping DMA port that currently does nothing besides
-     * extending the DMA port to accept snoops without complaining.
-     */
-    class SnoopingDmaPort : public DmaPort
-    {
-
-      protected:
-
-        virtual void recvTimingSnoopReq(PacketPtr pkt)
-        { }
-
-        virtual Tick recvAtomicSnoop(PacketPtr pkt)
-        { return 0; }
-
-        virtual void recvFunctionalSnoop(PacketPtr pkt)
-        { }
-
-        virtual bool isSnooping() const { return true; }
-
-      public:
-
-        /**
-         * A snooping DMA port merely calls the construtor of the DMA
-         * port.
-         */
-        SnoopingDmaPort(MemObject *dev, System *s) :
-            DmaPort(dev, s)
-        { }
-    };
-
     /** Queues of requests for all the different lookup levels */
     std::list<WalkerState *> stateQueues[MAX_LOOKUP_LEVELS];
 
@@ -822,16 +823,15 @@ class TableWalker : public MemObject
      * currently busy. */
     std::list<WalkerState *> pendingQueue;
 
-
-    /** Port to issue translation requests from */
-    SnoopingDmaPort port;
-
-    /** If we're draining keep the drain event around until we're drained */
-    DrainManager *drainManager;
-
     /** The MMU to forward second stage look upts to */
     Stage2MMU *stage2Mmu;
 
+    /** Port shared by the two table walkers. */
+    DmaPort* port;
+
+    /** Requestor id assigned by the MMU. */
+    RequestorID requestorId;
+
     /** Indicates whether this table walker is part of the stage 2 mmu */
     const bool isStage2;
 
@@ -846,9 +846,6 @@ class TableWalker : public MemObject
     /** If a timing translation is currently in progress */
     bool pending;
 
-    /** Request id for requests generated by this walker */
-    MasterID masterId;
-
     /** The number of walks belonging to squashed instructions that can be
      * removed from the pendingQueue per cycle. */
     unsigned numSquashable;
@@ -859,7 +856,29 @@ class TableWalker : public MemObject
     bool _haveVirtualization;
     uint8_t physAddrRange;
     bool _haveLargeAsid64;
-    ArmSystem *armSys;
+
+    /** Statistics */
+   struct TableWalkerStats : public Stats::Group {
+        TableWalkerStats(Stats::Group *parent);
+        Stats::Scalar walks;
+        Stats::Scalar walksShortDescriptor;
+        Stats::Scalar walksLongDescriptor;
+        Stats::Vector walksShortTerminatedAtLevel;
+        Stats::Vector walksLongTerminatedAtLevel;
+        Stats::Scalar squashedBefore;
+        Stats::Scalar squashedAfter;
+        Stats::Histogram walkWaitTime;
+        Stats::Histogram walkServiceTime;
+        Stats::Histogram pendingWalks; // essentially "L" of queueing theory
+        Stats::Vector pageSizes;
+        Stats::Vector2d requestOrigin;
+    } stats;
+
+    mutable unsigned pendingReqs;
+    mutable Tick pendingChangeTick;
+
+    static const unsigned REQUESTED = 0;
+    static const unsigned COMPLETED = 1;
 
   public:
    typedef ArmTableWalkerParams Params;
@@ -872,39 +891,34 @@ class TableWalker : public MemObject
         return dynamic_cast<const Params *>(_params);
     }
 
+    void init() override;
+
     bool haveLPAE() const { return _haveLPAE; }
     bool haveVirtualization() const { return _haveVirtualization; }
     bool haveLargeAsid64() const { return _haveLargeAsid64; }
     /** Checks if all state is cleared and if so, completes drain */
     void completeDrain();
-    unsigned int drain(DrainManager *dm);
-    virtual void drainResume();
-    virtual BaseMasterPort& getMasterPort(const std::string &if_name,
-                                          PortID idx = InvalidPortID);
-
-    /**
-     * Allow the MMU (overseeing both stage 1 and stage 2 TLBs) to
-     * access the table walker port through the TLB so that it can
-     * orchestrate staged translations.
-     *
-     * @return Our DMA port
-     */
-    DmaPort& getWalkerPort() { return port; }
-
-    Fault walk(RequestPtr req, ThreadContext *tc, uint16_t asid, uint8_t _vmid,
+    DrainState drain() override;
+    void drainResume() override;
+
+    Port &getPort(const std::string &if_name,
+                  PortID idx=InvalidPortID) override;
+
+    Fault walk(const RequestPtr &req, ThreadContext *tc,
+               uint16_t asid, uint8_t _vmid,
                bool _isHyp, TLB::Mode mode, TLB::Translation *_trans,
                bool timing, bool functional, bool secure,
-               TLB::ArmTranslationType tranType);
+               TLB::ArmTranslationType tranType, bool _stage2Req);
 
     void setTlb(TLB *_tlb) { tlb = _tlb; }
     TLB* getTlb() { return tlb; }
-    void setMMU(Stage2MMU *m) { stage2Mmu = m; }
+    void setMMU(Stage2MMU *m, RequestorID requestor_id);
     void memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr,
                   uint8_t texcb, bool s);
     void memAttrsLPAE(ThreadContext *tc, TlbEntry &te,
                       LongDescriptor &lDescriptor);
-    void memAttrsAArch64(ThreadContext *tc, TlbEntry &te, uint8_t attrIndx,
-                         uint8_t sh);
+    void memAttrsAArch64(ThreadContext *tc, TlbEntry &te,
+                         LongDescriptor &lDescriptor);
 
     static LookupLevel toLookupLevel(uint8_t lookup_level_as_int);
 
@@ -912,35 +926,32 @@ class TableWalker : public MemObject
 
     void doL1Descriptor();
     void doL1DescriptorWrapper();
-    EventWrapper<TableWalker,
-                 &TableWalker::doL1DescriptorWrapper> doL1DescEvent;
+    EventFunctionWrapper doL1DescEvent;
 
     void doL2Descriptor();
     void doL2DescriptorWrapper();
-    EventWrapper<TableWalker,
-                 &TableWalker::doL2DescriptorWrapper> doL2DescEvent;
+    EventFunctionWrapper doL2DescEvent;
 
     void doLongDescriptor();
 
     void doL0LongDescriptorWrapper();
-    EventWrapper<TableWalker,
-                 &TableWalker::doL0LongDescriptorWrapper> doL0LongDescEvent;
+    EventFunctionWrapper doL0LongDescEvent;
     void doL1LongDescriptorWrapper();
-    EventWrapper<TableWalker,
-                 &TableWalker::doL1LongDescriptorWrapper> doL1LongDescEvent;
+    EventFunctionWrapper doL1LongDescEvent;
     void doL2LongDescriptorWrapper();
-    EventWrapper<TableWalker,
-                 &TableWalker::doL2LongDescriptorWrapper> doL2LongDescEvent;
+    EventFunctionWrapper doL2LongDescEvent;
     void doL3LongDescriptorWrapper();
-    EventWrapper<TableWalker,
-                 &TableWalker::doL3LongDescriptorWrapper> doL3LongDescEvent;
+    EventFunctionWrapper doL3LongDescEvent;
 
     void doLongDescriptorWrapper(LookupLevel curr_lookup_level);
+    Event* LongDescEventByLevel[4];
 
     bool fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes,
         Request::Flags flags, int queueIndex, Event *event,
         void (TableWalker::*doDescriptor)());
 
+    Fault generateLongDescFault(ArmFault::FaultSource src);
+
     void insertTableEntry(DescriptorBase &descriptor, bool longDescriptor);
 
     Fault processWalk();
@@ -951,9 +962,16 @@ class TableWalker : public MemObject
     static bool checkAddrSizeFaultAArch64(Addr addr, int currPhysAddrRange);
     Fault processWalkAArch64();
     void processWalkWrapper();
-    EventWrapper<TableWalker, &TableWalker::processWalkWrapper> doProcessEvent;
+    EventFunctionWrapper doProcessEvent;
 
     void nextWalk(ThreadContext *tc);
+
+    void pendingChange();
+
+    static uint8_t pageSizeNtoStatBin(uint8_t N);
+
+    Fault testWalk(Addr pa, Addr size, TlbEntry::DomainType domain,
+                   LookupLevel lookup_level);
 };
 
 } // namespace ArmISA