2 * Copyright (c) 2010-2012 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Copyright (c) 2001-2005 The Regents of The University of Michigan
15 * All rights reserved.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 #include "arch/arm/faults.hh"
49 #include "arch/arm/pagetable.hh"
50 #include "arch/arm/system.hh"
51 #include "arch/arm/table_walker.hh"
52 #include "arch/arm/tlb.hh"
53 #include "arch/arm/utility.hh"
54 #include "base/inifile.hh"
55 #include "base/str.hh"
56 #include "base/trace.hh"
57 #include "cpu/thread_context.hh"
58 #include "debug/Checkpoint.hh"
59 #include "debug/TLB.hh"
60 #include "debug/TLBVerbose.hh"
61 #include "mem/page_table.hh"
62 #include "params/ArmTLB.hh"
63 #include "sim/full_system.hh"
64 #include "sim/process.hh"
67 using namespace ArmISA
;
69 TLB::TLB(const Params
*p
)
70 : BaseTLB(p
), size(p
->size
) , tableWalker(p
->walker
),
71 rangeMRU(1), bootUncacheability(false), miscRegValid(false)
73 table
= new TlbEntry
[size
];
74 memset(table
, 0, sizeof(TlbEntry
) * size
);
76 tableWalker
->setTlb(this);
86 TLB::translateFunctional(ThreadContext
*tc
, Addr va
, Addr
&pa
)
90 TlbEntry
*e
= lookup(va
, contextId
, true);
98 TLB::lookup(Addr va
, uint8_t cid
, bool functional
)
101 TlbEntry
*retval
= NULL
;
103 // Maitaining LRU array
106 while (retval
== NULL
&& x
< size
) {
107 if (table
[x
].match(va
, cid
)) {
109 // We only move the hit entry ahead when the position is higher than rangeMRU
110 if (x
> rangeMRU
&& !functional
) {
111 TlbEntry tmp_entry
= table
[x
];
112 for(int i
= x
; i
> 0; i
--)
113 table
[i
] = table
[i
-1];
114 table
[0] = tmp_entry
;
124 DPRINTF(TLBVerbose
, "Lookup %#x, cid %#x -> %s ppn %#x size: %#x pa: %#x ap:%d\n",
125 va
, cid
, retval
? "hit" : "miss", retval
? retval
->pfn
: 0,
126 retval
? retval
->size
: 0, retval
? retval
->pAddr(va
) : 0,
127 retval
? retval
->ap
: 0);
132 // insert a new TLB entry
134 TLB::insert(Addr addr
, TlbEntry
&entry
)
136 DPRINTF(TLB
, "Inserting entry into TLB with pfn:%#x size:%#x vpn: %#x"
137 " asid:%d N:%d global:%d valid:%d nc:%d sNp:%d xn:%d ap:%#x"
138 " domain:%#x\n", entry
.pfn
, entry
.size
, entry
.vpn
, entry
.asid
,
139 entry
.N
, entry
.global
, entry
.valid
, entry
.nonCacheable
, entry
.sNp
,
140 entry
.xn
, entry
.ap
, entry
.domain
);
142 if (table
[size
-1].valid
)
143 DPRINTF(TLB
, " - Replacing Valid entry %#x, asn %d ppn %#x size: %#x ap:%d\n",
144 table
[size
-1].vpn
<< table
[size
-1].N
, table
[size
-1].asid
,
145 table
[size
-1].pfn
<< table
[size
-1].N
, table
[size
-1].size
,
148 //inserting to MRU position and evicting the LRU one
150 for(int i
= size
-1; i
> 0; i
--)
151 table
[i
] = table
[i
-1];
162 DPRINTF(TLB
, "Current TLB contents:\n");
166 DPRINTF(TLB
, " * %#x, asn %d ppn %#x size: %#x ap:%d\n",
167 te
->vpn
<< te
->N
, te
->asid
, te
->pfn
<< te
->N
, te
->size
, te
->ap
);
176 DPRINTF(TLB
, "Flushing all TLB entries\n");
182 DPRINTF(TLB
, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
183 te
->vpn
<< te
->N
, te
->asid
, te
->pfn
<< te
->N
, te
->size
, te
->ap
);
189 memset(table
, 0, sizeof(TlbEntry
) * size
);
196 TLB::flushMvaAsid(Addr mva
, uint64_t asn
)
198 DPRINTF(TLB
, "Flushing mva %#x asid: %#x\n", mva
, asn
);
201 te
= lookup(mva
, asn
);
203 DPRINTF(TLB
, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
204 te
->vpn
<< te
->N
, te
->asid
, te
->pfn
<< te
->N
, te
->size
, te
->ap
);
207 te
= lookup(mva
,asn
);
213 TLB::flushAsid(uint64_t asn
)
215 DPRINTF(TLB
, "Flushing all entries with asid: %#x\n", asn
);
222 if (te
->asid
== asn
) {
224 DPRINTF(TLB
, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
225 te
->vpn
<< te
->N
, te
->asid
, te
->pfn
<< te
->N
, te
->size
, te
->ap
);
234 TLB::flushMva(Addr mva
)
236 DPRINTF(TLB
, "Flushing all entries with mva: %#x\n", mva
);
243 Addr v
= te
->vpn
<< te
->N
;
244 if (mva
>= v
&& mva
< v
+ te
->size
) {
246 DPRINTF(TLB
, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
247 te
->vpn
<< te
->N
, te
->asid
, te
->pfn
<< te
->N
, te
->size
, te
->ap
);
258 // We might have unserialized something or switched CPUs, so make
259 // sure to re-read the misc regs.
260 miscRegValid
= false;
264 TLB::serialize(ostream
&os
)
266 DPRINTF(Checkpoint
, "Serializing Arm TLB\n");
268 SERIALIZE_SCALAR(_attr
);
270 int num_entries
= size
;
271 SERIALIZE_SCALAR(num_entries
);
272 for(int i
= 0; i
< size
; i
++){
273 nameOut(os
, csprintf("%s.TlbEntry%d", name(), i
));
274 table
[i
].serialize(os
);
279 TLB::unserialize(Checkpoint
*cp
, const string
§ion
)
281 DPRINTF(Checkpoint
, "Unserializing Arm TLB\n");
283 UNSERIALIZE_SCALAR(_attr
);
285 UNSERIALIZE_SCALAR(num_entries
);
286 for(int i
= 0; i
< min(size
, num_entries
); i
++){
287 table
[i
].unserialize(cp
, csprintf("%s.TlbEntry%d", section
, i
));
295 .name(name() + ".inst_hits")
296 .desc("ITB inst hits")
300 .name(name() + ".inst_misses")
301 .desc("ITB inst misses")
305 .name(name() + ".inst_accesses")
306 .desc("ITB inst accesses")
310 .name(name() + ".read_hits")
311 .desc("DTB read hits")
315 .name(name() + ".read_misses")
316 .desc("DTB read misses")
320 .name(name() + ".read_accesses")
321 .desc("DTB read accesses")
325 .name(name() + ".write_hits")
326 .desc("DTB write hits")
330 .name(name() + ".write_misses")
331 .desc("DTB write misses")
335 .name(name() + ".write_accesses")
336 .desc("DTB write accesses")
340 .name(name() + ".hits")
345 .name(name() + ".misses")
350 .name(name() + ".accesses")
351 .desc("DTB accesses")
355 .name(name() + ".flush_tlb")
356 .desc("Number of times complete TLB was flushed")
360 .name(name() + ".flush_tlb_mva")
361 .desc("Number of times TLB was flushed by MVA")
365 .name(name() + ".flush_tlb_mva_asid")
366 .desc("Number of times TLB was flushed by MVA & ASID")
370 .name(name() + ".flush_tlb_asid")
371 .desc("Number of times TLB was flushed by ASID")
375 .name(name() + ".flush_entries")
376 .desc("Number of entries that have been flushed from TLB")
380 .name(name() + ".align_faults")
381 .desc("Number of TLB faults due to alignment restrictions")
385 .name(name() + ".prefetch_faults")
386 .desc("Number of TLB faults due to prefetch")
390 .name(name() + ".domain_faults")
391 .desc("Number of TLB faults due to domain restrictions")
395 .name(name() + ".perms_faults")
396 .desc("Number of TLB faults due to permissions restrictions")
399 instAccesses
= instHits
+ instMisses
;
400 readAccesses
= readHits
+ readMisses
;
401 writeAccesses
= writeHits
+ writeMisses
;
402 hits
= readHits
+ writeHits
+ instHits
;
403 misses
= readMisses
+ writeMisses
+ instMisses
;
404 accesses
= readAccesses
+ writeAccesses
+ instAccesses
;
408 TLB::translateSe(RequestPtr req
, ThreadContext
*tc
, Mode mode
,
409 Translation
*translation
, bool &delay
, bool timing
)
413 Addr vaddr
= req
->getVaddr();
414 uint32_t flags
= req
->getFlags();
416 bool is_fetch
= (mode
== Execute
);
417 bool is_write
= (mode
== Write
);
420 assert(flags
& MustBeOne
);
421 if (sctlr
.a
|| !(flags
& AllowUnaligned
)) {
422 if (vaddr
& flags
& AlignmentMask
) {
423 return new DataAbort(vaddr
, 0, is_write
, ArmFault::AlignmentFault
);
429 Process
*p
= tc
->getProcessPtr();
431 if (!p
->pTable
->translate(vaddr
, paddr
))
432 return Fault(new GenericPageTableFault(vaddr
));
433 req
->setPaddr(paddr
);
439 TLB::trickBoxCheck(RequestPtr req
, Mode mode
, uint8_t domain
, bool sNp
)
445 TLB::walkTrickBoxCheck(Addr pa
, Addr va
, Addr sz
, bool is_exec
,
446 bool is_write
, uint8_t domain
, bool sNp
)
452 TLB::translateFs(RequestPtr req
, ThreadContext
*tc
, Mode mode
,
453 Translation
*translation
, bool &delay
, bool timing
, bool functional
)
455 // No such thing as a functional timing access
456 assert(!(timing
&& functional
));
460 DPRINTF(TLBVerbose
, "TLB variables changed!\n");
463 Addr vaddr
= req
->getVaddr();
464 uint32_t flags
= req
->getFlags();
466 bool is_fetch
= (mode
== Execute
);
467 bool is_write
= (mode
== Write
);
468 bool is_priv
= isPriv
&& !(flags
& UserMode
);
470 req
->setAsid(contextId
.asid
);
472 DPRINTF(TLBVerbose
, "CPSR is priv:%d UserMode:%d\n",
473 isPriv
, flags
& UserMode
);
474 // If this is a clrex instruction, provide a PA of 0 with no fault
475 // This will force the monitor to set the tracked address to 0
476 // a bit of a hack but this effectively clrears this processors monitor
477 if (flags
& Request::CLEAR_LL
){
479 req
->setFlags(Request::UNCACHEABLE
);
480 req
->setFlags(Request::CLEAR_LL
);
483 if ((req
->isInstFetch() && (!sctlr
.i
)) ||
484 ((!req
->isInstFetch()) && (!sctlr
.c
))){
485 req
->setFlags(Request::UNCACHEABLE
);
488 assert(flags
& MustBeOne
);
489 if (sctlr
.a
|| !(flags
& AllowUnaligned
)) {
490 if (vaddr
& flags
& AlignmentMask
) {
492 return new DataAbort(vaddr
, 0, is_write
, ArmFault::AlignmentFault
);
500 req
->setPaddr(vaddr
);
501 if (sctlr
.tre
== 0) {
502 req
->setFlags(Request::UNCACHEABLE
);
504 if (nmrr
.ir0
== 0 || nmrr
.or0
== 0 || prrr
.tr0
!= 0x2)
505 req
->setFlags(Request::UNCACHEABLE
);
508 // Set memory attributes
510 tableWalker
->memAttrs(tc
, temp_te
, sctlr
, 0, 1);
511 temp_te
.shareable
= true;
512 DPRINTF(TLBVerbose
, "(No MMU) setting memory attributes: shareable:\
513 %d, innerAttrs: %d, outerAttrs: %d\n", temp_te
.shareable
,
514 temp_te
.innerAttrs
, temp_te
.outerAttrs
);
515 setAttr(temp_te
.attributes
);
517 return trickBoxCheck(req
, mode
, 0, false);
520 DPRINTF(TLBVerbose
, "Translating vaddr=%#x context=%d\n", vaddr
, contextId
);
521 // Translation enabled
523 TlbEntry
*te
= lookup(vaddr
, contextId
);
525 if (req
->isPrefetch()){
526 //if the request is a prefetch don't attempt to fill the TLB
527 //or go any further with the memory access
529 return new PrefetchAbort(vaddr
, ArmFault::PrefetchTLBMiss
);
539 // start translation table walk, pass variables rather than
540 // re-retreaving in table walker for speed
541 DPRINTF(TLB
, "TLB Miss: Starting hardware table walker for %#x(%d)\n",
543 fault
= tableWalker
->walk(req
, tc
, contextId
, mode
, translation
,
545 if (timing
&& fault
== NoFault
) {
547 // for timing mode, return and wait for table walk
553 te
= lookup(vaddr
, contextId
);
566 // Set memory attributes
568 "Setting memory attributes: shareable: %d, innerAttrs: %d, \
570 te
->shareable
, te
->innerAttrs
, te
->outerAttrs
);
571 setAttr(te
->attributes
);
572 if (te
->nonCacheable
) {
573 req
->setFlags(Request::UNCACHEABLE
);
575 // Prevent prefetching from I/O devices.
576 if (req
->isPrefetch()) {
577 return new PrefetchAbort(vaddr
, ArmFault::PrefetchUncacheable
);
581 if (!bootUncacheability
&&
582 ((ArmSystem
*)tc
->getSystemPtr())->adderBootUncacheable(vaddr
))
583 req
->setFlags(Request::UNCACHEABLE
);
585 switch ( (dacr
>> (te
->domain
* 2)) & 0x3) {
588 DPRINTF(TLB
, "TLB Fault: Data abort on domain. DACR: %#x domain: %#x"
589 " write:%d sNp:%d\n", dacr
, te
->domain
, is_write
, te
->sNp
);
591 return new PrefetchAbort(vaddr
,
592 (te
->sNp
? ArmFault::Domain0
: ArmFault::Domain1
));
594 return new DataAbort(vaddr
, te
->domain
, is_write
,
595 (te
->sNp
? ArmFault::Domain0
: ArmFault::Domain1
));
597 // Continue with permissions check
600 panic("UNPRED domain\n");
602 req
->setPaddr(te
->pAddr(vaddr
));
603 fault
= trickBoxCheck(req
, mode
, te
->domain
, te
->sNp
);
621 DPRINTF(TLB
, "Access permissions 0, checking rs:%#x\n", (int)sctlr
.rs
);
623 switch ((int)sctlr
.rs
) {
628 abt
= is_write
|| !is_priv
;
644 abt
= !is_priv
&& is_write
;
650 panic("UNPRED premissions\n");
652 abt
= !is_priv
|| is_write
;
659 panic("Unknown permissions\n");
661 if ((is_fetch
) && (abt
|| te
->xn
)) {
663 DPRINTF(TLB
, "TLB Fault: Prefetch abort on permission check. AP:%d priv:%d"
664 " write:%d sNp:%d\n", ap
, is_priv
, is_write
, te
->sNp
);
665 return new PrefetchAbort(vaddr
,
666 (te
->sNp
? ArmFault::Permission0
:
667 ArmFault::Permission1
));
670 DPRINTF(TLB
, "TLB Fault: Data abort on permission check. AP:%d priv:%d"
671 " write:%d sNp:%d\n", ap
, is_priv
, is_write
, te
->sNp
);
672 return new DataAbort(vaddr
, te
->domain
, is_write
,
673 (te
->sNp
? ArmFault::Permission0
:
674 ArmFault::Permission1
));
677 req
->setPaddr(te
->pAddr(vaddr
));
678 // Check for a trickbox generated address fault
679 fault
= trickBoxCheck(req
, mode
, te
->domain
, te
->sNp
);
687 TLB::translateAtomic(RequestPtr req
, ThreadContext
*tc
, Mode mode
)
692 fault
= translateFs(req
, tc
, mode
, NULL
, delay
, false);
694 fault
= translateSe(req
, tc
, mode
, NULL
, delay
, false);
700 TLB::translateFunctional(RequestPtr req
, ThreadContext
*tc
, Mode mode
)
705 fault
= translateFs(req
, tc
, mode
, NULL
, delay
, false, true);
707 fault
= translateSe(req
, tc
, mode
, NULL
, delay
, false);
713 TLB::translateTiming(RequestPtr req
, ThreadContext
*tc
,
714 Translation
*translation
, Mode mode
)
720 fault
= translateFs(req
, tc
, mode
, translation
, delay
, true);
722 fault
= translateSe(req
, tc
, mode
, translation
, delay
, true);
723 DPRINTF(TLBVerbose
, "Translation returning delay=%d fault=%d\n", delay
, fault
!=
726 translation
->finish(fault
, req
, tc
, mode
);
728 translation
->markDelayed();
735 return &tableWalker
->getMasterPort("port");
741 ArmTLBParams::create()
743 return new ArmISA::TLB(this);