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