Han-sheng Liu has uploaded this change for review. ( https://gem5-review.googlesource.com/c/public/gem5/+/69057?usp=email )

Change subject: mem: Support backdoor request in AddrMapper
......................................................................

mem: Support backdoor request in AddrMapper

Change-Id: Iedbe8eb75006ce1b81e85910af848fb8c4cba646
---
M src/mem/SConscript
M src/mem/addr_mapper.cc
M src/mem/addr_mapper.hh
A src/mem/backdoor_manager.cc
A src/mem/backdoor_manager.hh
A src/mem/backdoor_manager.test.cc
6 files changed, 457 insertions(+), 1 deletion(-)



diff --git a/src/mem/SConscript b/src/mem/SConscript
index ca164c1..a8e0e1b 100644
--- a/src/mem/SConscript
+++ b/src/mem/SConscript
@@ -71,6 +71,7 @@

 Source('abstract_mem.cc')
 Source('addr_mapper.cc')
+Source('backdoor_manager.cc')
 Source('bridge.cc')
 Source('coherent_xbar.cc')
 Source('cfi_mem.cc')
@@ -105,6 +106,8 @@
 Source('mem_delay.cc')
 Source('port_terminator.cc')

+GTest('backdoor_manager.test', 'backdoor_manager.test.cc',
+      'backdoor_manager.cc', with_tag('gem5_trace'))
 GTest('translation_gen.test', 'translation_gen.test.cc')

 Source('translating_port_proxy.cc')
diff --git a/src/mem/addr_mapper.cc b/src/mem/addr_mapper.cc
index 091b9d5..3c4054b 100644
--- a/src/mem/addr_mapper.cc
+++ b/src/mem/addr_mapper.cc
@@ -84,6 +84,19 @@
     pkt->setAddr(orig_addr);
 }

+void
+AddrMapper::recvMemBackdoorReq(const MemBackdoorReq &req,
+                               MemBackdoorPtr &backdoor)
+{
+ AddrRange remapped_req_range = AddrRange(remapAddr(req.range().start()),
+                                             remapAddr(req.range().end()));
+    MemBackdoorReq remapped_req(remapped_req_range, req.flags());
+    memSidePort.sendMemBackdoorReq(remapped_req, backdoor);
+    if (backdoor != nullptr) {
+        backdoor = getRevertedBackdoor(backdoor, req.range());
+    }
+}
+
 Tick
 AddrMapper::recvAtomic(PacketPtr pkt)
 {
@@ -104,6 +117,19 @@
     return ret_tick;
 }

+Tick
+AddrMapper::recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr& backdoor)
+{
+    Addr orig_addr = pkt->getAddr();
+    pkt->setAddr(remapAddr(orig_addr));
+    Tick ret_tick = memSidePort.sendAtomicBackdoor(pkt, backdoor);
+    pkt->setAddr(orig_addr);
+    if (backdoor != nullptr) {
+        backdoor = getRevertedBackdoor(backdoor, pkt->getAddrRange());
+    }
+    return ret_tick;
+}
+
 bool
 AddrMapper::recvTimingReq(PacketPtr pkt)
 {
@@ -206,7 +232,8 @@
 RangeAddrMapper::RangeAddrMapper(const RangeAddrMapperParams &p) :
     AddrMapper(p),
     originalRanges(p.original_ranges),
-    remappedRanges(p.remapped_ranges)
+    remappedRanges(p.remapped_ranges),
+    backdoorManager(originalRanges, remappedRanges)
 {
     if (originalRanges.size() != remappedRanges.size())
         fatal("AddrMapper: original and shadowed range list must "
@@ -232,6 +259,13 @@
     return addr;
 }

+MemBackdoorPtr
+RangeAddrMapper::getRevertedBackdoor(MemBackdoorPtr &backdoor,
+                                     const AddrRange &range)
+{
+    return backdoorManager.getRevertedBackdoor(backdoor, range);
+}
+
 AddrRangeList
 RangeAddrMapper::getAddrRanges() const
 {
diff --git a/src/mem/addr_mapper.hh b/src/mem/addr_mapper.hh
index 40a0bb0..b788dd8 100644
--- a/src/mem/addr_mapper.hh
+++ b/src/mem/addr_mapper.hh
@@ -38,6 +38,10 @@
 #ifndef __MEM_ADDR_MAPPER_HH__
 #define __MEM_ADDR_MAPPER_HH__

+#include <vector>
+
+#include "mem/backdoor_manager.hh"
+#include "mem/packet.hh"
 #include "mem/port.hh"
 #include "params/AddrMapper.hh"
 #include "params/RangeAddrMapper.hh"
@@ -77,6 +81,20 @@
      */
     virtual Addr remapAddr(Addr addr) const = 0;

+    /**
+ * This function returns a backdoor that fulfills the initiator request,
+     * based on the target backdoor at the first parameter.
+     * Note that this function should return a backdoor in original address
+ * space, while the target backdoor is in remapped address space. Address
+     * reverting logic is probably required in this function.
+     *
+     * @param backdoor the backdoor obtained from target
+     * @param pkt the initiator request to be fulfilled
+     * @return a backdoor that fulfill the initiator request
+     */
+    virtual MemBackdoorPtr getRevertedBackdoor(MemBackdoorPtr &backdoor,
+                                               const AddrRange &range) = 0;
+
     class AddrMapperSenderState : public Packet::SenderState
     {

@@ -168,12 +186,24 @@
             mapper.recvFunctional(pkt);
         }

+        void recvMemBackdoorReq(const MemBackdoorReq &req,
+                                MemBackdoorPtr &backdoor) override
+        {
+            mapper.recvMemBackdoorReq(req, backdoor);
+        }
+
         Tick
         recvAtomic(PacketPtr pkt) override
         {
             return mapper.recvAtomic(pkt);
         }

+        Tick
+ recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr& backdoor) override
+        {
+            return mapper.recvAtomicBackdoor(pkt, backdoor);
+        }
+
         bool
         recvTimingReq(PacketPtr pkt) override
         {
@@ -209,10 +239,15 @@

     void recvFunctionalSnoop(PacketPtr pkt);

+    void recvMemBackdoorReq(const MemBackdoorReq &req,
+                            MemBackdoorPtr &backdoor);
+
     Tick recvAtomic(PacketPtr pkt);

     Tick recvAtomicSnoop(PacketPtr pkt);

+    Tick recvAtomicBackdoor(PacketPtr pkt, MemBackdoorPtr& backdoor);
+
     bool recvTimingReq(PacketPtr pkt);

     bool recvTimingResp(PacketPtr pkt);
@@ -269,12 +304,19 @@
     std::vector<AddrRange> remappedRanges;

     Addr remapAddr(Addr addr) const override;
+
+    MemBackdoorPtr getRevertedBackdoor(MemBackdoorPtr &backdoor,
+                                       const AddrRange &range) override;
+
     void
     recvRangeChange() override
     {
// TODO Check that our peer is actually expecting to receive accesses
         // in our output range(s).
     }
+
+  private:
+    BackdoorManager backdoorManager;
 };

 } // namespace gem5
diff --git a/src/mem/backdoor_manager.cc b/src/mem/backdoor_manager.cc
new file mode 100644
index 0000000..32d267c
--- /dev/null
+++ b/src/mem/backdoor_manager.cc
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2023 Google, Inc
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * 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.
+ */
+
+#include <utility>
+
+#include "base/logging.hh"
+#include "mem/backdoor_manager.hh"
+
+namespace gem5
+{
+
+BackdoorManager::BackdoorManager(const std::vector<AddrRange> &original_ranges, + const std::vector<AddrRange> &remapped_ranges)
+    : originalRanges(original_ranges),
+      remappedRanges(remapped_ranges),
+      backdoorLists(original_ranges.size())
+{
+}
+
+MemBackdoorPtr
+BackdoorManager::getRevertedBackdoor(MemBackdoorPtr backdoor,
+                                     const AddrRange &pkt_range)
+{
+    MemBackdoorPtr reverted_backdoor = findBackdoor(pkt_range);
+    if (reverted_backdoor == nullptr) {
+        reverted_backdoor = createRevertedBackdoor(backdoor, pkt_range);
+    }
+    return reverted_backdoor;
+}
+
+MemBackdoorPtr
+BackdoorManager::createRevertedBackdoor(MemBackdoorPtr backdoor,
+                                        const AddrRange &pkt_range)
+{
+ std::unique_ptr<MemBackdoor> reverted_backdoor = std::make_unique<MemBackdoor>();
+    reverted_backdoor->flags(backdoor->flags());
+    reverted_backdoor->ptr(backdoor->ptr());
+
+    Addr addr = pkt_range.start();
+    for (int i = 0; i < originalRanges.size(); ++i) {
+        if (originalRanges[i].contains(addr)) {
+            /** Does not support interleaved range backdoors. */
+            if (originalRanges[i].interleaved() ||
+                remappedRanges[i].interleaved()) {
+                return nullptr;
+            }
+
+            /** Shrink the backdoor to fit inside address range. */
+            AddrRange shrinked_backdoor_range =
+                backdoor->range() & remappedRanges[i];
+
+            Addr backdoor_offset =
+ shrinked_backdoor_range.start() - remappedRanges[i].start();
+            Addr backdoor_size = shrinked_backdoor_range.size();
+
+            /** Create the backdoor in original address view. */
+            reverted_backdoor->range(AddrRange(
+                originalRanges[i].start() + backdoor_offset,
+ originalRanges[i].start() + backdoor_offset + backdoor_size));
+
+            /**
+ * The backdoor pointer also needs to be shrinked to point to the
+             * beginning of the range.
+             */
+            Addr shrinked_offset =
+ shrinked_backdoor_range.start() - backdoor->range().start();
+            reverted_backdoor->ptr(backdoor->ptr() + shrinked_offset);
+
+            /**
+             * Bind the life cycle of the created backdoor with the target
+             * backdoor. Invalid and delete the created backdoor when the
+             * target backdoor is invalidated.
+             */
+ MemBackdoorPtr reverted_backdoor_raw_ptr = reverted_backdoor.get();
+            auto it = backdoorLists[i].insert(backdoorLists[i].end(),
+ std::move(reverted_backdoor));
+            backdoor->addInvalidationCallback(
+                [this, i, it](const MemBackdoor &backdoor) {
+ (*it)->invalidate(); // *it is unique_ptr reverted_backdoor
+                    this->backdoorLists[i].erase(it);
+                });
+            return reverted_backdoor_raw_ptr;
+        }
+    }
+    // Backdoor is not valid. Return an empty one.
+    panic("Target does not provide valid backdoor.");
+}
+
+MemBackdoorPtr
+BackdoorManager::findBackdoor(const AddrRange &pkt_range) const
+{
+    Addr addr = pkt_range.start();
+    Addr size = pkt_range.size();
+    for (int i = 0; i < originalRanges.size(); ++i) {
+        /** The original ranges should be disjoint, so at most one range
+         * contains the begin address.
+         */
+        if (originalRanges[i].contains(addr)) {
+            if (!originalRanges[i].contains(addr + size - 1)) {
+                /** The request range doesn't fit in any address range. */
+                return nullptr;
+            }
+            for (const auto &backdoor : backdoorLists[i]) {
+                if (backdoor->range().contains(addr) &&
+                    backdoor->range().contains(addr + size - 1)) {
+                    return backdoor.get();
+                }
+            }
+        }
+    }
+    return nullptr;
+}
+
+}  // namespace gem5
diff --git a/src/mem/backdoor_manager.hh b/src/mem/backdoor_manager.hh
new file mode 100644
index 0000000..676987c
--- /dev/null
+++ b/src/mem/backdoor_manager.hh
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2023 Google, Inc
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * 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.
+ */
+
+#ifndef __MEM_BACKDOOR_MANAGER_HH__
+#define __MEM_BACKDOOR_MANAGER_HH__
+
+#include <list>
+#include <memory>
+#include <vector>
+
+#include "mem/backdoor.hh"
+#include "mem/packet.hh"
+
+namespace gem5
+{
+
+/**
+ * This class manages the backdoors for RangeAddrMapper. It provides
+ * functionalities such as backdoor remapping, resource managing.
+ */
+class BackdoorManager
+{
+  public:
+    explicit BackdoorManager(const std::vector<AddrRange> &original_ranges,
+ const std::vector<AddrRange> &remapped_ranges);
+
+    MemBackdoorPtr getRevertedBackdoor(MemBackdoorPtr backdoor,
+                                       const AddrRange &pkt_range);
+
+  protected:
+    /**
+ * This function creates a new backdoor, whose address range contains the
+     * original request address. The address range is in initiator address
+     * view, and shouldn't exceed the original address range.
+     */
+    MemBackdoorPtr createRevertedBackdoor(MemBackdoorPtr backdoor,
+                                          const AddrRange &pkt_range);
+    /**
+ * This function returns a created backdoor that fulfills the request, or
+     * returns nullptr if there's no.
+     */
+    MemBackdoorPtr findBackdoor(const AddrRange &pkt_range) const;
+
+    const std::vector<AddrRange> &originalRanges;
+    const std::vector<AddrRange> &remappedRanges;
+
+    /**
+     * In this vector, each entry contains a list of backdoors that in the
+     * range in original address view.
+     */
+    std::vector<std::list<std::unique_ptr<MemBackdoor>>> backdoorLists;
+};
+}  // namespace gem5
+
+#endif  //__MEM_BACKDOOR_MANAGER_HH__
diff --git a/src/mem/backdoor_manager.test.cc b/src/mem/backdoor_manager.test.cc
new file mode 100644
index 0000000..05abc50
--- /dev/null
+++ b/src/mem/backdoor_manager.test.cc
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2023 Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+#include <vector>
+
+#include "base/addr_range.hh"
+#include "base/gtest/logging.hh"
+#include "mem/backdoor.hh"
+#include "mem/backdoor_manager.hh"
+
+namespace gem5
+{
+namespace backdoor_manager_test
+{
+const std::vector<AddrRange> kOriginalRange({AddrRange(0x0, 0x1000)});
+const std::vector<AddrRange> kRemappedRange({AddrRange(0x1000, 0x2000)});
+
+class BackdoorManagerTest : public BackdoorManager, public ::testing::Test
+{
+  public:
+    BackdoorManagerTest() : BackdoorManager(kOriginalRange, kRemappedRange)
+    {
+    }
+};
+
+TEST_F(BackdoorManagerTest, BasicRemapTest)
+{
+    /**
+     * The backdoor range is remappedRanges[0], and should be reverted into
+     * originalRanges[0].
+     */
+    AddrRange pkt_range = originalRanges[0];
+
+    uint8_t *ptr = nullptr;
+    MemBackdoor remapped_backdoor(remappedRanges[0], ptr,
+                                  MemBackdoor::Flags::Readable);
+    MemBackdoorPtr reverted_backdoor =
+        getRevertedBackdoor(&remapped_backdoor, pkt_range);
+
+    EXPECT_EQ(reverted_backdoor->range(), originalRanges[0]);
+    EXPECT_EQ(reverted_backdoor->ptr(), ptr);
+    ASSERT_EQ(backdoorLists[0].size(), 1);
+    EXPECT_EQ(backdoorLists[0].begin()->get(), reverted_backdoor);
+
+    /**
+ * After the target backdoor is invalidated, the new created backdoor should
+     * be freed and removed from the backdoor list.
+     */
+    remapped_backdoor.invalidate();
+    EXPECT_EQ(backdoorLists[0].size(), 0);
+}
+
+TEST_F(BackdoorManagerTest, ShrinkTest)
+{
+    AddrRange pkt_range = originalRanges[0];
+
+    /**
+ * The backdoor range is larger than the address remapper's address range.
+     * Backdoor is expected to be shrinked.
+     */
+    Addr diff = 0x1000;
+    AddrRange remapped_backdoor_range(
+        remappedRanges[0].start() - diff,  // 0x0
+        remappedRanges[0].end() + diff);   // 0x3000
+
+    uint8_t *ptr = nullptr;
+    MemBackdoor remapped_backdoor(remapped_backdoor_range, ptr,
+                                  MemBackdoor::Flags::Readable);
+    MemBackdoorPtr reverted_backdoor =
+        getRevertedBackdoor(&remapped_backdoor, pkt_range);
+
+    EXPECT_EQ(reverted_backdoor->range(), originalRanges[0]);
+    EXPECT_EQ(reverted_backdoor->ptr(), ptr + diff);
+
+    remapped_backdoor.invalidate();
+}
+
+TEST_F(BackdoorManagerTest, ReuseTest)
+{
+    /**
+ * The two packets have different address range, but both contained in the
+     * original address range.
+     */
+    Addr mid = originalRanges[0].start() + originalRanges[0].size() / 2;
+    AddrRange pkt_range_0 = AddrRange(originalRanges[0].start(), mid);
+    AddrRange pkt_range_1 = AddrRange(mid, originalRanges[0].end());
+
+    /**
+     * The address range of the backdoor covers the whole address range, so
+     * both packets can be fulfilled by this backdoor.
+     */
+    uint8_t *ptr = nullptr;
+    MemBackdoor remapped_backdoor(remappedRanges[0], ptr,
+                                  MemBackdoor::Flags::Readable);
+    /**
+     * For the first packet, a new backdoor should be constructed.
+     */
+    MemBackdoorPtr reverted_backdoor_0 =
+        getRevertedBackdoor(&remapped_backdoor, pkt_range_0);
+    EXPECT_EQ(backdoorLists[0].size(), 1);
+
+    /**
+ * For the second packet, it should return the same backdoor as previous
+     * one, and no new backdoor should be constructed.
+     */
+    MemBackdoorPtr reverted_backdoor_1 =
+        getRevertedBackdoor(&remapped_backdoor, pkt_range_1);
+    EXPECT_EQ(reverted_backdoor_0, reverted_backdoor_1);
+    EXPECT_EQ(backdoorLists[0].size(), 1);
+
+    remapped_backdoor.invalidate();
+}
+
+}  // namespace backdoor_manager_test
+}  // namespace gem5

--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/69057?usp=email To unsubscribe, or for help writing mail filters, visit https://gem5-review.googlesource.com/settings

Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: Iedbe8eb75006ce1b81e85910af848fb8c4cba646
Gerrit-Change-Number: 69057
Gerrit-PatchSet: 1
Gerrit-Owner: Han-sheng Liu <handsome...@google.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org

Reply via email to