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