# -*- mode:python -*-
-# Copyright (c) 2009, 2013 ARM Limited
+# Copyright (c) 2009, 2013, 2015 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
cxx_class = 'ArmISA::TableWalker'
cxx_header = "arch/arm/table_walker.hh"
is_stage2 = Param.Bool(False, "Is this object for stage 2 translation?")
- port = MasterPort("Port for TableWalker to do walk the translation with")
- sys = Param.System(Parent.any, "system object parameter")
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 = MasterPort("Port used by the two table walkers")
+
+ sys = Param.System(Parent.any, "system object parameter")
+
class ArmTLB(SimObject):
type = 'ArmTLB'
cxx_class = 'ArmISA::TLB'
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.itb
- stage2_tlb = ArmStage2TLB(walker = ArmStage2TableWalker())
+ 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.dtb
- stage2_tlb = ArmStage2TLB(walker = ArmStage2TableWalker())
+ stage2_tlb = ArmStage2TLB()
/*
- * Copyright (c) 2012-2013 ARM Limited
+ * Copyright (c) 2012-2013, 2015 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* Authors: Thomas Grocutt
*/
-#include "arch/arm/faults.hh"
#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"
-#include "debug/Checkpoint.hh"
-#include "debug/TLB.hh"
-#include "debug/TLBVerbose.hh"
using namespace ArmISA;
Stage2MMU::Stage2MMU(const Params *p)
- : SimObject(p), _stage1Tlb(p->tlb), _stage2Tlb(p->stage2_tlb)
+ : SimObject(p), _stage1Tlb(p->tlb), _stage2Tlb(p->stage2_tlb),
+ port(_stage1Tlb->getTableWalker(), p->sys),
+ masterId(p->sys->getMasterId(_stage1Tlb->getTableWalker()->name()))
{
- stage1Tlb()->setMMU(this);
- stage2Tlb()->setMMU(this);
+ // we use the stage-one table walker as the parent of the port,
+ // and to get our master id, this is done to keep things
+ // symmetrical with other ISAs in terms of naming and stats
+ stage1Tlb()->setMMU(this, masterId);
+ stage2Tlb()->setMMU(this, masterId);
}
Fault
Stage2MMU::readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr,
- uint8_t *data, int numBytes, Request::Flags flags, int masterId,
- bool isFunctional)
+ uint8_t *data, int numBytes, Request::Flags flags, bool isFunctional)
{
Fault fault;
Packet pkt = Packet(&req, MemCmd::ReadReq);
pkt.dataStatic(data);
if (isFunctional) {
- stage1Tlb()->getWalkerPort().sendFunctional(&pkt);
+ port.sendFunctional(&pkt);
} else {
- stage1Tlb()->getWalkerPort().sendAtomic(&pkt);
+ port.sendAtomic(&pkt);
}
assert(!pkt.isError());
}
Fault
Stage2MMU::readDataTimed(ThreadContext *tc, Addr descAddr,
- Stage2Translation *translation, int numBytes, Request::Flags flags,
- int masterId)
+ Stage2Translation *translation, int numBytes,
+ Request::Flags flags)
{
Fault fault;
// translate to physical address using the second stage MMU
}
if (_fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) {
- DmaPort& port = parent.stage1Tlb()->getWalkerPort();
- port.dmaAction(MemCmd::ReadReq, req->getPaddr(), numBytes,
- event, data, tc->getCpuPtr()->clockPeriod(),
- req->getFlags());
+ parent.getPort().dmaAction(MemCmd::ReadReq, req->getPaddr(), numBytes,
+ event, data, tc->getCpuPtr()->clockPeriod(),
+ req->getFlags());
} else {
// We can't do the DMA access as there's been a problem, so tell the
// event we're done
}
}
+unsigned int
+Stage2MMU::drain(DrainManager *dm)
+{
+ return port.drain(dm);
+}
+
ArmISA::Stage2MMU *
ArmStage2MMUParams::create()
{
/*
- * Copyright (c) 2012-2013 ARM Limited
+ * Copyright (c) 2012-2013, 2015 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
/** The TLB that will cache the stage 2 look ups. */
TLB *_stage2Tlb;
+ protected:
+
+ /**
+ * A snooping DMA port that currently does nothing besides
+ * extending the DMA port to accept snoops without
+ * complaining. Currently we take no action on any snoops.
+ */
+ 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)
+ { }
+ };
+
+ /** Port to issue translation requests from */
+ SnoopingDmaPort port;
+
+ /** Request id for requests generated by this MMU */
+ MasterID masterId;
+
public:
/** This translation class is used to trigger the data fetch once a timing
translation returns the translated physical address */
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.
+ */
+ DmaPort& getPort() { return port; }
+
+ unsigned int drain(DrainManager *dm);
+
Fault readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr,
- uint8_t *data, int numBytes, Request::Flags flags, int masterId,
- bool isFunctional);
+ uint8_t *data, int numBytes, Request::Flags flags, bool isFunctional);
Fault readDataTimed(ThreadContext *tc, Addr descAddr,
- Stage2Translation *translation, int numBytes, Request::Flags flags,
- int masterId);
+ Stage2Translation *translation, int numBytes,
+ Request::Flags flags);
TLB* stage1Tlb() const { return _stage1Tlb; }
TLB* stage2Tlb() const { return _stage2Tlb; }
/*
- * Copyright (c) 2010, 2012-2014 ARM Limited
+ * Copyright (c) 2010, 2012-2015 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
using namespace ArmISA;
TableWalker::TableWalker(const Params *p)
- : MemObject(p), port(this, p->sys), drainManager(NULL),
- stage2Mmu(NULL), isStage2(p->is_stage2), tlb(NULL),
- currState(NULL), pending(false), masterId(p->sys->getMasterId(name())),
+ : MemObject(p), drainManager(NULL),
+ stage2Mmu(NULL), port(NULL), masterId(Request::invldMasterId),
+ isStage2(p->is_stage2), tlb(NULL),
+ currState(NULL), pending(false),
numSquashable(p->num_squash_per_cycle),
pendingReqs(0),
pendingChangeTick(curTick()),
// Cache system-level properties
if (FullSystem) {
- armSys = dynamic_cast<ArmSystem *>(p->sys);
+ ArmSystem *armSys = dynamic_cast<ArmSystem *>(p->sys);
assert(armSys);
haveSecurity = armSys->haveSecurity();
_haveLPAE = armSys->haveLPAE();
physAddrRange = armSys->physAddrRange();
_haveLargeAsid64 = armSys->haveLargeAsid64();
} else {
- armSys = NULL;
haveSecurity = _haveLPAE = _haveVirtualization = false;
_haveLargeAsid64 = false;
physAddrRange = 32;
;
}
+void
+TableWalker::setMMU(Stage2MMU *m, MasterID master_id)
+{
+ stage2Mmu = m;
+ port = &m->getPort();
+ masterId = master_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");
+}
+
+BaseMasterPort&
+TableWalker::getMasterPort(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 MemObject::getMasterPort(if_name, idx);
+}
+
TableWalker::WalkerState::WalkerState() :
tc(nullptr), aarch64(false), el(EL0), physAddrRange(0), req(nullptr),
asid(0), vmid(0), isHyp(false), transState(nullptr),
unsigned int
TableWalker::drain(DrainManager *dm)
{
- unsigned int count = port.drain(dm);
-
bool state_queues_not_empty = false;
for (int i = 0; i < MAX_LOOKUP_LEVELS; ++i) {
DPRINTF(Drain, "TableWalker not drained\n");
// return port drain count plus the table walker itself needs to drain
- return count + 1;
+ return 1;
} else {
setDrainState(Drainable::Drained);
DPRINTF(Drain, "TableWalker free, no need to drain\n");
// table walker is drained, but its ports may still need to be drained
- return count;
+ return 0;
}
}
}
}
-BaseMasterPort&
-TableWalker::getMasterPort(const std::string &if_name, PortID idx)
-{
- if (if_name == "port") {
- return port;
- }
- return MemObject::getMasterPort(if_name, idx);
-}
-
Fault
TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
uint8_t _vmid, bool _isHyp, TLB::Mode _mode,
panic("Invalid table lookup level");
break;
}
- port.dmaAction(MemCmd::ReadReq, desc_addr, sizeof(uint64_t),
+ port->dmaAction(MemCmd::ReadReq, desc_addr, sizeof(uint64_t),
event, (uint8_t*) &currState->longDesc.data,
currState->tc->getCpuPtr()->clockPeriod(), flag);
DPRINTF(TLBVerbose,
stateQueues[start_lookup_level].push_back(currState);
currState = NULL;
} else if (!currState->functional) {
- port.dmaAction(MemCmd::ReadReq, desc_addr, sizeof(uint64_t),
+ port->dmaAction(MemCmd::ReadReq, desc_addr, sizeof(uint64_t),
NULL, (uint8_t*) &currState->longDesc.data,
currState->tc->getCpuPtr()->clockPeriod(), flag);
doLongDescriptor();
masterId);
PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
pkt->dataStatic((uint8_t*) &currState->longDesc.data);
- port.sendFunctional(pkt);
+ port->sendFunctional(pkt);
doLongDescriptor();
delete req;
delete pkt;
currState->vaddr);
currState->stage2Tran = tran;
stage2Mmu->readDataTimed(currState->tc, descAddr, tran, numBytes,
- flags, masterId);
+ flags);
fault = tran->fault;
} else {
fault = stage2Mmu->readDataUntimed(currState->tc,
- currState->vaddr, descAddr, data, numBytes, flags, masterId,
+ currState->vaddr, descAddr, data, numBytes, flags,
currState->functional);
}
}
} else {
if (isTiming) {
- port.dmaAction(MemCmd::ReadReq, descAddr, numBytes, event, data,
+ port->dmaAction(MemCmd::ReadReq, descAddr, numBytes, event, data,
currState->tc->getCpuPtr()->clockPeriod(),flags);
if (queueIndex >= 0) {
DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n",
currState = NULL;
}
} else if (!currState->functional) {
- port.dmaAction(MemCmd::ReadReq, descAddr, numBytes, NULL, data,
+ port->dmaAction(MemCmd::ReadReq, descAddr, numBytes, NULL, data,
currState->tc->getCpuPtr()->clockPeriod(), flags);
(this->*doDescriptor)();
} else {
req->taskId(ContextSwitchTaskId::DMA);
PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
pkt->dataStatic(data);
- port.sendFunctional(pkt);
+ port->sendFunctional(pkt);
(this->*doDescriptor)();
delete req;
delete pkt;
/*
- * Copyright (c) 2010-2014 ARM Limited
+ * Copyright (c) 2010-2015 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
#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/eventq.hh"
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];
* 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;
+
+ /** Master id assigned by the MMU. */
+ MasterID masterId;
+
/** Indicates whether this table walker is part of the stage 2 mmu */
const bool isStage2;
/** 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;
bool _haveVirtualization;
uint8_t physAddrRange;
bool _haveLargeAsid64;
- ArmSystem *armSys;
/** Statistics */
Stats::Scalar statWalks;
return dynamic_cast<const Params *>(_params);
}
+ virtual void init();
+
bool haveLPAE() const { return _haveLPAE; }
bool haveVirtualization() const { return _haveVirtualization; }
bool haveLargeAsid64() const { return _haveLargeAsid64; }
void completeDrain();
unsigned int drain(DrainManager *dm);
virtual void drainResume();
+
virtual BaseMasterPort& getMasterPort(const std::string &if_name,
PortID idx = InvalidPortID);
- void regStats();
- /**
- * 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; }
+ void regStats();
Fault walk(RequestPtr req, ThreadContext *tc, uint16_t asid, uint8_t _vmid,
bool _isHyp, TLB::Mode mode, TLB::Translation *_trans,
void setTlb(TLB *_tlb) { tlb = _tlb; }
TLB* getTlb() { return tlb; }
- void setMMU(Stage2MMU *m) { stage2Mmu = m; }
+ void setMMU(Stage2MMU *m, MasterID master_id);
void memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr,
uint8_t texcb, bool s);
void memAttrsLPAE(ThreadContext *tc, TlbEntry &te,
}
void
-TLB::setMMU(Stage2MMU *m)
+TLB::setMMU(Stage2MMU *m, MasterID master_id)
{
stage2Mmu = m;
- tableWalker->setMMU(m);
+ tableWalker->setMMU(m, master_id);
}
bool
BaseMasterPort*
TLB::getMasterPort()
{
- return &tableWalker->getMasterPort("port");
-}
-
-DmaPort&
-TLB::getWalkerPort()
-{
- return tableWalker->getWalkerPort();
+ return &stage2Mmu->getPort();
}
void
/// setup all the back pointers
virtual void init();
- void setMMU(Stage2MMU *m);
+ TableWalker *getTableWalker() { return tableWalker; }
+
+ void setMMU(Stage2MMU *m, MasterID master_id);
int getsize() const { return size; }
*/
virtual BaseMasterPort* getMasterPort();
- /**
- * Allow the MMU (overseeing both stage 1 and stage 2 TLBs) to
- * access the table walker port of this TLB so that it can
- * orchestrate staged translations.
- *
- * @return The table walker DMA port
- */
- DmaPort& getWalkerPort();
-
// Caching misc register values here.
// Writing to misc registers needs to invalidate them.
// translateFunctional/translateSe/translateFs checks if they are
-# Copyright (c) 2012-2013 ARM Limited
+# Copyright (c) 2012-2013, 2015 ARM Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
_cached_ports += ["itb.walker.port", "dtb.walker.port"]
- if buildEnv['TARGET_ISA'] in ['arm']:
- _cached_ports += ["istage2_mmu.stage2_tlb.walker.port",
- "dstage2_mmu.stage2_tlb.walker.port"]
_uncached_slave_ports = []
_uncached_master_ports = []
if iwc and dwc:
self.itb_walker_cache = iwc
self.dtb_walker_cache = dwc
- if buildEnv['TARGET_ISA'] in ['arm']:
- self.itb_walker_cache_bus = CoherentXBar()
- self.dtb_walker_cache_bus = CoherentXBar()
- self.itb_walker_cache_bus.master = iwc.cpu_side
- self.dtb_walker_cache_bus.master = dwc.cpu_side
- self.itb.walker.port = self.itb_walker_cache_bus.slave
- self.dtb.walker.port = self.dtb_walker_cache_bus.slave
- self.istage2_mmu.stage2_tlb.walker.port = self.itb_walker_cache_bus.slave
- self.dstage2_mmu.stage2_tlb.walker.port = self.dtb_walker_cache_bus.slave
- else:
- self.itb.walker.port = iwc.cpu_side
- self.dtb.walker.port = dwc.cpu_side
+ self.itb.walker.port = iwc.cpu_side
+ self.dtb.walker.port = dwc.cpu_side
self._cached_ports += ["itb_walker_cache.mem_side", \
"dtb_walker_cache.mem_side"]
else:
self._cached_ports += ["itb.walker.port", "dtb.walker.port"]
- if buildEnv['TARGET_ISA'] in ['arm']:
- self._cached_ports += ["istage2_mmu.stage2_tlb.walker.port", \
- "dstage2_mmu.stage2_tlb.walker.port"]
-
# Checker doesn't need its own tlb caches because it does
# functional accesses only
if self.checker != NULL:
self._cached_ports += ["checker.itb.walker.port", \
"checker.dtb.walker.port"]
- if buildEnv['TARGET_ISA'] in ['arm']:
- self._cached_ports += ["checker.istage2_mmu.stage2_tlb.walker.port", \
- "checker.dstage2_mmu.stage2_tlb.walker.port"]
def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc = None, dwc = None):
self.addPrivateSplitL1Caches(ic, dc, iwc, dwc)