tlb.cc revision 3856:8815ad4f0661
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 (!write && asi == ASI_QUAD_LDD) 579 goto continueDtbFlow; 580 581 if (AsiIsTwin(asi)) 582 panic("Twin ASIs not supported\n"); 583 if (AsiIsPartialStore(asi)) 584 panic("Partial Store ASIs not supported\n"); 585 if (AsiIsInterrupt(asi)) 586 panic("Interrupt ASIs not supported\n"); 587 588 if (AsiIsMmu(asi)) 589 goto handleMmuRegAccess; 590 if (AsiIsScratchPad(asi)) 591 goto handleScratchRegAccess; 592 if (AsiIsQueue(asi)) 593 goto handleQueueRegAccess; 594 if (AsiIsSparcError(asi)) 595 goto handleSparcErrorRegAccess; 596 597 if (!AsiIsReal(asi) && !AsiIsNucleus(asi)) 598 panic("Accessing ASI %#X. Should we?\n", asi); 599 } 600 601continueDtbFlow: 602 // If the asi is unaligned trap 603 if (vaddr & size-1) { 604 writeSfr(tc, vaddr, false, ct, false, OtherFault, asi); 605 return new MemAddressNotAligned; 606 } 607 608 if (addr_mask) 609 vaddr = vaddr & VAddrAMask; 610 611 if (!validVirtualAddress(vaddr, addr_mask)) { 612 writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi); 613 return new DataAccessException; 614 } 615 616 617 if ((!lsu_dm && !hpriv) || AsiIsReal(asi)) { 618 real = true; 619 context = 0; 620 }; 621 622 if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) { 623 req->setPaddr(vaddr & PAddrImplMask); 624 return NoFault; 625 } 626 627 e = lookup(vaddr, part_id, real, context); 628 629 if (e == NULL || !e->valid) { 630 tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS, 631 vaddr & ~BytesInPageMask | context); 632 DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n"); 633 if (real) 634 return new DataRealTranslationMiss; 635 else 636 return new FastDataAccessMMUMiss; 637 638 } 639 640 641 if (write && !e->pte.writable()) { 642 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi); 643 return new FastDataAccessProtection; 644 } 645 646 if (e->pte.nofault() && !AsiIsNoFault(asi)) { 647 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi); 648 return new DataAccessException; 649 } 650 651 if (e->pte.sideffect()) 652 req->setFlags(req->getFlags() | UNCACHEABLE); 653 654 655 if (!priv && e->pte.priv()) { 656 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi); 657 return new DataAccessException; 658 } 659 660 // cache translation date for next translation 661 cacheValid = true; 662 cacheState = tlbdata; 663 if (cacheEntry[0] != e && cacheEntry[1] != e) { 664 cacheEntry[1] = cacheEntry[0]; 665 cacheEntry[0] = e; 666 cacheAsi[1] = cacheAsi[0]; 667 cacheAsi[0] = asi; 668 if (implicit) 669 cacheAsi[0] = (ASI)0; 670 } 671 672 req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) | 673 vaddr & e->pte.size()-1); 674 DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr()); 675 return NoFault; 676 /** Normal flow ends here. */ 677 678handleScratchRegAccess: 679 if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) { 680 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); 681 return new DataAccessException; 682 } 683 goto regAccessOk; 684 685handleQueueRegAccess: 686 if (!priv && !hpriv) { 687 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); 688 return new PrivilegedAction; 689 } 690 if (priv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) { 691 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); 692 return new DataAccessException; 693 } 694 goto regAccessOk; 695 696handleSparcErrorRegAccess: 697 if (!hpriv) { 698 if (priv) { 699 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); 700 return new DataAccessException; 701 } else { 702 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); 703 return new PrivilegedAction; 704 } 705 } 706 goto regAccessOk; 707 708 709regAccessOk: 710handleMmuRegAccess: 711 DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n"); 712 req->setMmapedIpr(true); 713 req->setPaddr(req->getVaddr()); 714 return NoFault; 715}; 716 717Tick 718DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) 719{ 720 Addr va = pkt->getAddr(); 721 ASI asi = (ASI)pkt->req->getAsi(); 722 uint64_t temp, data; 723 uint64_t tsbtemp, cnftemp; 724 725 DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n", 726 (uint32_t)pkt->req->getAsi(), pkt->getAddr()); 727 728 switch (asi) { 729 case ASI_LSU_CONTROL_REG: 730 assert(va == 0); 731 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_LSU_CTRL)); 732 break; 733 case ASI_MMU: 734 switch (va) { 735 case 0x8: 736 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_P_CONTEXT)); 737 break; 738 case 0x10: 739 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_S_CONTEXT)); 740 break; 741 default: 742 goto doMmuReadError; 743 } 744 break; 745 case ASI_QUEUE: 746 pkt->set(tc->readMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD + 747 (va >> 4) - 0x3c)); 748 break; 749 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0: 750 assert(va == 0); 751 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0)); 752 break; 753 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1: 754 assert(va == 0); 755 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1)); 756 break; 757 case ASI_DMMU_CTXT_ZERO_CONFIG: 758 assert(va == 0); 759 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG)); 760 break; 761 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0: 762 assert(va == 0); 763 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0)); 764 break; 765 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1: 766 assert(va == 0); 767 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1)); 768 break; 769 case ASI_IMMU_CTXT_ZERO_CONFIG: 770 assert(va == 0); 771 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG)); 772 break; 773 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0: 774 assert(va == 0); 775 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0)); 776 break; 777 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1: 778 assert(va == 0); 779 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1)); 780 break; 781 case ASI_DMMU_CTXT_NONZERO_CONFIG: 782 assert(va == 0); 783 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG)); 784 break; 785 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0: 786 assert(va == 0); 787 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0)); 788 break; 789 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1: 790 assert(va == 0); 791 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1)); 792 break; 793 case ASI_IMMU_CTXT_NONZERO_CONFIG: 794 assert(va == 0); 795 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG)); 796 break; 797 case ASI_SPARC_ERROR_STATUS_REG: 798 warn("returning 0 for SPARC ERROR regsiter read\n"); 799 pkt->set(0); 800 break; 801 case ASI_HYP_SCRATCHPAD: 802 case ASI_SCRATCHPAD: 803 pkt->set(tc->readMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3))); 804 break; 805 case ASI_IMMU: 806 switch (va) { 807 case 0x0: 808 temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS); 809 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48); 810 break; 811 case 0x30: 812 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS)); 813 break; 814 default: 815 goto doMmuReadError; 816 } 817 break; 818 case ASI_DMMU: 819 switch (va) { 820 case 0x0: 821 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS); 822 pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48); 823 break; 824 case 0x30: 825 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS)); 826 break; 827 case 0x80: 828 pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID)); 829 break; 830 default: 831 goto doMmuReadError; 832 } 833 break; 834 case ASI_DMMU_TSB_PS0_PTR_REG: 835 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS); 836 if (bits(temp,12,0) == 0) { 837 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0); 838 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG); 839 } else { 840 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0); 841 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG); 842 } 843 data = mbits(tsbtemp,63,13); 844 data |= temp >> (9 + bits(cnftemp,2,0) * 3) & 845 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4); 846 pkt->set(data); 847 break; 848 case ASI_DMMU_TSB_PS1_PTR_REG: 849 temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS); 850 if (bits(temp,12,0) == 0) { 851 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1); 852 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG); 853 } else { 854 tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1); 855 cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG); 856 } 857 data = mbits(tsbtemp,63,13); 858 if (bits(tsbtemp,12,12)) 859 data |= ULL(1) << (13+bits(tsbtemp,3,0)); 860 data |= temp >> (9 + bits(cnftemp,2,0) * 3) & 861 mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4); 862 pkt->set(data); 863 break; 864 865 default: 866doMmuReadError: 867 panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n", 868 (uint32_t)asi, va); 869 } 870 pkt->result = Packet::Success; 871 return tc->getCpuPtr()->cycles(1); 872} 873 874Tick 875DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt) 876{ 877 uint64_t data = gtoh(pkt->get<uint64_t>()); 878 Addr va = pkt->getAddr(); 879 ASI asi = (ASI)pkt->req->getAsi(); 880 881 Addr ta_insert; 882 Addr va_insert; 883 Addr ct_insert; 884 int part_insert; 885 int entry_insert = -1; 886 bool real_insert; 887 PageTableEntry pte; 888 889 DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n", 890 (uint32_t)asi, va, data); 891 892 switch (asi) { 893 case ASI_LSU_CONTROL_REG: 894 assert(va == 0); 895 tc->setMiscRegWithEffect(MISCREG_MMU_LSU_CTRL, data); 896 break; 897 case ASI_MMU: 898 switch (va) { 899 case 0x8: 900 tc->setMiscRegWithEffect(MISCREG_MMU_P_CONTEXT, data); 901 break; 902 case 0x10: 903 tc->setMiscRegWithEffect(MISCREG_MMU_S_CONTEXT, data); 904 break; 905 default: 906 goto doMmuWriteError; 907 } 908 break; 909 case ASI_QUEUE: 910 assert(mbits(data,13,6) == data); 911 tc->setMiscRegWithEffect(MISCREG_QUEUE_CPU_MONDO_HEAD + 912 (va >> 4) - 0x3c, data); 913 break; 914 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS0: 915 assert(va == 0); 916 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS0, data); 917 break; 918 case ASI_DMMU_CTXT_ZERO_TSB_BASE_PS1: 919 assert(va == 0); 920 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_TSB_PS1, data); 921 break; 922 case ASI_DMMU_CTXT_ZERO_CONFIG: 923 assert(va == 0); 924 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_C0_CONFIG, data); 925 break; 926 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS0: 927 assert(va == 0); 928 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0, data); 929 break; 930 case ASI_IMMU_CTXT_ZERO_TSB_BASE_PS1: 931 assert(va == 0); 932 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1, data); 933 break; 934 case ASI_IMMU_CTXT_ZERO_CONFIG: 935 assert(va == 0); 936 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG, data); 937 break; 938 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS0: 939 assert(va == 0); 940 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS0, data); 941 break; 942 case ASI_DMMU_CTXT_NONZERO_TSB_BASE_PS1: 943 assert(va == 0); 944 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_TSB_PS1, data); 945 break; 946 case ASI_DMMU_CTXT_NONZERO_CONFIG: 947 assert(va == 0); 948 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_CX_CONFIG, data); 949 break; 950 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS0: 951 assert(va == 0); 952 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0, data); 953 break; 954 case ASI_IMMU_CTXT_NONZERO_TSB_BASE_PS1: 955 assert(va == 0); 956 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1, data); 957 break; 958 case ASI_IMMU_CTXT_NONZERO_CONFIG: 959 assert(va == 0); 960 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG, data); 961 break; 962 case ASI_SPARC_ERROR_EN_REG: 963 case ASI_SPARC_ERROR_STATUS_REG: 964 warn("Ignoring write to SPARC ERROR regsiter\n"); 965 break; 966 case ASI_HYP_SCRATCHPAD: 967 case ASI_SCRATCHPAD: 968 tc->setMiscRegWithEffect(MISCREG_SCRATCHPAD_R0 + (va >> 3), data); 969 break; 970 case ASI_IMMU: 971 switch (va) { 972 case 0x30: 973 tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS, data); 974 break; 975 default: 976 goto doMmuWriteError; 977 } 978 break; 979 case ASI_ITLB_DATA_ACCESS_REG: 980 entry_insert = bits(va, 8,3); 981 case ASI_ITLB_DATA_IN_REG: 982 assert(entry_insert != -1 || mbits(va,10,9) == va); 983 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS); 984 va_insert = mbits(ta_insert, 63,13); 985 ct_insert = mbits(ta_insert, 12,0); 986 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID); 987 real_insert = bits(va, 9,9); 988 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v : 989 PageTableEntry::sun4u); 990 tc->getITBPtr()->insert(va_insert, part_insert, ct_insert, real_insert, 991 pte, entry_insert); 992 break; 993 case ASI_DTLB_DATA_ACCESS_REG: 994 entry_insert = bits(va, 8,3); 995 case ASI_DTLB_DATA_IN_REG: 996 assert(entry_insert != -1 || mbits(va,10,9) == va); 997 ta_insert = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS); 998 va_insert = mbits(ta_insert, 63,13); 999 ct_insert = mbits(ta_insert, 12,0); 1000 part_insert = tc->readMiscRegWithEffect(MISCREG_MMU_PART_ID); 1001 real_insert = bits(va, 9,9); 1002 pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v : 1003 PageTableEntry::sun4u); 1004 insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert); 1005 break; 1006 case ASI_DMMU: 1007 switch (va) { 1008 case 0x30: 1009 tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS, data); 1010 break; 1011 case 0x80: 1012 tc->setMiscRegWithEffect(MISCREG_MMU_PART_ID, data); 1013 break; 1014 default: 1015 goto doMmuWriteError; 1016 } 1017 break; 1018 default: 1019doMmuWriteError: 1020 panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n", 1021 (uint32_t)pkt->req->getAsi(), pkt->getAddr(), data); 1022 } 1023 pkt->result = Packet::Success; 1024 return tc->getCpuPtr()->cycles(1); 1025} 1026 1027void 1028TLB::serialize(std::ostream &os) 1029{ 1030 panic("Need to implement serialize tlb for SPARC\n"); 1031} 1032 1033void 1034TLB::unserialize(Checkpoint *cp, const std::string §ion) 1035{ 1036 panic("Need to implement unserialize tlb for SPARC\n"); 1037} 1038 1039 1040DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB) 1041 1042BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB) 1043 1044 Param<int> size; 1045 1046END_DECLARE_SIM_OBJECT_PARAMS(ITB) 1047 1048BEGIN_INIT_SIM_OBJECT_PARAMS(ITB) 1049 1050 INIT_PARAM_DFLT(size, "TLB size", 48) 1051 1052END_INIT_SIM_OBJECT_PARAMS(ITB) 1053 1054 1055CREATE_SIM_OBJECT(ITB) 1056{ 1057 return new ITB(getInstanceName(), size); 1058} 1059 1060REGISTER_SIM_OBJECT("SparcITB", ITB) 1061 1062BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB) 1063 1064 Param<int> size; 1065 1066END_DECLARE_SIM_OBJECT_PARAMS(DTB) 1067 1068BEGIN_INIT_SIM_OBJECT_PARAMS(DTB) 1069 1070 INIT_PARAM_DFLT(size, "TLB size", 64) 1071 1072END_INIT_SIM_OBJECT_PARAMS(DTB) 1073 1074 1075CREATE_SIM_OBJECT(DTB) 1076{ 1077 return new DTB(getInstanceName(), size); 1078} 1079 1080REGISTER_SIM_OBJECT("SparcDTB", DTB) 1081} 1082