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