tlb.cc (7781:a9f9eed35b18) tlb.cc (7850:02450f4443ce)
1/*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
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.
13 *
14 * Copyright (c) 2001-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
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.
27 *
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.
39 *
40 * Authors: Ali Saidi
41 * Nathan Binkert
42 * Steve Reinhardt
43 */
44
45#include <string>
46#include <vector>
47
48#include "arch/arm/faults.hh"
49#include "arch/arm/pagetable.hh"
50#include "arch/arm/tlb.hh"
51#include "arch/arm/utility.hh"
52#include "base/inifile.hh"
53#include "base/str.hh"
54#include "base/trace.hh"
55#include "cpu/thread_context.hh"
56#include "mem/page_table.hh"
57#include "params/ArmTLB.hh"
58#include "sim/process.hh"
59
60#if FULL_SYSTEM
61#include "arch/arm/table_walker.hh"
62#endif
63
64using namespace std;
65using namespace ArmISA;
66
67TLB::TLB(const Params *p)
68 : BaseTLB(p), size(p->size)
69#if FULL_SYSTEM
70 , tableWalker(p->walker)
71#endif
72 , rangeMRU(1), miscRegValid(false)
73{
74 table = new TlbEntry[size];
75 memset(table, 0, sizeof(TlbEntry[size]));
76
77#if FULL_SYSTEM
78 tableWalker->setTlb(this);
79#endif
80}
81
82TLB::~TLB()
83{
84 if (table)
85 delete [] table;
86}
87
88bool
89TLB::translateFunctional(ThreadContext *tc, Addr va, Addr &pa)
90{
91 if (!miscRegValid)
92 updateMiscReg(tc);
93 TlbEntry *e = lookup(va, contextId, true);
94 if (!e)
95 return false;
96 pa = e->pAddr(va);
97 return true;
98}
99
100TlbEntry*
101TLB::lookup(Addr va, uint8_t cid, bool functional)
102{
103
104 TlbEntry *retval = NULL;
105
106 // Maitaining LRU array
107
108 int x = 0;
109 while (retval == NULL && x < size) {
110 if (table[x].match(va, cid)) {
111
112 // We only move the hit entry ahead when the position is higher than rangeMRU
113 if (x > rangeMRU) {
114 TlbEntry tmp_entry = table[x];
115 for(int i = x; i > 0; i--)
116 table[i] = table[i-1];
117 table[0] = tmp_entry;
118 retval = &table[0];
119 } else {
120 retval = &table[x];
121 }
122 break;
123 }
124 x++;
125 }
126
127 DPRINTF(TLBVerbose, "Lookup %#x, cid %#x -> %s ppn %#x size: %#x pa: %#x ap:%d\n",
128 va, cid, retval ? "hit" : "miss", retval ? retval->pfn : 0,
129 retval ? retval->size : 0, retval ? retval->pAddr(va) : 0,
130 retval ? retval->ap : 0);
131 ;
132 return retval;
133}
134
135// insert a new TLB entry
136void
137TLB::insert(Addr addr, TlbEntry &entry)
138{
139 DPRINTF(TLB, "Inserting entry into TLB with pfn:%#x size:%#x vpn: %#x"
140 " asid:%d N:%d global:%d valid:%d nc:%d sNp:%d xn:%d ap:%#x"
141 " domain:%#x\n", entry.pfn, entry.size, entry.vpn, entry.asid,
142 entry.N, entry.global, entry.valid, entry.nonCacheable, entry.sNp,
143 entry.xn, entry.ap, entry.domain);
144
145 if (table[size-1].valid)
146 DPRINTF(TLB, " - Replacing Valid entry %#x, asn %d ppn %#x size: %#x ap:%d\n",
147 table[size-1].vpn << table[size-1].N, table[size-1].asid,
148 table[size-1].pfn << table[size-1].N, table[size-1].size,
149 table[size-1].ap);
150
151 //inserting to MRU position and evicting the LRU one
152
153 for(int i = size-1; i > 0; i--)
154 table[i] = table[i-1];
155 table[0] = entry;
156
157 inserts++;
158}
159
160void
161TLB::printTlb()
162{
163 int x = 0;
164 TlbEntry *te;
165 DPRINTF(TLB, "Current TLB contents:\n");
166 while (x < size) {
167 te = &table[x];
168 if (te->valid)
169 DPRINTF(TLB, " * %#x, asn %d ppn %#x size: %#x ap:%d\n",
170 te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
171 x++;
172 }
173}
174
175
176void
177TLB::flushAll()
178{
179 DPRINTF(TLB, "Flushing all TLB entries\n");
180 int x = 0;
181 TlbEntry *te;
182 while (x < size) {
183 te = &table[x];
184 if (te->valid) {
185 DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
186 te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
187 flushedEntries++;
188 }
189 x++;
190 }
191
192 memset(table, 0, sizeof(TlbEntry[size]));
193
194 flushTlb++;
195}
196
197
198void
199TLB::flushMvaAsid(Addr mva, uint64_t asn)
200{
201 DPRINTF(TLB, "Flushing mva %#x asid: %#x\n", mva, asn);
202 TlbEntry *te;
203
204 te = lookup(mva, asn);
205 while (te != NULL) {
206 DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
207 te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
208 te->valid = false;
209 flushedEntries++;
210 te = lookup(mva,asn);
211 }
212 flushTlbMvaAsid++;
213}
214
215void
216TLB::flushAsid(uint64_t asn)
217{
218 DPRINTF(TLB, "Flushing all entries with asid: %#x\n", asn);
219
220 int x = 0;
221 TlbEntry *te;
222
223 while (x < size) {
224 te = &table[x];
225 if (te->asid == asn) {
226 te->valid = false;
227 DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
228 te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
229 flushedEntries++;
230 }
231 x++;
232 }
233 flushTlbAsid++;
234}
235
236void
237TLB::flushMva(Addr mva)
238{
239 DPRINTF(TLB, "Flushing all entries with mva: %#x\n", mva);
240
241 int x = 0;
242 TlbEntry *te;
243
244 while (x < size) {
245 te = &table[x];
246 Addr v = te->vpn << te->N;
247 if (mva >= v && mva < v + te->size) {
248 te->valid = false;
249 DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
250 te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
251 flushedEntries++;
252 }
253 x++;
254 }
255 flushTlbMva++;
256}
257
258void
259TLB::serialize(ostream &os)
260{
261 DPRINTF(Checkpoint, "Serializing Arm TLB\n");
262
263 SERIALIZE_SCALAR(_attr);
264 for(int i = 0; i < size; i++){
265 nameOut(os, csprintf("%s.TlbEntry%d", name(), i));
266 table[i].serialize(os);
267 }
268}
269
270void
271TLB::unserialize(Checkpoint *cp, const string &section)
272{
273 DPRINTF(Checkpoint, "Unserializing Arm TLB\n");
274
275 UNSERIALIZE_SCALAR(_attr);
276 for(int i = 0; i < size; i++){
277 table[i].unserialize(cp, csprintf("%s.TlbEntry%d", section, i));
278 }
279 miscRegValid = false;
280}
281
282void
283TLB::regStats()
284{
285 instHits
286 .name(name() + ".inst_hits")
287 .desc("ITB inst hits")
288 ;
289
290 instMisses
291 .name(name() + ".inst_misses")
292 .desc("ITB inst misses")
293 ;
294
295 instAccesses
296 .name(name() + ".inst_accesses")
297 .desc("ITB inst accesses")
298 ;
299
300 readHits
301 .name(name() + ".read_hits")
302 .desc("DTB read hits")
303 ;
304
305 readMisses
306 .name(name() + ".read_misses")
307 .desc("DTB read misses")
308 ;
309
310 readAccesses
311 .name(name() + ".read_accesses")
312 .desc("DTB read accesses")
313 ;
314
315 writeHits
316 .name(name() + ".write_hits")
317 .desc("DTB write hits")
318 ;
319
320 writeMisses
321 .name(name() + ".write_misses")
322 .desc("DTB write misses")
323 ;
324
325 writeAccesses
326 .name(name() + ".write_accesses")
327 .desc("DTB write accesses")
328 ;
329
330 hits
331 .name(name() + ".hits")
332 .desc("DTB hits")
333 ;
334
335 misses
336 .name(name() + ".misses")
337 .desc("DTB misses")
338 ;
339
340 accesses
341 .name(name() + ".accesses")
342 .desc("DTB accesses")
343 ;
344
345 flushTlb
346 .name(name() + ".flush_tlb")
347 .desc("Number of times complete TLB was flushed")
348 ;
349
350 flushTlbMva
351 .name(name() + ".flush_tlb_mva")
352 .desc("Number of times TLB was flushed by MVA")
353 ;
354
355 flushTlbMvaAsid
356 .name(name() + ".flush_tlb_mva_asid")
357 .desc("Number of times TLB was flushed by MVA & ASID")
358 ;
359
360 flushTlbAsid
361 .name(name() + ".flush_tlb_asid")
362 .desc("Number of times TLB was flushed by ASID")
363 ;
364
365 flushedEntries
366 .name(name() + ".flush_entries")
367 .desc("Number of entries that have been flushed from TLB")
368 ;
369
370 alignFaults
371 .name(name() + ".align_faults")
372 .desc("Number of TLB faults due to alignment restrictions")
373 ;
374
375 prefetchFaults
376 .name(name() + ".prefetch_faults")
377 .desc("Number of TLB faults due to prefetch")
378 ;
379
380 domainFaults
381 .name(name() + ".domain_faults")
382 .desc("Number of TLB faults due to domain restrictions")
383 ;
384
385 permsFaults
386 .name(name() + ".perms_faults")
387 .desc("Number of TLB faults due to permissions restrictions")
388 ;
389
390 instAccesses = instHits + instMisses;
391 readAccesses = readHits + readMisses;
392 writeAccesses = writeHits + writeMisses;
393 hits = readHits + writeHits + instHits;
394 misses = readMisses + writeMisses + instMisses;
395 accesses = readAccesses + writeAccesses + instAccesses;
396}
397
398#if !FULL_SYSTEM
399Fault
400TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
401 Translation *translation, bool &delay, bool timing)
402{
403 if (!miscRegValid)
404 updateMiscReg(tc);
405 Addr vaddr = req->getVaddr();
406 uint32_t flags = req->getFlags();
407
408 bool is_fetch = (mode == Execute);
409 bool is_write = (mode == Write);
410
411 if (!is_fetch) {
412 assert(flags & MustBeOne);
413 if (sctlr.a || !(flags & AllowUnaligned)) {
414 if (vaddr & flags & AlignmentMask) {
415 return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
416 }
417 }
418 }
419
420 Addr paddr;
421 Process *p = tc->getProcessPtr();
422
423 if (!p->pTable->translate(vaddr, paddr))
424 return Fault(new GenericPageTableFault(vaddr));
425 req->setPaddr(paddr);
426
427 return NoFault;
428}
429
430#else // FULL_SYSTEM
431
432Fault
433TLB::trickBoxCheck(RequestPtr req, Mode mode, uint8_t domain, bool sNp)
434{
435 return NoFault;
436}
437
438Fault
439TLB::walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec,
440 bool is_write, uint8_t domain, bool sNp)
441{
442 return NoFault;
443}
444
445Fault
446TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
447 Translation *translation, bool &delay, bool timing)
448{
449 if (!miscRegValid)
450 updateMiscReg(tc);
451
452 Addr vaddr = req->getVaddr();
453 uint32_t flags = req->getFlags();
454
455 bool is_fetch = (mode == Execute);
456 bool is_write = (mode == Write);
457 bool is_priv = isPriv && !(flags & UserMode);
458
459 DPRINTF(TLBVerbose, "CPSR is user:%d UserMode:%d\n",
460 isPriv, flags & UserMode);
461 // If this is a clrex instruction, provide a PA of 0 with no fault
462 // This will force the monitor to set the tracked address to 0
463 // a bit of a hack but this effectively clrears this processors monitor
464 if (flags & Request::CLEAR_LL){
465 req->setPaddr(0);
466 req->setFlags(Request::UNCACHEABLE);
467 req->setFlags(Request::CLEAR_LL);
468 return NoFault;
469 }
470 if ((req->isInstFetch() && (!sctlr.i)) ||
471 ((!req->isInstFetch()) && (!sctlr.c))){
472 req->setFlags(Request::UNCACHEABLE);
473 }
474 if (!is_fetch) {
475 assert(flags & MustBeOne);
476 if (sctlr.a || !(flags & AllowUnaligned)) {
477 if (vaddr & flags & AlignmentMask) {
478 alignFaults++;
479 return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
480 }
481 }
482 }
483
484 Fault fault;
485
486 if (!sctlr.m) {
487 req->setPaddr(vaddr);
488 if (sctlr.tre == 0) {
489 req->setFlags(Request::UNCACHEABLE);
490 } else {
491 if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
492 req->setFlags(Request::UNCACHEABLE);
493 }
494
495 // Set memory attributes
496 TlbEntry temp_te;
497 tableWalker->memAttrs(tc, temp_te, sctlr, 0, 1);
498 temp_te.shareable = true;
499 DPRINTF(TLBVerbose, "(No MMU) setting memory attributes: shareable:\
500 %d, innerAttrs: %d, outerAttrs: %d\n", temp_te.shareable,
501 temp_te.innerAttrs, temp_te.outerAttrs);
502 setAttr(temp_te.attributes);
503
504 return trickBoxCheck(req, mode, 0, false);
505 }
506
507 DPRINTF(TLBVerbose, "Translating vaddr=%#x context=%d\n", vaddr, contextId);
508 // Translation enabled
509
510 TlbEntry *te = lookup(vaddr, contextId);
511 if (te == NULL) {
512 if (req->isPrefetch()){
513 //if the request is a prefetch don't attempt to fill the TLB
514 //or go any further with the memory access
515 prefetchFaults++;
516 return new PrefetchAbort(vaddr, ArmFault::PrefetchTLBMiss);
517 }
518
519 if (is_fetch)
520 instMisses++;
521 else if (is_write)
522 writeMisses++;
523 else
524 readMisses++;
525
526 // start translation table walk, pass variables rather than
527 // re-retreaving in table walker for speed
528 DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d)\n",
529 vaddr, contextId);
530 fault = tableWalker->walk(req, tc, contextId, mode, translation,
531 timing);
532 if (timing) {
533 delay = true;
534 // for timing mode, return and wait for table walk
535 return fault;
536 }
537 if (fault)
538 return fault;
539
540 te = lookup(vaddr, contextId);
541 if (!te)
542 printTlb();
543 assert(te);
544 } else {
545 if (is_fetch)
546 instHits++;
547 else if (is_write)
548 writeHits++;
549 else
550 readHits++;
551 }
552
553 // Set memory attributes
554 DPRINTF(TLBVerbose,
555 "Setting memory attributes: shareable: %d, innerAttrs: %d, \
556 outerAttrs: %d\n",
557 te->shareable, te->innerAttrs, te->outerAttrs);
558 setAttr(te->attributes);
1/*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
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.
13 *
14 * Copyright (c) 2001-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
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.
27 *
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.
39 *
40 * Authors: Ali Saidi
41 * Nathan Binkert
42 * Steve Reinhardt
43 */
44
45#include <string>
46#include <vector>
47
48#include "arch/arm/faults.hh"
49#include "arch/arm/pagetable.hh"
50#include "arch/arm/tlb.hh"
51#include "arch/arm/utility.hh"
52#include "base/inifile.hh"
53#include "base/str.hh"
54#include "base/trace.hh"
55#include "cpu/thread_context.hh"
56#include "mem/page_table.hh"
57#include "params/ArmTLB.hh"
58#include "sim/process.hh"
59
60#if FULL_SYSTEM
61#include "arch/arm/table_walker.hh"
62#endif
63
64using namespace std;
65using namespace ArmISA;
66
67TLB::TLB(const Params *p)
68 : BaseTLB(p), size(p->size)
69#if FULL_SYSTEM
70 , tableWalker(p->walker)
71#endif
72 , rangeMRU(1), miscRegValid(false)
73{
74 table = new TlbEntry[size];
75 memset(table, 0, sizeof(TlbEntry[size]));
76
77#if FULL_SYSTEM
78 tableWalker->setTlb(this);
79#endif
80}
81
82TLB::~TLB()
83{
84 if (table)
85 delete [] table;
86}
87
88bool
89TLB::translateFunctional(ThreadContext *tc, Addr va, Addr &pa)
90{
91 if (!miscRegValid)
92 updateMiscReg(tc);
93 TlbEntry *e = lookup(va, contextId, true);
94 if (!e)
95 return false;
96 pa = e->pAddr(va);
97 return true;
98}
99
100TlbEntry*
101TLB::lookup(Addr va, uint8_t cid, bool functional)
102{
103
104 TlbEntry *retval = NULL;
105
106 // Maitaining LRU array
107
108 int x = 0;
109 while (retval == NULL && x < size) {
110 if (table[x].match(va, cid)) {
111
112 // We only move the hit entry ahead when the position is higher than rangeMRU
113 if (x > rangeMRU) {
114 TlbEntry tmp_entry = table[x];
115 for(int i = x; i > 0; i--)
116 table[i] = table[i-1];
117 table[0] = tmp_entry;
118 retval = &table[0];
119 } else {
120 retval = &table[x];
121 }
122 break;
123 }
124 x++;
125 }
126
127 DPRINTF(TLBVerbose, "Lookup %#x, cid %#x -> %s ppn %#x size: %#x pa: %#x ap:%d\n",
128 va, cid, retval ? "hit" : "miss", retval ? retval->pfn : 0,
129 retval ? retval->size : 0, retval ? retval->pAddr(va) : 0,
130 retval ? retval->ap : 0);
131 ;
132 return retval;
133}
134
135// insert a new TLB entry
136void
137TLB::insert(Addr addr, TlbEntry &entry)
138{
139 DPRINTF(TLB, "Inserting entry into TLB with pfn:%#x size:%#x vpn: %#x"
140 " asid:%d N:%d global:%d valid:%d nc:%d sNp:%d xn:%d ap:%#x"
141 " domain:%#x\n", entry.pfn, entry.size, entry.vpn, entry.asid,
142 entry.N, entry.global, entry.valid, entry.nonCacheable, entry.sNp,
143 entry.xn, entry.ap, entry.domain);
144
145 if (table[size-1].valid)
146 DPRINTF(TLB, " - Replacing Valid entry %#x, asn %d ppn %#x size: %#x ap:%d\n",
147 table[size-1].vpn << table[size-1].N, table[size-1].asid,
148 table[size-1].pfn << table[size-1].N, table[size-1].size,
149 table[size-1].ap);
150
151 //inserting to MRU position and evicting the LRU one
152
153 for(int i = size-1; i > 0; i--)
154 table[i] = table[i-1];
155 table[0] = entry;
156
157 inserts++;
158}
159
160void
161TLB::printTlb()
162{
163 int x = 0;
164 TlbEntry *te;
165 DPRINTF(TLB, "Current TLB contents:\n");
166 while (x < size) {
167 te = &table[x];
168 if (te->valid)
169 DPRINTF(TLB, " * %#x, asn %d ppn %#x size: %#x ap:%d\n",
170 te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
171 x++;
172 }
173}
174
175
176void
177TLB::flushAll()
178{
179 DPRINTF(TLB, "Flushing all TLB entries\n");
180 int x = 0;
181 TlbEntry *te;
182 while (x < size) {
183 te = &table[x];
184 if (te->valid) {
185 DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
186 te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
187 flushedEntries++;
188 }
189 x++;
190 }
191
192 memset(table, 0, sizeof(TlbEntry[size]));
193
194 flushTlb++;
195}
196
197
198void
199TLB::flushMvaAsid(Addr mva, uint64_t asn)
200{
201 DPRINTF(TLB, "Flushing mva %#x asid: %#x\n", mva, asn);
202 TlbEntry *te;
203
204 te = lookup(mva, asn);
205 while (te != NULL) {
206 DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
207 te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
208 te->valid = false;
209 flushedEntries++;
210 te = lookup(mva,asn);
211 }
212 flushTlbMvaAsid++;
213}
214
215void
216TLB::flushAsid(uint64_t asn)
217{
218 DPRINTF(TLB, "Flushing all entries with asid: %#x\n", asn);
219
220 int x = 0;
221 TlbEntry *te;
222
223 while (x < size) {
224 te = &table[x];
225 if (te->asid == asn) {
226 te->valid = false;
227 DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
228 te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
229 flushedEntries++;
230 }
231 x++;
232 }
233 flushTlbAsid++;
234}
235
236void
237TLB::flushMva(Addr mva)
238{
239 DPRINTF(TLB, "Flushing all entries with mva: %#x\n", mva);
240
241 int x = 0;
242 TlbEntry *te;
243
244 while (x < size) {
245 te = &table[x];
246 Addr v = te->vpn << te->N;
247 if (mva >= v && mva < v + te->size) {
248 te->valid = false;
249 DPRINTF(TLB, " - %#x, asn %d ppn %#x size: %#x ap:%d\n",
250 te->vpn << te->N, te->asid, te->pfn << te->N, te->size, te->ap);
251 flushedEntries++;
252 }
253 x++;
254 }
255 flushTlbMva++;
256}
257
258void
259TLB::serialize(ostream &os)
260{
261 DPRINTF(Checkpoint, "Serializing Arm TLB\n");
262
263 SERIALIZE_SCALAR(_attr);
264 for(int i = 0; i < size; i++){
265 nameOut(os, csprintf("%s.TlbEntry%d", name(), i));
266 table[i].serialize(os);
267 }
268}
269
270void
271TLB::unserialize(Checkpoint *cp, const string &section)
272{
273 DPRINTF(Checkpoint, "Unserializing Arm TLB\n");
274
275 UNSERIALIZE_SCALAR(_attr);
276 for(int i = 0; i < size; i++){
277 table[i].unserialize(cp, csprintf("%s.TlbEntry%d", section, i));
278 }
279 miscRegValid = false;
280}
281
282void
283TLB::regStats()
284{
285 instHits
286 .name(name() + ".inst_hits")
287 .desc("ITB inst hits")
288 ;
289
290 instMisses
291 .name(name() + ".inst_misses")
292 .desc("ITB inst misses")
293 ;
294
295 instAccesses
296 .name(name() + ".inst_accesses")
297 .desc("ITB inst accesses")
298 ;
299
300 readHits
301 .name(name() + ".read_hits")
302 .desc("DTB read hits")
303 ;
304
305 readMisses
306 .name(name() + ".read_misses")
307 .desc("DTB read misses")
308 ;
309
310 readAccesses
311 .name(name() + ".read_accesses")
312 .desc("DTB read accesses")
313 ;
314
315 writeHits
316 .name(name() + ".write_hits")
317 .desc("DTB write hits")
318 ;
319
320 writeMisses
321 .name(name() + ".write_misses")
322 .desc("DTB write misses")
323 ;
324
325 writeAccesses
326 .name(name() + ".write_accesses")
327 .desc("DTB write accesses")
328 ;
329
330 hits
331 .name(name() + ".hits")
332 .desc("DTB hits")
333 ;
334
335 misses
336 .name(name() + ".misses")
337 .desc("DTB misses")
338 ;
339
340 accesses
341 .name(name() + ".accesses")
342 .desc("DTB accesses")
343 ;
344
345 flushTlb
346 .name(name() + ".flush_tlb")
347 .desc("Number of times complete TLB was flushed")
348 ;
349
350 flushTlbMva
351 .name(name() + ".flush_tlb_mva")
352 .desc("Number of times TLB was flushed by MVA")
353 ;
354
355 flushTlbMvaAsid
356 .name(name() + ".flush_tlb_mva_asid")
357 .desc("Number of times TLB was flushed by MVA & ASID")
358 ;
359
360 flushTlbAsid
361 .name(name() + ".flush_tlb_asid")
362 .desc("Number of times TLB was flushed by ASID")
363 ;
364
365 flushedEntries
366 .name(name() + ".flush_entries")
367 .desc("Number of entries that have been flushed from TLB")
368 ;
369
370 alignFaults
371 .name(name() + ".align_faults")
372 .desc("Number of TLB faults due to alignment restrictions")
373 ;
374
375 prefetchFaults
376 .name(name() + ".prefetch_faults")
377 .desc("Number of TLB faults due to prefetch")
378 ;
379
380 domainFaults
381 .name(name() + ".domain_faults")
382 .desc("Number of TLB faults due to domain restrictions")
383 ;
384
385 permsFaults
386 .name(name() + ".perms_faults")
387 .desc("Number of TLB faults due to permissions restrictions")
388 ;
389
390 instAccesses = instHits + instMisses;
391 readAccesses = readHits + readMisses;
392 writeAccesses = writeHits + writeMisses;
393 hits = readHits + writeHits + instHits;
394 misses = readMisses + writeMisses + instMisses;
395 accesses = readAccesses + writeAccesses + instAccesses;
396}
397
398#if !FULL_SYSTEM
399Fault
400TLB::translateSe(RequestPtr req, ThreadContext *tc, Mode mode,
401 Translation *translation, bool &delay, bool timing)
402{
403 if (!miscRegValid)
404 updateMiscReg(tc);
405 Addr vaddr = req->getVaddr();
406 uint32_t flags = req->getFlags();
407
408 bool is_fetch = (mode == Execute);
409 bool is_write = (mode == Write);
410
411 if (!is_fetch) {
412 assert(flags & MustBeOne);
413 if (sctlr.a || !(flags & AllowUnaligned)) {
414 if (vaddr & flags & AlignmentMask) {
415 return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
416 }
417 }
418 }
419
420 Addr paddr;
421 Process *p = tc->getProcessPtr();
422
423 if (!p->pTable->translate(vaddr, paddr))
424 return Fault(new GenericPageTableFault(vaddr));
425 req->setPaddr(paddr);
426
427 return NoFault;
428}
429
430#else // FULL_SYSTEM
431
432Fault
433TLB::trickBoxCheck(RequestPtr req, Mode mode, uint8_t domain, bool sNp)
434{
435 return NoFault;
436}
437
438Fault
439TLB::walkTrickBoxCheck(Addr pa, Addr va, Addr sz, bool is_exec,
440 bool is_write, uint8_t domain, bool sNp)
441{
442 return NoFault;
443}
444
445Fault
446TLB::translateFs(RequestPtr req, ThreadContext *tc, Mode mode,
447 Translation *translation, bool &delay, bool timing)
448{
449 if (!miscRegValid)
450 updateMiscReg(tc);
451
452 Addr vaddr = req->getVaddr();
453 uint32_t flags = req->getFlags();
454
455 bool is_fetch = (mode == Execute);
456 bool is_write = (mode == Write);
457 bool is_priv = isPriv && !(flags & UserMode);
458
459 DPRINTF(TLBVerbose, "CPSR is user:%d UserMode:%d\n",
460 isPriv, flags & UserMode);
461 // If this is a clrex instruction, provide a PA of 0 with no fault
462 // This will force the monitor to set the tracked address to 0
463 // a bit of a hack but this effectively clrears this processors monitor
464 if (flags & Request::CLEAR_LL){
465 req->setPaddr(0);
466 req->setFlags(Request::UNCACHEABLE);
467 req->setFlags(Request::CLEAR_LL);
468 return NoFault;
469 }
470 if ((req->isInstFetch() && (!sctlr.i)) ||
471 ((!req->isInstFetch()) && (!sctlr.c))){
472 req->setFlags(Request::UNCACHEABLE);
473 }
474 if (!is_fetch) {
475 assert(flags & MustBeOne);
476 if (sctlr.a || !(flags & AllowUnaligned)) {
477 if (vaddr & flags & AlignmentMask) {
478 alignFaults++;
479 return new DataAbort(vaddr, 0, is_write, ArmFault::AlignmentFault);
480 }
481 }
482 }
483
484 Fault fault;
485
486 if (!sctlr.m) {
487 req->setPaddr(vaddr);
488 if (sctlr.tre == 0) {
489 req->setFlags(Request::UNCACHEABLE);
490 } else {
491 if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
492 req->setFlags(Request::UNCACHEABLE);
493 }
494
495 // Set memory attributes
496 TlbEntry temp_te;
497 tableWalker->memAttrs(tc, temp_te, sctlr, 0, 1);
498 temp_te.shareable = true;
499 DPRINTF(TLBVerbose, "(No MMU) setting memory attributes: shareable:\
500 %d, innerAttrs: %d, outerAttrs: %d\n", temp_te.shareable,
501 temp_te.innerAttrs, temp_te.outerAttrs);
502 setAttr(temp_te.attributes);
503
504 return trickBoxCheck(req, mode, 0, false);
505 }
506
507 DPRINTF(TLBVerbose, "Translating vaddr=%#x context=%d\n", vaddr, contextId);
508 // Translation enabled
509
510 TlbEntry *te = lookup(vaddr, contextId);
511 if (te == NULL) {
512 if (req->isPrefetch()){
513 //if the request is a prefetch don't attempt to fill the TLB
514 //or go any further with the memory access
515 prefetchFaults++;
516 return new PrefetchAbort(vaddr, ArmFault::PrefetchTLBMiss);
517 }
518
519 if (is_fetch)
520 instMisses++;
521 else if (is_write)
522 writeMisses++;
523 else
524 readMisses++;
525
526 // start translation table walk, pass variables rather than
527 // re-retreaving in table walker for speed
528 DPRINTF(TLB, "TLB Miss: Starting hardware table walker for %#x(%d)\n",
529 vaddr, contextId);
530 fault = tableWalker->walk(req, tc, contextId, mode, translation,
531 timing);
532 if (timing) {
533 delay = true;
534 // for timing mode, return and wait for table walk
535 return fault;
536 }
537 if (fault)
538 return fault;
539
540 te = lookup(vaddr, contextId);
541 if (!te)
542 printTlb();
543 assert(te);
544 } else {
545 if (is_fetch)
546 instHits++;
547 else if (is_write)
548 writeHits++;
549 else
550 readHits++;
551 }
552
553 // Set memory attributes
554 DPRINTF(TLBVerbose,
555 "Setting memory attributes: shareable: %d, innerAttrs: %d, \
556 outerAttrs: %d\n",
557 te->shareable, te->innerAttrs, te->outerAttrs);
558 setAttr(te->attributes);
559 if (te->nonCacheable)
559 if (te->nonCacheable) {
560 req->setFlags(Request::UNCACHEABLE);
561
560 req->setFlags(Request::UNCACHEABLE);
561
562 // Prevent prefetching from I/O devices.
563 if (req->isPrefetch()) {
564 return new PrefetchAbort(vaddr, ArmFault::PrefetchUncacheable);
565 }
566 }
567
562 switch ( (dacr >> (te->domain * 2)) & 0x3) {
563 case 0:
564 domainFaults++;
565 DPRINTF(TLB, "TLB Fault: Data abort on domain. DACR: %#x domain: %#x"
566 " write:%d sNp:%d\n", dacr, te->domain, is_write, te->sNp);
567 if (is_fetch)
568 return new PrefetchAbort(vaddr,
569 (te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
570 else
571 return new DataAbort(vaddr, te->domain, is_write,
572 (te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
573 case 1:
574 // Continue with permissions check
575 break;
576 case 2:
577 panic("UNPRED domain\n");
578 case 3:
579 req->setPaddr(te->pAddr(vaddr));
580 fault = trickBoxCheck(req, mode, te->domain, te->sNp);
581 if (fault)
582 return fault;
583 return NoFault;
584 }
585
586 uint8_t ap = te->ap;
587
588 if (sctlr.afe == 1)
589 ap |= 1;
590
591 bool abt;
592
593 /* if (!sctlr.xp)
594 ap &= 0x3;
595*/
596 switch (ap) {
597 case 0:
598 DPRINTF(TLB, "Access permissions 0, checking rs:%#x\n", (int)sctlr.rs);
599 if (!sctlr.xp) {
600 switch ((int)sctlr.rs) {
601 case 2:
602 abt = is_write;
603 break;
604 case 1:
605 abt = is_write || !is_priv;
606 break;
607 case 0:
608 case 3:
609 default:
610 abt = true;
611 break;
612 }
613 } else {
614 abt = true;
615 }
616 break;
617 case 1:
618 abt = !is_priv;
619 break;
620 case 2:
621 abt = !is_priv && is_write;
622 break;
623 case 3:
624 abt = false;
625 break;
626 case 4:
627 panic("UNPRED premissions\n");
628 case 5:
629 abt = !is_priv || is_write;
630 break;
631 case 6:
632 case 7:
633 abt = is_write;
634 break;
635 default:
636 panic("Unknown permissions\n");
637 }
638 if ((is_fetch) && (abt || te->xn)) {
639 permsFaults++;
640 DPRINTF(TLB, "TLB Fault: Prefetch abort on permission check. AP:%d priv:%d"
641 " write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
642 return new PrefetchAbort(vaddr,
643 (te->sNp ? ArmFault::Permission0 :
644 ArmFault::Permission1));
645 } else if (abt) {
646 permsFaults++;
647 DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d priv:%d"
648 " write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
649 return new DataAbort(vaddr, te->domain, is_write,
650 (te->sNp ? ArmFault::Permission0 :
651 ArmFault::Permission1));
652 }
653
654 req->setPaddr(te->pAddr(vaddr));
655 // Check for a trickbox generated address fault
656 fault = trickBoxCheck(req, mode, te->domain, te->sNp);
657 if (fault)
658 return fault;
659
660 return NoFault;
661}
662
663#endif
664
665Fault
666TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
667{
668 bool delay = false;
669 Fault fault;
670#if FULL_SYSTEM
671 fault = translateFs(req, tc, mode, NULL, delay, false);
672#else
673 fault = translateSe(req, tc, mode, NULL, delay, false);
674#endif
675 assert(!delay);
676 return fault;
677}
678
679Fault
680TLB::translateTiming(RequestPtr req, ThreadContext *tc,
681 Translation *translation, Mode mode)
682{
683 assert(translation);
684 bool delay = false;
685 Fault fault;
686#if FULL_SYSTEM
687 fault = translateFs(req, tc, mode, translation, delay, true);
688#else
689 fault = translateSe(req, tc, mode, translation, delay, true);
690#endif
691 if (!delay)
692 translation->finish(fault, req, tc, mode);
693 return fault;
694}
695
696Port*
697TLB::getPort()
698{
699#if FULL_SYSTEM
700 return tableWalker->getPort("port");
701#else
702 return NULL;
703#endif
704}
705
706
707
708ArmISA::TLB *
709ArmTLBParams::create()
710{
711 return new ArmISA::TLB(this);
712}
568 switch ( (dacr >> (te->domain * 2)) & 0x3) {
569 case 0:
570 domainFaults++;
571 DPRINTF(TLB, "TLB Fault: Data abort on domain. DACR: %#x domain: %#x"
572 " write:%d sNp:%d\n", dacr, te->domain, is_write, te->sNp);
573 if (is_fetch)
574 return new PrefetchAbort(vaddr,
575 (te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
576 else
577 return new DataAbort(vaddr, te->domain, is_write,
578 (te->sNp ? ArmFault::Domain0 : ArmFault::Domain1));
579 case 1:
580 // Continue with permissions check
581 break;
582 case 2:
583 panic("UNPRED domain\n");
584 case 3:
585 req->setPaddr(te->pAddr(vaddr));
586 fault = trickBoxCheck(req, mode, te->domain, te->sNp);
587 if (fault)
588 return fault;
589 return NoFault;
590 }
591
592 uint8_t ap = te->ap;
593
594 if (sctlr.afe == 1)
595 ap |= 1;
596
597 bool abt;
598
599 /* if (!sctlr.xp)
600 ap &= 0x3;
601*/
602 switch (ap) {
603 case 0:
604 DPRINTF(TLB, "Access permissions 0, checking rs:%#x\n", (int)sctlr.rs);
605 if (!sctlr.xp) {
606 switch ((int)sctlr.rs) {
607 case 2:
608 abt = is_write;
609 break;
610 case 1:
611 abt = is_write || !is_priv;
612 break;
613 case 0:
614 case 3:
615 default:
616 abt = true;
617 break;
618 }
619 } else {
620 abt = true;
621 }
622 break;
623 case 1:
624 abt = !is_priv;
625 break;
626 case 2:
627 abt = !is_priv && is_write;
628 break;
629 case 3:
630 abt = false;
631 break;
632 case 4:
633 panic("UNPRED premissions\n");
634 case 5:
635 abt = !is_priv || is_write;
636 break;
637 case 6:
638 case 7:
639 abt = is_write;
640 break;
641 default:
642 panic("Unknown permissions\n");
643 }
644 if ((is_fetch) && (abt || te->xn)) {
645 permsFaults++;
646 DPRINTF(TLB, "TLB Fault: Prefetch abort on permission check. AP:%d priv:%d"
647 " write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
648 return new PrefetchAbort(vaddr,
649 (te->sNp ? ArmFault::Permission0 :
650 ArmFault::Permission1));
651 } else if (abt) {
652 permsFaults++;
653 DPRINTF(TLB, "TLB Fault: Data abort on permission check. AP:%d priv:%d"
654 " write:%d sNp:%d\n", ap, is_priv, is_write, te->sNp);
655 return new DataAbort(vaddr, te->domain, is_write,
656 (te->sNp ? ArmFault::Permission0 :
657 ArmFault::Permission1));
658 }
659
660 req->setPaddr(te->pAddr(vaddr));
661 // Check for a trickbox generated address fault
662 fault = trickBoxCheck(req, mode, te->domain, te->sNp);
663 if (fault)
664 return fault;
665
666 return NoFault;
667}
668
669#endif
670
671Fault
672TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
673{
674 bool delay = false;
675 Fault fault;
676#if FULL_SYSTEM
677 fault = translateFs(req, tc, mode, NULL, delay, false);
678#else
679 fault = translateSe(req, tc, mode, NULL, delay, false);
680#endif
681 assert(!delay);
682 return fault;
683}
684
685Fault
686TLB::translateTiming(RequestPtr req, ThreadContext *tc,
687 Translation *translation, Mode mode)
688{
689 assert(translation);
690 bool delay = false;
691 Fault fault;
692#if FULL_SYSTEM
693 fault = translateFs(req, tc, mode, translation, delay, true);
694#else
695 fault = translateSe(req, tc, mode, translation, delay, true);
696#endif
697 if (!delay)
698 translation->finish(fault, req, tc, mode);
699 return fault;
700}
701
702Port*
703TLB::getPort()
704{
705#if FULL_SYSTEM
706 return tableWalker->getPort("port");
707#else
708 return NULL;
709#endif
710}
711
712
713
714ArmISA::TLB *
715ArmTLBParams::create()
716{
717 return new ArmISA::TLB(this);
718}