mem: Fix guest corruption when caches handle uncacheable accesses
[gem5.git] / src / mem / bus.hh
index 541e2f3635185d3ac5d56c9b7ef1031ee4d3eefa..59dabbfe418ace8e7bf32884c294d7835fe54d2f 100644 (file)
@@ -51,7 +51,7 @@
 #ifndef __MEM_BUS_HH__
 #define __MEM_BUS_HH__
 
-#include <list>
+#include <deque>
 #include <set>
 
 #include "base/addr_range_map.hh"
@@ -94,7 +94,7 @@ class BaseBus : public MemObject
      * whereas a response layer holds master ports.
      */
     template <typename PortClass>
-    class Layer
+    class Layer : public Drainable
     {
 
       public:
@@ -118,7 +118,7 @@ class BaseBus : public MemObject
          *
          * @return 1 if busy or waiting to retry, or 0 if idle
          */
-        unsigned int drain(Event *de);
+        unsigned int drain(DrainManager *dm);
 
         /**
          * Get the bus layer's name
@@ -206,14 +206,14 @@ class BaseBus : public MemObject
         /** the clock speed for the bus layer */
         Tick clock;
 
-        /** event for signalling when drained */
-        Event * drainEvent;
+        /** manager to signal when drained */
+        DrainManager *drainManager;
 
         /**
          * An array of ports that retry should be called
          * on because the original send failed for whatever reason.
          */
-        std::list<PortClass*> retryList;
+        std::deque<PortClass*> retryList;
 
         /**
          * Release the bus layer after being occupied and return to an
@@ -228,15 +228,15 @@ class BaseBus : public MemObject
     };
 
     /** cycles of overhead per transaction */
-    int headerCycles;
+    const Cycles headerCycles;
     /** the width of the bus in bytes */
-    int width;
+    const uint32_t width;
 
     typedef AddrRangeMap<PortID>::iterator PortMapIter;
     typedef AddrRangeMap<PortID>::const_iterator PortMapConstIter;
     AddrRangeMap<PortID> portMap;
 
-    AddrRangeList defaultRange;
+    AddrRange defaultRange;
 
     /**
      * Function called by the port when the bus is recieving a range change.
@@ -256,25 +256,21 @@ class BaseBus : public MemObject
     struct PortCache {
         bool valid;
         PortID id;
-        Addr start;
-        Addr end;
+        AddrRange range;
     };
 
     PortCache portCache[3];
 
     // Checks the cache and returns the id of the port that has the requested
     // address within its range
-    inline PortID checkPortCache(Addr addr) {
-        if (portCache[0].valid && addr >= portCache[0].start &&
-            addr < portCache[0].end) {
+    inline PortID checkPortCache(Addr addr) const {
+        if (portCache[0].valid && portCache[0].range.contains(addr)) {
             return portCache[0].id;
         }
-        if (portCache[1].valid && addr >= portCache[1].start &&
-                   addr < portCache[1].end) {
+        if (portCache[1].valid && portCache[1].range.contains(addr)) {
             return portCache[1].id;
         }
-        if (portCache[2].valid && addr >= portCache[2].start &&
-            addr < portCache[2].end) {
+        if (portCache[2].valid && portCache[2].range.contains(addr)) {
             return portCache[2].id;
         }
 
@@ -282,21 +278,18 @@ class BaseBus : public MemObject
     }
 
     // Clears the earliest entry of the cache and inserts a new port entry
-    inline void updatePortCache(short id, Addr start, Addr end) {
+    inline void updatePortCache(short id, const AddrRange& range) {
         portCache[2].valid = portCache[1].valid;
         portCache[2].id    = portCache[1].id;
-        portCache[2].start = portCache[1].start;
-        portCache[2].end   = portCache[1].end;
+        portCache[2].range = portCache[1].range;
 
         portCache[1].valid = portCache[0].valid;
         portCache[1].id    = portCache[0].id;
-        portCache[1].start = portCache[0].start;
-        portCache[1].end   = portCache[0].end;
+        portCache[1].range = portCache[0].range;
 
         portCache[0].valid = true;
         portCache[0].id    = id;
-        portCache[0].start = start;
-        portCache[0].end   = end;
+        portCache[0].range = range;
     }
 
     // Clears the cache. Needs to be called in constructor.
@@ -321,13 +314,22 @@ class BaseBus : public MemObject
     Tick calcPacketTiming(PacketPtr pkt);
 
     /**
-     * Ask everyone on the bus what their size is
+     * Ask everyone on the bus what their size is and determine the
+     * bus size as either the maximum, or if no device specifies a
+     * block size return the default.
      *
-     * @return the max of all the sizes
+     * @return the max of all the sizes or the default if none is set
      */
-    unsigned findBlockSize();
+    unsigned deviceBlockSize() const;
 
-    std::set<PortID> inRecvRangeChange;
+    /**
+     * Remember for each of the master ports of the bus if we got an
+     * address range from the connected slave. For convenience, also
+     * keep track of if we got ranges from all the slave modules or
+     * not.
+     */
+    std::vector<bool> gotAddrRanges;
+    bool gotAllAddrRanges;
 
     /** The master and slave ports of the bus */
     std::vector<SlavePort*> slavePorts;
@@ -346,11 +348,9 @@ class BaseBus : public MemObject
        address not handled by another port and not in default device's
        range will cause a fatal error.  If false, just send all
        addresses not handled by another port to default device. */
-    bool useDefaultRange;
+    const bool useDefaultRange;
 
-    unsigned defaultBlockSize;
-    unsigned cachedBlockSize;
-    bool cachedBlockSizeValid;
+    uint32_t blockSize;
 
     BaseBus(const BaseBusParams *p);
 
@@ -358,11 +358,15 @@ class BaseBus : public MemObject
 
   public:
 
+    virtual void init();
+
     /** A function used to return the port associated with this bus object. */
-    virtual MasterPort& getMasterPort(const std::string& if_name, int idx = -1);
-    virtual SlavePort& getSlavePort(const std::string& if_name, int idx = -1);
+    BaseMasterPort& getMasterPort(const std::string& if_name,
+                                  PortID idx = InvalidPortID);
+    BaseSlavePort& getSlavePort(const std::string& if_name,
+                                PortID idx = InvalidPortID);
 
-    virtual unsigned int drain(Event *de) = 0;
+    virtual unsigned int drain(DrainManager *dm) = 0;
 
 };