tlb.cc revision 5224:0e354459fb8a
1/* 2 * Copyright 2007 MIPS Technologies, Inc. All Rights Reserved 3 * 4 * This software is part of the M5 simulator. 5 * 6 * THIS IS A LEGAL AGREEMENT. BY DOWNLOADING, USING, COPYING, CREATING 7 * DERIVATIVE WORKS, AND/OR DISTRIBUTING THIS SOFTWARE YOU ARE AGREEING 8 * TO THESE TERMS AND CONDITIONS. 9 * 10 * Permission is granted to use, copy, create derivative works and 11 * distribute this software and such derivative works for any purpose, 12 * so long as (1) the copyright notice above, this grant of permission, 13 * and the disclaimer below appear in all copies and derivative works 14 * made, (2) the copyright notice above is augmented as appropriate to 15 * reflect the addition of any new copyrightable work in a derivative 16 * work (e.g., Copyright N) <Publication Year> Copyright Owner), and (3) 17 * the name of MIPS Technologies, Inc. ($(B!H(BMIPS$(B!I(B) is not used in any 18 * advertising or publicity pertaining to the use or distribution of 19 * this software without specific, written prior authorization. 20 * 21 * THIS SOFTWARE IS PROVIDED $(B!H(BAS IS.$(B!I(B MIPS MAKES NO WARRANTIES AND 22 * DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, STATUTORY, IMPLIED OR 23 * OTHERWISE, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND 25 * NON-INFRINGEMENT OF THIRD PARTY RIGHTS, REGARDING THIS SOFTWARE. 26 * IN NO EVENT SHALL MIPS BE LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, 27 * INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL, OR PUNITIVE DAMAGES OF 28 * ANY KIND OR NATURE, ARISING OUT OF OR IN CONNECTION WITH THIS AGREEMENT, 29 * THIS SOFTWARE AND/OR THE USE OF THIS SOFTWARE, WHETHER SUCH LIABILITY 30 * IS ASSERTED ON THE BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE OR 31 * STRICT LIABILITY), OR OTHERWISE, EVEN IF MIPS HAS BEEN WARNED OF THE 32 * POSSIBILITY OF ANY SUCH LOSS OR DAMAGE IN ADVANCE. 33 * 34 * Authors: Jaidev P. Patwardhan 35 * 36 */ 37 38#include <string> 39#include <vector> 40 41#include "arch/mips/pra_constants.hh" 42#include "arch/mips/pagetable.hh" 43#include "arch/mips/tlb.hh" 44#include "arch/mips/faults.hh" 45#include "arch/mips/utility.hh" 46#include "base/inifile.hh" 47#include "base/str.hh" 48#include "base/trace.hh" 49#include "cpu/thread_context.hh" 50#include "sim/process.hh" 51#include "mem/page_table.hh" 52#include "params/MipsDTB.hh" 53#include "params/MipsITB.hh" 54#include "params/MipsTLB.hh" 55#include "params/MipsUTB.hh" 56 57 58using namespace std; 59using namespace MipsISA; 60 61/////////////////////////////////////////////////////////////////////// 62// 63// MIPS TLB 64// 65 66#define MODE2MASK(X) (1 << (X)) 67 68TLB::TLB(const Params *p) 69 : SimObject(p), size(p->size), nlu(0) 70{ 71 table = new MipsISA::PTE[size]; 72 memset(table, 0, sizeof(MipsISA::PTE[size])); 73 smallPages=0; 74} 75 76TLB::~TLB() 77{ 78 if (table) 79 delete [] table; 80} 81 82// look up an entry in the TLB 83MipsISA::PTE * 84TLB::lookup(Addr vpn, uint8_t asn) const 85{ 86 // assume not found... 87 MipsISA::PTE *retval = NULL; 88 PageTable::const_iterator i = lookupTable.find(vpn); 89 if (i != lookupTable.end()) { 90 while (i->first == vpn) { 91 int index = i->second; 92 MipsISA::PTE *pte = &table[index]; 93 94 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */ 95 Addr Mask = pte->Mask; 96 Addr InvMask = ~Mask; 97 Addr VPN = pte->VPN; 98 // warn("Valid: %d - %d\n",pte->V0,pte->V1); 99 if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G || (asn == pte->asid))) 100 { // We have a VPN + ASID Match 101 retval = pte; 102 break; 103 } 104 ++i; 105 } 106 } 107 108 DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn, 109 retval ? "hit" : "miss", retval ? retval->PFN1 : 0); 110 return retval; 111} 112 113MipsISA::PTE* TLB::getEntry(unsigned Index) const 114{ 115 // Make sure that Index is valid 116 assert(Index<size); 117 return &table[Index]; 118} 119 120int TLB::probeEntry(Addr vpn,uint8_t asn) const 121{ 122 // assume not found... 123 MipsISA::PTE *retval = NULL; 124 int Ind=-1; 125 PageTable::const_iterator i = lookupTable.find(vpn); 126 if (i != lookupTable.end()) { 127 while (i->first == vpn) { 128 int index = i->second; 129 MipsISA::PTE *pte = &table[index]; 130 131 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */ 132 Addr Mask = pte->Mask; 133 Addr InvMask = ~Mask; 134 Addr VPN = pte->VPN; 135 if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G || (asn == pte->asid))) 136 { // We have a VPN + ASID Match 137 retval = pte; 138 Ind = index; 139 break; 140 } 141 142 ++i; 143 } 144 } 145 DPRINTF(MipsPRA,"VPN: %x, asid: %d, Result of TLBP: %d\n",vpn,asn,Ind); 146 return Ind; 147} 148Fault inline 149TLB::checkCacheability(RequestPtr &req) 150{ 151 Addr VAddrUncacheable = 0xA0000000; 152 // In MIPS, cacheability is controlled by certain bits of the virtual address 153 // or by the TLB entry 154 if((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) { 155 // mark request as uncacheable 156 req->setFlags(req->getFlags() | UNCACHEABLE); 157 } 158 return NoFault; 159} 160void TLB::insertAt(MipsISA::PTE &pte, unsigned Index, int _smallPages) 161{ 162 smallPages=_smallPages; 163 if(Index > size){ 164 warn("Attempted to write at index (%d) beyond TLB size (%d)",Index,size); 165 } else { 166 // Update TLB 167 DPRINTF(TLB,"TLB[%d]: %x %x %x %x\n",Index,pte.Mask<<11,((pte.VPN << 11) | pte.asid),((pte.PFN0 <<6) | (pte.C0 << 3) | (pte.D0 << 2) | (pte.V0 <<1) | pte.G), 168 ((pte.PFN1 <<6) | (pte.C1 << 3) | (pte.D1 << 2) | (pte.V1 <<1) | pte.G)); 169 if(table[Index].V0 == true || table[Index].V1 == true){ // Previous entry is valid 170 PageTable::iterator i = lookupTable.find(table[Index].VPN); 171 lookupTable.erase(i); 172 } 173 table[Index]=pte; 174 // Update fast lookup table 175 lookupTable.insert(make_pair(table[Index].VPN, Index)); 176 // int TestIndex=probeEntry(pte.VPN,pte.asid); 177 // warn("Inserted at: %d, Found at: %d (%x)\n",Index,TestIndex,pte.Mask); 178 } 179 180} 181 182// insert a new TLB entry 183void 184TLB::insert(Addr addr, MipsISA::PTE &pte) 185{ 186 fatal("TLB Insert not yet implemented\n"); 187 188 189 /* MipsISA::VAddr vaddr = addr; 190 if (table[nlu].valid) { 191 Addr oldvpn = table[nlu].tag; 192 PageTable::iterator i = lookupTable.find(oldvpn); 193 194 if (i == lookupTable.end()) 195 panic("TLB entry not found in lookupTable"); 196 197 int index; 198 while ((index = i->second) != nlu) { 199 if (table[index].tag != oldvpn) 200 panic("TLB entry not found in lookupTable"); 201 202 ++i; 203 } 204 205 DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn); 206 207 lookupTable.erase(i); 208 } 209 210 DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn); 211 212 table[nlu] = pte; 213 table[nlu].tag = vaddr.vpn(); 214 table[nlu].valid = true; 215 216 lookupTable.insert(make_pair(vaddr.vpn(), nlu)); 217 nextnlu(); 218 */ 219} 220 221void 222TLB::flushAll() 223{ 224 DPRINTF(TLB, "flushAll\n"); 225 memset(table, 0, sizeof(MipsISA::PTE[size])); 226 lookupTable.clear(); 227 nlu = 0; 228} 229 230void 231TLB::serialize(ostream &os) 232{ 233 SERIALIZE_SCALAR(size); 234 SERIALIZE_SCALAR(nlu); 235 236 for (int i = 0; i < size; i++) { 237 nameOut(os, csprintf("%s.PTE%d", name(), i)); 238 table[i].serialize(os); 239 } 240} 241 242void 243TLB::unserialize(Checkpoint *cp, const string §ion) 244{ 245 UNSERIALIZE_SCALAR(size); 246 UNSERIALIZE_SCALAR(nlu); 247 248 for (int i = 0; i < size; i++) { 249 table[i].unserialize(cp, csprintf("%s.PTE%d", section, i)); 250 if (table[i].V0 || table[i].V1) { 251 lookupTable.insert(make_pair(table[i].VPN, i)); 252 } 253 } 254} 255 256void 257TLB::regStats() 258{ 259 read_hits 260 .name(name() + ".read_hits") 261 .desc("DTB read hits") 262 ; 263 264 read_misses 265 .name(name() + ".read_misses") 266 .desc("DTB read misses") 267 ; 268 269 270 read_accesses 271 .name(name() + ".read_accesses") 272 .desc("DTB read accesses") 273 ; 274 275 write_hits 276 .name(name() + ".write_hits") 277 .desc("DTB write hits") 278 ; 279 280 write_misses 281 .name(name() + ".write_misses") 282 .desc("DTB write misses") 283 ; 284 285 286 write_accesses 287 .name(name() + ".write_accesses") 288 .desc("DTB write accesses") 289 ; 290 291 hits 292 .name(name() + ".hits") 293 .desc("DTB hits") 294 ; 295 296 misses 297 .name(name() + ".misses") 298 .desc("DTB misses") 299 ; 300 301 invalids 302 .name(name() + ".invalids") 303 .desc("DTB access violations") 304 ; 305 306 accesses 307 .name(name() + ".accesses") 308 .desc("DTB accesses") 309 ; 310 311 hits = read_hits + write_hits; 312 misses = read_misses + write_misses; 313 accesses = read_accesses + write_accesses; 314} 315 316Fault 317ITB::translate(RequestPtr &req, ThreadContext *tc) 318{ 319#if !FULL_SYSTEM 320 Process * p = tc->getProcessPtr(); 321 322 Fault fault = p->pTable->translate(req); 323 if(fault != NoFault) 324 return fault; 325 326 return NoFault; 327#else 328 if(MipsISA::IsKSeg0(req->getVaddr())) 329 { 330 // Address will not be translated through TLB, set response, and go! 331 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr())); 332 if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned()) 333 { 334 AddressErrorFault *Flt = new AddressErrorFault(); 335 /* BadVAddr must be set */ 336 Flt->BadVAddr = req->getVaddr(); 337 return Flt; 338 } 339 } 340 else if(MipsISA::IsKSeg1(req->getVaddr())) 341 { 342 // Address will not be translated through TLB, set response, and go! 343 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr())); 344 } 345 else 346 { 347 /* This is an optimization - smallPages is updated every time a TLB operation is performed 348 That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we 349 do a TLB lookup */ 350 Addr VPN; 351 if(smallPages==1){ 352 VPN=((req->getVaddr() >> 11)); 353 } else { 354 VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC); 355 } 356 uint8_t Asid = req->getAsid(); 357 if(req->isMisaligned()){ // Unaligned address! 358 AddressErrorFault *Flt = new AddressErrorFault(); 359 /* BadVAddr must be set */ 360 Flt->BadVAddr = req->getVaddr(); 361 return Flt; 362 } 363 MipsISA::PTE *pte = lookup(VPN,Asid); 364 if(pte != NULL) 365 {// Ok, found something 366 /* Check for valid bits */ 367 int EvenOdd; 368 bool Valid; 369 if((((req->getVaddr()) >> pte->AddrShiftAmount) & 1) ==0){ 370 // Check even bits 371 Valid = pte->V0; 372 EvenOdd = 0; 373 } else { 374 // Check odd bits 375 Valid = pte->V1; 376 EvenOdd = 1; 377 } 378 379 if(Valid == false) 380 {//Invalid entry 381 ItbInvalidFault *Flt = new ItbInvalidFault(); 382 /* EntryHi VPN, ASID fields must be set */ 383 Flt->EntryHi_Asid = Asid; 384 Flt->EntryHi_VPN2 = (VPN>>2); 385 Flt->EntryHi_VPN2X = (VPN & 0x3); 386 387 /* BadVAddr must be set */ 388 Flt->BadVAddr = req->getVaddr(); 389 390 /* Context must be set */ 391 Flt->Context_BadVPN2 = (VPN >> 2); 392 return Flt; 393 } 394 else 395 {// Ok, this is really a match, set paddr 396 // hits++; 397 Addr PAddr; 398 if(EvenOdd == 0){ 399 PAddr = pte->PFN0; 400 }else{ 401 PAddr = pte->PFN1; 402 } 403 PAddr >>= (pte->AddrShiftAmount-12); 404 PAddr <<= pte->AddrShiftAmount; 405 PAddr |= ((req->getVaddr()) & pte->OffsetMask); 406 req->setPaddr(PAddr); 407 408 409 } 410 } 411 else 412 { // Didn't find any match, return a TLB Refill Exception 413 // misses++; 414 ItbRefillFault *Flt=new ItbRefillFault(); 415 /* EntryHi VPN, ASID fields must be set */ 416 Flt->EntryHi_Asid = Asid; 417 Flt->EntryHi_VPN2 = (VPN>>2); 418 Flt->EntryHi_VPN2X = (VPN & 0x3); 419 420 421 /* BadVAddr must be set */ 422 Flt->BadVAddr = req->getVaddr(); 423 424 /* Context must be set */ 425 Flt->Context_BadVPN2 = (VPN >> 2); 426 return Flt; 427 } 428 } 429 return checkCacheability(req); 430#endif 431} 432 433Fault 434DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) 435{ 436#if !FULL_SYSTEM 437 Process * p = tc->getProcessPtr(); 438 439 Fault fault = p->pTable->translate(req); 440 if(fault != NoFault) 441 return fault; 442 443 return NoFault; 444#else 445 if(MipsISA::IsKSeg0(req->getVaddr())) 446 { 447 // Address will not be translated through TLB, set response, and go! 448 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr())); 449 if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned()) 450 { 451 StoreAddressErrorFault *Flt = new StoreAddressErrorFault(); 452 /* BadVAddr must be set */ 453 Flt->BadVAddr = req->getVaddr(); 454 455 return Flt; 456 } 457 } 458 else if(MipsISA::IsKSeg1(req->getVaddr())) 459 { 460 // Address will not be translated through TLB, set response, and go! 461 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr())); 462 } 463 else 464 { 465 /* This is an optimization - smallPages is updated every time a TLB operation is performed 466 That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we 467 do a TLB lookup */ 468 Addr VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC); 469 if(smallPages==1){ 470 VPN=((req->getVaddr() >> 11)); 471 } 472 uint8_t Asid = req->getAsid(); 473 MipsISA::PTE *pte = lookup(VPN,Asid); 474 if(req->isMisaligned()){ // Unaligned address! 475 StoreAddressErrorFault *Flt = new StoreAddressErrorFault(); 476 /* BadVAddr must be set */ 477 Flt->BadVAddr = req->getVaddr(); 478 return Flt; 479 } 480 if(pte != NULL) 481 {// Ok, found something 482 /* Check for valid bits */ 483 int EvenOdd; 484 bool Valid; 485 bool Dirty; 486 if(((((req->getVaddr()) >> pte->AddrShiftAmount) & 1)) ==0){ 487 // Check even bits 488 Valid = pte->V0; 489 Dirty = pte->D0; 490 EvenOdd = 0; 491 492 } else { 493 // Check odd bits 494 Valid = pte->V1; 495 Dirty = pte->D1; 496 EvenOdd = 1; 497 } 498 499 if(Valid == false) 500 {//Invalid entry 501 // invalids++; 502 DtbInvalidFault *Flt = new DtbInvalidFault(); 503 /* EntryHi VPN, ASID fields must be set */ 504 Flt->EntryHi_Asid = Asid; 505 Flt->EntryHi_VPN2 = (VPN>>2); 506 Flt->EntryHi_VPN2X = (VPN & 0x3); 507 508 509 /* BadVAddr must be set */ 510 Flt->BadVAddr = req->getVaddr(); 511 512 /* Context must be set */ 513 Flt->Context_BadVPN2 = (VPN >> 2); 514 515 return Flt; 516 } 517 else 518 {// Ok, this is really a match, set paddr 519 // hits++; 520 if(!Dirty) 521 { 522 TLBModifiedFault *Flt = new TLBModifiedFault(); 523 /* EntryHi VPN, ASID fields must be set */ 524 Flt->EntryHi_Asid = Asid; 525 Flt->EntryHi_VPN2 = (VPN>>2); 526 Flt->EntryHi_VPN2X = (VPN & 0x3); 527 528 529 /* BadVAddr must be set */ 530 Flt->BadVAddr = req->getVaddr(); 531 532 /* Context must be set */ 533 Flt->Context_BadVPN2 = (VPN >> 2); 534 return Flt; 535 536 } 537 Addr PAddr; 538 if(EvenOdd == 0){ 539 PAddr = pte->PFN0; 540 }else{ 541 PAddr = pte->PFN1; 542 } 543 PAddr >>= (pte->AddrShiftAmount-12); 544 PAddr <<= pte->AddrShiftAmount; 545 PAddr |= ((req->getVaddr()) & pte->OffsetMask); 546 req->setPaddr(PAddr); 547 } 548 } 549 else 550 { // Didn't find any match, return a TLB Refill Exception 551 // misses++; 552 DtbRefillFault *Flt=new DtbRefillFault(); 553 /* EntryHi VPN, ASID fields must be set */ 554 Flt->EntryHi_Asid = Asid; 555 Flt->EntryHi_VPN2 = (VPN>>2); 556 Flt->EntryHi_VPN2X = (VPN & 0x3); 557 558 559 /* BadVAddr must be set */ 560 Flt->BadVAddr = req->getVaddr(); 561 562 /* Context must be set */ 563 Flt->Context_BadVPN2 = (VPN >> 2); 564 return Flt; 565 } 566 } 567 return checkCacheability(req); 568#endif 569} 570 571/////////////////////////////////////////////////////////////////////// 572// 573// Mips ITB 574// 575ITB::ITB(const Params *p) 576 : TLB(p) 577{} 578 579 580// void 581// ITB::regStats() 582// { 583// /* hits - causes failure for some reason 584// .name(name() + ".hits") 585// .desc("ITB hits"); 586// misses 587// .name(name() + ".misses") 588// .desc("ITB misses"); 589// acv 590// .name(name() + ".acv") 591// .desc("ITB acv"); 592// accesses 593// .name(name() + ".accesses") 594// .desc("ITB accesses"); 595 596// accesses = hits + misses + invalids; */ 597// } 598 599 600 601/////////////////////////////////////////////////////////////////////// 602// 603// Mips DTB 604// 605DTB::DTB(const Params *p) 606 : TLB(p) 607{} 608 609/////////////////////////////////////////////////////////////////////// 610// 611// Mips UTB 612// 613UTB::UTB(const Params *p) 614 : ITB(p), DTB(p) 615{} 616 617 618 619MipsISA::PTE & 620TLB::index(bool advance) 621{ 622 MipsISA::PTE *pte = &table[nlu]; 623 624 if (advance) 625 nextnlu(); 626 627 return *pte; 628} 629 630MipsISA::ITB * 631MipsITBParams::create() 632{ 633 return new MipsISA::ITB(this); 634} 635 636MipsISA::DTB * 637MipsDTBParams::create() 638{ 639 return new MipsISA::DTB(this); 640} 641 642MipsISA::UTB * 643MipsUTBParams::create() 644{ 645 return new MipsISA::UTB(this); 646} 647