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