arm: Share a port for the two table walker objects
This patch changes how the MMU and table walkers are created such that a single port is used to connect the MMU and the TLBs to the memory system. Previously two ports were needed as there are two table walker objects (stage one and stage two), and they both had a port. Now the port itself is moved to the Stage2MMU, and each TableWalker is simply using the port from the parent. By using the same port we also remove the need for having an additional crossbar joining the two ports before the walker cache or the L2. This simplifies the creation of the CPU cache topology in BaseCPU.py considerably. Moreover, for naming and symmetry reasons, the TLB walker port is connected through the stage-one table walker thus making the naming identical to x86. Along the same line, we use the stage-one table walker to generate the master id that is used by all TLB-related requests.
This commit is contained in:
parent
bd70db5521
commit
d64b34bef8
8 changed files with 161 additions and 148 deletions
|
@ -1,6 +1,6 @@
|
||||||
# -*- mode:python -*-
|
# -*- mode:python -*-
|
||||||
|
|
||||||
# Copyright (c) 2009, 2013 ARM Limited
|
# Copyright (c) 2009, 2013, 2015 ARM Limited
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# The license below extends only to copyright in the software and shall
|
# The license below extends only to copyright in the software and shall
|
||||||
|
@ -48,11 +48,17 @@ class ArmTableWalker(MemObject):
|
||||||
cxx_class = 'ArmISA::TableWalker'
|
cxx_class = 'ArmISA::TableWalker'
|
||||||
cxx_header = "arch/arm/table_walker.hh"
|
cxx_header = "arch/arm/table_walker.hh"
|
||||||
is_stage2 = Param.Bool(False, "Is this object for stage 2 translation?")
|
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,
|
num_squash_per_cycle = Param.Unsigned(2,
|
||||||
"Number of outstanding walks that can be squashed per cycle")
|
"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):
|
class ArmTLB(SimObject):
|
||||||
type = 'ArmTLB'
|
type = 'ArmTLB'
|
||||||
cxx_class = 'ArmISA::TLB'
|
cxx_class = 'ArmISA::TLB'
|
||||||
|
@ -77,10 +83,16 @@ class ArmStage2MMU(SimObject):
|
||||||
tlb = Param.ArmTLB("Stage 1 TLB")
|
tlb = Param.ArmTLB("Stage 1 TLB")
|
||||||
stage2_tlb = Param.ArmTLB("Stage 2 TLB")
|
stage2_tlb = Param.ArmTLB("Stage 2 TLB")
|
||||||
|
|
||||||
|
sys = Param.System(Parent.any, "system object parameter")
|
||||||
|
|
||||||
class ArmStage2IMMU(ArmStage2MMU):
|
class ArmStage2IMMU(ArmStage2MMU):
|
||||||
|
# We rely on the itb being a parameter of the CPU, and get the
|
||||||
|
# appropriate object that way
|
||||||
tlb = Parent.itb
|
tlb = Parent.itb
|
||||||
stage2_tlb = ArmStage2TLB(walker = ArmStage2TableWalker())
|
stage2_tlb = ArmStage2TLB()
|
||||||
|
|
||||||
class ArmStage2DMMU(ArmStage2MMU):
|
class ArmStage2DMMU(ArmStage2MMU):
|
||||||
|
# We rely on the dtb being a parameter of the CPU, and get the
|
||||||
|
# appropriate object that way
|
||||||
tlb = Parent.dtb
|
tlb = Parent.dtb
|
||||||
stage2_tlb = ArmStage2TLB(walker = ArmStage2TableWalker())
|
stage2_tlb = ArmStage2TLB()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2013 ARM Limited
|
* Copyright (c) 2012-2013, 2015 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -37,29 +37,31 @@
|
||||||
* Authors: Thomas Grocutt
|
* Authors: Thomas Grocutt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "arch/arm/faults.hh"
|
|
||||||
#include "arch/arm/stage2_mmu.hh"
|
#include "arch/arm/stage2_mmu.hh"
|
||||||
|
#include "arch/arm/faults.hh"
|
||||||
#include "arch/arm/system.hh"
|
#include "arch/arm/system.hh"
|
||||||
|
#include "arch/arm/table_walker.hh"
|
||||||
#include "arch/arm/tlb.hh"
|
#include "arch/arm/tlb.hh"
|
||||||
#include "cpu/base.hh"
|
#include "cpu/base.hh"
|
||||||
#include "cpu/thread_context.hh"
|
#include "cpu/thread_context.hh"
|
||||||
#include "debug/Checkpoint.hh"
|
|
||||||
#include "debug/TLB.hh"
|
|
||||||
#include "debug/TLBVerbose.hh"
|
|
||||||
|
|
||||||
using namespace ArmISA;
|
using namespace ArmISA;
|
||||||
|
|
||||||
Stage2MMU::Stage2MMU(const Params *p)
|
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);
|
// we use the stage-one table walker as the parent of the port,
|
||||||
stage2Tlb()->setMMU(this);
|
// 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
|
Fault
|
||||||
Stage2MMU::readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr,
|
Stage2MMU::readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr,
|
||||||
uint8_t *data, int numBytes, Request::Flags flags, int masterId,
|
uint8_t *data, int numBytes, Request::Flags flags, bool isFunctional)
|
||||||
bool isFunctional)
|
|
||||||
{
|
{
|
||||||
Fault fault;
|
Fault fault;
|
||||||
|
|
||||||
|
@ -77,9 +79,9 @@ Stage2MMU::readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr,
|
||||||
Packet pkt = Packet(&req, MemCmd::ReadReq);
|
Packet pkt = Packet(&req, MemCmd::ReadReq);
|
||||||
pkt.dataStatic(data);
|
pkt.dataStatic(data);
|
||||||
if (isFunctional) {
|
if (isFunctional) {
|
||||||
stage1Tlb()->getWalkerPort().sendFunctional(&pkt);
|
port.sendFunctional(&pkt);
|
||||||
} else {
|
} else {
|
||||||
stage1Tlb()->getWalkerPort().sendAtomic(&pkt);
|
port.sendAtomic(&pkt);
|
||||||
}
|
}
|
||||||
assert(!pkt.isError());
|
assert(!pkt.isError());
|
||||||
}
|
}
|
||||||
|
@ -96,8 +98,8 @@ Stage2MMU::readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr,
|
||||||
|
|
||||||
Fault
|
Fault
|
||||||
Stage2MMU::readDataTimed(ThreadContext *tc, Addr descAddr,
|
Stage2MMU::readDataTimed(ThreadContext *tc, Addr descAddr,
|
||||||
Stage2Translation *translation, int numBytes, Request::Flags flags,
|
Stage2Translation *translation, int numBytes,
|
||||||
int masterId)
|
Request::Flags flags)
|
||||||
{
|
{
|
||||||
Fault fault;
|
Fault fault;
|
||||||
// translate to physical address using the second stage MMU
|
// translate to physical address using the second stage MMU
|
||||||
|
@ -128,10 +130,9 @@ Stage2MMU::Stage2Translation::finish(const Fault &_fault, RequestPtr req,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) {
|
if (_fault == NoFault && !req->getFlags().isSet(Request::NO_ACCESS)) {
|
||||||
DmaPort& port = parent.stage1Tlb()->getWalkerPort();
|
parent.getPort().dmaAction(MemCmd::ReadReq, req->getPaddr(), numBytes,
|
||||||
port.dmaAction(MemCmd::ReadReq, req->getPaddr(), numBytes,
|
event, data, tc->getCpuPtr()->clockPeriod(),
|
||||||
event, data, tc->getCpuPtr()->clockPeriod(),
|
req->getFlags());
|
||||||
req->getFlags());
|
|
||||||
} else {
|
} else {
|
||||||
// We can't do the DMA access as there's been a problem, so tell the
|
// We can't do the DMA access as there's been a problem, so tell the
|
||||||
// event we're done
|
// event we're done
|
||||||
|
@ -139,6 +140,12 @@ Stage2MMU::Stage2Translation::finish(const Fault &_fault, RequestPtr req,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
Stage2MMU::drain(DrainManager *dm)
|
||||||
|
{
|
||||||
|
return port.drain(dm);
|
||||||
|
}
|
||||||
|
|
||||||
ArmISA::Stage2MMU *
|
ArmISA::Stage2MMU *
|
||||||
ArmStage2MMUParams::create()
|
ArmStage2MMUParams::create()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2013 ARM Limited
|
* Copyright (c) 2012-2013, 2015 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -55,6 +55,46 @@ class Stage2MMU : public SimObject
|
||||||
/** The TLB that will cache the stage 2 look ups. */
|
/** The TLB that will cache the stage 2 look ups. */
|
||||||
TLB *_stage2Tlb;
|
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:
|
public:
|
||||||
/** This translation class is used to trigger the data fetch once a timing
|
/** This translation class is used to trigger the data fetch once a timing
|
||||||
translation returns the translated physical address */
|
translation returns the translated physical address */
|
||||||
|
@ -96,12 +136,20 @@ class Stage2MMU : public SimObject
|
||||||
typedef ArmStage2MMUParams Params;
|
typedef ArmStage2MMUParams Params;
|
||||||
Stage2MMU(const Params *p);
|
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,
|
Fault readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr,
|
||||||
uint8_t *data, int numBytes, Request::Flags flags, int masterId,
|
uint8_t *data, int numBytes, Request::Flags flags, bool isFunctional);
|
||||||
bool isFunctional);
|
|
||||||
Fault readDataTimed(ThreadContext *tc, Addr descAddr,
|
Fault readDataTimed(ThreadContext *tc, Addr descAddr,
|
||||||
Stage2Translation *translation, int numBytes, Request::Flags flags,
|
Stage2Translation *translation, int numBytes,
|
||||||
int masterId);
|
Request::Flags flags);
|
||||||
|
|
||||||
TLB* stage1Tlb() const { return _stage1Tlb; }
|
TLB* stage1Tlb() const { return _stage1Tlb; }
|
||||||
TLB* stage2Tlb() const { return _stage2Tlb; }
|
TLB* stage2Tlb() const { return _stage2Tlb; }
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010, 2012-2014 ARM Limited
|
* Copyright (c) 2010, 2012-2015 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -56,9 +56,10 @@
|
||||||
using namespace ArmISA;
|
using namespace ArmISA;
|
||||||
|
|
||||||
TableWalker::TableWalker(const Params *p)
|
TableWalker::TableWalker(const Params *p)
|
||||||
: MemObject(p), port(this, p->sys), drainManager(NULL),
|
: MemObject(p), drainManager(NULL),
|
||||||
stage2Mmu(NULL), isStage2(p->is_stage2), tlb(NULL),
|
stage2Mmu(NULL), port(NULL), masterId(Request::invldMasterId),
|
||||||
currState(NULL), pending(false), masterId(p->sys->getMasterId(name())),
|
isStage2(p->is_stage2), tlb(NULL),
|
||||||
|
currState(NULL), pending(false),
|
||||||
numSquashable(p->num_squash_per_cycle),
|
numSquashable(p->num_squash_per_cycle),
|
||||||
pendingReqs(0),
|
pendingReqs(0),
|
||||||
pendingChangeTick(curTick()),
|
pendingChangeTick(curTick()),
|
||||||
|
@ -71,7 +72,7 @@ TableWalker::TableWalker(const Params *p)
|
||||||
|
|
||||||
// Cache system-level properties
|
// Cache system-level properties
|
||||||
if (FullSystem) {
|
if (FullSystem) {
|
||||||
armSys = dynamic_cast<ArmSystem *>(p->sys);
|
ArmSystem *armSys = dynamic_cast<ArmSystem *>(p->sys);
|
||||||
assert(armSys);
|
assert(armSys);
|
||||||
haveSecurity = armSys->haveSecurity();
|
haveSecurity = armSys->haveSecurity();
|
||||||
_haveLPAE = armSys->haveLPAE();
|
_haveLPAE = armSys->haveLPAE();
|
||||||
|
@ -79,7 +80,6 @@ TableWalker::TableWalker(const Params *p)
|
||||||
physAddrRange = armSys->physAddrRange();
|
physAddrRange = armSys->physAddrRange();
|
||||||
_haveLargeAsid64 = armSys->haveLargeAsid64();
|
_haveLargeAsid64 = armSys->haveLargeAsid64();
|
||||||
} else {
|
} else {
|
||||||
armSys = NULL;
|
|
||||||
haveSecurity = _haveLPAE = _haveVirtualization = false;
|
haveSecurity = _haveLPAE = _haveVirtualization = false;
|
||||||
_haveLargeAsid64 = false;
|
_haveLargeAsid64 = false;
|
||||||
physAddrRange = 32;
|
physAddrRange = 32;
|
||||||
|
@ -92,6 +92,35 @@ TableWalker::~TableWalker()
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() :
|
TableWalker::WalkerState::WalkerState() :
|
||||||
tc(nullptr), aarch64(false), el(EL0), physAddrRange(0), req(nullptr),
|
tc(nullptr), aarch64(false), el(EL0), physAddrRange(0), req(nullptr),
|
||||||
asid(0), vmid(0), isHyp(false), transState(nullptr),
|
asid(0), vmid(0), isHyp(false), transState(nullptr),
|
||||||
|
@ -119,8 +148,6 @@ TableWalker::completeDrain()
|
||||||
unsigned int
|
unsigned int
|
||||||
TableWalker::drain(DrainManager *dm)
|
TableWalker::drain(DrainManager *dm)
|
||||||
{
|
{
|
||||||
unsigned int count = port.drain(dm);
|
|
||||||
|
|
||||||
bool state_queues_not_empty = false;
|
bool state_queues_not_empty = false;
|
||||||
|
|
||||||
for (int i = 0; i < MAX_LOOKUP_LEVELS; ++i) {
|
for (int i = 0; i < MAX_LOOKUP_LEVELS; ++i) {
|
||||||
|
@ -136,13 +163,13 @@ TableWalker::drain(DrainManager *dm)
|
||||||
DPRINTF(Drain, "TableWalker not drained\n");
|
DPRINTF(Drain, "TableWalker not drained\n");
|
||||||
|
|
||||||
// return port drain count plus the table walker itself needs to drain
|
// return port drain count plus the table walker itself needs to drain
|
||||||
return count + 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
setDrainState(Drainable::Drained);
|
setDrainState(Drainable::Drained);
|
||||||
DPRINTF(Drain, "TableWalker free, no need to drain\n");
|
DPRINTF(Drain, "TableWalker free, no need to drain\n");
|
||||||
|
|
||||||
// table walker is drained, but its ports may still need to be drained
|
// table walker is drained, but its ports may still need to be drained
|
||||||
return count;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,15 +184,6 @@ TableWalker::drainResume()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseMasterPort&
|
|
||||||
TableWalker::getMasterPort(const std::string &if_name, PortID idx)
|
|
||||||
{
|
|
||||||
if (if_name == "port") {
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
return MemObject::getMasterPort(if_name, idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
Fault
|
Fault
|
||||||
TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
|
TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint16_t _asid,
|
||||||
uint8_t _vmid, bool _isHyp, TLB::Mode _mode,
|
uint8_t _vmid, bool _isHyp, TLB::Mode _mode,
|
||||||
|
@ -946,7 +964,7 @@ TableWalker::processWalkAArch64()
|
||||||
panic("Invalid table lookup level");
|
panic("Invalid table lookup level");
|
||||||
break;
|
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,
|
event, (uint8_t*) &currState->longDesc.data,
|
||||||
currState->tc->getCpuPtr()->clockPeriod(), flag);
|
currState->tc->getCpuPtr()->clockPeriod(), flag);
|
||||||
DPRINTF(TLBVerbose,
|
DPRINTF(TLBVerbose,
|
||||||
|
@ -955,7 +973,7 @@ TableWalker::processWalkAArch64()
|
||||||
stateQueues[start_lookup_level].push_back(currState);
|
stateQueues[start_lookup_level].push_back(currState);
|
||||||
currState = NULL;
|
currState = NULL;
|
||||||
} else if (!currState->functional) {
|
} 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,
|
NULL, (uint8_t*) &currState->longDesc.data,
|
||||||
currState->tc->getCpuPtr()->clockPeriod(), flag);
|
currState->tc->getCpuPtr()->clockPeriod(), flag);
|
||||||
doLongDescriptor();
|
doLongDescriptor();
|
||||||
|
@ -965,7 +983,7 @@ TableWalker::processWalkAArch64()
|
||||||
masterId);
|
masterId);
|
||||||
PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
|
PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
|
||||||
pkt->dataStatic((uint8_t*) &currState->longDesc.data);
|
pkt->dataStatic((uint8_t*) &currState->longDesc.data);
|
||||||
port.sendFunctional(pkt);
|
port->sendFunctional(pkt);
|
||||||
doLongDescriptor();
|
doLongDescriptor();
|
||||||
delete req;
|
delete req;
|
||||||
delete pkt;
|
delete pkt;
|
||||||
|
@ -1916,11 +1934,11 @@ TableWalker::fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes,
|
||||||
currState->vaddr);
|
currState->vaddr);
|
||||||
currState->stage2Tran = tran;
|
currState->stage2Tran = tran;
|
||||||
stage2Mmu->readDataTimed(currState->tc, descAddr, tran, numBytes,
|
stage2Mmu->readDataTimed(currState->tc, descAddr, tran, numBytes,
|
||||||
flags, masterId);
|
flags);
|
||||||
fault = tran->fault;
|
fault = tran->fault;
|
||||||
} else {
|
} else {
|
||||||
fault = stage2Mmu->readDataUntimed(currState->tc,
|
fault = stage2Mmu->readDataUntimed(currState->tc,
|
||||||
currState->vaddr, descAddr, data, numBytes, flags, masterId,
|
currState->vaddr, descAddr, data, numBytes, flags,
|
||||||
currState->functional);
|
currState->functional);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1939,7 +1957,7 @@ TableWalker::fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isTiming) {
|
if (isTiming) {
|
||||||
port.dmaAction(MemCmd::ReadReq, descAddr, numBytes, event, data,
|
port->dmaAction(MemCmd::ReadReq, descAddr, numBytes, event, data,
|
||||||
currState->tc->getCpuPtr()->clockPeriod(),flags);
|
currState->tc->getCpuPtr()->clockPeriod(),flags);
|
||||||
if (queueIndex >= 0) {
|
if (queueIndex >= 0) {
|
||||||
DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n",
|
DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n",
|
||||||
|
@ -1948,7 +1966,7 @@ TableWalker::fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes,
|
||||||
currState = NULL;
|
currState = NULL;
|
||||||
}
|
}
|
||||||
} else if (!currState->functional) {
|
} 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);
|
currState->tc->getCpuPtr()->clockPeriod(), flags);
|
||||||
(this->*doDescriptor)();
|
(this->*doDescriptor)();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1956,7 +1974,7 @@ TableWalker::fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes,
|
||||||
req->taskId(ContextSwitchTaskId::DMA);
|
req->taskId(ContextSwitchTaskId::DMA);
|
||||||
PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
|
PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
|
||||||
pkt->dataStatic(data);
|
pkt->dataStatic(data);
|
||||||
port.sendFunctional(pkt);
|
port->sendFunctional(pkt);
|
||||||
(this->*doDescriptor)();
|
(this->*doDescriptor)();
|
||||||
delete req;
|
delete req;
|
||||||
delete pkt;
|
delete pkt;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2010-2014 ARM Limited
|
* Copyright (c) 2010-2015 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -47,7 +47,6 @@
|
||||||
#include "arch/arm/system.hh"
|
#include "arch/arm/system.hh"
|
||||||
#include "arch/arm/tlb.hh"
|
#include "arch/arm/tlb.hh"
|
||||||
#include "dev/dma_device.hh"
|
#include "dev/dma_device.hh"
|
||||||
#include "mem/mem_object.hh"
|
|
||||||
#include "mem/request.hh"
|
#include "mem/request.hh"
|
||||||
#include "params/ArmTableWalker.hh"
|
#include "params/ArmTableWalker.hh"
|
||||||
#include "sim/eventq.hh"
|
#include "sim/eventq.hh"
|
||||||
|
@ -812,37 +811,6 @@ class TableWalker : public MemObject
|
||||||
|
|
||||||
protected:
|
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 */
|
/** Queues of requests for all the different lookup levels */
|
||||||
std::list<WalkerState *> stateQueues[MAX_LOOKUP_LEVELS];
|
std::list<WalkerState *> stateQueues[MAX_LOOKUP_LEVELS];
|
||||||
|
|
||||||
|
@ -850,16 +818,18 @@ class TableWalker : public MemObject
|
||||||
* currently busy. */
|
* currently busy. */
|
||||||
std::list<WalkerState *> pendingQueue;
|
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 */
|
/** If we're draining keep the drain event around until we're drained */
|
||||||
DrainManager *drainManager;
|
DrainManager *drainManager;
|
||||||
|
|
||||||
/** The MMU to forward second stage look upts to */
|
/** The MMU to forward second stage look upts to */
|
||||||
Stage2MMU *stage2Mmu;
|
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 */
|
/** Indicates whether this table walker is part of the stage 2 mmu */
|
||||||
const bool isStage2;
|
const bool isStage2;
|
||||||
|
|
||||||
|
@ -874,9 +844,6 @@ class TableWalker : public MemObject
|
||||||
/** If a timing translation is currently in progress */
|
/** If a timing translation is currently in progress */
|
||||||
bool pending;
|
bool pending;
|
||||||
|
|
||||||
/** Request id for requests generated by this walker */
|
|
||||||
MasterID masterId;
|
|
||||||
|
|
||||||
/** The number of walks belonging to squashed instructions that can be
|
/** The number of walks belonging to squashed instructions that can be
|
||||||
* removed from the pendingQueue per cycle. */
|
* removed from the pendingQueue per cycle. */
|
||||||
unsigned numSquashable;
|
unsigned numSquashable;
|
||||||
|
@ -887,7 +854,6 @@ class TableWalker : public MemObject
|
||||||
bool _haveVirtualization;
|
bool _haveVirtualization;
|
||||||
uint8_t physAddrRange;
|
uint8_t physAddrRange;
|
||||||
bool _haveLargeAsid64;
|
bool _haveLargeAsid64;
|
||||||
ArmSystem *armSys;
|
|
||||||
|
|
||||||
/** Statistics */
|
/** Statistics */
|
||||||
Stats::Scalar statWalks;
|
Stats::Scalar statWalks;
|
||||||
|
@ -920,6 +886,8 @@ class TableWalker : public MemObject
|
||||||
return dynamic_cast<const Params *>(_params);
|
return dynamic_cast<const Params *>(_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void init();
|
||||||
|
|
||||||
bool haveLPAE() const { return _haveLPAE; }
|
bool haveLPAE() const { return _haveLPAE; }
|
||||||
bool haveVirtualization() const { return _haveVirtualization; }
|
bool haveVirtualization() const { return _haveVirtualization; }
|
||||||
bool haveLargeAsid64() const { return _haveLargeAsid64; }
|
bool haveLargeAsid64() const { return _haveLargeAsid64; }
|
||||||
|
@ -927,18 +895,11 @@ class TableWalker : public MemObject
|
||||||
void completeDrain();
|
void completeDrain();
|
||||||
unsigned int drain(DrainManager *dm);
|
unsigned int drain(DrainManager *dm);
|
||||||
virtual void drainResume();
|
virtual void drainResume();
|
||||||
|
|
||||||
virtual BaseMasterPort& getMasterPort(const std::string &if_name,
|
virtual BaseMasterPort& getMasterPort(const std::string &if_name,
|
||||||
PortID idx = InvalidPortID);
|
PortID idx = InvalidPortID);
|
||||||
void regStats();
|
|
||||||
|
|
||||||
/**
|
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; }
|
|
||||||
|
|
||||||
Fault walk(RequestPtr req, ThreadContext *tc, uint16_t asid, uint8_t _vmid,
|
Fault walk(RequestPtr req, ThreadContext *tc, uint16_t asid, uint8_t _vmid,
|
||||||
bool _isHyp, TLB::Mode mode, TLB::Translation *_trans,
|
bool _isHyp, TLB::Mode mode, TLB::Translation *_trans,
|
||||||
|
@ -947,7 +908,7 @@ class TableWalker : public MemObject
|
||||||
|
|
||||||
void setTlb(TLB *_tlb) { tlb = _tlb; }
|
void setTlb(TLB *_tlb) { tlb = _tlb; }
|
||||||
TLB* getTlb() { return 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,
|
void memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr,
|
||||||
uint8_t texcb, bool s);
|
uint8_t texcb, bool s);
|
||||||
void memAttrsLPAE(ThreadContext *tc, TlbEntry &te,
|
void memAttrsLPAE(ThreadContext *tc, TlbEntry &te,
|
||||||
|
|
|
@ -100,10 +100,10 @@ TLB::init()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TLB::setMMU(Stage2MMU *m)
|
TLB::setMMU(Stage2MMU *m, MasterID master_id)
|
||||||
{
|
{
|
||||||
stage2Mmu = m;
|
stage2Mmu = m;
|
||||||
tableWalker->setMMU(m);
|
tableWalker->setMMU(m, master_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -1215,13 +1215,7 @@ TLB::translateComplete(RequestPtr req, ThreadContext *tc,
|
||||||
BaseMasterPort*
|
BaseMasterPort*
|
||||||
TLB::getMasterPort()
|
TLB::getMasterPort()
|
||||||
{
|
{
|
||||||
return &tableWalker->getMasterPort("port");
|
return &stage2Mmu->getPort();
|
||||||
}
|
|
||||||
|
|
||||||
DmaPort&
|
|
||||||
TLB::getWalkerPort()
|
|
||||||
{
|
|
||||||
return tableWalker->getWalkerPort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -163,7 +163,9 @@ class TLB : public BaseTLB
|
||||||
/// setup all the back pointers
|
/// setup all the back pointers
|
||||||
virtual void init();
|
virtual void init();
|
||||||
|
|
||||||
void setMMU(Stage2MMU *m);
|
TableWalker *getTableWalker() { return tableWalker; }
|
||||||
|
|
||||||
|
void setMMU(Stage2MMU *m, MasterID master_id);
|
||||||
|
|
||||||
int getsize() const { return size; }
|
int getsize() const { return size; }
|
||||||
|
|
||||||
|
@ -308,15 +310,6 @@ class TLB : public BaseTLB
|
||||||
*/
|
*/
|
||||||
virtual BaseMasterPort* getMasterPort();
|
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.
|
// Caching misc register values here.
|
||||||
// Writing to misc registers needs to invalidate them.
|
// Writing to misc registers needs to invalidate them.
|
||||||
// translateFunctional/translateSe/translateFs checks if they are
|
// translateFunctional/translateSe/translateFs checks if they are
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2012-2013 ARM Limited
|
# Copyright (c) 2012-2013, 2015 ARM Limited
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# The license below extends only to copyright in the software and shall
|
# The license below extends only to copyright in the software and shall
|
||||||
|
@ -214,9 +214,6 @@ class BaseCPU(MemObject):
|
||||||
|
|
||||||
if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
|
if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
|
||||||
_cached_ports += ["itb.walker.port", "dtb.walker.port"]
|
_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_slave_ports = []
|
||||||
_uncached_master_ports = []
|
_uncached_master_ports = []
|
||||||
|
@ -273,35 +270,18 @@ class BaseCPU(MemObject):
|
||||||
if iwc and dwc:
|
if iwc and dwc:
|
||||||
self.itb_walker_cache = iwc
|
self.itb_walker_cache = iwc
|
||||||
self.dtb_walker_cache = dwc
|
self.dtb_walker_cache = dwc
|
||||||
if buildEnv['TARGET_ISA'] in ['arm']:
|
self.itb.walker.port = iwc.cpu_side
|
||||||
self.itb_walker_cache_bus = CoherentXBar()
|
self.dtb.walker.port = dwc.cpu_side
|
||||||
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._cached_ports += ["itb_walker_cache.mem_side", \
|
self._cached_ports += ["itb_walker_cache.mem_side", \
|
||||||
"dtb_walker_cache.mem_side"]
|
"dtb_walker_cache.mem_side"]
|
||||||
else:
|
else:
|
||||||
self._cached_ports += ["itb.walker.port", "dtb.walker.port"]
|
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
|
# Checker doesn't need its own tlb caches because it does
|
||||||
# functional accesses only
|
# functional accesses only
|
||||||
if self.checker != NULL:
|
if self.checker != NULL:
|
||||||
self._cached_ports += ["checker.itb.walker.port", \
|
self._cached_ports += ["checker.itb.walker.port", \
|
||||||
"checker.dtb.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):
|
def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc = None, dwc = None):
|
||||||
self.addPrivateSplitL1Caches(ic, dc, iwc, dwc)
|
self.addPrivateSplitL1Caches(ic, dc, iwc, dwc)
|
||||||
|
|
Loading…
Reference in a new issue