diff --git a/src/mem/SConscript b/src/mem/SConscript index 6e017e0397..e2a91146d0 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -71,6 +71,7 @@ SimObject('ThreadBridge.py', sim_objects=['ThreadBridge']) 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('serial_link.cc') 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 091b9d56aa..3c4054b6ef 100644 --- a/src/mem/addr_mapper.cc +++ b/src/mem/addr_mapper.cc @@ -84,6 +84,19 @@ AddrMapper::recvFunctionalSnoop(PacketPtr pkt) 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 @@ AddrMapper::recvAtomicSnoop(PacketPtr pkt) 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 @@ AddrMapper::recvRangeChange() 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 @@ RangeAddrMapper::remapAddr(Addr addr) const 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 40a0bb033b..41709f38ab 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 + +#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 @@ class AddrMapper : public SimObject */ 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 range 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 @@ class AddrMapper : public SimObject 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 @@ class AddrMapper : public SimObject 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 @@ class RangeAddrMapper : public AddrMapper std::vector 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 0000000000..32d267c7a3 --- /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 + +#include "base/logging.hh" +#include "mem/backdoor_manager.hh" + +namespace gem5 +{ + +BackdoorManager::BackdoorManager(const std::vector &original_ranges, + const std::vector &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 reverted_backdoor = std::make_unique(); + 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 0000000000..676987c370 --- /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 +#include +#include + +#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 &original_ranges, + const std::vector &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 &originalRanges; + const std::vector &remappedRanges; + + /** + * In this vector, each entry contains a list of backdoors that in the + * range in original address view. + */ + std::vector>> 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 0000000000..05abc50f2f --- /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 +#include + +#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 kOriginalRange({AddrRange(0x0, 0x1000)}); +const std::vector 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