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