Deleted Added
sdiff udiff text old ( 3833:b5faabcf350e ) new ( 3836:659b8c627478 )
full compact
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 "arch/sparc/asi.hh"
32#include "arch/sparc/miscregfile.hh"
33#include "arch/sparc/tlb.hh"
34#include "base/bitfield.hh"
35#include "base/trace.hh"
36#include "cpu/thread_context.hh"
37#include "cpu/base.hh"
38#include "mem/packet_access.hh"
39#include "mem/request.hh"
40#include "sim/builder.hh"
41
42/* @todo remove some of the magic constants. -- ali
43 * */
44namespace SparcISA
45{
46
47TLB::TLB(const std::string &name, int s)
48 : SimObject(name), size(s), usedEntries(0), cacheValid(false)
49{
50 // To make this work you'll have to change the hypervisor and OS
51 if (size > 64)
52 fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");
53
54 tlb = new TlbEntry[size];
55 memset(tlb, 0, sizeof(TlbEntry) * size);
56}
57
58void
59TLB::clearUsedBits()
60{
61 MapIter i;
62 for (i = lookupTable.begin(); i != lookupTable.end();) {
63 TlbEntry *t = i->second;
64 if (!t->pte.locked()) {
65 t->used = false;
66 usedEntries--;
67 }
68 }
69}
70
71
72void
73TLB::insert(Addr va, int partition_id, int context_id, bool real,
74 const PageTableEntry& PTE, int entry)
75{
76
77
78 MapIter i;
79 TlbEntry *new_entry = NULL;
80 int x;
81
82 cacheValid = false;
83
84 DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d\n",
85 va, PTE.paddr(), partition_id, context_id, (int)real);
86
87 if (entry != -1) {
88 assert(entry < size && entry >= 0);
89 new_entry = &tlb[entry];
90 } else {
91 for (x = 0; x < size; x++) {
92 if (!tlb[x].valid || !tlb[x].used) {
93 new_entry = &tlb[x];
94 break;
95 }
96 }
97 }
98
99 // Update the last ently if their all locked
100 if (!new_entry)
101 new_entry = &tlb[size-1];
102
103 assert(PTE.valid());
104 new_entry->range.va = va;
105 new_entry->range.size = PTE.size();
106 new_entry->range.partitionId = partition_id;
107 new_entry->range.contextId = context_id;
108 new_entry->range.real = real;
109 new_entry->pte = PTE;
110 new_entry->used = true;;
111 new_entry->valid = true;
112 usedEntries++;
113
114
115 // Demap any entry that conflicts
116 i = lookupTable.find(new_entry->range);
117 if (i != lookupTable.end()) {
118 i->second->valid = false;
119 if (i->second->used) {
120 i->second->used = false;
121 usedEntries--;
122 }
123 DPRINTF(TLB, "TLB: Found conflicting entry, deleting it\n");
124 lookupTable.erase(i);
125 }
126
127 lookupTable.insert(new_entry->range, new_entry);;
128
129 // If all entries have there used bit set, clear it on them all, but the
130 // one we just inserted
131 if (usedEntries == size) {
132 clearUsedBits();
133 new_entry->used = true;
134 usedEntries++;
135 }
136
137}
138
139
140TlbEntry*
141TLB::lookup(Addr va, int partition_id, bool real, int context_id)
142{
143 MapIter i;
144 TlbRange tr;
145 TlbEntry *t;
146
147 DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n",
148 va, partition_id, context_id, real);
149 // Assemble full address structure
150 tr.va = va;
151 tr.size = va + MachineBytes;
152 tr.contextId = context_id;
153 tr.partitionId = partition_id;
154 tr.real = real;
155
156 // Try to find the entry
157 i = lookupTable.find(tr);
158 if (i == lookupTable.end()) {
159 DPRINTF(TLB, "TLB: No valid entry found\n");
160 return NULL;
161 }
162
163 // Mark the entries used bit and clear other used bits in needed
164 t = i->second;
165 DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),
166 t->pte.size());
167 if (!t->used) {
168 t->used = true;
169 usedEntries++;
170 if (usedEntries == size) {
171 clearUsedBits();
172 t->used = true;
173 usedEntries++;
174 }
175 }
176
177 return t;
178}
179
180void
181TLB::dumpAll()
182{
183 for (int x = 0; x < size; x++) {
184 if (tlb[x].valid) {
185 DPRINTFN("%4d: %#2x:%#2x %c %#4x %#8x %#8x %#16x\n",
186 x, tlb[x].range.partitionId, tlb[x].range.contextId,
187 tlb[x].range.real ? 'R' : ' ', tlb[x].range.size,
188 tlb[x].range.va, tlb[x].pte.paddr(), tlb[x].pte());
189 }
190 }
191}
192
193void
194TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
195{
196 TlbRange tr;
197 MapIter i;
198
199 cacheValid = false;
200
201 // Assemble full address structure
202 tr.va = va;
203 tr.size = va + MachineBytes;
204 tr.contextId = context_id;
205 tr.partitionId = partition_id;
206 tr.real = real;
207
208 // Demap any entry that conflicts
209 i = lookupTable.find(tr);
210 if (i != lookupTable.end()) {
211 i->second->valid = false;
212 if (i->second->used) {
213 i->second->used = false;
214 usedEntries--;
215 }
216 lookupTable.erase(i);
217 }
218}
219
220void
221TLB::demapContext(int partition_id, int context_id)
222{
223 int x;
224 cacheValid = false;
225 for (x = 0; x < size; x++) {
226 if (tlb[x].range.contextId == context_id &&
227 tlb[x].range.partitionId == partition_id) {
228 tlb[x].valid = false;
229 if (tlb[x].used) {
230 tlb[x].used = false;
231 usedEntries--;
232 }
233 lookupTable.erase(tlb[x].range);
234 }
235 }
236}
237
238void
239TLB::demapAll(int partition_id)
240{
241 int x;
242 cacheValid = false;
243 for (x = 0; x < size; x++) {
244 if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) {
245 tlb[x].valid = false;
246 if (tlb[x].used) {
247 tlb[x].used = false;
248 usedEntries--;
249 }
250 lookupTable.erase(tlb[x].range);
251 }
252 }
253}
254
255void
256TLB::invalidateAll()
257{
258 int x;
259 cacheValid = false;
260
261 for (x = 0; x < size; x++) {
262 tlb[x].valid = false;
263 }
264 usedEntries = 0;
265}
266
267uint64_t
268TLB::TteRead(int entry) {
269 assert(entry < size);
270 return tlb[entry].pte();
271}
272
273uint64_t
274TLB::TagRead(int entry) {
275 assert(entry < size);
276 uint64_t tag;
277
278 tag = tlb[entry].range.contextId | tlb[entry].range.va |
279 (uint64_t)tlb[entry].range.partitionId << 61;
280 tag |= tlb[entry].range.real ? ULL(1) << 60 : 0;
281 tag |= (uint64_t)~tlb[entry].pte._size() << 56;
282 return tag;
283}
284
285bool
286TLB::validVirtualAddress(Addr va, bool am)
287{
288 if (am)
289 return true;
290 if (va >= StartVAddrHole && va <= EndVAddrHole)
291 return false;
292 return true;
293}
294
295void
296TLB::writeSfsr(ThreadContext *tc, int reg, bool write, ContextType ct,
297 bool se, FaultTypes ft, int asi)
298{
299 uint64_t sfsr;
300 sfsr = tc->readMiscReg(reg);
301
302 if (sfsr & 0x1)
303 sfsr = 0x3;
304 else
305 sfsr = 1;
306
307 if (write)
308 sfsr |= 1 << 2;
309 sfsr |= ct << 4;
310 if (se)
311 sfsr |= 1 << 6;
312 sfsr |= ft << 7;
313 sfsr |= asi << 16;
314 tc->setMiscRegWithEffect(reg, sfsr);
315}
316
317void
318TLB::writeTagAccess(ThreadContext *tc, int reg, Addr va, int context)
319{
320 tc->setMiscRegWithEffect(reg, mbits(va, 63,13) | mbits(context,12,0));
321}
322
323void
324ITB::writeSfsr(ThreadContext *tc, bool write, ContextType ct,
325 bool se, FaultTypes ft, int asi)
326{
327 DPRINTF(TLB, "TLB: ITB Fault: w=%d ct=%d ft=%d asi=%d\n",
328 (int)write, ct, ft, asi);
329 TLB::writeSfsr(tc, MISCREG_MMU_ITLB_SFSR, write, ct, se, ft, asi);
330}
331
332void
333ITB::writeTagAccess(ThreadContext *tc, Addr va, int context)
334{
335 TLB::writeTagAccess(tc, MISCREG_MMU_ITLB_TAG_ACCESS, va, context);
336}
337
338void
339DTB::writeSfr(ThreadContext *tc, Addr a, bool write, ContextType ct,
340 bool se, FaultTypes ft, int asi)
341{
342 DPRINTF(TLB, "TLB: DTB Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n",
343 a, (int)write, ct, ft, asi);
344 TLB::writeSfsr(tc, MISCREG_MMU_DTLB_SFSR, write, ct, se, ft, asi);
345 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_SFAR, a);
346}
347
348void
349DTB::writeTagAccess(ThreadContext *tc, Addr va, int context)
350{
351 TLB::writeTagAccess(tc, MISCREG_MMU_DTLB_TAG_ACCESS, va, context);
352}
353
354
355
356Fault
357ITB::translate(RequestPtr &req, ThreadContext *tc)
358{
359 uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA);
360
361 Addr vaddr = req->getVaddr();
362 TlbEntry *e;
363
364 assert(req->getAsi() == ASI_IMPLICIT);
365
366 DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n",
367 vaddr, req->getSize());
368
369 // Be fast if we can!
370 if (cacheValid && cacheState == tlbdata) {
371 if (cacheEntry) {
372 if (cacheEntry->range.va < vaddr + sizeof(MachInst) &&
373 cacheEntry->range.va + cacheEntry->range.size >= vaddr) {
374 req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) |
375 vaddr & cacheEntry->pte.size()-1 );
376 return NoFault;
377 }
378 } else {
379 req->setPaddr(vaddr & PAddrImplMask);
380 return NoFault;
381 }
382 }
383
384 bool hpriv = bits(tlbdata,0,0);
385 bool red = bits(tlbdata,1,1);
386 bool priv = bits(tlbdata,2,2);
387 bool addr_mask = bits(tlbdata,3,3);
388 bool lsu_im = bits(tlbdata,4,4);
389
390 int part_id = bits(tlbdata,15,8);
391 int tl = bits(tlbdata,18,16);
392 int pri_context = bits(tlbdata,47,32);
393 int context;
394 ContextType ct;
395 int asi;
396 bool real = false;
397
398 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsuim:%d part_id: %#X\n",
399 priv, hpriv, red, lsu_im, part_id);
400
401 if (tl > 0) {
402 asi = ASI_N;
403 ct = Nucleus;
404 context = 0;
405 } else {
406 asi = ASI_P;
407 ct = Primary;
408 context = pri_context;
409 }
410
411 if ( hpriv || red ) {
412 cacheValid = true;
413 cacheState = tlbdata;
414 cacheEntry = NULL;
415 req->setPaddr(vaddr & PAddrImplMask);
416 return NoFault;
417 }
418
419 // If the access is unaligned trap
420 if (vaddr & 0x3) {
421 writeSfsr(tc, false, ct, false, OtherFault, asi);
422 return new MemAddressNotAligned;
423 }
424
425 if (addr_mask)
426 vaddr = vaddr & VAddrAMask;
427
428 if (!validVirtualAddress(vaddr, addr_mask)) {
429 writeSfsr(tc, false, ct, false, VaOutOfRange, asi);
430 return new InstructionAccessException;
431 }
432
433 if (!lsu_im) {
434 e = lookup(vaddr, part_id, true);
435 real = true;
436 context = 0;
437 } else {
438 e = lookup(vaddr, part_id, false, context);
439 }
440
441 if (e == NULL || !e->valid) {
442 tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS,
443 vaddr & ~BytesInPageMask | context);
444 if (real)
445 return new InstructionRealTranslationMiss;
446 else
447 return new FastInstructionAccessMMUMiss;
448 }
449
450 // were not priviledged accesing priv page
451 if (!priv && e->pte.priv()) {
452 writeSfsr(tc, false, ct, false, PrivViolation, asi);
453 return new InstructionAccessException;
454 }
455
456 // cache translation date for next translation
457 cacheValid = true;
458 cacheState = tlbdata;
459 cacheEntry = e;
460
461 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
462 vaddr & e->pte.size()-1 );
463 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
464 return NoFault;
465}
466
467
468
469Fault
470DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
471{
472 /* @todo this could really use some profiling and fixing to make it faster! */
473 uint64_t tlbdata = tc->readMiscReg(MISCREG_TLB_DATA);
474 Addr vaddr = req->getVaddr();
475 Addr size = req->getSize();
476 ASI asi;
477 asi = (ASI)req->getAsi();
478 bool implicit = false;
479 bool hpriv = bits(tlbdata,0,0);
480
481 DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
482 vaddr, size, asi);
483
484 if (asi == ASI_IMPLICIT)
485 implicit = true;
486
487 if (hpriv && implicit) {
488 req->setPaddr(vaddr & PAddrImplMask);
489 return NoFault;
490 }
491
492 // Be fast if we can!
493 if (cacheValid && cacheState == tlbdata) {
494 if (cacheEntry[0] && cacheAsi[0] == asi && cacheEntry[0]->range.va < vaddr + size &&
495 cacheEntry[0]->range.va + cacheEntry[0]->range.size >= vaddr) {
496 req->setPaddr(cacheEntry[0]->pte.paddr() & ~(cacheEntry[0]->pte.size()-1) |
497 vaddr & cacheEntry[0]->pte.size()-1 );
498 return NoFault;
499 }
500 if (cacheEntry[1] && cacheAsi[1] == asi && cacheEntry[1]->range.va < vaddr + size &&
501 cacheEntry[1]->range.va + cacheEntry[1]->range.size >= vaddr) {
502 req->setPaddr(cacheEntry[1]->pte.paddr() & ~(cacheEntry[1]->pte.size()-1) |
503 vaddr & cacheEntry[1]->pte.size()-1 );
504 return NoFault;
505 }
506 }
507
508 bool red = bits(tlbdata,1,1);
509 bool priv = bits(tlbdata,2,2);
510 bool addr_mask = bits(tlbdata,3,3);
511 bool lsu_dm = bits(tlbdata,5,5);
512
513 int part_id = bits(tlbdata,15,8);
514 int tl = bits(tlbdata,18,16);
515 int pri_context = bits(tlbdata,47,32);
516 int sec_context = bits(tlbdata,47,32);
517
518 bool real = false;
519 ContextType ct = Primary;
520 int context = 0;
521
522 TlbEntry *e;
523
524 DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
525 priv, hpriv, red, lsu_dm, part_id);
526
527 if (implicit) {
528 if (tl > 0) {
529 asi = ASI_N;
530 ct = Nucleus;
531 context = 0;
532 } else {
533 asi = ASI_P;
534 ct = Primary;
535 context = pri_context;
536 }
537 } else if (!hpriv && !red) {
538 if (tl > 0 || AsiIsNucleus(asi)) {
539 ct = Nucleus;
540 context = 0;
541 } else if (AsiIsSecondary(asi)) {
542 ct = Secondary;
543 context = sec_context;
544 } else {
545 context = pri_context;
546 ct = Primary; //???
547 }
548
549 // We need to check for priv level/asi priv
550 if (!priv && !AsiIsUnPriv(asi)) {
551 // It appears that context should be Nucleus in these cases?
552 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
553 return new PrivilegedAction;
554 }
555 if (priv && AsiIsHPriv(asi)) {
556 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi);
557 return new DataAccessException;
558 }
559
560 } else if (hpriv) {
561 if (asi == ASI_P) {
562 ct = Primary;
563 context = pri_context;
564 goto continueDtbFlow;
565 }
566 }
567
568 if (!implicit) {
569 if (AsiIsLittle(asi))
570 panic("Little Endian ASIs not supported\n");
571 if (AsiIsBlock(asi))
572 panic("Block ASIs not supported\n");
573 if (AsiIsNoFault(asi))
574 panic("No Fault ASIs not supported\n");
575 if (write && asi == ASI_LDTX_P)
576 // block init store (like write hint64)
577 goto continueDtbFlow;
578 if (AsiIsTwin(asi))
579 panic("Twin ASIs not supported\n");
580 if (AsiIsPartialStore(asi))
581 panic("Partial Store ASIs not supported\n");
582 if (AsiIsInterrupt(asi))
583 panic("Interrupt ASIs not supported\n");
584
585 if (AsiIsMmu(asi))
586 goto handleMmuRegAccess;
587 if (AsiIsScratchPad(asi))
588 goto handleScratchRegAccess;
589 if (AsiIsQueue(asi))
590 goto handleQueueRegAccess;
591 if (AsiIsSparcError(asi))
592 goto handleSparcErrorRegAccess;
593
594 if (!AsiIsReal(asi) && !AsiIsNucleus(asi))
595 panic("Accessing ASI %#X. Should we?\n", asi);
596 }
597
598continueDtbFlow:
599 // If the asi is unaligned trap
600 if (vaddr & size-1) {
601 writeSfr(tc, vaddr, false, ct, false, OtherFault, asi);
602 return new MemAddressNotAligned;
603 }
604
605 if (addr_mask)
606 vaddr = vaddr & VAddrAMask;
607
608 if (!validVirtualAddress(vaddr, addr_mask)) {
609 writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi);
610 return new DataAccessException;
611 }
612
613
614 if ((!lsu_dm && !hpriv) || AsiIsReal(asi)) {
615 real = true;
616 context = 0;
617 };
618
619 if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
620 req->setPaddr(vaddr & PAddrImplMask);
621 return NoFault;
622 }
623
624 e = lookup(vaddr, part_id, real, context);
625
626 if (e == NULL || !e->valid) {
627 tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS,
628 vaddr & ~BytesInPageMask | context);
629 DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n");
630 if (real)
631 return new DataRealTranslationMiss;
632 else
633 return new FastDataAccessMMUMiss;
634
635 }
636
637
638 if (write && !e->pte.writable()) {
639 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi);
640 return new FastDataAccessProtection;
641 }
642
643 if (e->pte.nofault() && !AsiIsNoFault(asi)) {
644 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi);
645 return new DataAccessException;
646 }
647
648 if (e->pte.sideffect())
649 req->setFlags(req->getFlags() | UNCACHEABLE);
650
651
652 if (!priv && e->pte.priv()) {
653 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi);
654 return new DataAccessException;
655 }
656
657 // cache translation date for next translation
658 cacheValid = true;
659 cacheState = tlbdata;
660 if (cacheEntry[0] != e && cacheEntry[1] != e) {
661 cacheEntry[1] = cacheEntry[0];
662 cacheEntry[0] = e;
663 cacheAsi[1] = cacheAsi[0];
664 cacheAsi[0] = asi;
665 if (implicit)
666 cacheAsi[0] = (ASI)0;
667 }
668
669 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
670 vaddr & e->pte.size()-1);
671 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
672 return NoFault;
673 /** Normal flow ends here. */
674
675handleScratchRegAccess:
676 if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
677 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
678 return new DataAccessException;
679 }
680 goto regAccessOk;
681
682handleQueueRegAccess:
683 if (!priv && !hpriv) {
684 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
685 return new PrivilegedAction;
686 }
687 if (priv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
688 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
689 return new DataAccessException;
690 }
691 goto regAccessOk;
692
693handleSparcErrorRegAccess:
694 if (!hpriv) {
695 if (priv) {
696 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
697 return new DataAccessException;
698 } else {
699 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
700 return new PrivilegedAction;
701 }
702 }
703 goto regAccessOk;
704
705
706regAccessOk:
707handleMmuRegAccess:
708 DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n");
709 req->setMmapedIpr(true);
710 req->setPaddr(req->getVaddr());
711 return NoFault;
712};
713
714Tick
715DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
716{
717 Addr va = pkt->getAddr();
718 ASI asi = (ASI)pkt->req->getAsi();
719 uint64_t temp, data;
720 uint64_t tsbtemp, cnftemp;
721
722 DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
723 (uint32_t)pkt->req->getAsi(), pkt->getAddr());
724
725 switch (asi) {
726 case ASI_LSU_CONTROL_REG:
727 assert(va == 0);
728 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_LSU_CTRL));
729 break;
730 case ASI_MMU:
731 switch (va) {
732 case 0x8:
733 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT));
734 break;
735 case 0x10:
736 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT));
737 break;
738 default:
739 goto doMmuReadError;
740 }
741 break;
742 case ASI_QUEUE:
743 pkt->set(tc->readMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
744 (va >> 4) - 0x3c));
745 break;
746 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
747 assert(va == 0);
748 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0));
749 break;
750 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
751 assert(va == 0);
752 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1));
753 break;
754 case ASI_DMMU_CTXT_ZERO_CONFIG:
755 assert(va == 0);
756 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG));
757 break;
758 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
759 assert(va == 0);
760 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0));
761 break;
762 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
763 assert(va == 0);
764 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1));
765 break;
766 case ASI_IMMU_CTXT_ZERO_CONFIG:
767 assert(va == 0);
768 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG));
769 break;
770 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
771 assert(va == 0);
772 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0));
773 break;
774 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
775 assert(va == 0);
776 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1));
777 break;
778 case ASI_DMMU_CTXT_NONZERO_CONFIG:
779 assert(va == 0);
780 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG));
781 break;
782 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
783 assert(va == 0);
784 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0));
785 break;
786 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
787 assert(va == 0);
788 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1));
789 break;
790 case ASI_IMMU_CTXT_NONZERO_CONFIG:
791 assert(va == 0);
792 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG));
793 break;
794 case ASI_SPARC_ERROR_STATUS_REG:
795 warn("returning 0 for SPARC ERROR regsiter read\n");
796 pkt->set(0);
797 break;
798 case ASI_HYP_SCRATCHPAD:
799 case ASI_SCRATCHPAD:
800 pkt->set(tc->readMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3)));
801 break;
802 case ASI_IMMU:
803 switch (va) {
804 case 0x0:
805 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
806 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
807 break;
808 case 0x30:
809 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS));
810 break;
811 default:
812 goto doMmuReadError;
813 }
814 break;
815 case ASI_DMMU:
816 switch (va) {
817 case 0x0:
818 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
819 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48);
820 break;
821 case 0x30:
822 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS));
823 break;
824 case 0x80:
825 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID));
826 break;
827 default:
828 goto doMmuReadError;
829 }
830 break;
831 case ASI_DMMU_TSB_PS0_PTR_REG:
832 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
833 if (bits(temp,12,0) == 0) {
834 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0);
835 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
836 } else {
837 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0);
838 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
839 }
840 data = mbits(tsbtemp,63,13);
841 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
842 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
843 pkt->set(data);
844 break;
845 case ASI_DMMU_TSB_PS1_PTR_REG:
846 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
847 if (bits(temp,12,0) == 0) {
848 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1);
849 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG);
850 } else {
851 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1);
852 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG);
853 }
854 data = mbits(tsbtemp,63,13);
855 if (bits(tsbtemp,12,12))
856 data |= ULL(1) << (13+bits(tsbtemp,3,0));
857 data |= temp >> (9 + bits(cnftemp,2,0) * 3) &
858 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4);
859 pkt->set(data);
860 break;
861
862 default:
863doMmuReadError:
864 panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
865 (uint32_t)asi, va);
866 }
867 pkt->result = Packet::Success;
868 return tc->getCpuPtr()->cycles(1);
869}
870
871Tick
872DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
873{
874 uint64_t data = gtoh(pkt->get<uint64_t>());
875 Addr va = pkt->getAddr();
876 ASI asi = (ASI)pkt->req->getAsi();
877
878 Addr ta_insert;
879 Addr va_insert;
880 Addr ct_insert;
881 int part_insert;
882 int entry_insert = -1;
883 bool real_insert;
884 PageTableEntry pte;
885
886 DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
887 (uint32_t)asi, va, data);
888
889 switch (asi) {
890 case ASI_LSU_CONTROL_REG:
891 assert(va == 0);
892 tc->setMiscRegWithEffect(MISCREG_MMU_LSU_CTRL, data);
893 break;
894 case ASI_MMU:
895 switch (va) {
896 case 0x8:
897 tc->setMiscRegWithEffect(MISCREG_MMU_P_CONTEXT, data);
898 break;
899 case 0x10:
900 tc->setMiscRegWithEffect(MISCREG_MMU_S_CONTEXT, data);
901 break;
902 default:
903 goto doMmuWriteError;
904 }
905 break;
906 case ASI_QUEUE:
907 assert(mbits(data,13,6) == data);
908 tc->setMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD +
909 (va >> 4) - 0x3c, data);
910 break;
911 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0:
912 assert(va == 0);
913 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0, data);
914 break;
915 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1:
916 assert(va == 0);
917 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1, data);
918 break;
919 case ASI_DMMU_CTXT_ZERO_CONFIG:
920 assert(va == 0);
921 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG, data);
922 break;
923 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0:
924 assert(va == 0);
925 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0, data);
926 break;
927 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1:
928 assert(va == 0);
929 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1, data);
930 break;
931 case ASI_IMMU_CTXT_ZERO_CONFIG:
932 assert(va == 0);
933 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG, data);
934 break;
935 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0:
936 assert(va == 0);
937 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0, data);
938 break;
939 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1:
940 assert(va == 0);
941 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1, data);
942 break;
943 case ASI_DMMU_CTXT_NONZERO_CONFIG:
944 assert(va == 0);
945 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG, data);
946 break;
947 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0:
948 assert(va == 0);
949 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0, data);
950 break;
951 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1:
952 assert(va == 0);
953 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1, data);
954 break;
955 case ASI_IMMU_CTXT_NONZERO_CONFIG:
956 assert(va == 0);
957 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG, data);
958 break;
959 case ASI_SPARC_ERROR_EN_REG:
960 case ASI_SPARC_ERROR_STATUS_REG:
961 warn("Ignoring write to SPARC ERROR regsiter\n");
962 break;
963 case ASI_HYP_SCRATCHPAD:
964 case ASI_SCRATCHPAD:
965 tc->setMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3), data);
966 break;
967 case ASI_IMMU:
968 switch (va) {
969 case 0x30:
970 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS, data);
971 break;
972 default:
973 goto doMmuWriteError;
974 }
975 break;
976 case ASI_ITLB_DATA_ACCESS_REG:
977 entry_insert = bits(va, 8,3);
978 case ASI_ITLB_DATA_IN_REG:
979 assert(entry_insert != -1 || mbits(va,10,9) == va);
980 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS);
981 va_insert = mbits(ta_insert, 63,13);
982 ct_insert = mbits(ta_insert, 12,0);
983 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
984 real_insert = bits(va, 9,9);
985 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
986 PageTableEntry::sun4u);
987 tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert,
988 pte, entry_insert);
989 break;
990 case ASI_DTLB_DATA_ACCESS_REG:
991 entry_insert = bits(va, 8,3);
992 case ASI_DTLB_DATA_IN_REG:
993 assert(entry_insert != -1 || mbits(va,10,9) == va);
994 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS);
995 va_insert = mbits(ta_insert, 63,13);
996 ct_insert = mbits(ta_insert, 12,0);
997 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID);
998 real_insert = bits(va, 9,9);
999 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
1000 PageTableEntry::sun4u);
1001 insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
1002 break;
1003 case ASI_DMMU:
1004 switch (va) {
1005 case 0x30:
1006 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS, data);
1007 break;
1008 case 0x80:
1009 tc->setMiscRegWithEffect(MISCREG_MMU_PART_ID, data);
1010 break;
1011 default:
1012 goto doMmuWriteError;
1013 }
1014 break;
1015 default:
1016doMmuWriteError:
1017 panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
1018 (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
1019 }
1020 pkt->result = Packet::Success;
1021 return tc->getCpuPtr()->cycles(1);
1022}
1023
1024void
1025TLB::serialize(std::ostream &os)
1026{
1027 panic("Need to implement serialize tlb for SPARC\n");
1028}
1029
1030void
1031TLB::unserialize(Checkpoint *cp, const std::string &section)
1032{
1033 panic("Need to implement unserialize tlb for SPARC\n");
1034}
1035
1036
1037DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB)
1038
1039BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB)
1040
1041 Param<int> size;
1042
1043END_DECLARE_SIM_OBJECT_PARAMS(ITB)
1044
1045BEGIN_INIT_SIM_OBJECT_PARAMS(ITB)
1046
1047 INIT_PARAM_DFLT(size, "TLB size", 48)
1048
1049END_INIT_SIM_OBJECT_PARAMS(ITB)
1050
1051
1052CREATE_SIM_OBJECT(ITB)
1053{
1054 return new ITB(getInstanceName(), size);
1055}
1056
1057REGISTER_SIM_OBJECT("SparcITB", ITB)
1058
1059BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB)
1060
1061 Param<int> size;
1062
1063END_DECLARE_SIM_OBJECT_PARAMS(DTB)
1064
1065BEGIN_INIT_SIM_OBJECT_PARAMS(DTB)
1066
1067 INIT_PARAM_DFLT(size, "TLB size", 64)
1068
1069END_INIT_SIM_OBJECT_PARAMS(DTB)
1070
1071
1072CREATE_SIM_OBJECT(DTB)
1073{
1074 return new DTB(getInstanceName(), size);
1075}
1076
1077REGISTER_SIM_OBJECT("SparcDTB", DTB)
1078}