ARM: Implement the ARM TLB/Tablewalker. Needs performance improvements.

This commit is contained in:
Ali Saidi
2010-06-02 12:58:16 -05:00
parent f246be4cbc
commit cb9936cfde
15 changed files with 1236 additions and 113 deletions

View File

@@ -1,8 +1,17 @@
# -*- mode:python -*-
# Copyright (c) 2007-2008 The Florida State University
# Copyright (c) 2009 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
@@ -26,12 +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.
#
# Authors: Stephen Hines
# Authors: Ali Saidi
from m5.defines import buildEnv
from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
if buildEnv['FULL_SYSTEM']:
from MemObject import MemObject
class ArmTableWalker(MemObject):
type = 'ArmTableWalker'
cxx_class = 'ArmISA::TableWalker'
port = Port("Port for TableWalker to do walk the translation with")
sys = Param.System(Parent.any, "system object parameter")
min_backoff = Param.Tick(0, "Minimum backoff delay after failed send")
max_backoff = Param.Tick(100000, "Minimum backoff delay after failed send")
class ArmTLB(SimObject):
type = 'ArmTLB'
cxx_class = 'ArmISA::TLB'
size = Param.Int(64, "TLB size")
if buildEnv['FULL_SYSTEM']:
walker = Param.ArmTableWalker(ArmTableWalker(), "HW Table walker")

View File

@@ -65,12 +65,14 @@ if env['TARGET_ISA'] == 'arm':
SimObject('ArmTLB.py')
TraceFlag('Arm')
TraceFlag('TLBVerbose')
TraceFlag('Faults', "Trace Exceptions, interrupts, svc/swi")
TraceFlag('Predecoder', "Instructions returned by the predecoder")
if env['FULL_SYSTEM']:
Source('interrupts.cc')
Source('stacktrace.cc')
Source('system.cc')
Source('table_walker.cc')
SimObject('ArmInterrupts.py')
SimObject('ArmSystem.py')

View File

@@ -75,16 +75,17 @@ class ArmFault : public FaultBase
Translation1 = 0x7,
SynchronousExternalAbort0 = 0x8,
Domain0 = 0x9,
SynchronousExternalAbort1 = 0xa,
Domain1 = 0xb,
TranslationTableWalk0 = 0xc,
TranslationTableWalkExtAbt0 = 0xc,
Permission0 = 0xd,
SynchronousExternalAbort1 = 0xe,
TranslationTableWalkExtAbt1 = 0xe,
Permission1 = 0xf,
AsynchronousExternalAbort = 0x16,
MemoryAccessAsynchronousParityError = 0x18,
MemoryAccessSynchronousParityError = 0x19,
TranslationTableWalk1 = 0x1c,
SynchronousParityError = 0x1e
TranslationTableWalkPrtyErr0 = 0x1c,
TranslationTableWalkPrtyErr1 = 0x1e,
};
struct FaultVals
@@ -208,7 +209,7 @@ class DataAbort : public AbortFault<DataAbort>
static const MiscRegIndex FsrIndex = MISCREG_DFSR;
static const MiscRegIndex FarIndex = MISCREG_DFAR;
DataAbort(Addr _addr, bool _write, uint8_t _domain, uint8_t _status) :
DataAbort(Addr _addr, uint8_t _domain, bool _write, uint8_t _status) :
AbortFault<DataAbort>(_addr, _write, _domain, _status)
{}
};

View File

@@ -41,9 +41,10 @@
*/
#ifndef __ARCH_ARM_ISA_HH__
#define __ARCH_MRM_ISA_HH__
#define __ARCH_ARM_ISA_HH__
#include "arch/arm/registers.hh"
#include "arch/arm/tlb.hh"
#include "arch/arm/types.hh"
class ThreadContext;
@@ -223,6 +224,8 @@ namespace ArmISA
warn("The ccsidr register isn't implemented and "
"always reads as 0.\n");
break;
case MISCREG_ID_PFR0:
return 0x1031; // ThumbEE | !Jazelle | Thumb | ARM
}
return readMiscRegNoEffect(misc_reg);
}
@@ -347,6 +350,52 @@ namespace ArmISA
case MISCREG_MPIDR:
case MISCREG_FPSID:
return;
case MISCREG_TLBIALLIS:
case MISCREG_TLBIALL:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushAll();
tc->getDTBPtr()->flushAll();
return;
case MISCREG_ITLBIALL:
tc->getITBPtr()->flushAll();
return;
case MISCREG_DTLBIALL:
tc->getDTBPtr()->flushAll();
return;
case MISCREG_TLBIMVAIS:
case MISCREG_TLBIMVA:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
return;
case MISCREG_TLBIASIDIS:
case MISCREG_TLBIASID:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
return;
case MISCREG_TLBIMVAAIS:
case MISCREG_TLBIMVAA:
warn("Need to flush all TLBs in MP\n");
tc->getITBPtr()->flushMva(mbits(newVal, 31,12));
tc->getDTBPtr()->flushMva(mbits(newVal, 31,12));
return;
case MISCREG_ITLBIMVA:
tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
return;
case MISCREG_DTLBIMVA:
tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
bits(newVal, 7,0));
return;
case MISCREG_ITLBIASID:
tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
return;
case MISCREG_DTLBIASID:
tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
return;
}
setMiscRegNoEffect(misc_reg, newVal);
}

View File

@@ -138,47 +138,25 @@ let {{
return new WarnUnimplemented(
isRead ? "mrc bpiall" : "mcr bpiall", machInst);
case MISCREG_TLBIALLIS:
return new WarnUnimplemented(
isRead ? "mrc tlbiallis" : "mcr tlbiallis", machInst);
case MISCREG_TLBIMVAIS:
return new WarnUnimplemented(
isRead ? "mrc tlbimvais" : "mcr tlbimvais", machInst);
case MISCREG_TLBIASIDIS:
return new WarnUnimplemented(
isRead ? "mrc tlbiasidis" : "mcr tlbiasidis", machInst);
case MISCREG_TLBIMVAAIS:
return new WarnUnimplemented(
isRead ? "mrc tlbimvaais" : "mcr tlbimvaais", machInst);
case MISCREG_ITLBIALL:
return new WarnUnimplemented(
isRead ? "mrc itlbiall" : "mcr itlbiall", machInst);
case MISCREG_ITLBIMVA:
return new WarnUnimplemented(
isRead ? "mrc itlbimva" : "mcr itlbimva", machInst);
case MISCREG_ITLBIASID:
return new WarnUnimplemented(
isRead ? "mrc itlbiasid" : "mcr itlbiasid", machInst);
case MISCREG_DTLBIALL:
return new WarnUnimplemented(
isRead ? "mrc dtlbiall" : "mcr dtlbiall", machInst);
case MISCREG_DTLBIMVA:
return new WarnUnimplemented(
isRead ? "mrc dtlbimva" : "mcr dtlbimva", machInst);
case MISCREG_DTLBIASID:
return new WarnUnimplemented(
isRead ? "mrc dtlbiasid" : "mcr dtlbiasid", machInst);
case MISCREG_TLBIALL:
return new WarnUnimplemented(
isRead ? "mrc tlbiall" : "mcr tlbiall", machInst);
case MISCREG_TLBIMVA:
return new WarnUnimplemented(
isRead ? "mrc tlbimva" : "mcr tlbimva", machInst);
case MISCREG_TLBIASID:
return new WarnUnimplemented(
isRead ? "mrc tlbiasid" : "mcr tlbiasid", machInst);
case MISCREG_TLBIMVAA:
return new WarnUnimplemented(
isRead ? "mrc tlbimvaa" : "mcr tlbimvaa", machInst);
if (isRead) {
return new Unknown(machInst);
} else {
return new Mcr15(machInst, (IntRegIndex)miscReg, rt);
}
default:
if (isRead) {
return new Mrc15(machInst, rt, (IntRegIndex)miscReg);

View File

@@ -93,6 +93,9 @@ let {{
eaCode += ";"
memFlags = ["ArmISA::TLB::MustBeOne", "%d" % (size - 1)]
if user:
memFlags.append("ArmISA::TLB::UserMode")
if prefetch:
Name = "%s_%s" % (mnem.upper(), Name)
memFlags.append("Request::PREFETCH")
@@ -179,6 +182,9 @@ let {{
eaCode += ";"
memFlags = ["%d" % (size - 1), "ArmISA::TLB::MustBeOne"]
if user:
memFlags.append("ArmISA::TLB::UserMode")
if prefetch:
Name = "%s_%s" % (mnem.upper(), Name)
memFlags.append("Request::PREFETCH")

View File

@@ -107,6 +107,9 @@ let {{
accCode += "Base = Base %s;\n" % offset
memFlags = ["ArmISA::TLB::MustBeOne", "%d" % (size - 1)]
if user:
memFlags.append("ArmISA::TLB::UserMode")
if strex:
memFlags.append("Request::LLSC")
Name = "%s_%s" % (mnem.upper(), Name)
@@ -184,10 +187,14 @@ let {{
accCode += "Base = Base %s;\n" % offset
base = buildMemBase("MemoryReg", post, writeback)
emitStore(name, Name, False, eaCode, accCode, "",\
["ArmISA::TLB::MustBeOne", \
memFlags = ["ArmISA::TLB::MustBeOne", \
"ArmISA::TLB::AllowUnaligned", \
"%d" % (size - 1)], [], base)
"%d" % (size - 1)]
if user:
memFlags.append("ArmISA::TLB::UserMode")
emitStore(name, Name, False, eaCode, accCode, "",\
memFlags, [], base)
def buildDoubleImmStore(mnem, post, add, writeback, \
strex=False, vstr=False):

View File

@@ -38,6 +38,7 @@
*/
#include "arch/arm/miscregs.hh"
#include "base/misc.hh"
namespace ArmISA
{
@@ -424,6 +425,8 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
// Implementation defined
break;
}
warn("Unknown miscreg: CRn: %d Opc1: %d CRm: %d opc2: %d\n",
crn, opc1, crm, opc2);
// Unrecognized register
return NUM_MISCREGS;
}

View File

@@ -130,10 +130,13 @@ namespace ArmISA
MISCREG_DFAR,
MISCREG_IFAR,
MISCREG_MPIDR,
MISCREG_PRRR,
MISCREG_NMRR,
MISCREG_TTBCR,
MISCREG_ID_PFR0,
MISCREG_CP15_UNIMP_START,
MISCREG_CTR = MISCREG_CP15_UNIMP_START,
MISCREG_TCMTR,
MISCREG_ID_PFR0,
MISCREG_ID_PFR1,
MISCREG_ID_DFR0,
MISCREG_ID_AFR0,
@@ -159,7 +162,6 @@ namespace ArmISA
MISCREG_SCR,
MISCREG_SDER,
MISCREG_NSACR,
MISCREG_TTBCR,
MISCREG_V2PCWPR,
MISCREG_V2PCWPW,
MISCREG_V2PCWUR,
@@ -168,8 +170,6 @@ namespace ArmISA
MISCREG_V2POWPW,
MISCREG_V2POWUR,
MISCREG_V2POWUW,
MISCREG_PRRR,
MISCREG_NMRR,
MISCREG_VBAR,
MISCREG_MVBAR,
MISCREG_ISR,
@@ -205,18 +205,20 @@ namespace ArmISA
"dtlbiall", "dtlbimva", "dtlbiasid",
"tlbiall", "tlbimva", "tlbiasid", "tlbimvaa",
"dfsr", "ifsr", "dfar", "ifar", "mpidr",
"prrr", "nmrr", "ttbcr", "id_pfr0",
// Unimplemented below
"ctr", "tcmtr",
"id_pfr0", "id_pfr1", "id_dfr0", "id_afr0",
"id_pfr1", "id_dfr0", "id_afr0",
"id_mmfr0", "id_mmfr1", "id_mmfr2", "id_mmfr3",
"id_isar0", "id_isar1", "id_isar2", "id_isar3", "id_isar4", "id_isar5",
"par", "aidr", "actlr",
"adfsr", "aifsr",
"dcimvac", "dcisw", "mccsw",
"dccmvau",
"scr", "sder", "nsacr", "ttbcr",
"scr", "sder", "nsacr",
"v2pcwpr", "v2pcwpw", "v2pcwur", "v2pcwuw",
"v2powpr", "v2powpw", "v2powur", "v2powuw",
"prrr", "nmrr", "vbar", "mvbar", "isr", "fceidr",
"vbar", "mvbar", "isr", "fceidr",
"nop", "raz"
};
@@ -343,6 +345,49 @@ namespace ArmISA
Bitfield<27, 24> vfpHalfPrecision;
Bitfield<31, 28> raz;
EndBitUnion(MVFR1)
BitUnion32(PRRR)
Bitfield<1,0> tr0;
Bitfield<3,2> tr1;
Bitfield<5,4> tr2;
Bitfield<7,6> tr3;
Bitfield<9,8> tr4;
Bitfield<11,10> tr5;
Bitfield<13,12> tr6;
Bitfield<15,14> tr7;
Bitfield<16> ds0;
Bitfield<17> ds1;
Bitfield<18> ns0;
Bitfield<19> ns1;
Bitfield<24> nos0;
Bitfield<25> nos1;
Bitfield<26> nos2;
Bitfield<27> nos3;
Bitfield<28> nos4;
Bitfield<29> nos5;
Bitfield<30> nos6;
Bitfield<31> nos7;
EndBitUnion(PRRR)
BitUnion32(NMRR)
Bitfield<1,0> ir0;
Bitfield<3,2> ir1;
Bitfield<5,4> ir2;
Bitfield<7,6> ir3;
Bitfield<9,8> ir4;
Bitfield<11,10> ir5;
Bitfield<13,12> ir6;
Bitfield<15,14> ir7;
Bitfield<17,16> or0;
Bitfield<19,18> or1;
Bitfield<21,20> or2;
Bitfield<23,22> or3;
Bitfield<25,24> or4;
Bitfield<27,26> or5;
Bitfield<29,28> or6;
Bitfield<31,30> or7;
EndBitUnion(NMRR)
};
#endif // __ARCH_ARM_MISCREGS_HH__

View File

@@ -37,9 +37,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
* Steve Reinhardt
* Ali Saidi
* Authors: Ali Saidi
*/
#ifndef __ARCH_ARM_PAGETABLE_H__
@@ -73,22 +71,91 @@ struct PTE
};
struct TlbRange
{
Addr va;
Addr size;
int contextId;
bool global;
inline bool
operator<(const TlbRange &r2) const
{
if (!(global || r2.global)) {
if (contextId < r2.contextId)
return true;
else if (contextId > r2.contextId)
return false;
}
if (va < r2.va)
return true;
return false;
}
inline bool
operator==(const TlbRange &r2) const
{
return va == r2.va &&
size == r2.size &&
contextId == r2.contextId &&
global == r2.global;
}
};
// ITB/DTB table entry
struct TlbEntry
{
Addr tag; // virtual page number tag
Addr ppn; // physical page number
uint8_t asn; // address space number
bool valid; // valid page table entry
public:
enum MemoryType {
StronglyOrdered,
Device,
Normal
};
enum DomainType {
DomainNoAccess = 0,
DomainClient,
DomainReserved,
DomainManager
};
// Matching variables
Addr pfn;
Addr size; // Size of this entry, == Type of TLB Rec
Addr vpn; // Virtual Page Number
uint32_t asid; // Address Space Identifier
uint8_t N; // Number of bits in pagesize
bool global;
bool valid;
//Construct an entry that maps to physical address addr.
// Type of memory
bool nonCacheable; // Can we wrap this in mtype?
bool sNp; // Section descriptor
// Access permissions
bool xn; // Execute Never
uint8_t ap:3; // Access permissions bits
uint8_t domain:4; // Access Domain
TlbRange range; // For fast TLB searching
//Construct an entry that maps to physical address addr for SE mode
TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr)
{
tag = _vaddr >> PageShift;
ppn = _paddr >> PageShift;
asn = _asn;
pfn = _paddr >> PageShift;
size = PageBytes - 1;
asid = _asn;
global = false;
valid = true;
vpn = _vaddr >> PageShift;
nonCacheable = sNp = false;
xn = 0;
ap = 0; // ???
domain = DomainClient; //???
}
TlbEntry()
@@ -97,13 +164,28 @@ struct TlbEntry
void
updateVaddr(Addr new_vaddr)
{
tag = new_vaddr >> PageShift;
vpn = new_vaddr >> PageShift;
}
Addr
pageStart()
{
return ppn << PageShift;
return pfn << PageShift;
}
bool
match(Addr va, uint8_t cid)
{
Addr v = vpn << N;
if (valid && va >= v && va <= v + size && (global || cid == asid))
return true;
return false;
}
Addr
pAddr(Addr va)
{
return (pfn << N) | (va & size);
}
void serialize(std::ostream &os) { panic("Need to Implement\n"); }

View File

@@ -0,0 +1,323 @@
/*
* Copyright (c) 2010 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.
*
* Authors: Ali Saidi
*/
#include "arch/arm/faults.hh"
#include "arch/arm/table_walker.hh"
#include "arch/arm/tlb.hh"
#include "dev/io_device.hh"
#include "cpu/thread_context.hh"
using namespace ArmISA;
TableWalker::TableWalker(const Params *p)
: MemObject(p), port(NULL), tlb(NULL), tc(NULL), req(NULL),
doL1DescEvent(this), doL2DescEvent(this)
{}
TableWalker::~TableWalker()
{
;
}
unsigned int
drain(Event *de)
{
panic("Not implemented\n");
}
Port*
TableWalker::getPort(const std::string &if_name, int idx)
{
if (if_name == "port") {
if (port != NULL)
fatal("%s: port already connected to %s",
name(), port->getPeer()->name());
System *sys = params()->sys;
Tick minb = params()->min_backoff;
Tick maxb = params()->max_backoff;
port = new DmaPort(this, sys, minb, maxb);
return port;
}
return NULL;
}
Fault
TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode mode,
TLB::Translation *_trans, bool _timing)
{
// Right now 1 CPU == 1 TLB == 1 TLB walker
// In the future we might want to change this as multiple
// threads/contexts could share a walker and/or a TLB
if (tc || req)
panic("Overlapping TLB walks attempted\n");
tc = _tc;
transState = _trans;
req = _req;
fault = NoFault;
contextId = _cid;
timing = _timing;
// XXX These should be cached or grabbed from cached copies in
// the TLB, all these miscreg reads are expensive
vaddr = req->getVaddr() & ~PcModeMask;
sctlr = tc->readMiscReg(MISCREG_SCTLR);
cpsr = tc->readMiscReg(MISCREG_CPSR);
N = tc->readMiscReg(MISCREG_TTBCR);
Addr ttbr = 0;
isFetch = (mode == TLB::Execute);
isWrite = (mode == TLB::Write);
isPriv = (cpsr.mode != MODE_USER);
// If translation isn't enabled, we shouldn't be here
assert(sctlr.m);
if (N == 0 || mbits(vaddr, 31, 32-N)) {
ttbr = tc->readMiscReg(MISCREG_TTBR0);
} else {
ttbr = tc->readMiscReg(MISCREG_TTBR0);
N = 0;
}
Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(vaddr,31-N,20) << 2);
DPRINTF(TLB, "Begining table walk for address %#x at descriptor %#x\n",
vaddr, l1desc_addr);
// Trickbox address check
fault = tlb->walkTrickBoxCheck(l1desc_addr, vaddr, sizeof(uint32_t),
isFetch, 0, true);
if (fault) {
tc = NULL;
req = NULL;
return fault;
}
if (timing) {
port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
&doL1DescEvent, (uint8_t*)&l1Desc.data, (Tick)0);
} else {
port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
NULL, (uint8_t*)&l1Desc.data, (Tick)0);
doL1Descriptor();
}
return fault;
}
void
TableWalker::memAttrs(TlbEntry &te, uint8_t texcb)
{
if (sctlr.tre == 0) {
switch(texcb) {
case 0:
case 1:
case 4:
case 8:
te.nonCacheable = true;
break;
case 16:
if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0)
te.nonCacheable = true;
break;
}
} else {
PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
switch(bits(texcb, 2,0)) {
case 0:
if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
te.nonCacheable = true;
break;
case 1:
if (nmrr.ir1 == 0 || nmrr.or1 == 0 || prrr.tr1 != 0x2)
te.nonCacheable = true;
break;
case 2:
if (nmrr.ir2 == 0 || nmrr.or2 == 0 || prrr.tr2 != 0x2)
te.nonCacheable = true;
break;
case 3:
if (nmrr.ir3 == 0 || nmrr.or3 == 0 || prrr.tr3 != 0x2)
te.nonCacheable = true;
break;
case 4:
if (nmrr.ir4 == 0 || nmrr.or4 == 0 || prrr.tr4 != 0x2)
te.nonCacheable = true;
break;
case 5:
if (nmrr.ir5 == 0 || nmrr.or5 == 0 || prrr.tr5 != 0x2)
te.nonCacheable = true;
break;
case 6:
panic("Imp defined type\n");
case 7:
if (nmrr.ir7 == 0 || nmrr.or7 == 0 || prrr.tr7 != 0x2)
te.nonCacheable = true;
break;
}
}
}
void
TableWalker::doL1Descriptor()
{
DPRINTF(TLB, "L1 descriptor for %#x is %#x\n", vaddr, l1Desc.data);
TlbEntry te;
switch (l1Desc.type()) {
case L1Descriptor::Ignore:
case L1Descriptor::Reserved:
tc = NULL;
req = NULL;
fault = new DataAbort(vaddr, NULL, isWrite, ArmFault::Translation0);
return;
case L1Descriptor::Section:
if (sctlr.afe && bits(l1Desc.ap(), 0) == 0)
panic("Haven't implemented AFE\n");
if (l1Desc.supersection()) {
panic("Haven't implemented supersections\n");
}
te.N = 20;
te.pfn = l1Desc.pfn();
te.size = (1<<te.N) - 1;
te.global = !l1Desc.global();
te.valid = true;
te.vpn = vaddr >> te.N;
te.sNp = true;
te.xn = l1Desc.xn();
te.ap = l1Desc.ap();
te.domain = l1Desc.domain();
te.asid = contextId;
memAttrs(te, l1Desc.texcb());
DPRINTF(TLB, "Inserting Section Descriptor into TLB\n");
DPRINTF(TLB, " - N%d pfn:%#x size: %#x global:%d valid: %d\n",
te.N, te.pfn, te.size, te.global, te.valid);
DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d\n",
te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid);
DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n",
l1Desc.domain(), l1Desc.data, (l1Desc.data >> 5) & 0xF );
tc = NULL;
req = NULL;
tlb->insert(vaddr, te);
return;
case L1Descriptor::PageTable:
Addr l2desc_addr;
l2desc_addr = l1Desc.l2Addr() | (bits(vaddr, 19,12) << 2);
DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n", l2desc_addr);
// Trickbox address check
fault = tlb->walkTrickBoxCheck(l2desc_addr, vaddr, sizeof(uint32_t),
isFetch, l1Desc.domain(), false);
if (fault) {
tc = NULL;
req = NULL;
return;
}
if (timing) {
port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
&doL2DescEvent, (uint8_t*)&l2Desc.data, 0);
} else {
port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
NULL, (uint8_t*)&l2Desc.data, 0);
doL2Descriptor();
}
return;
default:
panic("A new type in a 2 bit field?\n");
}
}
void
TableWalker::doL2Descriptor()
{
DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", vaddr, l2Desc.data);
TlbEntry te;
if (sctlr.afe && bits(l1Desc.ap(), 0) == 0)
panic("Haven't implemented AFE\n");
if (l2Desc.invalid()) {
DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
tc = NULL;
req = NULL;
fault = new DataAbort(vaddr, l1Desc.domain(), isWrite, ArmFault::Translation1);
return;
}
if (l2Desc.large()) {
te.N = 16;
te.pfn = l2Desc.pfn();
} else {
te.N = 12;
te.pfn = l2Desc.pfn();
}
te.valid = true;
te.size = (1 << te.N) - 1;
te.asid = contextId;
te.sNp = false;
te.vpn = vaddr >> te.N;
te.global = l2Desc.global();
te.xn = l2Desc.xn();
te.ap = l2Desc.ap();
te.domain = l1Desc.domain();
memAttrs(te, l2Desc.texcb());
tc = NULL;
req = NULL;
tlb->insert(vaddr, te);
}
ArmISA::TableWalker *
ArmTableWalkerParams::create()
{
return new ArmISA::TableWalker(this);
}

View File

@@ -0,0 +1,272 @@
/*
* Copyright (c) 2010 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.
*
* Authors: Ali Saidi
*/
#ifndef __ARCH_ARM_TABLE_WALKER_HH__
#define __ARCH_ARM_TABLE_WALKER_HH__
#include "arch/arm/miscregs.hh"
#include "arch/arm/tlb.hh"
#include "mem/mem_object.hh"
#include "mem/request.hh"
#include "mem/request.hh"
#include "params/ArmTableWalker.hh"
#include "sim/faults.hh"
#include "sim/eventq.hh"
class DmaPort;
class ThreadContext;
namespace ArmISA {
class Translation;
class TLB;
class TableWalker : public MemObject
{
protected:
struct L1Descriptor {
/** Type of page table entry ARM DDI 0406B: B3-8*/
enum EntryType {
Ignore,
PageTable,
Section,
Reserved
};
uint32_t data;
EntryType type() const
{
return (EntryType)(data & 0x3);
}
/** Is the page a Supersection (16MB)?*/
bool supersection() const
{
return bits(data, 18);
}
/** Return the physcal address of the entry, bits in position*/
Addr paddr() const
{
if (supersection())
panic("Super sections not implemented\n");
return mbits(data, 31,20);
}
/** Return the physical frame, bits shifted right */
Addr pfn() const
{
if (supersection())
panic("Super sections not implemented\n");
return bits(data, 31,20);
}
/** Is the translation global (no asid used)? */
bool global() const
{
return bits(data, 17);
}
/** Is the translation not allow execution? */
bool xn() const
{
return bits(data, 17);
}
/** Three bit access protection flags */
uint8_t ap() const
{
return (bits(data, 15) << 2) | bits(data,11,10);
}
/** Domain Client/Manager: ARM DDI 0406B: B3-31 */
uint8_t domain() const
{
return bits(data,8,5);
}
/** Address of L2 descriptor if it exists */
Addr l2Addr() const
{
return mbits(data, 31,10);
}
/** Memory region attributes: ARM DDI 0406B: B3-32 */
uint8_t texcb() const
{
return bits(data, 2) | bits(data,3) << 1 | bits(data, 12, 14) << 2;
}
};
/** Level 2 page table descriptor */
struct L2Descriptor {
uint32_t data;
/** Is the entry invalid */
bool invalid() const
{
return bits(data, 1,0) == 0;;
}
/** What is the size of the mapping? */
bool large() const
{
return bits(data, 1) == 0;
}
/** Is execution allowed on this mapping? */
bool xn() const
{
return large() ? bits(data, 15) : bits(data, 0);
}
/** Is the translation global (no asid used)? */
bool global() const
{
return !bits(data, 11);
}
/** Three bit access protection flags */
uint8_t ap() const
{
return bits(data, 5, 4) | (bits(data, 9) << 2);
}
/** Memory region attributes: ARM DDI 0406B: B3-32 */
uint8_t texcb() const
{
return large() ?
(bits(data, 2) | (bits(data,3) << 1) | (bits(data, 12, 14) << 2)) :
(bits(data, 2) | (bits(data,3) << 1) | (bits(data, 6, 8) << 2));
}
/** Return the physical frame, bits shifted right */
Addr pfn() const
{
return large() ? bits(data, 31, 16) : bits(data, 31, 12);
}
};
/** Port to issue translation requests from */
DmaPort *port;
/** TLB that is initiating these table walks */
TLB *tlb;
/** Thread context that we're doing the walk for */
ThreadContext *tc;
/** Request that is currently being serviced */
RequestPtr req;
/** Context ID that we're servicing the request under */
uint8_t contextId;
/** Translation state for delayed requests */
TLB::Translation *transState;
/** The fault that we are going to return */
Fault fault;
/** The virtual address that is being translated */
Addr vaddr;
/** Cached copy of the sctlr as it existed when translation began */
SCTLR sctlr;
/** Cached copy of the cpsr as it existed when the translation began */
CPSR cpsr;
/** Width of the base address held in TTRB0 */
uint32_t N;
/** If the access is a write */
bool isWrite;
/** If the access is not from user mode */
bool isPriv;
/** If the access is a fetch (for execution, and no-exec) must be checked?*/
bool isFetch;
/** If the mode is timing or atomic */
bool timing;
L1Descriptor l1Desc;
L2Descriptor l2Desc;
public:
typedef ArmTableWalkerParams Params;
TableWalker(const Params *p);
virtual ~TableWalker();
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
virtual unsigned int drain(Event *de) { panic("write me\n"); }
virtual Port *getPort(const std::string &if_name, int idx = -1);
Fault walk(RequestPtr req, ThreadContext *tc, uint8_t cid, TLB::Mode mode,
TLB::Translation *_trans, bool timing);
void setTlb(TLB *_tlb) { tlb = _tlb; }
private:
void memAttrs(TlbEntry &te, uint8_t texcb);
void doL1Descriptor();
EventWrapper<TableWalker, &TableWalker::doL1Descriptor> doL1DescEvent;
void doL2Descriptor();
EventWrapper<TableWalker, &TableWalker::doL2Descriptor> doL2DescEvent;
};
} // namespace ArmISA
#endif //__ARCH_ARM_TABLE_WALKER_HH__

View File

@@ -47,6 +47,7 @@
#include "arch/arm/faults.hh"
#include "arch/arm/pagetable.hh"
#include "arch/arm/table_walker.hh"
#include "arch/arm/tlb.hh"
#include "arch/arm/utility.hh"
#include "base/inifile.hh"
@@ -57,16 +58,19 @@
#include "params/ArmTLB.hh"
#include "sim/process.hh"
using namespace std;
using namespace ArmISA;
TLB::TLB(const Params *p)
: BaseTLB(p), size(p->size), nlu(0)
#if FULL_SYSTEM
, tableWalker(p->walker)
#endif
{
table = new ArmISA::PTE[size];
memset(table, 0, sizeof(ArmISA::PTE[size]));
table = new TlbEntry[size];
memset(table, 0, sizeof(TlbEntry[size]));
tableWalker->setTlb(this);
}
TLB::~TLB()
@@ -75,50 +79,157 @@ TLB::~TLB()
delete [] table;
}
ArmISA::PTE *
TLB::lookup(Addr vpn, uint8_t asn) const
TlbEntry*
TLB::lookup(Addr va, uint8_t cid)
{
panic("lookup() not implemented for ARM\n");
// XXX This should either turn into a TlbMap or add caching
TlbEntry *retval = NULL;
// Do some kind of caching, fast indexing, anything
int x = 0;
while (retval == NULL && x < size) {
if (table[x].match(va, cid)) {
retval = &table[x];
if (x == nlu)
nextnlu();
break;
}
x++;
}
DPRINTF(TLBVerbose, "Lookup %#x, cid %#x -> %s ppn %#x size: %#x pa: %#x ap:%d\n",
va, cid, retval ? "hit" : "miss", retval ? retval->pfn : 0,
retval ? retval->size : 0, retval ? retval->pAddr(va) : 0,
retval ? retval->ap : 0);
;
return retval;
}
// insert a new TLB entry
void
TLB::insert(Addr addr, ArmISA::PTE &pte)
TLB::insert(Addr addr, TlbEntry &entry)
{
fatal("TLB Insert not yet implemented\n");
DPRINTF(TLB, "Inserting entry into TLB with pfn:%#x size:%#x vpn: %#x"
" asid:%d N:%d global:%d valid:%d nc:%d sNp:%d xn:%d ap:%#x"
" domain:%#x\n", entry.pfn, entry.size, entry.vpn, entry.asid,
entry.N, entry.global, entry.valid, entry.nonCacheable, entry.sNp,
entry.xn, entry.ap, entry.domain);
if (table[nlu].valid)
DPRINTF(TLB, " - Replacing Valid entry %#x, asn %d ppn %#x size: %#x ap:%d\n",
table[nlu].vpn << table[nlu].N, table[nlu].asid, table[nlu].pfn << table[nlu].N,
table[nlu].size, table[nlu].ap);
// XXX Update caching, lookup table etc
table[nlu] = entry;
// XXX Figure out how entries are generally inserted in ARM
nextnlu();
}
void
TLB::printTlb()
{
int x = 0;
TlbEntry *te;
DPRINTF(TLB, "Current TLB contents:\n");
while (x < size) {
te = &table[x];
if (te->valid)
DPRINTF(TLB, " * %#x, asn %d ppn %#x size: %#x ap:%d\n",
te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
x++;
}
}
void
TLB::flushAll()
{
DPRINTF(TLB, "flushAll\n");
memset(table, 0, sizeof(ArmISA::PTE[size]));
lookupTable.clear();
DPRINTF(TLB, "Flushing all TLB entries\n");
int x = 0;
TlbEntry *te;
while (x < size) {
te = &table[x];
if (te->valid)
DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
x++;
}
memset(table, 0, sizeof(TlbEntry[size]));
nlu = 0;
}
void
TLB::flushMvaAsid(Addr mva, uint64_t asn)
{
DPRINTF(TLB, "Flushing mva %#x asid: %#x\n", mva, asn);
TlbEntry *te;
te = lookup(mva, asn);
while (te != NULL) {
DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
te->valid = false;
te = lookup(mva,asn);
}
}
void
TLB::flushAsid(uint64_t asn)
{
DPRINTF(TLB, "Flushing all entries with asid: %#x\n", asn);
int x = 0;
TlbEntry *te;
while (x < size) {
te = &table[x];
if (te->asid == asn) {
te->valid = false;
DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
}
x++;
}
}
void
TLB::flushMva(Addr mva)
{
DPRINTF(TLB, "Flushing all entries with mva: %#x\n", mva);
int x = 0;
TlbEntry *te;
while (x < size) {
te = &table[x];
Addr v = te->vpn << te->N;
if (mva >= v && mva < v + te->size) {
te->valid = false;
DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
}
x++;
}
}
void
TLB::serialize(ostream &os)
{
SERIALIZE_SCALAR(size);
SERIALIZE_SCALAR(nlu);
for (int i = 0; i < size; i++) {
nameOut(os, csprintf("%s.PTE%d", name(), i));
table[i].serialize(os);
}
panic("Implement Serialize\n");
}
void
TLB::unserialize(Checkpoint *cp, const string &section)
{
UNSERIALIZE_SCALAR(size);
UNSERIALIZE_SCALAR(nlu);
panic("Need to properly unserialize TLB\n");
for (int i = 0; i < size; i++) {
table[i].unserialize(cp, csprintf("%s.PTE%d", section, i));
}
}
void
@@ -182,50 +293,227 @@ TLB::regStats()
}
Fault
TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
TLB::trickBoxCheck(RequestPtr req, Mode mode, uint8_t domain, bool sNp)
{
return NoFault;
}
Fault
TLB::walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec,
uint8_t domain, bool sNp)
{
return NoFault;
}
#if !FULL_SYSTEM
Fault
TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
Translation *translation, bool &delay, bool timing)
{
// XXX Cache misc registers and have miscreg write function inv cache
Addr vaddr = req->getVaddr() & ~PcModeMask;
SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
uint32_t flags = req->getFlags();
if (mode != Execute) {
assert(flags & MustBeOne);
bool is_fetch = (mode == Execute);
bool is_write = (mode == Write);
if (sctlr.a || (flags & AllowUnaligned) == 0) {
if ((vaddr & flags & AlignmentMask) != 0) {
return new DataAbort(vaddr, (mode == Write), 0,
ArmFault::AlignmentFault);
if (!is_fetch) {
assert(flags & MustBeOne);
if (sctlr.a || !(flags & AllowUnaligned)) {
if (vaddr & flags & AlignmentMask) {
return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
}
}
}
#if !FULL_SYSTEM
Process * p = tc->getProcessPtr();
Addr paddr;
Process *p = tc->getProcessPtr();
if (!p->pTable->translate(vaddr, paddr))
return Fault(new GenericPageTableFault(vaddr));
req->setPaddr(paddr);
return NoFault;
#else
if (!sctlr.m) {
req->setPaddr(vaddr);
return NoFault;
}
warn_once("MPU translation not implemented\n");
req->setPaddr(vaddr);
return NoFault;
#endif
}
void
#else // FULL_SYSTEM
Fault
TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
Translation *translation, bool &delay, bool timing)
{
// XXX Cache misc registers and have miscreg write function inv cache
Addr vaddr = req->getVaddr() & ~PcModeMask;
SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
uint32_t flags = req->getFlags();
bool is_fetch = (mode == Execute);
bool is_write = (mode == Write);
bool is_priv = (cpsr.mode != MODE_USER) && !(flags & UserMode);
DPRINTF(TLBVerbose, "CPSR is user:%d UserMode:%d\n", cpsr.mode == MODE_USER, flags
& UserMode);
if (!is_fetch) {
assert(flags & MustBeOne);
if (sctlr.a || !(flags & AllowUnaligned)) {
if (vaddr & flags & AlignmentMask) {
return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
}
}
}
uint32_t context_id = tc->readMiscReg(MISCREG_CONTEXTIDR);
Fault fault;
if (!sctlr.m) {
req->setPaddr(vaddr);
if (sctlr.tre == 0) {
req->setFlags(Request::UNCACHEABLE);
} else {
PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
req->setFlags(Request::UNCACHEABLE);
}
return trickBoxCheck(req, mode, 0, false);
}
DPRINTF(TLBVerbose, "Translating vaddr=%#x context=%d\n", vaddr, context_id);
// Translation enabled
TlbEntry *te = lookup(vaddr, context_id);
if (te == NULL) {
// start translation table walk, pass variables rather than
// re-retreaving in table walker for speed
DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d)\n",
vaddr, context_id);
fault = tableWalker->walk(req, tc, context_id, mode, translation,
timing);
if (timing)
delay = true;
if (fault)
return fault;
te = lookup(vaddr, context_id);
if (!te)
printTlb();
assert(te);
}
uint32_t dacr = tc->readMiscReg(MISCREG_DACR);
switch ( (dacr >> (te->domain * 2)) & 0x3) {
case 0:
DPRINTF(TLB, "TLB Fault: Data abort on domain. DACR: %#x domain: %#x"
" write:%d sNp:%d\n", dacr, te->domain, is_write, te->sNp);
if (is_fetch)
return new PrefetchAbort(vaddr,
(te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
else
return new DataAbort(vaddr, te->domain, is_write,
(te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
case 1:
// Continue with permissions check
break;
case 2:
panic("UNPRED domain\n");
case 3:
req->setPaddr(te->pAddr(vaddr));
fault = trickBoxCheck(req, mode, te->domain, te->sNp);
if (fault)
return fault;
return NoFault;
}
uint8_t ap = te->ap;
if (sctlr.afe == 1)
ap |= 1;
bool abt;
switch (ap) {
case 0:
abt = true;
break;
case 1:
abt = !is_priv;
break;
case 2:
abt = !is_priv && is_write;
break;
case 3:
abt = false;
break;
case 4:
panic("UNPRED premissions\n");
case 5:
abt = !is_priv || is_write;
break;
case 6:
case 7:
abt = is_write;
break;
default:
panic("Unknown permissions\n");
}
if ((is_fetch) && (abt || te->xn)) {
DPRINTF(TLB, "TLB Fault: Prefetch abort on permission check. AP:%d priv:%d"
" write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
return new PrefetchAbort(vaddr,
(te->sNp ? ArmFault::Permission0 :
ArmFault::Permission1));
} else if (abt) {
DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d priv:%d"
" write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
return new DataAbort(vaddr, te->domain, is_write,
(te->sNp ? ArmFault::Permission0 :
ArmFault::Permission1));
}
req->setPaddr(te->pAddr(vaddr));
// Check for a trickbox generated address fault
fault = trickBoxCheck(req, mode, te->domain, te->sNp);
if (fault)
return fault;
return NoFault;
}
#endif
Fault
TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
{
bool delay = false;
Fault fault;
#if FULL_SYSTEM
fault = translateFs(req, tc, mode, NULL, delay, false);
#else
fault = translateSe(req, tc, mode, NULL, delay, false);
#endif
assert(!delay);
return fault;
}
Fault
TLB::translateTiming(RequestPtr req, ThreadContext *tc,
Translation *translation, Mode mode)
{
assert(translation);
translation->finish(translateAtomic(req, tc, mode), req, tc, mode);
bool delay = false;
Fault fault;
#if FULL_SYSTEM
fault = translateFs(req, tc, mode, translation, delay, true);
#else
fault = translateSe(req, tc, mode, translation, delay, true);
#endif
if (!delay)
translation->finish(fault, req, tc, mode);
return fault;
}
ArmISA::TLB *

View File

@@ -59,6 +59,8 @@ class ThreadContext;
namespace ArmISA {
class TableWalker;
class TLB : public BaseTLB
{
public:
@@ -71,21 +73,24 @@ class TLB : public BaseTLB
AlignDoubleWord = 0x7,
AllowUnaligned = 0x8,
// Priv code operating as if it wasn't
UserMode = 0x10,
// Because zero otherwise looks like a valid setting and may be used
// accidentally, this bit must be non-zero to show it was used on
// purpose.
MustBeOne = 0x10
MustBeOne = 0x20
};
protected:
typedef std::multimap<Addr, int> PageTable;
PageTable lookupTable; // Quick lookup into page table
ArmISA::PTE *table; // the Page Table
TlbEntry *table; // the Page Table
int size; // TLB Size
int nlu; // not last used entry (for replacement)
TableWalker *tableWalker;
void nextnlu() { if (++nlu >= size) nlu = 0; }
ArmISA::PTE *lookup(Addr vpn, uint8_t asn) const;
TlbEntry *lookup(Addr vpn, uint8_t asn);
// Access Stats
mutable Stats::Scalar read_hits;
@@ -101,6 +106,7 @@ class TLB : public BaseTLB
Stats::Formula invalids;
Stats::Formula accesses;
public:
typedef ArmTLBParams Params;
TLB(const Params *p);
@@ -108,17 +114,49 @@ class TLB : public BaseTLB
virtual ~TLB();
int getsize() const { return size; }
void insert(Addr vaddr, ArmISA::PTE &pte);
void insert(Addr vaddr, TlbEntry &pte);
/** Reset the entire TLB */
void flushAll();
/** Remove any entries that match both a va and asn
* @param mva virtual address to flush
* @param asn contextid/asn to flush on match
*/
void flushMvaAsid(Addr mva, uint64_t asn);
/** Remove any entries that match the asn
* @param asn contextid/asn to flush on match
*/
void flushAsid(uint64_t asn);
/** Remove all entries that match the va regardless of asn
* @param mva address to flush from cache
*/
void flushMva(Addr mva);
Fault trickBoxCheck(RequestPtr req, Mode mode, uint8_t domain, bool sNp);
Fault walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec, uint8_t
domain, bool sNp);
void printTlb();
void demapPage(Addr vaddr, uint64_t asn)
{
panic("demapPage unimplemented.\n");
flushMvaAsid(vaddr, asn);
}
static bool validVirtualAddress(Addr vaddr);
#if FULL_SYSTEM
Fault translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
Translation *translation, bool &delay, bool timing);
#else
Fault translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
Translation *translation, bool &delay, bool timing);
#endif
Fault translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode);
void translateTiming(RequestPtr req, ThreadContext *tc,
Fault translateTiming(RequestPtr req, ThreadContext *tc,
Translation *translation, Mode mode);
// Checkpointing

View File

@@ -114,7 +114,6 @@ class BaseCPU(MemObject):
interrupts = Param.MipsInterrupts(
MipsInterrupts(), "Interrupt Controller")
elif buildEnv['TARGET_ISA'] == 'arm':
UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
dtb = Param.ArmTLB(ArmTLB(), "Data TLB")
itb = Param.ArmTLB(ArmTLB(), "Instruction TLB")
if buildEnv['FULL_SYSTEM']:
@@ -158,6 +157,10 @@ class BaseCPU(MemObject):
"interrupts.pio",
"interrupts.int_port"]
if buildEnv['TARGET_ISA'] == 'arm' and buildEnv['FULL_SYSTEM']:
_mem_ports = ["itb.walker.port",
"dtb.walker.port"]
def connectMemPorts(self, bus):
for p in self._mem_ports:
if p != 'physmem_port':
@@ -170,8 +173,9 @@ class BaseCPU(MemObject):
self.icache_port = ic.cpu_side
self.dcache_port = dc.cpu_side
self._mem_ports = ['icache.mem_side', 'dcache.mem_side']
if buildEnv['TARGET_ISA'] == 'x86' and buildEnv['FULL_SYSTEM']:
self._mem_ports += ["itb.walker_port", "dtb.walker_port"]
if buildEnv['FULL_SYSTEM']:
if buildEnv['TARGET_ISA'] in ['x86', 'arm']:
self._mem_ports += ["itb.walker.port", "dtb.walker.port"]
def addTwoLevelCacheHierarchy(self, ic, dc, l2c):
self.addPrivateSplitL1Caches(ic, dc)