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