tlb.cc (7811:a8fc35183c10) tlb.cc (8105:906864dd0937)
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Ali Saidi
29 */
30
31#include <cstring>
32
33#include "arch/sparc/asi.hh"
34#include "arch/sparc/faults.hh"
35#include "arch/sparc/registers.hh"
36#include "arch/sparc/tlb.hh"
37#include "base/bitfield.hh"
38#include "base/trace.hh"
39#include "cpu/thread_context.hh"
40#include "cpu/base.hh"
41#include "mem/packet_access.hh"
42#include "mem/request.hh"
43#include "sim/system.hh"
44
45/* @todo remove some of the magic constants. -- ali
46 * */
47namespace SparcISA {
48
49TLB::TLB(const Params *p)
50 : BaseTLB(p), size(p->size), usedEntries(0), lastReplaced(0),
51 cacheValid(false)
52{
53 // To make this work you'll have to change the hypervisor and OS
54 if (size > 64)
55 fatal("SPARC T1 TLB registers don't support more than 64 TLB entries");
56
57 tlb = new TlbEntry[size];
58 std::memset(tlb, 0, sizeof(TlbEntry) * size);
59
60 for (int x = 0; x < size; x++)
61 freeList.push_back(&tlb[x]);
62
63 c0_tsb_ps0 = 0;
64 c0_tsb_ps1 = 0;
65 c0_config = 0;
66 cx_tsb_ps0 = 0;
67 cx_tsb_ps1 = 0;
68 cx_config = 0;
69 sfsr = 0;
70 tag_access = 0;
71 sfar = 0;
72 cacheEntry[0] = NULL;
73 cacheEntry[1] = NULL;
74}
75
76void
77TLB::clearUsedBits()
78{
79 MapIter i;
80 for (i = lookupTable.begin(); i != lookupTable.end(); i++) {
81 TlbEntry *t = i->second;
82 if (!t->pte.locked()) {
83 t->used = false;
84 usedEntries--;
85 }
86 }
87}
88
89
90void
91TLB::insert(Addr va, int partition_id, int context_id, bool real,
92 const PageTableEntry& PTE, int entry)
93{
94 MapIter i;
95 TlbEntry *new_entry = NULL;
96// TlbRange tr;
97 int x;
98
99 cacheValid = false;
100 va &= ~(PTE.size()-1);
101 /* tr.va = va;
102 tr.size = PTE.size() - 1;
103 tr.contextId = context_id;
104 tr.partitionId = partition_id;
105 tr.real = real;
106*/
107
108 DPRINTF(TLB,
109 "TLB: Inserting Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
110 va, PTE.paddr(), partition_id, context_id, (int)real, entry);
111
112 // Demap any entry that conflicts
113 for (x = 0; x < size; x++) {
114 if (tlb[x].range.real == real &&
115 tlb[x].range.partitionId == partition_id &&
116 tlb[x].range.va < va + PTE.size() - 1 &&
117 tlb[x].range.va + tlb[x].range.size >= va &&
118 (real || tlb[x].range.contextId == context_id ))
119 {
120 if (tlb[x].valid) {
121 freeList.push_front(&tlb[x]);
122 DPRINTF(TLB, "TLB: Conflicting entry %#X , deleting it\n", x);
123
124 tlb[x].valid = false;
125 if (tlb[x].used) {
126 tlb[x].used = false;
127 usedEntries--;
128 }
129 lookupTable.erase(tlb[x].range);
130 }
131 }
132 }
133
134 if (entry != -1) {
135 assert(entry < size && entry >= 0);
136 new_entry = &tlb[entry];
137 } else {
138 if (!freeList.empty()) {
139 new_entry = freeList.front();
140 } else {
141 x = lastReplaced;
142 do {
143 ++x;
144 if (x == size)
145 x = 0;
146 if (x == lastReplaced)
147 goto insertAllLocked;
148 } while (tlb[x].pte.locked());
149 lastReplaced = x;
150 new_entry = &tlb[x];
151 }
152 }
153
154insertAllLocked:
155 // Update the last ently if their all locked
156 if (!new_entry) {
157 new_entry = &tlb[size-1];
158 }
159
160 freeList.remove(new_entry);
161 if (new_entry->valid && new_entry->used)
162 usedEntries--;
163 if (new_entry->valid)
164 lookupTable.erase(new_entry->range);
165
166
167 assert(PTE.valid());
168 new_entry->range.va = va;
169 new_entry->range.size = PTE.size() - 1;
170 new_entry->range.partitionId = partition_id;
171 new_entry->range.contextId = context_id;
172 new_entry->range.real = real;
173 new_entry->pte = PTE;
174 new_entry->used = true;;
175 new_entry->valid = true;
176 usedEntries++;
177
178 i = lookupTable.insert(new_entry->range, new_entry);
179 assert(i != lookupTable.end());
180
181 // If all entries have their used bit set, clear it on them all,
182 // but the one we just inserted
183 if (usedEntries == size) {
184 clearUsedBits();
185 new_entry->used = true;
186 usedEntries++;
187 }
188}
189
190
191TlbEntry*
192TLB::lookup(Addr va, int partition_id, bool real, int context_id,
193 bool update_used)
194{
195 MapIter i;
196 TlbRange tr;
197 TlbEntry *t;
198
199 DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n",
200 va, partition_id, context_id, real);
201 // Assemble full address structure
202 tr.va = va;
203 tr.size = 1;
204 tr.contextId = context_id;
205 tr.partitionId = partition_id;
206 tr.real = real;
207
208 // Try to find the entry
209 i = lookupTable.find(tr);
210 if (i == lookupTable.end()) {
211 DPRINTF(TLB, "TLB: No valid entry found\n");
212 return NULL;
213 }
214
215 // Mark the entries used bit and clear other used bits in needed
216 t = i->second;
217 DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),
218 t->pte.size());
219
220 // Update the used bits only if this is a real access (not a fake
221 // one from virttophys()
222 if (!t->used && update_used) {
223 t->used = true;
224 usedEntries++;
225 if (usedEntries == size) {
226 clearUsedBits();
227 t->used = true;
228 usedEntries++;
229 }
230 }
231
232 return t;
233}
234
235void
236TLB::dumpAll()
237{
238 MapIter i;
239 for (int x = 0; x < size; x++) {
240 if (tlb[x].valid) {
241 DPRINTFN("%4d: %#2x:%#2x %c %#4x %#8x %#8x %#16x\n",
242 x, tlb[x].range.partitionId, tlb[x].range.contextId,
243 tlb[x].range.real ? 'R' : ' ', tlb[x].range.size,
244 tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte());
245 }
246 }
247}
248
249void
250TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
251{
252 TlbRange tr;
253 MapIter i;
254
255 DPRINTF(IPR, "TLB: Demapping Page va=%#x pid=%#d cid=%d r=%d\n",
256 va, partition_id, context_id, real);
257
258 cacheValid = false;
259
260 // Assemble full address structure
261 tr.va = va;
262 tr.size = 1;
263 tr.contextId = context_id;
264 tr.partitionId = partition_id;
265 tr.real = real;
266
267 // Demap any entry that conflicts
268 i = lookupTable.find(tr);
269 if (i != lookupTable.end()) {
270 DPRINTF(IPR, "TLB: Demapped page\n");
271 i->second->valid = false;
272 if (i->second->used) {
273 i->second->used = false;
274 usedEntries--;
275 }
276 freeList.push_front(i->second);
277 lookupTable.erase(i);
278 }
279}
280
281void
282TLB::demapContext(int partition_id, int context_id)
283{
284 DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",
285 partition_id, context_id);
286 cacheValid = false;
287 for (int x = 0; x < size; x++) {
288 if (tlb[x].range.contextId == context_id &&
289 tlb[x].range.partitionId == partition_id) {
290 if (tlb[x].valid == true) {
291 freeList.push_front(&tlb[x]);
292 }
293 tlb[x].valid = false;
294 if (tlb[x].used) {
295 tlb[x].used = false;
296 usedEntries--;
297 }
298 lookupTable.erase(tlb[x].range);
299 }
300 }
301}
302
303void
304TLB::demapAll(int partition_id)
305{
306 DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);
307 cacheValid = false;
308 for (int x = 0; x < size; x++) {
309 if (tlb[x].valid && !tlb[x].pte.locked() &&
310 tlb[x].range.partitionId == partition_id) {
311 freeList.push_front(&tlb[x]);
312 tlb[x].valid = false;
313 if (tlb[x].used) {
314 tlb[x].used = false;
315 usedEntries--;
316 }
317 lookupTable.erase(tlb[x].range);
318 }
319 }
320}
321
322void
323TLB::invalidateAll()
324{
325 cacheValid = false;
326 lookupTable.clear();
327
328 for (int x = 0; x < size; x++) {
329 if (tlb[x].valid == true)
330 freeList.push_back(&tlb[x]);
331 tlb[x].valid = false;
332 tlb[x].used = false;
333 }
334 usedEntries = 0;
335}
336
337uint64_t
338TLB::TteRead(int entry)
339{
340 if (entry >= size)
341 panic("entry: %d\n", entry);
342
343 assert(entry < size);
344 if (tlb[entry].valid)
345 return tlb[entry].pte();
346 else
347 return (uint64_t)-1ll;
348}
349
350uint64_t
351TLB::TagRead(int entry)
352{
353 assert(entry < size);
354 uint64_t tag;
355 if (!tlb[entry].valid)
356 return (uint64_t)-1ll;
357
358 tag = tlb[entry].range.contextId;
359 tag |= tlb[entry].range.va;
360 tag |= (uint64_t)tlb[entry].range.partitionId << 61;
361 tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
362 tag |= (uint64_t)~tlb[entry].pte._size() << 56;
363 return tag;
364}
365
366bool
367TLB::validVirtualAddress(Addr va, bool am)
368{
369 if (am)
370 return true;
371 if (va >= StartVAddrHole && va <= EndVAddrHole)
372 return false;
373 return true;
374}
375
376void
377TLB::writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi)
378{
379 if (sfsr & 0x1)
380 sfsr = 0x3;
381 else
382 sfsr = 1;
383
384 if (write)
385 sfsr |= 1 << 2;
386 sfsr |= ct << 4;
387 if (se)
388 sfsr |= 1 << 6;
389 sfsr |= ft << 7;
390 sfsr |= asi << 16;
391}
392
393void
394TLB::writeTagAccess(Addr va, int context)
395{
396 DPRINTF(TLB, "TLB: Writing Tag Access: va: %#X ctx: %#X value: %#X\n",
397 va, context, mbits(va, 63,13) | mbits(context,12,0));
398
399 tag_access = mbits(va, 63,13) | mbits(context,12,0);
400}
401
402void
403TLB::writeSfsr(Addr a, bool write, ContextType ct,
404 bool se, FaultTypes ft, int asi)
405{
406 DPRINTF(TLB, "TLB: Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n",
407 a, (int)write, ct, ft, asi);
408 TLB::writeSfsr(write, ct, se, ft, asi);
409 sfar = a;
410}
411
412Fault
413TLB::translateInst(RequestPtr req, ThreadContext *tc)
414{
415 uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
416
417 Addr vaddr = req->getVaddr();
418 TlbEntry *e;
419
420 assert(req->getAsi() == ASI_IMPLICIT);
421
422 DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n",
423 vaddr, req->getSize());
424
425 // Be fast if we can!
426 if (cacheValid && cacheState == tlbdata) {
427 if (cacheEntry[0]) {
428 if (cacheEntry[0]->range.va < vaddr + sizeof(MachInst) &&
429 cacheEntry[0]->range.va + cacheEntry[0]->range.size >= vaddr) {
430 req->setPaddr(cacheEntry[0]->pte.translate(vaddr));
431 return NoFault;
432 }
433 } else {
434 req->setPaddr(vaddr & PAddrImplMask);
435 return NoFault;
436 }
437 }
438
439 bool hpriv = bits(tlbdata,0,0);
440 bool red = bits(tlbdata,1,1);
441 bool priv = bits(tlbdata,2,2);
442 bool addr_mask = bits(tlbdata,3,3);
443 bool lsu_im = bits(tlbdata,4,4);
444
445 int part_id = bits(tlbdata,15,8);
446 int tl = bits(tlbdata,18,16);
447 int pri_context = bits(tlbdata,47,32);
448 int context;
449 ContextType ct;
450 int asi;
451 bool real = false;
452
453 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n",
454 priv, hpriv, red, lsu_im, part_id);
455
456 if (tl > 0) {
457 asi = ASI_N;
458 ct = Nucleus;
459 context = 0;
460 } else {
461 asi = ASI_P;
462 ct = Primary;
463 context = pri_context;
464 }
465
466 if ( hpriv || red ) {
467 cacheValid = true;
468 cacheState = tlbdata;
469 cacheEntry[0] = NULL;
470 req->setPaddr(vaddr & PAddrImplMask);
471 return NoFault;
472 }
473
474 // If the access is unaligned trap
475 if (vaddr & 0x3) {
476 writeSfsr(false, ct, false, OtherFault, asi);
477 return new MemAddressNotAligned;
478 }
479
480 if (addr_mask)
481 vaddr = vaddr & VAddrAMask;
482
483 if (!validVirtualAddress(vaddr, addr_mask)) {
484 writeSfsr(false, ct, false, VaOutOfRange, asi);
485 return new InstructionAccessException;
486 }
487
488 if (!lsu_im) {
489 e = lookup(vaddr, part_id, true);
490 real = true;
491 context = 0;
492 } else {
493 e = lookup(vaddr, part_id, false, context);
494 }
495
496 if (e == NULL || !e->valid) {
497 writeTagAccess(vaddr, context);
498 if (real)
499 return new InstructionRealTranslationMiss;
500 else
501#if FULL_SYSTEM
502 return new FastInstructionAccessMMUMiss;
503#else
504 return new FastInstructionAccessMMUMiss(req->getVaddr());
505#endif
506 }
507
508 // were not priviledged accesing priv page
509 if (!priv && e->pte.priv()) {
510 writeTagAccess(vaddr, context);
511 writeSfsr(false, ct, false, PrivViolation, asi);
512 return new InstructionAccessException;
513 }
514
515 // cache translation date for next translation
516 cacheValid = true;
517 cacheState = tlbdata;
518 cacheEntry[0] = e;
519
520 req->setPaddr(e->pte.translate(vaddr));
521 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
522 return NoFault;
523}
524
525Fault
526TLB::translateData(RequestPtr req, ThreadContext *tc, bool write)
527{
528 /*
529 * @todo this could really use some profiling and fixing to make
530 * it faster!
531 */
532 uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
533 Addr vaddr = req->getVaddr();
534 Addr size = req->getSize();
535 ASI asi;
536 asi = (ASI)req->getAsi();
537 bool implicit = false;
538 bool hpriv = bits(tlbdata,0,0);
539 bool unaligned = vaddr & (size - 1);
540
541 DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
542 vaddr, size, asi);
543
544 if (lookupTable.size() != 64 - freeList.size())
545 panic("Lookup table size: %d tlb size: %d\n", lookupTable.size(),
546 freeList.size());
547 if (asi == ASI_IMPLICIT)
548 implicit = true;
549
550 // Only use the fast path here if there doesn't need to be an unaligned
551 // trap later
552 if (!unaligned) {
553 if (hpriv && implicit) {
554 req->setPaddr(vaddr & PAddrImplMask);
555 return NoFault;
556 }
557
558 // Be fast if we can!
559 if (cacheValid && cacheState == tlbdata) {
560
561
562
563 if (cacheEntry[0]) {
564 TlbEntry *ce = cacheEntry[0];
565 Addr ce_va = ce->range.va;
566 if (cacheAsi[0] == asi &&
567 ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
568 (!write || ce->pte.writable())) {
569 req->setPaddr(ce->pte.translate(vaddr));
570 if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
571 req->setFlags(Request::UNCACHEABLE);
572 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
573 return NoFault;
574 } // if matched
575 } // if cache entry valid
576 if (cacheEntry[1]) {
577 TlbEntry *ce = cacheEntry[1];
578 Addr ce_va = ce->range.va;
579 if (cacheAsi[1] == asi &&
580 ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
581 (!write || ce->pte.writable())) {
582 req->setPaddr(ce->pte.translate(vaddr));
583 if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
584 req->setFlags(Request::UNCACHEABLE);
585 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
586 return NoFault;
587 } // if matched
588 } // if cache entry valid
589 }
590 }
591
592 bool red = bits(tlbdata,1,1);
593 bool priv = bits(tlbdata,2,2);
594 bool addr_mask = bits(tlbdata,3,3);
595 bool lsu_dm = bits(tlbdata,5,5);
596
597 int part_id = bits(tlbdata,15,8);
598 int tl = bits(tlbdata,18,16);
599 int pri_context = bits(tlbdata,47,32);
600 int sec_context = bits(tlbdata,63,48);
601
602 bool real = false;
603 ContextType ct = Primary;
604 int context = 0;
605
606 TlbEntry *e;
607
608 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
609 priv, hpriv, red, lsu_dm, part_id);
610
611 if (implicit) {
612 if (tl > 0) {
613 asi = ASI_N;
614 ct = Nucleus;
615 context = 0;
616 } else {
617 asi = ASI_P;
618 ct = Primary;
619 context = pri_context;
620 }
621 } else {
622 // We need to check for priv level/asi priv
623 if (!priv && !hpriv && !asiIsUnPriv(asi)) {
624 // It appears that context should be Nucleus in these cases?
625 writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);
626 return new PrivilegedAction;
627 }
628
629 if (!hpriv && asiIsHPriv(asi)) {
630 writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);
631 return new DataAccessException;
632 }
633
634 if (asiIsPrimary(asi)) {
635 context = pri_context;
636 ct = Primary;
637 } else if (asiIsSecondary(asi)) {
638 context = sec_context;
639 ct = Secondary;
640 } else if (asiIsNucleus(asi)) {
641 ct = Nucleus;
642 context = 0;
643 } else { // ????
644 ct = Primary;
645 context = pri_context;
646 }
647 }
648
649 if (!implicit && asi != ASI_P && asi != ASI_S) {
650 if (asiIsLittle(asi))
651 panic("Little Endian ASIs not supported\n");
652
653 //XXX It's unclear from looking at the documentation how a no fault
654 // load differs from a regular one, other than what happens concerning
655 // nfo and e bits in the TTE
656// if (asiIsNoFault(asi))
657// panic("No Fault ASIs not supported\n");
658
659 if (asiIsPartialStore(asi))
660 panic("Partial Store ASIs not supported\n");
661
662 if (asiIsCmt(asi))
663 panic("Cmt ASI registers not implmented\n");
664
665 if (asiIsInterrupt(asi))
666 goto handleIntRegAccess;
667 if (asiIsMmu(asi))
668 goto handleMmuRegAccess;
669 if (asiIsScratchPad(asi))
670 goto handleScratchRegAccess;
671 if (asiIsQueue(asi))
672 goto handleQueueRegAccess;
673 if (asiIsSparcError(asi))
674 goto handleSparcErrorRegAccess;
675
676 if (!asiIsReal(asi) && !asiIsNucleus(asi) && !asiIsAsIfUser(asi) &&
677 !asiIsTwin(asi) && !asiIsBlock(asi) && !asiIsNoFault(asi))
678 panic("Accessing ASI %#X. Should we?\n", asi);
679 }
680
681 // If the asi is unaligned trap
682 if (unaligned) {
683 writeSfsr(vaddr, false, ct, false, OtherFault, asi);
684 return new MemAddressNotAligned;
685 }
686
687 if (addr_mask)
688 vaddr = vaddr & VAddrAMask;
689
690 if (!validVirtualAddress(vaddr, addr_mask)) {
691 writeSfsr(vaddr, false, ct, true, VaOutOfRange, asi);
692 return new DataAccessException;
693 }
694
695 if ((!lsu_dm && !hpriv && !red) || asiIsReal(asi)) {
696 real = true;
697 context = 0;
698 }
699
700 if (hpriv && (implicit || (!asiIsAsIfUser(asi) && !asiIsReal(asi)))) {
701 req->setPaddr(vaddr & PAddrImplMask);
702 return NoFault;
703 }
704
705 e = lookup(vaddr, part_id, real, context);
706
707 if (e == NULL || !e->valid) {
708 writeTagAccess(vaddr, context);
709 DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
710 if (real)
711 return new DataRealTranslationMiss;
712 else
713#if FULL_SYSTEM
714 return new FastDataAccessMMUMiss;
715#else
716 return new FastDataAccessMMUMiss(req->getVaddr());
717#endif
718
719 }
720
721 if (!priv && e->pte.priv()) {
722 writeTagAccess(vaddr, context);
723 writeSfsr(vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
724 return new DataAccessException;
725 }
726
727 if (write && !e->pte.writable()) {
728 writeTagAccess(vaddr, context);
729 writeSfsr(vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
730 return new FastDataAccessProtection;
731 }
732
733 if (e->pte.nofault() && !asiIsNoFault(asi)) {
734 writeTagAccess(vaddr, context);
735 writeSfsr(vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
736 return new DataAccessException;
737 }
738
739 if (e->pte.sideffect() && asiIsNoFault(asi)) {
740 writeTagAccess(vaddr, context);
741 writeSfsr(vaddr, write, ct, e->pte.sideffect(), SideEffect, asi);
742 return new DataAccessException;
743 }
744
745 if (e->pte.sideffect() || (e->pte.paddr() >> 39) & 1)
746 req->setFlags(Request::UNCACHEABLE);
747
748 // cache translation date for next translation
749 cacheState = tlbdata;
750 if (!cacheValid) {
751 cacheEntry[1] = NULL;
752 cacheEntry[0] = NULL;
753 }
754
755 if (cacheEntry[0] != e && cacheEntry[1] != e) {
756 cacheEntry[1] = cacheEntry[0];
757 cacheEntry[0] = e;
758 cacheAsi[1] = cacheAsi[0];
759 cacheAsi[0] = asi;
760 if (implicit)
761 cacheAsi[0] = (ASI)0;
762 }
763 cacheValid = true;
764 req->setPaddr(e->pte.translate(vaddr));
765 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
766 return NoFault;
767
768 /** Normal flow ends here. */
769handleIntRegAccess:
770 if (!hpriv) {
771 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
772 if (priv)
773 return new DataAccessException;
774 else
775 return new PrivilegedAction;
776 }
777
778 if ((asi == ASI_SWVR_UDB_INTR_W && !write) ||
779 (asi == ASI_SWVR_UDB_INTR_R && write)) {
780 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
781 return new DataAccessException;
782 }
783
784 goto regAccessOk;
785
786
787handleScratchRegAccess:
788 if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
789 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
790 return new DataAccessException;
791 }
792 goto regAccessOk;
793
794handleQueueRegAccess:
795 if (!priv && !hpriv) {
796 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
797 return new PrivilegedAction;
798 }
799 if ((!hpriv && vaddr & 0xF) || vaddr > 0x3f8 || vaddr < 0x3c0) {
800 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
801 return new DataAccessException;
802 }
803 goto regAccessOk;
804
805handleSparcErrorRegAccess:
806 if (!hpriv) {
807 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
808 if (priv)
809 return new DataAccessException;
810 else
811 return new PrivilegedAction;
812 }
813 goto regAccessOk;
814
815
816regAccessOk:
817handleMmuRegAccess:
818 DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Ali Saidi
29 */
30
31#include <cstring>
32
33#include "arch/sparc/asi.hh"
34#include "arch/sparc/faults.hh"
35#include "arch/sparc/registers.hh"
36#include "arch/sparc/tlb.hh"
37#include "base/bitfield.hh"
38#include "base/trace.hh"
39#include "cpu/thread_context.hh"
40#include "cpu/base.hh"
41#include "mem/packet_access.hh"
42#include "mem/request.hh"
43#include "sim/system.hh"
44
45/* @todo remove some of the magic constants. -- ali
46 * */
47namespace SparcISA {
48
49TLB::TLB(const Params *p)
50 : BaseTLB(p), size(p->size), usedEntries(0), lastReplaced(0),
51 cacheValid(false)
52{
53 // To make this work you'll have to change the hypervisor and OS
54 if (size > 64)
55 fatal("SPARC T1 TLB registers don't support more than 64 TLB entries");
56
57 tlb = new TlbEntry[size];
58 std::memset(tlb, 0, sizeof(TlbEntry) * size);
59
60 for (int x = 0; x < size; x++)
61 freeList.push_back(&tlb[x]);
62
63 c0_tsb_ps0 = 0;
64 c0_tsb_ps1 = 0;
65 c0_config = 0;
66 cx_tsb_ps0 = 0;
67 cx_tsb_ps1 = 0;
68 cx_config = 0;
69 sfsr = 0;
70 tag_access = 0;
71 sfar = 0;
72 cacheEntry[0] = NULL;
73 cacheEntry[1] = NULL;
74}
75
76void
77TLB::clearUsedBits()
78{
79 MapIter i;
80 for (i = lookupTable.begin(); i != lookupTable.end(); i++) {
81 TlbEntry *t = i->second;
82 if (!t->pte.locked()) {
83 t->used = false;
84 usedEntries--;
85 }
86 }
87}
88
89
90void
91TLB::insert(Addr va, int partition_id, int context_id, bool real,
92 const PageTableEntry& PTE, int entry)
93{
94 MapIter i;
95 TlbEntry *new_entry = NULL;
96// TlbRange tr;
97 int x;
98
99 cacheValid = false;
100 va &= ~(PTE.size()-1);
101 /* tr.va = va;
102 tr.size = PTE.size() - 1;
103 tr.contextId = context_id;
104 tr.partitionId = partition_id;
105 tr.real = real;
106*/
107
108 DPRINTF(TLB,
109 "TLB: Inserting Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
110 va, PTE.paddr(), partition_id, context_id, (int)real, entry);
111
112 // Demap any entry that conflicts
113 for (x = 0; x < size; x++) {
114 if (tlb[x].range.real == real &&
115 tlb[x].range.partitionId == partition_id &&
116 tlb[x].range.va < va + PTE.size() - 1 &&
117 tlb[x].range.va + tlb[x].range.size >= va &&
118 (real || tlb[x].range.contextId == context_id ))
119 {
120 if (tlb[x].valid) {
121 freeList.push_front(&tlb[x]);
122 DPRINTF(TLB, "TLB: Conflicting entry %#X , deleting it\n", x);
123
124 tlb[x].valid = false;
125 if (tlb[x].used) {
126 tlb[x].used = false;
127 usedEntries--;
128 }
129 lookupTable.erase(tlb[x].range);
130 }
131 }
132 }
133
134 if (entry != -1) {
135 assert(entry < size && entry >= 0);
136 new_entry = &tlb[entry];
137 } else {
138 if (!freeList.empty()) {
139 new_entry = freeList.front();
140 } else {
141 x = lastReplaced;
142 do {
143 ++x;
144 if (x == size)
145 x = 0;
146 if (x == lastReplaced)
147 goto insertAllLocked;
148 } while (tlb[x].pte.locked());
149 lastReplaced = x;
150 new_entry = &tlb[x];
151 }
152 }
153
154insertAllLocked:
155 // Update the last ently if their all locked
156 if (!new_entry) {
157 new_entry = &tlb[size-1];
158 }
159
160 freeList.remove(new_entry);
161 if (new_entry->valid && new_entry->used)
162 usedEntries--;
163 if (new_entry->valid)
164 lookupTable.erase(new_entry->range);
165
166
167 assert(PTE.valid());
168 new_entry->range.va = va;
169 new_entry->range.size = PTE.size() - 1;
170 new_entry->range.partitionId = partition_id;
171 new_entry->range.contextId = context_id;
172 new_entry->range.real = real;
173 new_entry->pte = PTE;
174 new_entry->used = true;;
175 new_entry->valid = true;
176 usedEntries++;
177
178 i = lookupTable.insert(new_entry->range, new_entry);
179 assert(i != lookupTable.end());
180
181 // If all entries have their used bit set, clear it on them all,
182 // but the one we just inserted
183 if (usedEntries == size) {
184 clearUsedBits();
185 new_entry->used = true;
186 usedEntries++;
187 }
188}
189
190
191TlbEntry*
192TLB::lookup(Addr va, int partition_id, bool real, int context_id,
193 bool update_used)
194{
195 MapIter i;
196 TlbRange tr;
197 TlbEntry *t;
198
199 DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n",
200 va, partition_id, context_id, real);
201 // Assemble full address structure
202 tr.va = va;
203 tr.size = 1;
204 tr.contextId = context_id;
205 tr.partitionId = partition_id;
206 tr.real = real;
207
208 // Try to find the entry
209 i = lookupTable.find(tr);
210 if (i == lookupTable.end()) {
211 DPRINTF(TLB, "TLB: No valid entry found\n");
212 return NULL;
213 }
214
215 // Mark the entries used bit and clear other used bits in needed
216 t = i->second;
217 DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),
218 t->pte.size());
219
220 // Update the used bits only if this is a real access (not a fake
221 // one from virttophys()
222 if (!t->used && update_used) {
223 t->used = true;
224 usedEntries++;
225 if (usedEntries == size) {
226 clearUsedBits();
227 t->used = true;
228 usedEntries++;
229 }
230 }
231
232 return t;
233}
234
235void
236TLB::dumpAll()
237{
238 MapIter i;
239 for (int x = 0; x < size; x++) {
240 if (tlb[x].valid) {
241 DPRINTFN("%4d: %#2x:%#2x %c %#4x %#8x %#8x %#16x\n",
242 x, tlb[x].range.partitionId, tlb[x].range.contextId,
243 tlb[x].range.real ? 'R' : ' ', tlb[x].range.size,
244 tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte());
245 }
246 }
247}
248
249void
250TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
251{
252 TlbRange tr;
253 MapIter i;
254
255 DPRINTF(IPR, "TLB: Demapping Page va=%#x pid=%#d cid=%d r=%d\n",
256 va, partition_id, context_id, real);
257
258 cacheValid = false;
259
260 // Assemble full address structure
261 tr.va = va;
262 tr.size = 1;
263 tr.contextId = context_id;
264 tr.partitionId = partition_id;
265 tr.real = real;
266
267 // Demap any entry that conflicts
268 i = lookupTable.find(tr);
269 if (i != lookupTable.end()) {
270 DPRINTF(IPR, "TLB: Demapped page\n");
271 i->second->valid = false;
272 if (i->second->used) {
273 i->second->used = false;
274 usedEntries--;
275 }
276 freeList.push_front(i->second);
277 lookupTable.erase(i);
278 }
279}
280
281void
282TLB::demapContext(int partition_id, int context_id)
283{
284 DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",
285 partition_id, context_id);
286 cacheValid = false;
287 for (int x = 0; x < size; x++) {
288 if (tlb[x].range.contextId == context_id &&
289 tlb[x].range.partitionId == partition_id) {
290 if (tlb[x].valid == true) {
291 freeList.push_front(&tlb[x]);
292 }
293 tlb[x].valid = false;
294 if (tlb[x].used) {
295 tlb[x].used = false;
296 usedEntries--;
297 }
298 lookupTable.erase(tlb[x].range);
299 }
300 }
301}
302
303void
304TLB::demapAll(int partition_id)
305{
306 DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);
307 cacheValid = false;
308 for (int x = 0; x < size; x++) {
309 if (tlb[x].valid && !tlb[x].pte.locked() &&
310 tlb[x].range.partitionId == partition_id) {
311 freeList.push_front(&tlb[x]);
312 tlb[x].valid = false;
313 if (tlb[x].used) {
314 tlb[x].used = false;
315 usedEntries--;
316 }
317 lookupTable.erase(tlb[x].range);
318 }
319 }
320}
321
322void
323TLB::invalidateAll()
324{
325 cacheValid = false;
326 lookupTable.clear();
327
328 for (int x = 0; x < size; x++) {
329 if (tlb[x].valid == true)
330 freeList.push_back(&tlb[x]);
331 tlb[x].valid = false;
332 tlb[x].used = false;
333 }
334 usedEntries = 0;
335}
336
337uint64_t
338TLB::TteRead(int entry)
339{
340 if (entry >= size)
341 panic("entry: %d\n", entry);
342
343 assert(entry < size);
344 if (tlb[entry].valid)
345 return tlb[entry].pte();
346 else
347 return (uint64_t)-1ll;
348}
349
350uint64_t
351TLB::TagRead(int entry)
352{
353 assert(entry < size);
354 uint64_t tag;
355 if (!tlb[entry].valid)
356 return (uint64_t)-1ll;
357
358 tag = tlb[entry].range.contextId;
359 tag |= tlb[entry].range.va;
360 tag |= (uint64_t)tlb[entry].range.partitionId << 61;
361 tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
362 tag |= (uint64_t)~tlb[entry].pte._size() << 56;
363 return tag;
364}
365
366bool
367TLB::validVirtualAddress(Addr va, bool am)
368{
369 if (am)
370 return true;
371 if (va >= StartVAddrHole && va <= EndVAddrHole)
372 return false;
373 return true;
374}
375
376void
377TLB::writeSfsr(bool write, ContextType ct, bool se, FaultTypes ft, int asi)
378{
379 if (sfsr & 0x1)
380 sfsr = 0x3;
381 else
382 sfsr = 1;
383
384 if (write)
385 sfsr |= 1 << 2;
386 sfsr |= ct << 4;
387 if (se)
388 sfsr |= 1 << 6;
389 sfsr |= ft << 7;
390 sfsr |= asi << 16;
391}
392
393void
394TLB::writeTagAccess(Addr va, int context)
395{
396 DPRINTF(TLB, "TLB: Writing Tag Access: va: %#X ctx: %#X value: %#X\n",
397 va, context, mbits(va, 63,13) | mbits(context,12,0));
398
399 tag_access = mbits(va, 63,13) | mbits(context,12,0);
400}
401
402void
403TLB::writeSfsr(Addr a, bool write, ContextType ct,
404 bool se, FaultTypes ft, int asi)
405{
406 DPRINTF(TLB, "TLB: Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n",
407 a, (int)write, ct, ft, asi);
408 TLB::writeSfsr(write, ct, se, ft, asi);
409 sfar = a;
410}
411
412Fault
413TLB::translateInst(RequestPtr req, ThreadContext *tc)
414{
415 uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
416
417 Addr vaddr = req->getVaddr();
418 TlbEntry *e;
419
420 assert(req->getAsi() == ASI_IMPLICIT);
421
422 DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n",
423 vaddr, req->getSize());
424
425 // Be fast if we can!
426 if (cacheValid && cacheState == tlbdata) {
427 if (cacheEntry[0]) {
428 if (cacheEntry[0]->range.va < vaddr + sizeof(MachInst) &&
429 cacheEntry[0]->range.va + cacheEntry[0]->range.size >= vaddr) {
430 req->setPaddr(cacheEntry[0]->pte.translate(vaddr));
431 return NoFault;
432 }
433 } else {
434 req->setPaddr(vaddr & PAddrImplMask);
435 return NoFault;
436 }
437 }
438
439 bool hpriv = bits(tlbdata,0,0);
440 bool red = bits(tlbdata,1,1);
441 bool priv = bits(tlbdata,2,2);
442 bool addr_mask = bits(tlbdata,3,3);
443 bool lsu_im = bits(tlbdata,4,4);
444
445 int part_id = bits(tlbdata,15,8);
446 int tl = bits(tlbdata,18,16);
447 int pri_context = bits(tlbdata,47,32);
448 int context;
449 ContextType ct;
450 int asi;
451 bool real = false;
452
453 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n",
454 priv, hpriv, red, lsu_im, part_id);
455
456 if (tl > 0) {
457 asi = ASI_N;
458 ct = Nucleus;
459 context = 0;
460 } else {
461 asi = ASI_P;
462 ct = Primary;
463 context = pri_context;
464 }
465
466 if ( hpriv || red ) {
467 cacheValid = true;
468 cacheState = tlbdata;
469 cacheEntry[0] = NULL;
470 req->setPaddr(vaddr & PAddrImplMask);
471 return NoFault;
472 }
473
474 // If the access is unaligned trap
475 if (vaddr & 0x3) {
476 writeSfsr(false, ct, false, OtherFault, asi);
477 return new MemAddressNotAligned;
478 }
479
480 if (addr_mask)
481 vaddr = vaddr & VAddrAMask;
482
483 if (!validVirtualAddress(vaddr, addr_mask)) {
484 writeSfsr(false, ct, false, VaOutOfRange, asi);
485 return new InstructionAccessException;
486 }
487
488 if (!lsu_im) {
489 e = lookup(vaddr, part_id, true);
490 real = true;
491 context = 0;
492 } else {
493 e = lookup(vaddr, part_id, false, context);
494 }
495
496 if (e == NULL || !e->valid) {
497 writeTagAccess(vaddr, context);
498 if (real)
499 return new InstructionRealTranslationMiss;
500 else
501#if FULL_SYSTEM
502 return new FastInstructionAccessMMUMiss;
503#else
504 return new FastInstructionAccessMMUMiss(req->getVaddr());
505#endif
506 }
507
508 // were not priviledged accesing priv page
509 if (!priv && e->pte.priv()) {
510 writeTagAccess(vaddr, context);
511 writeSfsr(false, ct, false, PrivViolation, asi);
512 return new InstructionAccessException;
513 }
514
515 // cache translation date for next translation
516 cacheValid = true;
517 cacheState = tlbdata;
518 cacheEntry[0] = e;
519
520 req->setPaddr(e->pte.translate(vaddr));
521 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
522 return NoFault;
523}
524
525Fault
526TLB::translateData(RequestPtr req, ThreadContext *tc, bool write)
527{
528 /*
529 * @todo this could really use some profiling and fixing to make
530 * it faster!
531 */
532 uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
533 Addr vaddr = req->getVaddr();
534 Addr size = req->getSize();
535 ASI asi;
536 asi = (ASI)req->getAsi();
537 bool implicit = false;
538 bool hpriv = bits(tlbdata,0,0);
539 bool unaligned = vaddr & (size - 1);
540
541 DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
542 vaddr, size, asi);
543
544 if (lookupTable.size() != 64 - freeList.size())
545 panic("Lookup table size: %d tlb size: %d\n", lookupTable.size(),
546 freeList.size());
547 if (asi == ASI_IMPLICIT)
548 implicit = true;
549
550 // Only use the fast path here if there doesn't need to be an unaligned
551 // trap later
552 if (!unaligned) {
553 if (hpriv && implicit) {
554 req->setPaddr(vaddr & PAddrImplMask);
555 return NoFault;
556 }
557
558 // Be fast if we can!
559 if (cacheValid && cacheState == tlbdata) {
560
561
562
563 if (cacheEntry[0]) {
564 TlbEntry *ce = cacheEntry[0];
565 Addr ce_va = ce->range.va;
566 if (cacheAsi[0] == asi &&
567 ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
568 (!write || ce->pte.writable())) {
569 req->setPaddr(ce->pte.translate(vaddr));
570 if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
571 req->setFlags(Request::UNCACHEABLE);
572 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
573 return NoFault;
574 } // if matched
575 } // if cache entry valid
576 if (cacheEntry[1]) {
577 TlbEntry *ce = cacheEntry[1];
578 Addr ce_va = ce->range.va;
579 if (cacheAsi[1] == asi &&
580 ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
581 (!write || ce->pte.writable())) {
582 req->setPaddr(ce->pte.translate(vaddr));
583 if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
584 req->setFlags(Request::UNCACHEABLE);
585 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
586 return NoFault;
587 } // if matched
588 } // if cache entry valid
589 }
590 }
591
592 bool red = bits(tlbdata,1,1);
593 bool priv = bits(tlbdata,2,2);
594 bool addr_mask = bits(tlbdata,3,3);
595 bool lsu_dm = bits(tlbdata,5,5);
596
597 int part_id = bits(tlbdata,15,8);
598 int tl = bits(tlbdata,18,16);
599 int pri_context = bits(tlbdata,47,32);
600 int sec_context = bits(tlbdata,63,48);
601
602 bool real = false;
603 ContextType ct = Primary;
604 int context = 0;
605
606 TlbEntry *e;
607
608 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
609 priv, hpriv, red, lsu_dm, part_id);
610
611 if (implicit) {
612 if (tl > 0) {
613 asi = ASI_N;
614 ct = Nucleus;
615 context = 0;
616 } else {
617 asi = ASI_P;
618 ct = Primary;
619 context = pri_context;
620 }
621 } else {
622 // We need to check for priv level/asi priv
623 if (!priv && !hpriv && !asiIsUnPriv(asi)) {
624 // It appears that context should be Nucleus in these cases?
625 writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);
626 return new PrivilegedAction;
627 }
628
629 if (!hpriv && asiIsHPriv(asi)) {
630 writeSfsr(vaddr, write, Nucleus, false, IllegalAsi, asi);
631 return new DataAccessException;
632 }
633
634 if (asiIsPrimary(asi)) {
635 context = pri_context;
636 ct = Primary;
637 } else if (asiIsSecondary(asi)) {
638 context = sec_context;
639 ct = Secondary;
640 } else if (asiIsNucleus(asi)) {
641 ct = Nucleus;
642 context = 0;
643 } else { // ????
644 ct = Primary;
645 context = pri_context;
646 }
647 }
648
649 if (!implicit && asi != ASI_P && asi != ASI_S) {
650 if (asiIsLittle(asi))
651 panic("Little Endian ASIs not supported\n");
652
653 //XXX It's unclear from looking at the documentation how a no fault
654 // load differs from a regular one, other than what happens concerning
655 // nfo and e bits in the TTE
656// if (asiIsNoFault(asi))
657// panic("No Fault ASIs not supported\n");
658
659 if (asiIsPartialStore(asi))
660 panic("Partial Store ASIs not supported\n");
661
662 if (asiIsCmt(asi))
663 panic("Cmt ASI registers not implmented\n");
664
665 if (asiIsInterrupt(asi))
666 goto handleIntRegAccess;
667 if (asiIsMmu(asi))
668 goto handleMmuRegAccess;
669 if (asiIsScratchPad(asi))
670 goto handleScratchRegAccess;
671 if (asiIsQueue(asi))
672 goto handleQueueRegAccess;
673 if (asiIsSparcError(asi))
674 goto handleSparcErrorRegAccess;
675
676 if (!asiIsReal(asi) && !asiIsNucleus(asi) && !asiIsAsIfUser(asi) &&
677 !asiIsTwin(asi) && !asiIsBlock(asi) && !asiIsNoFault(asi))
678 panic("Accessing ASI %#X. Should we?\n", asi);
679 }
680
681 // If the asi is unaligned trap
682 if (unaligned) {
683 writeSfsr(vaddr, false, ct, false, OtherFault, asi);
684 return new MemAddressNotAligned;
685 }
686
687 if (addr_mask)
688 vaddr = vaddr & VAddrAMask;
689
690 if (!validVirtualAddress(vaddr, addr_mask)) {
691 writeSfsr(vaddr, false, ct, true, VaOutOfRange, asi);
692 return new DataAccessException;
693 }
694
695 if ((!lsu_dm && !hpriv && !red) || asiIsReal(asi)) {
696 real = true;
697 context = 0;
698 }
699
700 if (hpriv && (implicit || (!asiIsAsIfUser(asi) && !asiIsReal(asi)))) {
701 req->setPaddr(vaddr & PAddrImplMask);
702 return NoFault;
703 }
704
705 e = lookup(vaddr, part_id, real, context);
706
707 if (e == NULL || !e->valid) {
708 writeTagAccess(vaddr, context);
709 DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
710 if (real)
711 return new DataRealTranslationMiss;
712 else
713#if FULL_SYSTEM
714 return new FastDataAccessMMUMiss;
715#else
716 return new FastDataAccessMMUMiss(req->getVaddr());
717#endif
718
719 }
720
721 if (!priv && e->pte.priv()) {
722 writeTagAccess(vaddr, context);
723 writeSfsr(vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
724 return new DataAccessException;
725 }
726
727 if (write && !e->pte.writable()) {
728 writeTagAccess(vaddr, context);
729 writeSfsr(vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
730 return new FastDataAccessProtection;
731 }
732
733 if (e->pte.nofault() && !asiIsNoFault(asi)) {
734 writeTagAccess(vaddr, context);
735 writeSfsr(vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
736 return new DataAccessException;
737 }
738
739 if (e->pte.sideffect() && asiIsNoFault(asi)) {
740 writeTagAccess(vaddr, context);
741 writeSfsr(vaddr, write, ct, e->pte.sideffect(), SideEffect, asi);
742 return new DataAccessException;
743 }
744
745 if (e->pte.sideffect() || (e->pte.paddr() >> 39) & 1)
746 req->setFlags(Request::UNCACHEABLE);
747
748 // cache translation date for next translation
749 cacheState = tlbdata;
750 if (!cacheValid) {
751 cacheEntry[1] = NULL;
752 cacheEntry[0] = NULL;
753 }
754
755 if (cacheEntry[0] != e && cacheEntry[1] != e) {
756 cacheEntry[1] = cacheEntry[0];
757 cacheEntry[0] = e;
758 cacheAsi[1] = cacheAsi[0];
759 cacheAsi[0] = asi;
760 if (implicit)
761 cacheAsi[0] = (ASI)0;
762 }
763 cacheValid = true;
764 req->setPaddr(e->pte.translate(vaddr));
765 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
766 return NoFault;
767
768 /** Normal flow ends here. */
769handleIntRegAccess:
770 if (!hpriv) {
771 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
772 if (priv)
773 return new DataAccessException;
774 else
775 return new PrivilegedAction;
776 }
777
778 if ((asi == ASI_SWVR_UDB_INTR_W && !write) ||
779 (asi == ASI_SWVR_UDB_INTR_R && write)) {
780 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
781 return new DataAccessException;
782 }
783
784 goto regAccessOk;
785
786
787handleScratchRegAccess:
788 if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
789 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
790 return new DataAccessException;
791 }
792 goto regAccessOk;
793
794handleQueueRegAccess:
795 if (!priv && !hpriv) {
796 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
797 return new PrivilegedAction;
798 }
799 if ((!hpriv && vaddr & 0xF) || vaddr > 0x3f8 || vaddr < 0x3c0) {
800 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
801 return new DataAccessException;
802 }
803 goto regAccessOk;
804
805handleSparcErrorRegAccess:
806 if (!hpriv) {
807 writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
808 if (priv)
809 return new DataAccessException;
810 else
811 return new PrivilegedAction;
812 }
813 goto regAccessOk;
814
815
816regAccessOk:
817handleMmuRegAccess:
818 DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
819 req->setFlags(Request::MMAPED_IPR);
819 req->setFlags(Request::MMAPPED_IPR);
820 req->setPaddr(req->getVaddr());
821 return NoFault;
822};
823
824Fault
825TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
826{
827 if (mode == Execute)
828 return translateInst(req, tc);
829 else
830 return translateData(req, tc, mode == Write);
831}
832
833void
834TLB::translateTiming(RequestPtr req, ThreadContext *tc,
835 Translation *translation, Mode mode)
836{
837 assert(translation);
838 translation->finish(translateAtomic(req, tc, mode), req, tc, mode);
839}
840
841#if FULL_SYSTEM
842
843Tick
844TLB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
845{
846 Addr va = pkt->getAddr();
847 ASI asi = (ASI)pkt->req->getAsi();
848 uint64_t temp;
849
850 DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
851 (uint32_t)pkt->req->getAsi(), pkt->getAddr());
852
853 TLB *itb = tc->getITBPtr();
854
855 switch (asi) {
856 case ASI_LSU_CONTROL_REG:
857 assert(va == 0);
858 pkt->set(tc->readMiscReg(MISCREG_MMU_LSU_CTRL));
859 break;
860 case ASI_MMU:
861 switch (va) {
862 case 0x8:
863 pkt->set(tc->readMiscReg(MISCREG_MMU_P_CONTEXT));
864 break;
865 case 0x10:
866 pkt->set(tc->readMiscReg(MISCREG_MMU_S_CONTEXT));
867 break;
868 default:
869 goto doMmuReadError;
870 }
871 break;
872 case ASI_QUEUE:
873 pkt->set(tc->readMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +
874 (va >> 4) - 0x3c));
875 break;
876 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
877 assert(va == 0);
878 pkt->set(c0_tsb_ps0);
879 break;
880 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
881 assert(va == 0);
882 pkt->set(c0_tsb_ps1);
883 break;
884 case ASI_DMMU_CTXT_ZERO_CONFIG:
885 assert(va == 0);
886 pkt->set(c0_config);
887 break;
888 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
889 assert(va == 0);
890 pkt->set(itb->c0_tsb_ps0);
891 break;
892 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
893 assert(va == 0);
894 pkt->set(itb->c0_tsb_ps1);
895 break;
896 case ASI_IMMU_CTXT_ZERO_CONFIG:
897 assert(va == 0);
898 pkt->set(itb->c0_config);
899 break;
900 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
901 assert(va == 0);
902 pkt->set(cx_tsb_ps0);
903 break;
904 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
905 assert(va == 0);
906 pkt->set(cx_tsb_ps1);
907 break;
908 case ASI_DMMU_CTXT_NONZERO_CONFIG:
909 assert(va == 0);
910 pkt->set(cx_config);
911 break;
912 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
913 assert(va == 0);
914 pkt->set(itb->cx_tsb_ps0);
915 break;
916 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
917 assert(va == 0);
918 pkt->set(itb->cx_tsb_ps1);
919 break;
920 case ASI_IMMU_CTXT_NONZERO_CONFIG:
921 assert(va == 0);
922 pkt->set(itb->cx_config);
923 break;
924 case ASI_SPARC_ERROR_STATUS_REG:
925 pkt->set((uint64_t)0);
926 break;
927 case ASI_HYP_SCRATCHPAD:
928 case ASI_SCRATCHPAD:
929 pkt->set(tc->readMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
930 break;
931 case ASI_IMMU:
932 switch (va) {
933 case 0x0:
934 temp = itb->tag_access;
935 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
936 break;
937 case 0x18:
938 pkt->set(itb->sfsr);
939 break;
940 case 0x30:
941 pkt->set(itb->tag_access);
942 break;
943 default:
944 goto doMmuReadError;
945 }
946 break;
947 case ASI_DMMU:
948 switch (va) {
949 case 0x0:
950 temp = tag_access;
951 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
952 break;
953 case 0x18:
954 pkt->set(sfsr);
955 break;
956 case 0x20:
957 pkt->set(sfar);
958 break;
959 case 0x30:
960 pkt->set(tag_access);
961 break;
962 case 0x80:
963 pkt->set(tc->readMiscReg(MISCREG_MMU_PART_ID));
964 break;
965 default:
966 goto doMmuReadError;
967 }
968 break;
969 case ASI_DMMU_TSB_PS0_PTR_REG:
970 pkt->set(MakeTsbPtr(Ps0,
971 tag_access,
972 c0_tsb_ps0,
973 c0_config,
974 cx_tsb_ps0,
975 cx_config));
976 break;
977 case ASI_DMMU_TSB_PS1_PTR_REG:
978 pkt->set(MakeTsbPtr(Ps1,
979 tag_access,
980 c0_tsb_ps1,
981 c0_config,
982 cx_tsb_ps1,
983 cx_config));
984 break;
985 case ASI_IMMU_TSB_PS0_PTR_REG:
986 pkt->set(MakeTsbPtr(Ps0,
987 itb->tag_access,
988 itb->c0_tsb_ps0,
989 itb->c0_config,
990 itb->cx_tsb_ps0,
991 itb->cx_config));
992 break;
993 case ASI_IMMU_TSB_PS1_PTR_REG:
994 pkt->set(MakeTsbPtr(Ps1,
995 itb->tag_access,
996 itb->c0_tsb_ps1,
997 itb->c0_config,
998 itb->cx_tsb_ps1,
999 itb->cx_config));
1000 break;
1001 case ASI_SWVR_INTR_RECEIVE:
1002 {
1003 SparcISA::Interrupts * interrupts =
1004 dynamic_cast<SparcISA::Interrupts *>(
1005 tc->getCpuPtr()->getInterruptController());
1006 pkt->set(interrupts->get_vec(IT_INT_VEC));
1007 }
1008 break;
1009 case ASI_SWVR_UDB_INTR_R:
1010 {
1011 SparcISA::Interrupts * interrupts =
1012 dynamic_cast<SparcISA::Interrupts *>(
1013 tc->getCpuPtr()->getInterruptController());
1014 temp = findMsbSet(interrupts->get_vec(IT_INT_VEC));
1015 tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, temp);
1016 pkt->set(temp);
1017 }
1018 break;
1019 default:
1020doMmuReadError:
1021 panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
1022 (uint32_t)asi, va);
1023 }
1024 pkt->makeAtomicResponse();
1025 return tc->getCpuPtr()->ticks(1);
1026}
1027
1028Tick
1029TLB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
1030{
1031 uint64_t data = pkt->get<uint64_t>();
1032 Addr va = pkt->getAddr();
1033 ASI asi = (ASI)pkt->req->getAsi();
1034
1035 Addr ta_insert;
1036 Addr va_insert;
1037 Addr ct_insert;
1038 int part_insert;
1039 int entry_insert = -1;
1040 bool real_insert;
1041 bool ignore;
1042 int part_id;
1043 int ctx_id;
1044 PageTableEntry pte;
1045
1046 DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
1047 (uint32_t)asi, va, data);
1048
1049 TLB *itb = tc->getITBPtr();
1050
1051 switch (asi) {
1052 case ASI_LSU_CONTROL_REG:
1053 assert(va == 0);
1054 tc->setMiscReg(MISCREG_MMU_LSU_CTRL, data);
1055 break;
1056 case ASI_MMU:
1057 switch (va) {
1058 case 0x8:
1059 tc->setMiscReg(MISCREG_MMU_P_CONTEXT, data);
1060 break;
1061 case 0x10:
1062 tc->setMiscReg(MISCREG_MMU_S_CONTEXT, data);
1063 break;
1064 default:
1065 goto doMmuWriteError;
1066 }
1067 break;
1068 case ASI_QUEUE:
1069 assert(mbits(data,13,6) == data);
1070 tc->setMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +
1071 (va >> 4) - 0x3c, data);
1072 break;
1073 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
1074 assert(va == 0);
1075 c0_tsb_ps0 = data;
1076 break;
1077 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
1078 assert(va == 0);
1079 c0_tsb_ps1 = data;
1080 break;
1081 case ASI_DMMU_CTXT_ZERO_CONFIG:
1082 assert(va == 0);
1083 c0_config = data;
1084 break;
1085 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
1086 assert(va == 0);
1087 itb->c0_tsb_ps0 = data;
1088 break;
1089 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
1090 assert(va == 0);
1091 itb->c0_tsb_ps1 = data;
1092 break;
1093 case ASI_IMMU_CTXT_ZERO_CONFIG:
1094 assert(va == 0);
1095 itb->c0_config = data;
1096 break;
1097 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
1098 assert(va == 0);
1099 cx_tsb_ps0 = data;
1100 break;
1101 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
1102 assert(va == 0);
1103 cx_tsb_ps1 = data;
1104 break;
1105 case ASI_DMMU_CTXT_NONZERO_CONFIG:
1106 assert(va == 0);
1107 cx_config = data;
1108 break;
1109 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
1110 assert(va == 0);
1111 itb->cx_tsb_ps0 = data;
1112 break;
1113 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
1114 assert(va == 0);
1115 itb->cx_tsb_ps1 = data;
1116 break;
1117 case ASI_IMMU_CTXT_NONZERO_CONFIG:
1118 assert(va == 0);
1119 itb->cx_config = data;
1120 break;
1121 case ASI_SPARC_ERROR_EN_REG:
1122 case ASI_SPARC_ERROR_STATUS_REG:
1123 inform("Ignoring write to SPARC ERROR regsiter\n");
1124 break;
1125 case ASI_HYP_SCRATCHPAD:
1126 case ASI_SCRATCHPAD:
1127 tc->setMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
1128 break;
1129 case ASI_IMMU:
1130 switch (va) {
1131 case 0x18:
1132 itb->sfsr = data;
1133 break;
1134 case 0x30:
1135 sext<59>(bits(data, 59,0));
1136 itb->tag_access = data;
1137 break;
1138 default:
1139 goto doMmuWriteError;
1140 }
1141 break;
1142 case ASI_ITLB_DATA_ACCESS_REG:
1143 entry_insert = bits(va, 8,3);
1144 case ASI_ITLB_DATA_IN_REG:
1145 assert(entry_insert != -1 || mbits(va,10,9) == va);
1146 ta_insert = itb->tag_access;
1147 va_insert = mbits(ta_insert, 63,13);
1148 ct_insert = mbits(ta_insert, 12,0);
1149 part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1150 real_insert = bits(va, 9,9);
1151 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1152 PageTableEntry::sun4u);
1153 tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
1154 pte, entry_insert);
1155 break;
1156 case ASI_DTLB_DATA_ACCESS_REG:
1157 entry_insert = bits(va, 8,3);
1158 case ASI_DTLB_DATA_IN_REG:
1159 assert(entry_insert != -1 || mbits(va,10,9) == va);
1160 ta_insert = tag_access;
1161 va_insert = mbits(ta_insert, 63,13);
1162 ct_insert = mbits(ta_insert, 12,0);
1163 part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1164 real_insert = bits(va, 9,9);
1165 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1166 PageTableEntry::sun4u);
1167 insert(va_insert, part_insert, ct_insert, real_insert, pte,
1168 entry_insert);
1169 break;
1170 case ASI_IMMU_DEMAP:
1171 ignore = false;
1172 ctx_id = -1;
1173 part_id = tc->readMiscReg(MISCREG_MMU_PART_ID);
1174 switch (bits(va,5,4)) {
1175 case 0:
1176 ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1177 break;
1178 case 1:
1179 ignore = true;
1180 break;
1181 case 3:
1182 ctx_id = 0;
1183 break;
1184 default:
1185 ignore = true;
1186 }
1187
1188 switch (bits(va,7,6)) {
1189 case 0: // demap page
1190 if (!ignore)
1191 tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
1192 bits(va,9,9), ctx_id);
1193 break;
1194 case 1: // demap context
1195 if (!ignore)
1196 tc->getITBPtr()->demapContext(part_id, ctx_id);
1197 break;
1198 case 2:
1199 tc->getITBPtr()->demapAll(part_id);
1200 break;
1201 default:
1202 panic("Invalid type for IMMU demap\n");
1203 }
1204 break;
1205 case ASI_DMMU:
1206 switch (va) {
1207 case 0x18:
1208 sfsr = data;
1209 break;
1210 case 0x30:
1211 sext<59>(bits(data, 59,0));
1212 tag_access = data;
1213 break;
1214 case 0x80:
1215 tc->setMiscReg(MISCREG_MMU_PART_ID, data);
1216 break;
1217 default:
1218 goto doMmuWriteError;
1219 }
1220 break;
1221 case ASI_DMMU_DEMAP:
1222 ignore = false;
1223 ctx_id = -1;
1224 part_id = tc->readMiscReg(MISCREG_MMU_PART_ID);
1225 switch (bits(va,5,4)) {
1226 case 0:
1227 ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1228 break;
1229 case 1:
1230 ctx_id = tc->readMiscReg(MISCREG_MMU_S_CONTEXT);
1231 break;
1232 case 3:
1233 ctx_id = 0;
1234 break;
1235 default:
1236 ignore = true;
1237 }
1238
1239 switch (bits(va,7,6)) {
1240 case 0: // demap page
1241 if (!ignore)
1242 demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
1243 break;
1244 case 1: // demap context
1245 if (!ignore)
1246 demapContext(part_id, ctx_id);
1247 break;
1248 case 2:
1249 demapAll(part_id);
1250 break;
1251 default:
1252 panic("Invalid type for IMMU demap\n");
1253 }
1254 break;
1255 case ASI_SWVR_INTR_RECEIVE:
1256 {
1257 int msb;
1258 // clear all the interrupts that aren't set in the write
1259 SparcISA::Interrupts * interrupts =
1260 dynamic_cast<SparcISA::Interrupts *>(
1261 tc->getCpuPtr()->getInterruptController());
1262 while (interrupts->get_vec(IT_INT_VEC) & data) {
1263 msb = findMsbSet(interrupts->get_vec(IT_INT_VEC) & data);
1264 tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, msb);
1265 }
1266 }
1267 break;
1268 case ASI_SWVR_UDB_INTR_W:
1269 tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
1270 postInterrupt(bits(data, 5, 0), 0);
1271 break;
1272 default:
1273doMmuWriteError:
1274 panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1275 (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1276 }
1277 pkt->makeAtomicResponse();
1278 return tc->getCpuPtr()->ticks(1);
1279}
1280
1281#endif
1282
1283void
1284TLB::GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs)
1285{
1286 uint64_t tag_access = mbits(addr,63,13) | mbits(ctx,12,0);
1287 TLB * itb = tc->getITBPtr();
1288 ptrs[0] = MakeTsbPtr(Ps0, tag_access,
1289 c0_tsb_ps0,
1290 c0_config,
1291 cx_tsb_ps0,
1292 cx_config);
1293 ptrs[1] = MakeTsbPtr(Ps1, tag_access,
1294 c0_tsb_ps1,
1295 c0_config,
1296 cx_tsb_ps1,
1297 cx_config);
1298 ptrs[2] = MakeTsbPtr(Ps0, tag_access,
1299 itb->c0_tsb_ps0,
1300 itb->c0_config,
1301 itb->cx_tsb_ps0,
1302 itb->cx_config);
1303 ptrs[3] = MakeTsbPtr(Ps1, tag_access,
1304 itb->c0_tsb_ps1,
1305 itb->c0_config,
1306 itb->cx_tsb_ps1,
1307 itb->cx_config);
1308}
1309
1310uint64_t
1311TLB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb,
1312 uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config)
1313{
1314 uint64_t tsb;
1315 uint64_t config;
1316
1317 if (bits(tag_access, 12,0) == 0) {
1318 tsb = c0_tsb;
1319 config = c0_config;
1320 } else {
1321 tsb = cX_tsb;
1322 config = cX_config;
1323 }
1324
1325 uint64_t ptr = mbits(tsb,63,13);
1326 bool split = bits(tsb,12,12);
1327 int tsb_size = bits(tsb,3,0);
1328 int page_size = (ps == Ps0) ? bits(config, 2,0) : bits(config,10,8);
1329
1330 if (ps == Ps1 && split)
1331 ptr |= ULL(1) << (13 + tsb_size);
1332 ptr |= (tag_access >> (9 + page_size * 3)) & mask(12+tsb_size, 4);
1333
1334 return ptr;
1335}
1336
1337void
1338TLB::serialize(std::ostream &os)
1339{
1340 SERIALIZE_SCALAR(size);
1341 SERIALIZE_SCALAR(usedEntries);
1342 SERIALIZE_SCALAR(lastReplaced);
1343
1344 // convert the pointer based free list into an index based one
1345 int *free_list = (int*)malloc(sizeof(int) * size);
1346 int cntr = 0;
1347 std::list<TlbEntry*>::iterator i;
1348 i = freeList.begin();
1349 while (i != freeList.end()) {
1350 free_list[cntr++] = ((size_t)*i - (size_t)tlb)/ sizeof(TlbEntry);
1351 i++;
1352 }
1353 SERIALIZE_SCALAR(cntr);
1354 SERIALIZE_ARRAY(free_list, cntr);
1355
1356 SERIALIZE_SCALAR(c0_tsb_ps0);
1357 SERIALIZE_SCALAR(c0_tsb_ps1);
1358 SERIALIZE_SCALAR(c0_config);
1359 SERIALIZE_SCALAR(cx_tsb_ps0);
1360 SERIALIZE_SCALAR(cx_tsb_ps1);
1361 SERIALIZE_SCALAR(cx_config);
1362 SERIALIZE_SCALAR(sfsr);
1363 SERIALIZE_SCALAR(tag_access);
1364
1365 for (int x = 0; x < size; x++) {
1366 nameOut(os, csprintf("%s.PTE%d", name(), x));
1367 tlb[x].serialize(os);
1368 }
1369 SERIALIZE_SCALAR(sfar);
1370}
1371
1372void
1373TLB::unserialize(Checkpoint *cp, const std::string &section)
1374{
1375 int oldSize;
1376
1377 paramIn(cp, section, "size", oldSize);
1378 if (oldSize != size)
1379 panic("Don't support unserializing different sized TLBs\n");
1380 UNSERIALIZE_SCALAR(usedEntries);
1381 UNSERIALIZE_SCALAR(lastReplaced);
1382
1383 int cntr;
1384 UNSERIALIZE_SCALAR(cntr);
1385
1386 int *free_list = (int*)malloc(sizeof(int) * cntr);
1387 freeList.clear();
1388 UNSERIALIZE_ARRAY(free_list, cntr);
1389 for (int x = 0; x < cntr; x++)
1390 freeList.push_back(&tlb[free_list[x]]);
1391
1392 UNSERIALIZE_SCALAR(c0_tsb_ps0);
1393 UNSERIALIZE_SCALAR(c0_tsb_ps1);
1394 UNSERIALIZE_SCALAR(c0_config);
1395 UNSERIALIZE_SCALAR(cx_tsb_ps0);
1396 UNSERIALIZE_SCALAR(cx_tsb_ps1);
1397 UNSERIALIZE_SCALAR(cx_config);
1398 UNSERIALIZE_SCALAR(sfsr);
1399 UNSERIALIZE_SCALAR(tag_access);
1400
1401 lookupTable.clear();
1402 for (int x = 0; x < size; x++) {
1403 tlb[x].unserialize(cp, csprintf("%s.PTE%d", section, x));
1404 if (tlb[x].valid)
1405 lookupTable.insert(tlb[x].range, &tlb[x]);
1406
1407 }
1408 UNSERIALIZE_SCALAR(sfar);
1409}
1410
1411} // namespace SparcISA
1412
1413SparcISA::TLB *
1414SparcTLBParams::create()
1415{
1416 return new SparcISA::TLB(this);
1417}
820 req->setPaddr(req->getVaddr());
821 return NoFault;
822};
823
824Fault
825TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode)
826{
827 if (mode == Execute)
828 return translateInst(req, tc);
829 else
830 return translateData(req, tc, mode == Write);
831}
832
833void
834TLB::translateTiming(RequestPtr req, ThreadContext *tc,
835 Translation *translation, Mode mode)
836{
837 assert(translation);
838 translation->finish(translateAtomic(req, tc, mode), req, tc, mode);
839}
840
841#if FULL_SYSTEM
842
843Tick
844TLB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
845{
846 Addr va = pkt->getAddr();
847 ASI asi = (ASI)pkt->req->getAsi();
848 uint64_t temp;
849
850 DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
851 (uint32_t)pkt->req->getAsi(), pkt->getAddr());
852
853 TLB *itb = tc->getITBPtr();
854
855 switch (asi) {
856 case ASI_LSU_CONTROL_REG:
857 assert(va == 0);
858 pkt->set(tc->readMiscReg(MISCREG_MMU_LSU_CTRL));
859 break;
860 case ASI_MMU:
861 switch (va) {
862 case 0x8:
863 pkt->set(tc->readMiscReg(MISCREG_MMU_P_CONTEXT));
864 break;
865 case 0x10:
866 pkt->set(tc->readMiscReg(MISCREG_MMU_S_CONTEXT));
867 break;
868 default:
869 goto doMmuReadError;
870 }
871 break;
872 case ASI_QUEUE:
873 pkt->set(tc->readMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +
874 (va >> 4) - 0x3c));
875 break;
876 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
877 assert(va == 0);
878 pkt->set(c0_tsb_ps0);
879 break;
880 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
881 assert(va == 0);
882 pkt->set(c0_tsb_ps1);
883 break;
884 case ASI_DMMU_CTXT_ZERO_CONFIG:
885 assert(va == 0);
886 pkt->set(c0_config);
887 break;
888 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
889 assert(va == 0);
890 pkt->set(itb->c0_tsb_ps0);
891 break;
892 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
893 assert(va == 0);
894 pkt->set(itb->c0_tsb_ps1);
895 break;
896 case ASI_IMMU_CTXT_ZERO_CONFIG:
897 assert(va == 0);
898 pkt->set(itb->c0_config);
899 break;
900 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
901 assert(va == 0);
902 pkt->set(cx_tsb_ps0);
903 break;
904 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
905 assert(va == 0);
906 pkt->set(cx_tsb_ps1);
907 break;
908 case ASI_DMMU_CTXT_NONZERO_CONFIG:
909 assert(va == 0);
910 pkt->set(cx_config);
911 break;
912 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
913 assert(va == 0);
914 pkt->set(itb->cx_tsb_ps0);
915 break;
916 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
917 assert(va == 0);
918 pkt->set(itb->cx_tsb_ps1);
919 break;
920 case ASI_IMMU_CTXT_NONZERO_CONFIG:
921 assert(va == 0);
922 pkt->set(itb->cx_config);
923 break;
924 case ASI_SPARC_ERROR_STATUS_REG:
925 pkt->set((uint64_t)0);
926 break;
927 case ASI_HYP_SCRATCHPAD:
928 case ASI_SCRATCHPAD:
929 pkt->set(tc->readMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
930 break;
931 case ASI_IMMU:
932 switch (va) {
933 case 0x0:
934 temp = itb->tag_access;
935 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
936 break;
937 case 0x18:
938 pkt->set(itb->sfsr);
939 break;
940 case 0x30:
941 pkt->set(itb->tag_access);
942 break;
943 default:
944 goto doMmuReadError;
945 }
946 break;
947 case ASI_DMMU:
948 switch (va) {
949 case 0x0:
950 temp = tag_access;
951 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
952 break;
953 case 0x18:
954 pkt->set(sfsr);
955 break;
956 case 0x20:
957 pkt->set(sfar);
958 break;
959 case 0x30:
960 pkt->set(tag_access);
961 break;
962 case 0x80:
963 pkt->set(tc->readMiscReg(MISCREG_MMU_PART_ID));
964 break;
965 default:
966 goto doMmuReadError;
967 }
968 break;
969 case ASI_DMMU_TSB_PS0_PTR_REG:
970 pkt->set(MakeTsbPtr(Ps0,
971 tag_access,
972 c0_tsb_ps0,
973 c0_config,
974 cx_tsb_ps0,
975 cx_config));
976 break;
977 case ASI_DMMU_TSB_PS1_PTR_REG:
978 pkt->set(MakeTsbPtr(Ps1,
979 tag_access,
980 c0_tsb_ps1,
981 c0_config,
982 cx_tsb_ps1,
983 cx_config));
984 break;
985 case ASI_IMMU_TSB_PS0_PTR_REG:
986 pkt->set(MakeTsbPtr(Ps0,
987 itb->tag_access,
988 itb->c0_tsb_ps0,
989 itb->c0_config,
990 itb->cx_tsb_ps0,
991 itb->cx_config));
992 break;
993 case ASI_IMMU_TSB_PS1_PTR_REG:
994 pkt->set(MakeTsbPtr(Ps1,
995 itb->tag_access,
996 itb->c0_tsb_ps1,
997 itb->c0_config,
998 itb->cx_tsb_ps1,
999 itb->cx_config));
1000 break;
1001 case ASI_SWVR_INTR_RECEIVE:
1002 {
1003 SparcISA::Interrupts * interrupts =
1004 dynamic_cast<SparcISA::Interrupts *>(
1005 tc->getCpuPtr()->getInterruptController());
1006 pkt->set(interrupts->get_vec(IT_INT_VEC));
1007 }
1008 break;
1009 case ASI_SWVR_UDB_INTR_R:
1010 {
1011 SparcISA::Interrupts * interrupts =
1012 dynamic_cast<SparcISA::Interrupts *>(
1013 tc->getCpuPtr()->getInterruptController());
1014 temp = findMsbSet(interrupts->get_vec(IT_INT_VEC));
1015 tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, temp);
1016 pkt->set(temp);
1017 }
1018 break;
1019 default:
1020doMmuReadError:
1021 panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
1022 (uint32_t)asi, va);
1023 }
1024 pkt->makeAtomicResponse();
1025 return tc->getCpuPtr()->ticks(1);
1026}
1027
1028Tick
1029TLB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
1030{
1031 uint64_t data = pkt->get<uint64_t>();
1032 Addr va = pkt->getAddr();
1033 ASI asi = (ASI)pkt->req->getAsi();
1034
1035 Addr ta_insert;
1036 Addr va_insert;
1037 Addr ct_insert;
1038 int part_insert;
1039 int entry_insert = -1;
1040 bool real_insert;
1041 bool ignore;
1042 int part_id;
1043 int ctx_id;
1044 PageTableEntry pte;
1045
1046 DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
1047 (uint32_t)asi, va, data);
1048
1049 TLB *itb = tc->getITBPtr();
1050
1051 switch (asi) {
1052 case ASI_LSU_CONTROL_REG:
1053 assert(va == 0);
1054 tc->setMiscReg(MISCREG_MMU_LSU_CTRL, data);
1055 break;
1056 case ASI_MMU:
1057 switch (va) {
1058 case 0x8:
1059 tc->setMiscReg(MISCREG_MMU_P_CONTEXT, data);
1060 break;
1061 case 0x10:
1062 tc->setMiscReg(MISCREG_MMU_S_CONTEXT, data);
1063 break;
1064 default:
1065 goto doMmuWriteError;
1066 }
1067 break;
1068 case ASI_QUEUE:
1069 assert(mbits(data,13,6) == data);
1070 tc->setMiscReg(MISCREG_QUEUE_CPU_MONDO_HEAD +
1071 (va >> 4) - 0x3c, data);
1072 break;
1073 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
1074 assert(va == 0);
1075 c0_tsb_ps0 = data;
1076 break;
1077 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
1078 assert(va == 0);
1079 c0_tsb_ps1 = data;
1080 break;
1081 case ASI_DMMU_CTXT_ZERO_CONFIG:
1082 assert(va == 0);
1083 c0_config = data;
1084 break;
1085 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
1086 assert(va == 0);
1087 itb->c0_tsb_ps0 = data;
1088 break;
1089 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
1090 assert(va == 0);
1091 itb->c0_tsb_ps1 = data;
1092 break;
1093 case ASI_IMMU_CTXT_ZERO_CONFIG:
1094 assert(va == 0);
1095 itb->c0_config = data;
1096 break;
1097 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
1098 assert(va == 0);
1099 cx_tsb_ps0 = data;
1100 break;
1101 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
1102 assert(va == 0);
1103 cx_tsb_ps1 = data;
1104 break;
1105 case ASI_DMMU_CTXT_NONZERO_CONFIG:
1106 assert(va == 0);
1107 cx_config = data;
1108 break;
1109 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
1110 assert(va == 0);
1111 itb->cx_tsb_ps0 = data;
1112 break;
1113 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
1114 assert(va == 0);
1115 itb->cx_tsb_ps1 = data;
1116 break;
1117 case ASI_IMMU_CTXT_NONZERO_CONFIG:
1118 assert(va == 0);
1119 itb->cx_config = data;
1120 break;
1121 case ASI_SPARC_ERROR_EN_REG:
1122 case ASI_SPARC_ERROR_STATUS_REG:
1123 inform("Ignoring write to SPARC ERROR regsiter\n");
1124 break;
1125 case ASI_HYP_SCRATCHPAD:
1126 case ASI_SCRATCHPAD:
1127 tc->setMiscReg(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
1128 break;
1129 case ASI_IMMU:
1130 switch (va) {
1131 case 0x18:
1132 itb->sfsr = data;
1133 break;
1134 case 0x30:
1135 sext<59>(bits(data, 59,0));
1136 itb->tag_access = data;
1137 break;
1138 default:
1139 goto doMmuWriteError;
1140 }
1141 break;
1142 case ASI_ITLB_DATA_ACCESS_REG:
1143 entry_insert = bits(va, 8,3);
1144 case ASI_ITLB_DATA_IN_REG:
1145 assert(entry_insert != -1 || mbits(va,10,9) == va);
1146 ta_insert = itb->tag_access;
1147 va_insert = mbits(ta_insert, 63,13);
1148 ct_insert = mbits(ta_insert, 12,0);
1149 part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1150 real_insert = bits(va, 9,9);
1151 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1152 PageTableEntry::sun4u);
1153 tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
1154 pte, entry_insert);
1155 break;
1156 case ASI_DTLB_DATA_ACCESS_REG:
1157 entry_insert = bits(va, 8,3);
1158 case ASI_DTLB_DATA_IN_REG:
1159 assert(entry_insert != -1 || mbits(va,10,9) == va);
1160 ta_insert = tag_access;
1161 va_insert = mbits(ta_insert, 63,13);
1162 ct_insert = mbits(ta_insert, 12,0);
1163 part_insert = tc->readMiscReg(MISCREG_MMU_PART_ID);
1164 real_insert = bits(va, 9,9);
1165 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1166 PageTableEntry::sun4u);
1167 insert(va_insert, part_insert, ct_insert, real_insert, pte,
1168 entry_insert);
1169 break;
1170 case ASI_IMMU_DEMAP:
1171 ignore = false;
1172 ctx_id = -1;
1173 part_id = tc->readMiscReg(MISCREG_MMU_PART_ID);
1174 switch (bits(va,5,4)) {
1175 case 0:
1176 ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1177 break;
1178 case 1:
1179 ignore = true;
1180 break;
1181 case 3:
1182 ctx_id = 0;
1183 break;
1184 default:
1185 ignore = true;
1186 }
1187
1188 switch (bits(va,7,6)) {
1189 case 0: // demap page
1190 if (!ignore)
1191 tc->getITBPtr()->demapPage(mbits(va,63,13), part_id,
1192 bits(va,9,9), ctx_id);
1193 break;
1194 case 1: // demap context
1195 if (!ignore)
1196 tc->getITBPtr()->demapContext(part_id, ctx_id);
1197 break;
1198 case 2:
1199 tc->getITBPtr()->demapAll(part_id);
1200 break;
1201 default:
1202 panic("Invalid type for IMMU demap\n");
1203 }
1204 break;
1205 case ASI_DMMU:
1206 switch (va) {
1207 case 0x18:
1208 sfsr = data;
1209 break;
1210 case 0x30:
1211 sext<59>(bits(data, 59,0));
1212 tag_access = data;
1213 break;
1214 case 0x80:
1215 tc->setMiscReg(MISCREG_MMU_PART_ID, data);
1216 break;
1217 default:
1218 goto doMmuWriteError;
1219 }
1220 break;
1221 case ASI_DMMU_DEMAP:
1222 ignore = false;
1223 ctx_id = -1;
1224 part_id = tc->readMiscReg(MISCREG_MMU_PART_ID);
1225 switch (bits(va,5,4)) {
1226 case 0:
1227 ctx_id = tc->readMiscReg(MISCREG_MMU_P_CONTEXT);
1228 break;
1229 case 1:
1230 ctx_id = tc->readMiscReg(MISCREG_MMU_S_CONTEXT);
1231 break;
1232 case 3:
1233 ctx_id = 0;
1234 break;
1235 default:
1236 ignore = true;
1237 }
1238
1239 switch (bits(va,7,6)) {
1240 case 0: // demap page
1241 if (!ignore)
1242 demapPage(mbits(va,63,13), part_id, bits(va,9,9), ctx_id);
1243 break;
1244 case 1: // demap context
1245 if (!ignore)
1246 demapContext(part_id, ctx_id);
1247 break;
1248 case 2:
1249 demapAll(part_id);
1250 break;
1251 default:
1252 panic("Invalid type for IMMU demap\n");
1253 }
1254 break;
1255 case ASI_SWVR_INTR_RECEIVE:
1256 {
1257 int msb;
1258 // clear all the interrupts that aren't set in the write
1259 SparcISA::Interrupts * interrupts =
1260 dynamic_cast<SparcISA::Interrupts *>(
1261 tc->getCpuPtr()->getInterruptController());
1262 while (interrupts->get_vec(IT_INT_VEC) & data) {
1263 msb = findMsbSet(interrupts->get_vec(IT_INT_VEC) & data);
1264 tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, msb);
1265 }
1266 }
1267 break;
1268 case ASI_SWVR_UDB_INTR_W:
1269 tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
1270 postInterrupt(bits(data, 5, 0), 0);
1271 break;
1272 default:
1273doMmuWriteError:
1274 panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1275 (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1276 }
1277 pkt->makeAtomicResponse();
1278 return tc->getCpuPtr()->ticks(1);
1279}
1280
1281#endif
1282
1283void
1284TLB::GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs)
1285{
1286 uint64_t tag_access = mbits(addr,63,13) | mbits(ctx,12,0);
1287 TLB * itb = tc->getITBPtr();
1288 ptrs[0] = MakeTsbPtr(Ps0, tag_access,
1289 c0_tsb_ps0,
1290 c0_config,
1291 cx_tsb_ps0,
1292 cx_config);
1293 ptrs[1] = MakeTsbPtr(Ps1, tag_access,
1294 c0_tsb_ps1,
1295 c0_config,
1296 cx_tsb_ps1,
1297 cx_config);
1298 ptrs[2] = MakeTsbPtr(Ps0, tag_access,
1299 itb->c0_tsb_ps0,
1300 itb->c0_config,
1301 itb->cx_tsb_ps0,
1302 itb->cx_config);
1303 ptrs[3] = MakeTsbPtr(Ps1, tag_access,
1304 itb->c0_tsb_ps1,
1305 itb->c0_config,
1306 itb->cx_tsb_ps1,
1307 itb->cx_config);
1308}
1309
1310uint64_t
1311TLB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb,
1312 uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config)
1313{
1314 uint64_t tsb;
1315 uint64_t config;
1316
1317 if (bits(tag_access, 12,0) == 0) {
1318 tsb = c0_tsb;
1319 config = c0_config;
1320 } else {
1321 tsb = cX_tsb;
1322 config = cX_config;
1323 }
1324
1325 uint64_t ptr = mbits(tsb,63,13);
1326 bool split = bits(tsb,12,12);
1327 int tsb_size = bits(tsb,3,0);
1328 int page_size = (ps == Ps0) ? bits(config, 2,0) : bits(config,10,8);
1329
1330 if (ps == Ps1 && split)
1331 ptr |= ULL(1) << (13 + tsb_size);
1332 ptr |= (tag_access >> (9 + page_size * 3)) & mask(12+tsb_size, 4);
1333
1334 return ptr;
1335}
1336
1337void
1338TLB::serialize(std::ostream &os)
1339{
1340 SERIALIZE_SCALAR(size);
1341 SERIALIZE_SCALAR(usedEntries);
1342 SERIALIZE_SCALAR(lastReplaced);
1343
1344 // convert the pointer based free list into an index based one
1345 int *free_list = (int*)malloc(sizeof(int) * size);
1346 int cntr = 0;
1347 std::list<TlbEntry*>::iterator i;
1348 i = freeList.begin();
1349 while (i != freeList.end()) {
1350 free_list[cntr++] = ((size_t)*i - (size_t)tlb)/ sizeof(TlbEntry);
1351 i++;
1352 }
1353 SERIALIZE_SCALAR(cntr);
1354 SERIALIZE_ARRAY(free_list, cntr);
1355
1356 SERIALIZE_SCALAR(c0_tsb_ps0);
1357 SERIALIZE_SCALAR(c0_tsb_ps1);
1358 SERIALIZE_SCALAR(c0_config);
1359 SERIALIZE_SCALAR(cx_tsb_ps0);
1360 SERIALIZE_SCALAR(cx_tsb_ps1);
1361 SERIALIZE_SCALAR(cx_config);
1362 SERIALIZE_SCALAR(sfsr);
1363 SERIALIZE_SCALAR(tag_access);
1364
1365 for (int x = 0; x < size; x++) {
1366 nameOut(os, csprintf("%s.PTE%d", name(), x));
1367 tlb[x].serialize(os);
1368 }
1369 SERIALIZE_SCALAR(sfar);
1370}
1371
1372void
1373TLB::unserialize(Checkpoint *cp, const std::string &section)
1374{
1375 int oldSize;
1376
1377 paramIn(cp, section, "size", oldSize);
1378 if (oldSize != size)
1379 panic("Don't support unserializing different sized TLBs\n");
1380 UNSERIALIZE_SCALAR(usedEntries);
1381 UNSERIALIZE_SCALAR(lastReplaced);
1382
1383 int cntr;
1384 UNSERIALIZE_SCALAR(cntr);
1385
1386 int *free_list = (int*)malloc(sizeof(int) * cntr);
1387 freeList.clear();
1388 UNSERIALIZE_ARRAY(free_list, cntr);
1389 for (int x = 0; x < cntr; x++)
1390 freeList.push_back(&tlb[free_list[x]]);
1391
1392 UNSERIALIZE_SCALAR(c0_tsb_ps0);
1393 UNSERIALIZE_SCALAR(c0_tsb_ps1);
1394 UNSERIALIZE_SCALAR(c0_config);
1395 UNSERIALIZE_SCALAR(cx_tsb_ps0);
1396 UNSERIALIZE_SCALAR(cx_tsb_ps1);
1397 UNSERIALIZE_SCALAR(cx_config);
1398 UNSERIALIZE_SCALAR(sfsr);
1399 UNSERIALIZE_SCALAR(tag_access);
1400
1401 lookupTable.clear();
1402 for (int x = 0; x < size; x++) {
1403 tlb[x].unserialize(cp, csprintf("%s.PTE%d", section, x));
1404 if (tlb[x].valid)
1405 lookupTable.insert(tlb[x].range, &tlb[x]);
1406
1407 }
1408 UNSERIALIZE_SCALAR(sfar);
1409}
1410
1411} // namespace SparcISA
1412
1413SparcISA::TLB *
1414SparcTLBParams::create()
1415{
1416 return new SparcISA::TLB(this);
1417}