diff --git a/src/arch/arm/ArmMMU.py b/src/arch/arm/ArmMMU.py index 06fb964955..e44be8485f 100644 --- a/src/arch/arm/ArmMMU.py +++ b/src/arch/arm/ArmMMU.py @@ -35,8 +35,28 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from m5.objects.ArmTLB import ArmITB, ArmDTB +from m5.objects.ArmTLB import ArmITB, ArmDTB, ArmStage2TLB from m5.objects.BaseMMU import BaseMMU +from m5.objects.ClockedObject import ClockedObject +from m5.params import * +from m5.proxy import * + +# Basic stage 1 translation objects +class ArmTableWalker(ClockedObject): + type = 'ArmTableWalker' + cxx_class = 'ArmISA::TableWalker' + cxx_header = "arch/arm/table_walker.hh" + is_stage2 = Param.Bool(False, "Is this object for stage 2 translation?") + num_squash_per_cycle = Param.Unsigned(2, + "Number of outstanding walks that can be squashed per cycle") + + port = RequestPort("Table Walker port") + + sys = Param.System(Parent.any, "system object parameter") + +# Stage 2 translation objects, only used when virtualisation is being used +class ArmStage2TableWalker(ArmTableWalker): + is_stage2 = True class ArmMMU(BaseMMU): type = 'ArmMMU' @@ -45,10 +65,27 @@ class ArmMMU(BaseMMU): itb = ArmITB() dtb = ArmDTB() + stage2_itb = Param.ArmTLB(ArmStage2TLB(), "Stage 2 Instruction TLB") + stage2_dtb = Param.ArmTLB(ArmStage2TLB(), "Stage 2 Data TLB") + + itb_walker = Param.ArmTableWalker( + ArmTableWalker(), "HW Table walker") + dtb_walker = Param.ArmTableWalker( + ArmTableWalker(), "HW Table walker") + + stage2_itb_walker = Param.ArmTableWalker( + ArmStage2TableWalker(), "HW Table walker") + stage2_dtb_walker = Param.ArmTableWalker( + ArmStage2TableWalker(), "HW Table walker") + @classmethod def walkerPorts(cls): - return ["mmu.itb.walker.port", "mmu.dtb.walker.port"] + return ["mmu.itb_walker.port", "mmu.dtb_walker.port", + "mmu.stage2_itb_walker.port", "mmu.stage2_dtb_walker.port"] def connectWalkerPorts(self, iport, dport): - self.itb.walker.port = iport - self.dtb.walker.port = dport + self.itb_walker.port = iport + self.dtb_walker.port = dport + + self.stage2_itb_walker.port = iport + self.stage2_dtb_walker.port = dport diff --git a/src/arch/arm/ArmTLB.py b/src/arch/arm/ArmTLB.py index a821a048d7..db981d6529 100644 --- a/src/arch/arm/ArmTLB.py +++ b/src/arch/arm/ArmTLB.py @@ -39,24 +39,6 @@ from m5.SimObject import SimObject from m5.params import * from m5.proxy import * from m5.objects.BaseTLB import BaseTLB -from m5.objects.ClockedObject import ClockedObject - -# Basic stage 1 translation objects -class ArmTableWalker(ClockedObject): - type = 'ArmTableWalker' - cxx_class = 'ArmISA::TableWalker' - cxx_header = "arch/arm/table_walker.hh" - is_stage2 = Param.Bool(False, "Is this object for stage 2 translation?") - num_squash_per_cycle = Param.Unsigned(2, - "Number of outstanding walks that can be squashed per cycle") - - # The port to the memory system. This port is ultimately belonging - # to the Stage2MMU, and shared by the two table walkers, but we - # access it through the ITB and DTB walked objects in the CPU for - # symmetry with the other ISAs. - port = RequestPort("Port used by the two table walkers") - - sys = Param.System(Parent.any, "system object parameter") class ArmTLB(BaseTLB): type = 'ArmTLB' @@ -64,41 +46,14 @@ class ArmTLB(BaseTLB): cxx_header = "arch/arm/tlb.hh" sys = Param.System(Parent.any, "system object parameter") size = Param.Int(64, "TLB size") - walker = Param.ArmTableWalker(ArmTableWalker(), "HW Table walker") is_stage2 = Param.Bool(False, "Is this a stage 2 TLB?") -# Stage 2 translation objects, only used when virtualisation is being used -class ArmStage2TableWalker(ArmTableWalker): - is_stage2 = True - class ArmStage2TLB(ArmTLB): size = 32 - walker = ArmStage2TableWalker() is_stage2 = True -class ArmStage2MMU(SimObject): - type = 'ArmStage2MMU' - cxx_class = 'ArmISA::Stage2MMU' - cxx_header = 'arch/arm/stage2_mmu.hh' - tlb = Param.ArmTLB("Stage 1 TLB") - stage2_tlb = Param.ArmTLB("Stage 2 TLB") - - sys = Param.System(Parent.any, "system object parameter") - -class ArmStage2IMMU(ArmStage2MMU): - # We rely on the itb being a parameter of the CPU, and get the - # appropriate object that way - tlb = Parent.any - stage2_tlb = ArmStage2TLB() - -class ArmStage2DMMU(ArmStage2MMU): - # We rely on the dtb being a parameter of the CPU, and get the - # appropriate object that way - tlb = Parent.any - stage2_tlb = ArmStage2TLB() - class ArmITB(ArmTLB): - stage2_mmu = ArmStage2IMMU() + pass class ArmDTB(ArmTLB): - stage2_mmu = ArmStage2DMMU() + pass diff --git a/src/arch/arm/SConscript b/src/arch/arm/SConscript index a51d79484a..2a4f5cd3fc 100644 --- a/src/arch/arm/SConscript +++ b/src/arch/arm/SConscript @@ -94,7 +94,6 @@ if env['TARGET_ISA'] == 'arm': Source('system.cc') Source('table_walker.cc') Source('self_debug.cc') - Source('stage2_mmu.cc') Source('stage2_lookup.cc') Source('tlb.cc') Source('tlbi_op.cc') diff --git a/src/arch/arm/mmu.cc b/src/arch/arm/mmu.cc index b9a86373da..6045c33024 100644 --- a/src/arch/arm/mmu.cc +++ b/src/arch/arm/mmu.cc @@ -36,10 +36,52 @@ */ #include "arch/arm/mmu.hh" +#include "arch/arm/table_walker.hh" #include "arch/arm/tlbi_op.hh" using namespace ArmISA; +MMU::MMU(const ArmMMUParams &p) + : BaseMMU(p), + itbStage2(p.stage2_itb), dtbStage2(p.stage2_dtb), + itbWalker(p.itb_walker), dtbWalker(p.dtb_walker), + itbStage2Walker(p.stage2_itb_walker), + dtbStage2Walker(p.stage2_dtb_walker) +{} + +void +MMU::init() +{ + itbWalker->setMmu(this); + dtbWalker->setMmu(this); + itbStage2Walker->setMmu(this); + dtbStage2Walker->setMmu(this); + + itbStage2->setTableWalker(itbStage2Walker); + dtbStage2->setTableWalker(dtbStage2Walker); + + getITBPtr()->setStage2Tlb(itbStage2); + getITBPtr()->setTableWalker(itbWalker); + getDTBPtr()->setStage2Tlb(dtbStage2); + getDTBPtr()->setTableWalker(dtbWalker); +} + +TLB * +MMU::getTlb(BaseTLB::Mode mode, bool stage2) const +{ + if (mode == BaseTLB::Execute) { + if (stage2) + return itbStage2; + else + return getITBPtr(); + } else { + if (stage2) + return dtbStage2; + else + return getDTBPtr(); + } +} + bool MMU::translateFunctional(ThreadContext *tc, Addr vaddr, Addr &paddr) { @@ -50,10 +92,30 @@ Fault MMU::translateFunctional(const RequestPtr &req, ThreadContext *tc, BaseTLB::Mode mode, TLB::ArmTranslationType tran_type) { - if (mode == BaseTLB::Execute) - return getITBPtr()->translateFunctional(req, tc, mode, tran_type); - else - return getDTBPtr()->translateFunctional(req, tc, mode, tran_type); + return translateFunctional(req, tc, mode, tran_type, false); +} + +Fault +MMU::translateFunctional(const RequestPtr &req, ThreadContext *tc, + BaseTLB::Mode mode, TLB::ArmTranslationType tran_type, + bool stage2) +{ + return getTlb(mode, stage2)->translateFunctional( + req, tc, mode, tran_type); +} + +Fault +MMU::translateAtomic(const RequestPtr &req, ThreadContext *tc, + BaseTLB::Mode mode, bool stage2) +{ + return getTlb(mode, stage2)->translateAtomic(req, tc, mode); +} + +void +MMU::translateTiming(const RequestPtr &req, ThreadContext *tc, + BaseTLB::Translation *translation, BaseTLB::Mode mode, bool stage2) +{ + return getTlb(mode, stage2)->translateTiming(req, tc, translation, mode); } void diff --git a/src/arch/arm/mmu.hh b/src/arch/arm/mmu.hh index e5adb9508f..23fd5a253d 100644 --- a/src/arch/arm/mmu.hh +++ b/src/arch/arm/mmu.hh @@ -60,6 +60,17 @@ class MMU : public BaseMMU return static_cast(itb); } + TLB * getTlb(BaseTLB::Mode mode, bool stage2) const; + + protected: + TLB *itbStage2; + TLB *dtbStage2; + + TableWalker *itbWalker; + TableWalker *dtbWalker; + TableWalker *itbStage2Walker; + TableWalker *dtbStage2Walker; + public: enum TLBType { @@ -68,15 +79,26 @@ class MMU : public BaseMMU ALL_TLBS = 0x11 }; - MMU(const ArmMMUParams &p) - : BaseMMU(p) - {} + MMU(const ArmMMUParams &p); + + void init() override; bool translateFunctional(ThreadContext *tc, Addr vaddr, Addr &paddr); Fault translateFunctional(const RequestPtr &req, ThreadContext *tc, BaseTLB::Mode mode, TLB::ArmTranslationType tran_type); + Fault translateFunctional(const RequestPtr &req, ThreadContext *tc, + BaseTLB::Mode mode, TLB::ArmTranslationType tran_type, + bool stage2); + + using BaseMMU::translateAtomic; + Fault translateAtomic(const RequestPtr &req, ThreadContext *tc, + BaseTLB::Mode mode, bool stage2); + + void translateTiming(const RequestPtr &req, ThreadContext *tc, + BaseTLB::Translation *translation, BaseTLB::Mode mode, bool stage2); + void invalidateMiscReg(TLBType type = ALL_TLBS); template @@ -101,6 +123,14 @@ class MMU : public BaseMMU getDTBPtr()->flush(tlbi_op); } + void + flushAll() override + { + BaseMMU::flushAll(); + itbStage2->flushAll(); + dtbStage2->flushAll(); + } + uint64_t getAttr() const { diff --git a/src/arch/arm/stage2_mmu.cc b/src/arch/arm/stage2_mmu.cc deleted file mode 100644 index 0071bd8125..0000000000 --- a/src/arch/arm/stage2_mmu.cc +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2012-2013, 2015, 2021 Arm Limited - * 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 "arch/arm/stage2_mmu.hh" - -#include "arch/arm/faults.hh" -#include "arch/arm/system.hh" -#include "arch/arm/table_walker.hh" -#include "arch/arm/tlb.hh" -#include "cpu/base.hh" -#include "cpu/thread_context.hh" - -using namespace ArmISA; - -Stage2MMU::Stage2MMU(const Params &p) - : SimObject(p), _stage1Tlb(p.tlb), _stage2Tlb(p.stage2_tlb), - requestorId(p.sys->getRequestorId(_stage1Tlb->getTableWalker())), - port(_stage1Tlb->getTableWalker(), requestorId) -{ - // we use the stage-one table walker as the parent of the port, - // and to get our requestor id, this is done to keep things - // symmetrical with other ISAs in terms of naming and stats - stage1Tlb()->setMMU(this, requestorId); - stage2Tlb()->setMMU(this, requestorId); -} - -Fault -Stage2MMU::readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr, - uint8_t *data, int numBytes, Request::Flags flags, bool isFunctional) -{ - Fault fault; - - // translate to physical address using the second stage MMU - auto req = std::make_shared(); - req->setVirt(descAddr, numBytes, flags | Request::PT_WALK, - requestorId, 0); - if (isFunctional) { - fault = stage2Tlb()->translateFunctional(req, tc, BaseTLB::Read); - } else { - fault = stage2Tlb()->translateAtomic(req, tc, BaseTLB::Read); - } - - // Now do the access. - if (fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) { - Packet pkt = Packet(req, MemCmd::ReadReq); - pkt.dataStatic(data); - if (isFunctional) { - port.sendFunctional(&pkt); - } else { - port.sendAtomic(&pkt); - } - assert(!pkt.isError()); - } - - // If there was a fault annotate it with the flag saying the foult occured - // while doing a translation for a stage 1 page table walk. - if (fault != NoFault) { - ArmFault *armFault = reinterpret_cast(fault.get()); - armFault->annotate(ArmFault::S1PTW, true); - armFault->annotate(ArmFault::OVA, oVAddr); - } - return fault; -} - -void -Stage2MMU::readDataTimed(ThreadContext *tc, Addr descAddr, - Stage2Translation *translation, int numBytes, - Request::Flags flags) -{ - // translate to physical address using the second stage MMU - translation->setVirt( - descAddr, numBytes, flags | Request::PT_WALK, requestorId); - translation->translateTiming(tc); -} - -Stage2MMU::Stage2Translation::Stage2Translation(Stage2MMU &_parent, - uint8_t *_data, Event *_event, Addr _oVAddr) - : data(_data), numBytes(0), event(_event), parent(_parent), oVAddr(_oVAddr), - fault(NoFault) -{ - req = std::make_shared(); -} - -void -Stage2MMU::Stage2Translation::finish(const Fault &_fault, - const RequestPtr &req, - ThreadContext *tc, BaseTLB::Mode mode) -{ - fault = _fault; - - // If there was a fault annotate it with the flag saying the foult occured - // while doing a translation for a stage 1 page table walk. - if (fault != NoFault) { - ArmFault *armFault = reinterpret_cast(fault.get()); - armFault->annotate(ArmFault::S1PTW, true); - armFault->annotate(ArmFault::OVA, oVAddr); - } - - if (_fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) { - TableWalker::Port &port = parent.getTableWalkerPort(); - port.sendTimingReq( - req->getPaddr(), numBytes, data, req->getFlags(), - tc->getCpuPtr()->clockPeriod(), event); - } else { - // We can't do the DMA access as there's been a problem, so tell the - // event we're done - event->process(); - } -} diff --git a/src/arch/arm/stage2_mmu.hh b/src/arch/arm/stage2_mmu.hh deleted file mode 100644 index ebf68203d9..0000000000 --- a/src/arch/arm/stage2_mmu.hh +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2012-2013, 2015, 2021 Arm Limited - * 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 __ARCH_ARM_STAGE2_MMU_HH__ -#define __ARCH_ARM_STAGE2_MMU_HH__ - -#include "arch/arm/faults.hh" -#include "arch/arm/table_walker.hh" -#include "arch/arm/tlb.hh" -#include "mem/request.hh" -#include "params/ArmStage2MMU.hh" -#include "sim/eventq.hh" - -namespace ArmISA { - -class Stage2MMU : public SimObject -{ - private: - TLB *_stage1Tlb; - /** The TLB that will cache the stage 2 look ups. */ - TLB *_stage2Tlb; - - protected: - /** Request id for requests generated by this MMU */ - RequestorID requestorId; - - /** Port to issue translation requests from */ - TableWalker::Port port; - - public: - /** This translation class is used to trigger the data fetch once a timing - translation returns the translated physical address */ - class Stage2Translation : public BaseTLB::Translation - { - private: - uint8_t *data; - int numBytes; - RequestPtr req; - Event *event; - Stage2MMU &parent; - Addr oVAddr; - - public: - Fault fault; - - Stage2Translation(Stage2MMU &_parent, uint8_t *_data, Event *_event, - Addr _oVAddr); - - void - markDelayed() {} - - void - finish(const Fault &fault, const RequestPtr &req, ThreadContext *tc, - BaseTLB::Mode mode); - - void setVirt(Addr vaddr, int size, Request::Flags flags, - int requestorId) - { - numBytes = size; - req->setVirt(vaddr, size, flags, requestorId, 0); - } - - void translateTiming(ThreadContext *tc) - { - parent.stage2Tlb()->translateTiming(req, tc, this, BaseTLB::Read); - } - }; - - typedef ArmStage2MMUParams Params; - Stage2MMU(const Params &p); - - /** - * Get the port that ultimately belongs to the stage-two MMU, but - * is used by the two table walkers, and is exposed externally and - * connected through the stage-one table walker. - */ - TableWalker::Port& getTableWalkerPort() { return port; } - - Fault readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr, - uint8_t *data, int numBytes, Request::Flags flags, bool isFunctional); - void readDataTimed(ThreadContext *tc, Addr descAddr, - Stage2Translation *translation, int numBytes, - Request::Flags flags); - - TLB* stage1Tlb() const { return _stage1Tlb; } - TLB* stage2Tlb() const { return _stage2Tlb; } -}; - - - -} // namespace ArmISA - -#endif //__ARCH_ARM_STAGE2_MMU_HH__ - diff --git a/src/arch/arm/table_walker.cc b/src/arch/arm/table_walker.cc index 64ca81eda5..bc2d9bd2e3 100644 --- a/src/arch/arm/table_walker.cc +++ b/src/arch/arm/table_walker.cc @@ -40,7 +40,7 @@ #include #include "arch/arm/faults.hh" -#include "arch/arm/stage2_mmu.hh" +#include "arch/arm/mmu.hh" #include "arch/arm/system.hh" #include "arch/arm/tlb.hh" #include "base/compiler.hh" @@ -57,7 +57,8 @@ using namespace ArmISA; TableWalker::TableWalker(const Params &p) : ClockedObject(p), - stage2Mmu(NULL), port(NULL), requestorId(Request::invldRequestorId), + requestorId(p.sys->getRequestorId(this)), + port(new Port(this, requestorId)), isStage2(p.is_stage2), tlb(NULL), currState(NULL), pending(false), numSquashable(p.num_squash_per_cycle), @@ -98,31 +99,17 @@ TableWalker::~TableWalker() ; } -void -TableWalker::setMMU(Stage2MMU *m, RequestorID requestor_id) +TableWalker::Port & +TableWalker::getTableWalkerPort() { - stage2Mmu = m; - port = &m->getTableWalkerPort(); - requestorId = requestor_id; -} - -void -TableWalker::init() -{ - fatal_if(!stage2Mmu, "Table walker must have a valid stage-2 MMU\n"); - fatal_if(!port, "Table walker must have a valid port\n"); - fatal_if(!tlb, "Table walker must have a valid TLB\n"); + return static_cast(getPort("port")); } Port & TableWalker::getPort(const std::string &if_name, PortID idx) { if (if_name == "port") { - if (!isStage2) { - return *port; - } else { - fatal("Cannot access table walker port through stage-two walker\n"); - } + return *port; } return ClockedObject::getPort(if_name, idx); } @@ -2230,15 +2217,13 @@ TableWalker::fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes, Fault fault; if (isTiming) { - Stage2MMU::Stage2Translation *tran = new - Stage2MMU::Stage2Translation(*stage2Mmu, data, event, - currState->vaddr); + auto *tran = new + Stage2Walk(*this, data, event, currState->vaddr); currState->stage2Tran = tran; - stage2Mmu->readDataTimed(currState->tc, descAddr, tran, numBytes, - flags); + readDataTimed(currState->tc, descAddr, tran, numBytes, flags); fault = tran->fault; } else { - fault = stage2Mmu->readDataUntimed(currState->tc, + fault = readDataUntimed(currState->tc, currState->vaddr, descAddr, data, numBytes, flags, currState->functional); } @@ -2420,8 +2405,98 @@ TableWalker::pageSizeNtoStatBin(uint8_t N) } } -TableWalker::TableWalkerStats::TableWalkerStats(statistics::Group *parent) - : statistics::Group(parent), +Fault +TableWalker::readDataUntimed(ThreadContext *tc, Addr vaddr, Addr desc_addr, + uint8_t *data, int num_bytes, Request::Flags flags, bool functional) +{ + Fault fault; + + // translate to physical address using the second stage MMU + auto req = std::make_shared(); + req->setVirt(desc_addr, num_bytes, flags | Request::PT_WALK, + requestorId, 0); + if (functional) { + fault = mmu->translateFunctional(req, tc, BaseTLB::Read, + TLB::NormalTran, true); + } else { + fault = mmu->translateAtomic(req, tc, BaseTLB::Read, true); + } + + // Now do the access. + if (fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) { + Packet pkt = Packet(req, MemCmd::ReadReq); + pkt.dataStatic(data); + if (functional) { + port->sendFunctional(&pkt); + } else { + port->sendAtomic(&pkt); + } + assert(!pkt.isError()); + } + + // If there was a fault annotate it with the flag saying the foult occured + // while doing a translation for a stage 1 page table walk. + if (fault != NoFault) { + ArmFault *arm_fault = reinterpret_cast(fault.get()); + arm_fault->annotate(ArmFault::S1PTW, true); + arm_fault->annotate(ArmFault::OVA, vaddr); + } + return fault; +} + +void +TableWalker::readDataTimed(ThreadContext *tc, Addr desc_addr, + Stage2Walk *translation, int num_bytes, + Request::Flags flags) +{ + // translate to physical address using the second stage MMU + translation->setVirt( + desc_addr, num_bytes, flags | Request::PT_WALK, requestorId); + translation->translateTiming(tc); +} + +TableWalker::Stage2Walk::Stage2Walk(TableWalker &_parent, + uint8_t *_data, Event *_event, Addr vaddr) + : data(_data), numBytes(0), event(_event), parent(_parent), + oVAddr(vaddr), fault(NoFault) +{ + req = std::make_shared(); +} + +void +TableWalker::Stage2Walk::finish(const Fault &_fault, + const RequestPtr &req, + ThreadContext *tc, BaseTLB::Mode mode) +{ + fault = _fault; + + // If there was a fault annotate it with the flag saying the foult occured + // while doing a translation for a stage 1 page table walk. + if (fault != NoFault) { + ArmFault *arm_fault = reinterpret_cast(fault.get()); + arm_fault->annotate(ArmFault::S1PTW, true); + arm_fault->annotate(ArmFault::OVA, oVAddr); + } + + if (_fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) { + parent.getTableWalkerPort().sendTimingReq( + req->getPaddr(), numBytes, data, req->getFlags(), + tc->getCpuPtr()->clockPeriod(), event); + } else { + // We can't do the DMA access as there's been a problem, so tell the + // event we're done + event->process(); + } +} + +void +TableWalker::Stage2Walk::translateTiming(ThreadContext *tc) +{ + parent.mmu->translateTiming(req, tc, this, BaseTLB::Read, true); +} + +TableWalker::TableWalkerStats::TableWalkerStats(Stats::Group *parent) + : Stats::Group(parent), ADD_STAT(walks, statistics::units::Count::get(), "Table walker walks requested"), ADD_STAT(walksShortDescriptor, statistics::units::Count::get(), diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index 0c812ec9c8..5ba03cb9bf 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -57,7 +57,7 @@ class ThreadContext; namespace ArmISA { class Translation; class TLB; -class Stage2MMU; +class MMU; class TableWalker : public ClockedObject { @@ -897,6 +897,47 @@ class TableWalker : public ClockedObject RequestorID requestorId; }; + /** This translation class is used to trigger the data fetch once a timing + translation returns the translated physical address */ + class Stage2Walk : public BaseTLB::Translation + { + private: + uint8_t *data; + int numBytes; + RequestPtr req; + Event *event; + TableWalker &parent; + Addr oVAddr; + + public: + Fault fault; + + Stage2Walk(TableWalker &_parent, uint8_t *_data, Event *_event, + Addr vaddr); + + void markDelayed() {} + + void finish(const Fault &fault, const RequestPtr &req, + ThreadContext *tc, BaseTLB::Mode mode); + + void + setVirt(Addr vaddr, int size, Request::Flags flags, + int requestorId) + { + numBytes = size; + req->setVirt(vaddr, size, flags, requestorId, 0); + } + + void translateTiming(ThreadContext *tc); + }; + + Fault readDataUntimed(ThreadContext *tc, Addr vaddr, Addr desc_addr, + uint8_t *data, int num_bytes, Request::Flags flags, + bool functional); + void readDataTimed(ThreadContext *tc, Addr desc_addr, + Stage2Walk *translation, int num_bytes, + Request::Flags flags); + protected: /** Queues of requests for all the different lookup levels */ @@ -907,14 +948,14 @@ class TableWalker : public ClockedObject std::list pendingQueue; /** The MMU to forward second stage look upts to */ - Stage2MMU *stage2Mmu; - - /** Port shared by the two table walkers. */ - Port* port; + MMU *mmu; /** Requestor id assigned by the MMU. */ RequestorID requestorId; + /** Port shared by the two table walkers. */ + Port* port; + /** Indicates whether this table walker is part of the stage 2 mmu */ const bool isStage2; @@ -970,8 +1011,6 @@ class TableWalker : public ClockedObject TableWalker(const Params &p); virtual ~TableWalker(); - void init() override; - bool haveLPAE() const { return _haveLPAE; } bool haveVirtualization() const { return _haveVirtualization; } bool haveLargeAsid64() const { return _haveLargeAsid64; } @@ -984,15 +1023,17 @@ class TableWalker : public ClockedObject ::Port &getPort(const std::string &if_name, PortID idx=InvalidPortID) override; + Port &getTableWalkerPort(); + Fault walk(const RequestPtr &req, ThreadContext *tc, uint16_t asid, vmid_t _vmid, bool _isHyp, TLB::Mode mode, TLB::Translation *_trans, bool timing, bool functional, bool secure, TLB::ArmTranslationType tranType, bool _stage2Req); + void setMmu(MMU *_mmu) { mmu = _mmu; } void setTlb(TLB *_tlb) { tlb = _tlb; } TLB* getTlb() { return tlb; } - 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, diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc index 9cdaabd7a9..0f8a8d6bf5 100644 --- a/src/arch/arm/tlb.cc +++ b/src/arch/arm/tlb.cc @@ -50,7 +50,6 @@ #include "arch/arm/reg_abi.hh" #include "arch/arm/self_debug.hh" #include "arch/arm/stage2_lookup.hh" -#include "arch/arm/stage2_mmu.hh" #include "arch/arm/system.hh" #include "arch/arm/table_walker.hh" #include "arch/arm/tlbi_op.hh" @@ -77,24 +76,28 @@ using namespace ArmISA; TLB::TLB(const ArmTLBParams &p) : BaseTLB(p), table(new TlbEntry[p.size]), size(p.size), isStage2(p.is_stage2), stage2Req(false), stage2DescReq(false), _attr(0), - directToStage2(false), tableWalker(p.walker), stage2Tlb(NULL), - stage2Mmu(NULL), test(nullptr), stats(this), rangeMRU(1), + directToStage2(false), tableWalker(nullptr), stage2Tlb(nullptr), + test(nullptr), stats(this), rangeMRU(1), aarch64(false), aarch64EL(EL0), isPriv(false), isSecure(false), isHyp(false), asid(0), vmid(0), hcr(0), dacr(0), miscRegValid(false), miscRegContext(0), curTranType(NormalTran) { - const ArmSystem *sys = dynamic_cast(p.sys); - - tableWalker->setTlb(this); - // Cache system-level properties - haveLPAE = tableWalker->haveLPAE(); - haveVirtualization = tableWalker->haveVirtualization(); - haveLargeAsid64 = tableWalker->haveLargeAsid64(); - physAddrRange = tableWalker->physAddrRange(); + if (FullSystem) { + ArmSystem *arm_sys = dynamic_cast(p.sys); + assert(arm_sys); + haveLPAE = arm_sys->haveLPAE(); + haveVirtualization = arm_sys->haveVirtualization(); + haveLargeAsid64 = arm_sys->haveLargeAsid64(); + physAddrRange = arm_sys->physAddrRange(); + } else { + haveLPAE = false; + haveVirtualization = false; + haveLargeAsid64 = false; + physAddrRange = 48; + } - if (sys) - m5opRange = sys->m5opRange(); + m5opRange = p.sys->m5opRange(); } TLB::~TLB() @@ -103,17 +106,10 @@ TLB::~TLB() } void -TLB::init() +TLB::setTableWalker(TableWalker *table_walker) { - if (stage2Mmu && !isStage2) - stage2Tlb = stage2Mmu->stage2Tlb(); -} - -void -TLB::setMMU(Stage2MMU *m, RequestorID requestor_id) -{ - stage2Mmu = m; - tableWalker->setMMU(m, requestor_id); + tableWalker = table_walker; + tableWalker->setTlb(this); } bool @@ -1374,7 +1370,7 @@ TLB::translateComplete(const RequestPtr &req, ThreadContext *tc, Port * TLB::getTableWalkerPort() { - return &stage2Mmu->getTableWalkerPort(); + return &tableWalker->getTableWalkerPort(); } vmid_t diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh index 2d1b8e9240..3d96446d1e 100644 --- a/src/arch/arm/tlb.hh +++ b/src/arch/arm/tlb.hh @@ -57,7 +57,6 @@ namespace ArmISA { class TableWalker; class Stage2LookUp; -class Stage2MMU; class TLB; class TLBIALL; @@ -166,7 +165,6 @@ class TLB : public BaseTLB TableWalker *tableWalker; TLB *stage2Tlb; - Stage2MMU *stage2Mmu; TlbTestInterface *test; @@ -231,14 +229,13 @@ class TLB : public BaseTLB void takeOverFrom(BaseTLB *otlb) override; - /// setup all the back pointers - void init() override; - void setTestInterface(SimObject *ti); - TableWalker *getTableWalker() { return tableWalker; } + void setStage2Tlb(TLB *stage2_tlb) { stage2Tlb = stage2_tlb; } - void setMMU(Stage2MMU *m, RequestorID requestor_id); + void setTableWalker(TableWalker *table_walker); + + TableWalker *getTableWalker() { return tableWalker; } int getsize() const { return size; }