tlb.cc revision 3811:ee71d61347f1
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/trace.hh" 35#include "cpu/thread_context.hh" 36#include "sim/builder.hh" 37 38/* @todo remove some of the magic constants. -- ali 39 * */ 40namespace SparcISA 41{ 42 43TLB::TLB(const std::string &name, int s) 44 : SimObject(name), size(s) 45{ 46 // To make this work you'll have to change the hypervisor and OS 47 if (size > 64) 48 fatal("SPARC T1 TLB registers don't support more than 64 TLB entries."); 49 50 tlb = new TlbEntry[size]; 51 memset(tlb, 0, sizeof(TlbEntry) * size); 52} 53 54void 55TLB::clearUsedBits() 56{ 57 MapIter i; 58 for (i = lookupTable.begin(); i != lookupTable.end();) { 59 TlbEntry *t = i->second; 60 if (!t->pte.locked()) { 61 t->used = false; 62 usedEntries--; 63 } 64 } 65} 66 67 68void 69TLB::insert(Addr va, int partition_id, int context_id, bool real, 70 const PageTableEntry& PTE) 71{ 72 73 74 MapIter i; 75 TlbEntry *new_entry; 76 77 DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x, pid=%d cid=%d r=%d\n", 78 va, partition_id, context_id, (int)real); 79 80 int x = -1; 81 for (x = 0; x < size; x++) { 82 if (!tlb[x].valid || !tlb[x].used) { 83 new_entry = &tlb[x]; 84 break; 85 } 86 } 87 88 // Update the last ently if their all locked 89 if (x == -1) 90 x = size - 1; 91 92 assert(PTE.valid()); 93 new_entry->range.va = va; 94 new_entry->range.size = PTE.size(); 95 new_entry->range.partitionId = partition_id; 96 new_entry->range.contextId = context_id; 97 new_entry->range.real = real; 98 new_entry->pte = PTE; 99 new_entry->used = true;; 100 new_entry->valid = true; 101 usedEntries++; 102 103 104 // Demap any entry that conflicts 105 i = lookupTable.find(new_entry->range); 106 if (i != lookupTable.end()) { 107 i->second->valid = false; 108 if (i->second->used) { 109 i->second->used = false; 110 usedEntries--; 111 } 112 DPRINTF(TLB, "TLB: Found conflicting entry, deleting it\n"); 113 lookupTable.erase(i); 114 } 115 116 lookupTable.insert(new_entry->range, new_entry);; 117 118 // If all entries have there used bit set, clear it on them all, but the 119 // one we just inserted 120 if (usedEntries == size) { 121 clearUsedBits(); 122 new_entry->used = true; 123 usedEntries++; 124 } 125 126} 127 128 129TlbEntry* 130TLB::lookup(Addr va, int partition_id, bool real, int context_id) 131{ 132 MapIter i; 133 TlbRange tr; 134 TlbEntry *t; 135 136 DPRINTF(TLB, "TLB: Looking up entry va=%#x pid=%d cid=%d r=%d\n", 137 va, partition_id, context_id, real); 138 // Assemble full address structure 139 tr.va = va; 140 tr.size = va + MachineBytes; 141 tr.contextId = context_id; 142 tr.partitionId = partition_id; 143 tr.real = real; 144 145 // Try to find the entry 146 i = lookupTable.find(tr); 147 if (i == lookupTable.end()) { 148 DPRINTF(TLB, "TLB: No valid entry found\n"); 149 return NULL; 150 } 151 DPRINTF(TLB, "TLB: Valid entry found\n"); 152 153 // Mark the entries used bit and clear other used bits in needed 154 t = i->second; 155 if (!t->used) { 156 t->used = true; 157 usedEntries++; 158 if (usedEntries == size) { 159 clearUsedBits(); 160 t->used = true; 161 usedEntries++; 162 } 163 } 164 165 return t; 166} 167 168 169void 170TLB::demapPage(Addr va, int partition_id, bool real, int context_id) 171{ 172 TlbRange tr; 173 MapIter i; 174 175 // Assemble full address structure 176 tr.va = va; 177 tr.size = va + MachineBytes; 178 tr.contextId = context_id; 179 tr.partitionId = partition_id; 180 tr.real = real; 181 182 // Demap any entry that conflicts 183 i = lookupTable.find(tr); 184 if (i != lookupTable.end()) { 185 i->second->valid = false; 186 if (i->second->used) { 187 i->second->used = false; 188 usedEntries--; 189 } 190 lookupTable.erase(i); 191 } 192} 193 194void 195TLB::demapContext(int partition_id, int context_id) 196{ 197 int x; 198 for (x = 0; x < size; x++) { 199 if (tlb[x].range.contextId == context_id && 200 tlb[x].range.partitionId == partition_id) { 201 tlb[x].valid = false; 202 if (tlb[x].used) { 203 tlb[x].used = false; 204 usedEntries--; 205 } 206 lookupTable.erase(tlb[x].range); 207 } 208 } 209} 210 211void 212TLB::demapAll(int partition_id) 213{ 214 int x; 215 for (x = 0; x < size; x++) { 216 if (!tlb[x].pte.locked() && tlb[x].range.partitionId == partition_id) { 217 tlb[x].valid = false; 218 if (tlb[x].used) { 219 tlb[x].used = false; 220 usedEntries--; 221 } 222 lookupTable.erase(tlb[x].range); 223 } 224 } 225} 226 227void 228TLB::invalidateAll() 229{ 230 int x; 231 for (x = 0; x < size; x++) { 232 tlb[x].valid = false; 233 } 234 usedEntries = 0; 235} 236 237uint64_t 238TLB::TteRead(int entry) { 239 assert(entry < size); 240 return tlb[entry].pte(); 241} 242 243uint64_t 244TLB::TagRead(int entry) { 245 assert(entry < size); 246 uint64_t tag; 247 248 tag = tlb[entry].range.contextId | tlb[entry].range.va | 249 (uint64_t)tlb[entry].range.partitionId << 61; 250 tag |= tlb[entry].range.real ? ULL(1) << 60 : 0; 251 tag |= (uint64_t)~tlb[entry].pte._size() << 56; 252 return tag; 253} 254 255bool 256TLB::validVirtualAddress(Addr va, bool am) 257{ 258 if (am) 259 return true; 260 if (va >= StartVAddrHole && va <= EndVAddrHole) 261 return false; 262 return true; 263} 264 265void 266TLB::writeSfsr(ThreadContext *tc, int reg, bool write, ContextType ct, 267 bool se, FaultTypes ft, int asi) 268{ 269 uint64_t sfsr; 270 sfsr = tc->readMiscReg(reg); 271 272 if (sfsr & 0x1) 273 sfsr = 0x3; 274 else 275 sfsr = 1; 276 277 if (write) 278 sfsr |= 1 << 2; 279 sfsr |= ct << 4; 280 if (se) 281 sfsr |= 1 << 6; 282 sfsr |= ft << 7; 283 sfsr |= asi << 16; 284 tc->setMiscReg(reg, sfsr); 285} 286 287 288void 289ITB::writeSfsr(ThreadContext *tc, bool write, ContextType ct, 290 bool se, FaultTypes ft, int asi) 291{ 292 DPRINTF(TLB, "TLB: ITB Fault: w=%d ct=%d ft=%d asi=%d\n", 293 (int)write, ct, ft, asi); 294 TLB::writeSfsr(tc, MISCREG_MMU_ITLB_SFSR, write, ct, se, ft, asi); 295} 296 297void 298DTB::writeSfr(ThreadContext *tc, Addr a, bool write, ContextType ct, 299 bool se, FaultTypes ft, int asi) 300{ 301 DPRINTF(TLB, "TLB: DTB Fault: A=%#x w=%d ct=%d ft=%d asi=%d\n", 302 a, (int)write, ct, ft, asi); 303 TLB::writeSfsr(tc, MISCREG_MMU_DTLB_SFSR, write, ct, se, ft, asi); 304 tc->setMiscReg(MISCREG_MMU_DTLB_SFAR, a); 305} 306 307 308Fault 309ITB::translate(RequestPtr &req, ThreadContext *tc) 310{ 311 uint64_t hpstate = tc->readMiscReg(MISCREG_HPSTATE); 312 uint64_t pstate = tc->readMiscReg(MISCREG_PSTATE); 313 bool lsuIm = tc->readMiscReg(MISCREG_MMU_LSU_CTRL) >> 2 & 0x1; 314 uint64_t tl = tc->readMiscReg(MISCREG_TL); 315 uint64_t part_id = tc->readMiscReg(MISCREG_MMU_PART_ID); 316 bool addr_mask = pstate >> 3 & 0x1; 317 bool priv = pstate >> 2 & 0x1; 318 Addr vaddr = req->getVaddr(); 319 int context; 320 ContextType ct; 321 int asi; 322 bool real = false; 323 TlbEntry *e; 324 325 DPRINTF(TLB, "TLB: ITB Request to translate va=%#x size=%d\n", 326 vaddr, req->getSize()); 327 328 assert(req->getAsi() == ASI_IMPLICIT); 329 330 if (tl > 0) { 331 asi = ASI_N; 332 ct = Nucleus; 333 context = 0; 334 } else { 335 asi = ASI_P; 336 ct = Primary; 337 context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT); 338 } 339 340 if ( hpstate >> 2 & 0x1 || hpstate >> 5 & 0x1 ) { 341 req->setPaddr(req->getVaddr() & PAddrImplMask); 342 return NoFault; 343 } 344 345 // If the asi is unaligned trap 346 if (vaddr & 0x7) { 347 writeSfsr(tc, false, ct, false, OtherFault, asi); 348 return new MemAddressNotAligned; 349 } 350 351 if (addr_mask) 352 vaddr = vaddr & VAddrAMask; 353 354 if (!validVirtualAddress(vaddr, addr_mask)) { 355 writeSfsr(tc, false, ct, false, VaOutOfRange, asi); 356 return new InstructionAccessException; 357 } 358 359 if (lsuIm) { 360 e = lookup(req->getVaddr(), part_id, true); 361 real = true; 362 context = 0; 363 } else { 364 e = lookup(vaddr, part_id, false, context); 365 } 366 367 if (e == NULL || !e->valid) { 368 tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS, 369 vaddr & ~BytesInPageMask | context); 370 if (real) 371 return new InstructionRealTranslationMiss; 372 else 373 return new FastInstructionAccessMMUMiss; 374 } 375 376 // were not priviledged accesing priv page 377 if (!priv && e->pte.priv()) { 378 writeSfsr(tc, false, ct, false, PrivViolation, asi); 379 return new InstructionAccessException; 380 } 381 382 req->setPaddr(e->pte.paddr() & ~e->pte.size() | 383 req->getVaddr() & e->pte.size()); 384 return NoFault; 385} 386 387 388 389Fault 390DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) 391{ 392 /* @todo this could really use some profiling and fixing to make it faster! */ 393 uint64_t hpstate = tc->readMiscReg(MISCREG_HPSTATE); 394 uint64_t pstate = tc->readMiscReg(MISCREG_PSTATE); 395 bool lsuDm = tc->readMiscReg(MISCREG_MMU_LSU_CTRL) >> 3 & 0x1; 396 uint64_t tl = tc->readMiscReg(MISCREG_TL); 397 uint64_t part_id = tc->readMiscReg(MISCREG_MMU_PART_ID); 398 bool hpriv = hpstate >> 2 & 0x1; 399 bool red = hpstate >> 5 >> 0x1; 400 bool addr_mask = pstate >> 3 & 0x1; 401 bool priv = pstate >> 2 & 0x1; 402 bool implicit = false; 403 bool real = false; 404 Addr vaddr = req->getVaddr(); 405 Addr size = req->getSize(); 406 ContextType ct; 407 int context; 408 ASI asi; 409 410 TlbEntry *e; 411 412 asi = (ASI)req->getAsi(); 413 DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n", 414 vaddr, size, asi); 415 416 if (asi == ASI_IMPLICIT) 417 implicit = true; 418 419 if (implicit) { 420 if (tl > 0) { 421 asi = ASI_N; 422 ct = Nucleus; 423 context = 0; 424 } else { 425 asi = ASI_P; 426 ct = Primary; 427 context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT); 428 } 429 } else if (!hpriv && !red) { 430 if (tl > 0) { 431 ct = Nucleus; 432 context = 0; 433 } else if (AsiIsSecondary(asi)) { 434 ct = Secondary; 435 context = tc->readMiscReg(MISCREG_MMU_S_CONTEXT); 436 } else { 437 context = tc->readMiscReg(MISCREG_MMU_P_CONTEXT); 438 ct = Primary; //??? 439 } 440 441 // We need to check for priv level/asi priv 442 if (!priv && !AsiIsUnPriv(asi)) { 443 // It appears that context should be Nucleus in these cases? 444 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi); 445 return new PrivilegedAction; 446 } 447 if (priv && AsiIsHPriv(asi)) { 448 writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi); 449 return new DataAccessException; 450 } 451 452 } 453 454 // If the asi is unaligned trap 455 if (vaddr & size-1) { 456 writeSfr(tc, vaddr, false, ct, false, OtherFault, asi); 457 return new MemAddressNotAligned; 458 } 459 460 if (addr_mask) 461 vaddr = vaddr & VAddrAMask; 462 463 if (!validVirtualAddress(vaddr, addr_mask)) { 464 writeSfr(tc, vaddr, false, ct, true, VaOutOfRange, asi); 465 return new DataAccessException; 466 } 467 468 if (!implicit) { 469 if (AsiIsLittle(asi)) 470 panic("Little Endian ASIs not supported\n"); 471 if (AsiIsBlock(asi)) 472 panic("Block ASIs not supported\n"); 473 if (AsiIsNoFault(asi)) 474 panic("No Fault ASIs not supported\n"); 475 if (AsiIsTwin(asi)) 476 panic("Twin ASIs not supported\n"); 477 if (AsiIsPartialStore(asi)) 478 panic("Partial Store ASIs not supported\n"); 479 if (AsiIsMmu(asi)) 480 goto handleMmuRegAccess; 481 482 if (AsiIsScratchPad(asi)) 483 goto handleScratchRegAccess; 484 } 485 486 if ((!lsuDm && !hpriv) || AsiIsReal(asi)) { 487 real = true; 488 context = 0; 489 }; 490 491 if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) { 492 req->setPaddr(req->getVaddr() & PAddrImplMask); 493 return NoFault; 494 } 495 496 e = lookup(req->getVaddr(), part_id, real, context); 497 498 if (e == NULL || !e->valid) { 499 tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS, 500 vaddr & ~BytesInPageMask | context); 501 DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n"); 502 if (real) 503 return new DataRealTranslationMiss; 504 else 505 return new FastDataAccessMMUMiss; 506 507 } 508 509 510 if (write && !e->pte.writable()) { 511 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), OtherFault, asi); 512 return new FastDataAccessProtection; 513 } 514 515 if (e->pte.nofault() && !AsiIsNoFault(asi)) { 516 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), LoadFromNfo, asi); 517 return new DataAccessException; 518 } 519 520 if (e->pte.sideffect()) 521 req->setFlags(req->getFlags() | UNCACHEABLE); 522 523 524 if (!priv && e->pte.priv()) { 525 writeSfr(tc, vaddr, write, ct, e->pte.sideffect(), PrivViolation, asi); 526 return new DataAccessException; 527 } 528 529 req->setPaddr(e->pte.paddr() & ~e->pte.size() | 530 req->getVaddr() & e->pte.size()); 531 return NoFault; 532 /** Normal flow ends here. */ 533 534handleScratchRegAccess: 535 if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) { 536 writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi); 537 return new DataAccessException; 538 } 539handleMmuRegAccess: 540 DPRINTF(TLB, "TLB: DTB Translating MM IPR access\n"); 541 req->setMmapedIpr(true); 542 req->setPaddr(req->getVaddr()); 543 return NoFault; 544}; 545 546Tick 547DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) 548{ 549 panic("need to implement DTB::doMmuRegRead()\n"); 550} 551 552Tick 553DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt) 554{ 555 panic("need to implement DTB::doMmuRegWrite()\n"); 556} 557 558void 559TLB::serialize(std::ostream &os) 560{ 561 panic("Need to implement serialize tlb for SPARC\n"); 562} 563 564void 565TLB::unserialize(Checkpoint *cp, const std::string §ion) 566{ 567 panic("Need to implement unserialize tlb for SPARC\n"); 568} 569 570 571DEFINE_SIM_OBJECT_CLASS_NAME("SparcTLB", TLB) 572 573BEGIN_DECLARE_SIM_OBJECT_PARAMS(ITB) 574 575 Param<int> size; 576 577END_DECLARE_SIM_OBJECT_PARAMS(ITB) 578 579BEGIN_INIT_SIM_OBJECT_PARAMS(ITB) 580 581 INIT_PARAM_DFLT(size, "TLB size", 48) 582 583END_INIT_SIM_OBJECT_PARAMS(ITB) 584 585 586CREATE_SIM_OBJECT(ITB) 587{ 588 return new ITB(getInstanceName(), size); 589} 590 591REGISTER_SIM_OBJECT("SparcITB", ITB) 592 593BEGIN_DECLARE_SIM_OBJECT_PARAMS(DTB) 594 595 Param<int> size; 596 597END_DECLARE_SIM_OBJECT_PARAMS(DTB) 598 599BEGIN_INIT_SIM_OBJECT_PARAMS(DTB) 600 601 INIT_PARAM_DFLT(size, "TLB size", 64) 602 603END_INIT_SIM_OBJECT_PARAMS(DTB) 604 605 606CREATE_SIM_OBJECT(DTB) 607{ 608 return new DTB(getInstanceName(), size); 609} 610 611REGISTER_SIM_OBJECT("SparcDTB", DTB) 612} 613