tlb.cc revision 5222:bb733a878f85
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 "params/MipsDTB.hh" 51#include "params/MipsITB.hh" 52#include "params/MipsTLB.hh" 53#include "params/MipsUTB.hh" 54 55 56using namespace std; 57using namespace MipsISA; 58 59/////////////////////////////////////////////////////////////////////// 60// 61// MIPS TLB 62// 63 64#define MODE2MASK(X) (1 << (X)) 65 66TLB::TLB(const Params *p) 67 : SimObject(p), size(p->size), nlu(0) 68{ 69 table = new MipsISA::PTE[size]; 70 memset(table, 0, sizeof(MipsISA::PTE[size])); 71 smallPages=0; 72} 73 74TLB::~TLB() 75{ 76 if (table) 77 delete [] table; 78} 79 80// look up an entry in the TLB 81MipsISA::PTE * 82TLB::lookup(Addr vpn, uint8_t asn) const 83{ 84 // assume not found... 85 MipsISA::PTE *retval = NULL; 86 PageTable::const_iterator i = lookupTable.find(vpn); 87 if (i != lookupTable.end()) { 88 while (i->first == vpn) { 89 int index = i->second; 90 MipsISA::PTE *pte = &table[index]; 91 92 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */ 93 Addr Mask = pte->Mask; 94 Addr InvMask = ~Mask; 95 Addr VPN = pte->VPN; 96 // warn("Valid: %d - %d\n",pte->V0,pte->V1); 97 if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G || (asn == pte->asid))) 98 { // We have a VPN + ASID Match 99 retval = pte; 100 break; 101 } 102 ++i; 103 } 104 } 105 106 DPRINTF(TLB, "lookup %#x, asn %#x -> %s ppn %#x\n", vpn, (int)asn, 107 retval ? "hit" : "miss", retval ? retval->PFN1 : 0); 108 return retval; 109} 110 111MipsISA::PTE* TLB::getEntry(unsigned Index) const 112{ 113 // Make sure that Index is valid 114 assert(Index<size); 115 return &table[Index]; 116} 117 118int TLB::probeEntry(Addr vpn,uint8_t asn) const 119{ 120 // assume not found... 121 MipsISA::PTE *retval = NULL; 122 int Ind=-1; 123 PageTable::const_iterator i = lookupTable.find(vpn); 124 if (i != lookupTable.end()) { 125 while (i->first == vpn) { 126 int index = i->second; 127 MipsISA::PTE *pte = &table[index]; 128 129 /* 1KB TLB Lookup code - from MIPS ARM Volume III - Rev. 2.50 */ 130 Addr Mask = pte->Mask; 131 Addr InvMask = ~Mask; 132 Addr VPN = pte->VPN; 133 if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G || (asn == pte->asid))) 134 { // We have a VPN + ASID Match 135 retval = pte; 136 Ind = index; 137 break; 138 } 139 140 ++i; 141 } 142 } 143 DPRINTF(MipsPRA,"VPN: %x, asid: %d, Result of TLBP: %d\n",vpn,asn,Ind); 144 return Ind; 145} 146Fault inline 147TLB::checkCacheability(RequestPtr &req) 148{ 149 Addr VAddrUncacheable = 0xA0000000; 150 // In MIPS, cacheability is controlled by certain bits of the virtual address 151 // or by the TLB entry 152 if((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) { 153 // mark request as uncacheable 154 req->setFlags(req->getFlags() | UNCACHEABLE); 155 } 156 return NoFault; 157} 158void TLB::insertAt(MipsISA::PTE &pte, unsigned Index, int _smallPages) 159{ 160 smallPages=_smallPages; 161 if(Index > size){ 162 warn("Attempted to write at index (%d) beyond TLB size (%d)",Index,size); 163 } else { 164 // Update TLB 165 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), 166 ((pte.PFN1 <<6) | (pte.C1 << 3) | (pte.D1 << 2) | (pte.V1 <<1) | pte.G)); 167 if(table[Index].V0 == true || table[Index].V1 == true){ // Previous entry is valid 168 PageTable::iterator i = lookupTable.find(table[Index].VPN); 169 lookupTable.erase(i); 170 } 171 table[Index]=pte; 172 // Update fast lookup table 173 lookupTable.insert(make_pair(table[Index].VPN, Index)); 174 // int TestIndex=probeEntry(pte.VPN,pte.asid); 175 // warn("Inserted at: %d, Found at: %d (%x)\n",Index,TestIndex,pte.Mask); 176 } 177 178} 179 180// insert a new TLB entry 181void 182TLB::insert(Addr addr, MipsISA::PTE &pte) 183{ 184 fatal("TLB Insert not yet implemented\n"); 185 186 187 /* MipsISA::VAddr vaddr = addr; 188 if (table[nlu].valid) { 189 Addr oldvpn = table[nlu].tag; 190 PageTable::iterator i = lookupTable.find(oldvpn); 191 192 if (i == lookupTable.end()) 193 panic("TLB entry not found in lookupTable"); 194 195 int index; 196 while ((index = i->second) != nlu) { 197 if (table[index].tag != oldvpn) 198 panic("TLB entry not found in lookupTable"); 199 200 ++i; 201 } 202 203 DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn); 204 205 lookupTable.erase(i); 206 } 207 208 DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vaddr.vpn(), pte.ppn); 209 210 table[nlu] = pte; 211 table[nlu].tag = vaddr.vpn(); 212 table[nlu].valid = true; 213 214 lookupTable.insert(make_pair(vaddr.vpn(), nlu)); 215 nextnlu(); 216 */ 217} 218 219void 220TLB::flushAll() 221{ 222 DPRINTF(TLB, "flushAll\n"); 223 memset(table, 0, sizeof(MipsISA::PTE[size])); 224 lookupTable.clear(); 225 nlu = 0; 226} 227 228void 229TLB::serialize(ostream &os) 230{ 231 SERIALIZE_SCALAR(size); 232 SERIALIZE_SCALAR(nlu); 233 234 for (int i = 0; i < size; i++) { 235 nameOut(os, csprintf("%s.PTE%d", name(), i)); 236 table[i].serialize(os); 237 } 238} 239 240void 241TLB::unserialize(Checkpoint *cp, const string §ion) 242{ 243 UNSERIALIZE_SCALAR(size); 244 UNSERIALIZE_SCALAR(nlu); 245 246 for (int i = 0; i < size; i++) { 247 table[i].unserialize(cp, csprintf("%s.PTE%d", section, i)); 248 if (table[i].V0 || table[i].V1) { 249 lookupTable.insert(make_pair(table[i].VPN, i)); 250 } 251 } 252} 253 254void 255TLB::regStats() 256{ 257 read_hits 258 .name(name() + ".read_hits") 259 .desc("DTB read hits") 260 ; 261 262 read_misses 263 .name(name() + ".read_misses") 264 .desc("DTB read misses") 265 ; 266 267 268 read_accesses 269 .name(name() + ".read_accesses") 270 .desc("DTB read accesses") 271 ; 272 273 write_hits 274 .name(name() + ".write_hits") 275 .desc("DTB write hits") 276 ; 277 278 write_misses 279 .name(name() + ".write_misses") 280 .desc("DTB write misses") 281 ; 282 283 284 write_accesses 285 .name(name() + ".write_accesses") 286 .desc("DTB write accesses") 287 ; 288 289 hits 290 .name(name() + ".hits") 291 .desc("DTB hits") 292 ; 293 294 misses 295 .name(name() + ".misses") 296 .desc("DTB misses") 297 ; 298 299 invalids 300 .name(name() + ".invalids") 301 .desc("DTB access violations") 302 ; 303 304 accesses 305 .name(name() + ".accesses") 306 .desc("DTB accesses") 307 ; 308 309 hits = read_hits + write_hits; 310 misses = read_misses + write_misses; 311 accesses = read_accesses + write_accesses; 312} 313 314Fault 315ITB::translate(RequestPtr &req, ThreadContext *tc) 316{ 317 if(MipsISA::IsKSeg0(req->getVaddr())) 318 { 319 // Address will not be translated through TLB, set response, and go! 320 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr())); 321 if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned()) 322 { 323 AddressErrorFault *Flt = new AddressErrorFault(); 324 /* BadVAddr must be set */ 325 Flt->BadVAddr = req->getVaddr(); 326 return Flt; 327 } 328 } 329 else if(MipsISA::IsKSeg1(req->getVaddr())) 330 { 331 // Address will not be translated through TLB, set response, and go! 332 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr())); 333 } 334 else 335 { 336 /* This is an optimization - smallPages is updated every time a TLB operation is performed 337 That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we 338 do a TLB lookup */ 339 Addr VPN; 340 if(smallPages==1){ 341 VPN=((req->getVaddr() >> 11)); 342 } else { 343 VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC); 344 } 345 uint8_t Asid = req->getAsid(); 346 if(req->isMisaligned()){ // Unaligned address! 347 AddressErrorFault *Flt = new AddressErrorFault(); 348 /* BadVAddr must be set */ 349 Flt->BadVAddr = req->getVaddr(); 350 return Flt; 351 } 352 MipsISA::PTE *pte = lookup(VPN,Asid); 353 if(pte != NULL) 354 {// Ok, found something 355 /* Check for valid bits */ 356 int EvenOdd; 357 bool Valid; 358 if((((req->getVaddr()) >> pte->AddrShiftAmount) & 1) ==0){ 359 // Check even bits 360 Valid = pte->V0; 361 EvenOdd = 0; 362 } else { 363 // Check odd bits 364 Valid = pte->V1; 365 EvenOdd = 1; 366 } 367 368 if(Valid == false) 369 {//Invalid entry 370 ItbInvalidFault *Flt = new ItbInvalidFault(); 371 /* EntryHi VPN, ASID fields must be set */ 372 Flt->EntryHi_Asid = Asid; 373 Flt->EntryHi_VPN2 = (VPN>>2); 374 Flt->EntryHi_VPN2X = (VPN & 0x3); 375 376 /* BadVAddr must be set */ 377 Flt->BadVAddr = req->getVaddr(); 378 379 /* Context must be set */ 380 Flt->Context_BadVPN2 = (VPN >> 2); 381 return Flt; 382 } 383 else 384 {// Ok, this is really a match, set paddr 385 // hits++; 386 Addr PAddr; 387 if(EvenOdd == 0){ 388 PAddr = pte->PFN0; 389 }else{ 390 PAddr = pte->PFN1; 391 } 392 PAddr >>= (pte->AddrShiftAmount-12); 393 PAddr <<= pte->AddrShiftAmount; 394 PAddr |= ((req->getVaddr()) & pte->OffsetMask); 395 req->setPaddr(PAddr); 396 397 398 } 399 } 400 else 401 { // Didn't find any match, return a TLB Refill Exception 402 // misses++; 403 ItbRefillFault *Flt=new ItbRefillFault(); 404 /* EntryHi VPN, ASID fields must be set */ 405 Flt->EntryHi_Asid = Asid; 406 Flt->EntryHi_VPN2 = (VPN>>2); 407 Flt->EntryHi_VPN2X = (VPN & 0x3); 408 409 410 /* BadVAddr must be set */ 411 Flt->BadVAddr = req->getVaddr(); 412 413 /* Context must be set */ 414 Flt->Context_BadVPN2 = (VPN >> 2); 415 return Flt; 416 } 417 } 418 return checkCacheability(req); 419} 420 421Fault 422DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) 423{ 424 if(MipsISA::IsKSeg0(req->getVaddr())) 425 { 426 // Address will not be translated through TLB, set response, and go! 427 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr())); 428 if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned()) 429 { 430 StoreAddressErrorFault *Flt = new StoreAddressErrorFault(); 431 /* BadVAddr must be set */ 432 Flt->BadVAddr = req->getVaddr(); 433 434 return Flt; 435 } 436 } 437 else if(MipsISA::IsKSeg1(req->getVaddr())) 438 { 439 // Address will not be translated through TLB, set response, and go! 440 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr())); 441 } 442 else 443 { 444 /* This is an optimization - smallPages is updated every time a TLB operation is performed 445 That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we 446 do a TLB lookup */ 447 Addr VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC); 448 if(smallPages==1){ 449 VPN=((req->getVaddr() >> 11)); 450 } 451 uint8_t Asid = req->getAsid(); 452 MipsISA::PTE *pte = lookup(VPN,Asid); 453 if(req->isMisaligned()){ // Unaligned address! 454 StoreAddressErrorFault *Flt = new StoreAddressErrorFault(); 455 /* BadVAddr must be set */ 456 Flt->BadVAddr = req->getVaddr(); 457 return Flt; 458 } 459 if(pte != NULL) 460 {// Ok, found something 461 /* Check for valid bits */ 462 int EvenOdd; 463 bool Valid; 464 bool Dirty; 465 if(((((req->getVaddr()) >> pte->AddrShiftAmount) & 1)) ==0){ 466 // Check even bits 467 Valid = pte->V0; 468 Dirty = pte->D0; 469 EvenOdd = 0; 470 471 } else { 472 // Check odd bits 473 Valid = pte->V1; 474 Dirty = pte->D1; 475 EvenOdd = 1; 476 } 477 478 if(Valid == false) 479 {//Invalid entry 480 // invalids++; 481 DtbInvalidFault *Flt = new DtbInvalidFault(); 482 /* EntryHi VPN, ASID fields must be set */ 483 Flt->EntryHi_Asid = Asid; 484 Flt->EntryHi_VPN2 = (VPN>>2); 485 Flt->EntryHi_VPN2X = (VPN & 0x3); 486 487 488 /* BadVAddr must be set */ 489 Flt->BadVAddr = req->getVaddr(); 490 491 /* Context must be set */ 492 Flt->Context_BadVPN2 = (VPN >> 2); 493 494 return Flt; 495 } 496 else 497 {// Ok, this is really a match, set paddr 498 // hits++; 499 if(!Dirty) 500 { 501 TLBModifiedFault *Flt = new TLBModifiedFault(); 502 /* EntryHi VPN, ASID fields must be set */ 503 Flt->EntryHi_Asid = Asid; 504 Flt->EntryHi_VPN2 = (VPN>>2); 505 Flt->EntryHi_VPN2X = (VPN & 0x3); 506 507 508 /* BadVAddr must be set */ 509 Flt->BadVAddr = req->getVaddr(); 510 511 /* Context must be set */ 512 Flt->Context_BadVPN2 = (VPN >> 2); 513 return Flt; 514 515 } 516 Addr PAddr; 517 if(EvenOdd == 0){ 518 PAddr = pte->PFN0; 519 }else{ 520 PAddr = pte->PFN1; 521 } 522 PAddr >>= (pte->AddrShiftAmount-12); 523 PAddr <<= pte->AddrShiftAmount; 524 PAddr |= ((req->getVaddr()) & pte->OffsetMask); 525 req->setPaddr(PAddr); 526 } 527 } 528 else 529 { // Didn't find any match, return a TLB Refill Exception 530 // misses++; 531 DtbRefillFault *Flt=new DtbRefillFault(); 532 /* EntryHi VPN, ASID fields must be set */ 533 Flt->EntryHi_Asid = Asid; 534 Flt->EntryHi_VPN2 = (VPN>>2); 535 Flt->EntryHi_VPN2X = (VPN & 0x3); 536 537 538 /* BadVAddr must be set */ 539 Flt->BadVAddr = req->getVaddr(); 540 541 /* Context must be set */ 542 Flt->Context_BadVPN2 = (VPN >> 2); 543 return Flt; 544 } 545 } 546 return checkCacheability(req); 547} 548 549/////////////////////////////////////////////////////////////////////// 550// 551// Mips ITB 552// 553ITB::ITB(const Params *p) 554 : TLB(p) 555{} 556 557 558// void 559// ITB::regStats() 560// { 561// /* hits - causes failure for some reason 562// .name(name() + ".hits") 563// .desc("ITB hits"); 564// misses 565// .name(name() + ".misses") 566// .desc("ITB misses"); 567// acv 568// .name(name() + ".acv") 569// .desc("ITB acv"); 570// accesses 571// .name(name() + ".accesses") 572// .desc("ITB accesses"); 573 574// accesses = hits + misses + invalids; */ 575// } 576 577 578 579/////////////////////////////////////////////////////////////////////// 580// 581// Mips DTB 582// 583DTB::DTB(const Params *p) 584 : TLB(p) 585{} 586 587/////////////////////////////////////////////////////////////////////// 588// 589// Mips UTB 590// 591UTB::UTB(const Params *p) 592 : ITB(p), DTB(p) 593{} 594 595 596 597MipsISA::PTE & 598TLB::index(bool advance) 599{ 600 MipsISA::PTE *pte = &table[nlu]; 601 602 if (advance) 603 nextnlu(); 604 605 return *pte; 606} 607 608MipsISA::ITB * 609MipsITBParams::create() 610{ 611 return new MipsISA::ITB(this); 612} 613 614MipsISA::DTB * 615MipsDTBParams::create() 616{ 617 return new MipsISA::DTB(this); 618} 619 620MipsISA::UTB * 621MipsUTBParams::create() 622{ 623 return new MipsISA::UTB(this); 624} 625