tlb.cc revision 6023:47b4fcb10c11
17949SN/A/* 27949SN/A * Copyright (c) 2001-2005 The Regents of The University of Michigan 37949SN/A * Copyright (c) 2007 MIPS Technologies, Inc. 47949SN/A * All rights reserved. 57949SN/A * 67949SN/A * Redistribution and use in source and binary forms, with or without 77949SN/A * modification, are permitted provided that the following conditions are 87949SN/A * met: redistributions of source code must retain the above copyright 97949SN/A * notice, this list of conditions and the following disclaimer; 107949SN/A * redistributions in binary form must reproduce the above copyright 117949SN/A * notice, this list of conditions and the following disclaimer in the 127949SN/A * documentation and/or other materials provided with the distribution; 137949SN/A * neither the name of the copyright holders nor the names of its 147949SN/A * contributors may be used to endorse or promote products derived from 157949SN/A * this software without specific prior written permission. 167949SN/A * 177949SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 187949SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 197949SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 207949SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 217949SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 227949SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 237949SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 247949SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 257949SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 267949SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 277949SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 287949SN/A * 297949SN/A * Authors: Nathan Binkert 307949SN/A * Steve Reinhardt 317949SN/A * Jaidev Patwardhan 327949SN/A */ 337949SN/A 347949SN/A#include <string> 357949SN/A#include <vector> 367949SN/A 377949SN/A#include "arch/mips/pra_constants.hh" 387949SN/A#include "arch/mips/pagetable.hh" 397949SN/A#include "arch/mips/tlb.hh" 4013665Sandreas.sandberg@arm.com#include "arch/mips/faults.hh" 4112230Sgiacomo.travaglini@arm.com#include "arch/mips/utility.hh" 427949SN/A#include "base/inifile.hh" 439330Schander.sudanthi@arm.com#include "base/str.hh" 449330Schander.sudanthi@arm.com#include "base/trace.hh" 459338SAndreas.Sandberg@arm.com#include "cpu/thread_context.hh" 469330Schander.sudanthi@arm.com#include "sim/process.hh" 4712230Sgiacomo.travaglini@arm.com#include "mem/page_table.hh" 4812231Sgiacomo.travaglini@arm.com#include "params/MipsTLB.hh" 4912230Sgiacomo.travaglini@arm.com 509330Schander.sudanthi@arm.com 519330Schander.sudanthi@arm.comusing namespace std; 527949SN/Ausing namespace MipsISA; 539338SAndreas.Sandberg@arm.com 547949SN/A/////////////////////////////////////////////////////////////////////// 557949SN/A// 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 Process * p = tc->getProcessPtr(); 431 432 Fault fault = p->pTable->translate(req); 433 if(fault != NoFault) 434 return fault; 435 436 return NoFault; 437#else 438 if(MipsISA::IsKSeg0(req->getVaddr())) 439 { 440 // Address will not be translated through TLB, set response, and go! 441 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr())); 442 if(MipsISA::getOperatingMode(tc->readMiscReg(MipsISA::Status)) != mode_kernel || req->isMisaligned()) 443 { 444 StoreAddressErrorFault *Flt = new StoreAddressErrorFault(); 445 /* BadVAddr must be set */ 446 Flt->BadVAddr = req->getVaddr(); 447 448 return Flt; 449 } 450 } 451 else if(MipsISA::IsKSeg1(req->getVaddr())) 452 { 453 // Address will not be translated through TLB, set response, and go! 454 req->setPaddr(MipsISA::KSeg02Phys(req->getVaddr())); 455 } 456 else 457 { 458 /* This is an optimization - smallPages is updated every time a TLB operation is performed 459 That way, we don't need to look at Config3 _ SP and PageGrain _ ESP every time we 460 do a TLB lookup */ 461 Addr VPN=((req->getVaddr() >> 11) & 0xFFFFFFFC); 462 if(smallPages==1){ 463 VPN=((req->getVaddr() >> 11)); 464 } 465 uint8_t Asid = req->getAsid(); 466 MipsISA::PTE *pte = lookup(VPN,Asid); 467 if(req->isMisaligned()){ // Unaligned address! 468 StoreAddressErrorFault *Flt = new StoreAddressErrorFault(); 469 /* BadVAddr must be set */ 470 Flt->BadVAddr = req->getVaddr(); 471 return Flt; 472 } 473 if(pte != NULL) 474 {// Ok, found something 475 /* Check for valid bits */ 476 int EvenOdd; 477 bool Valid; 478 bool Dirty; 479 if(((((req->getVaddr()) >> pte->AddrShiftAmount) & 1)) ==0){ 480 // Check even bits 481 Valid = pte->V0; 482 Dirty = pte->D0; 483 EvenOdd = 0; 484 485 } else { 486 // Check odd bits 487 Valid = pte->V1; 488 Dirty = pte->D1; 489 EvenOdd = 1; 490 } 491 492 if(Valid == false) 493 {//Invalid entry 494 // invalids++; 495 DtbInvalidFault *Flt = new DtbInvalidFault(); 496 /* EntryHi VPN, ASID fields must be set */ 497 Flt->EntryHi_Asid = Asid; 498 Flt->EntryHi_VPN2 = (VPN>>2); 499 Flt->EntryHi_VPN2X = (VPN & 0x3); 500 501 502 /* BadVAddr must be set */ 503 Flt->BadVAddr = req->getVaddr(); 504 505 /* Context must be set */ 506 Flt->Context_BadVPN2 = (VPN >> 2); 507 508 return Flt; 509 } 510 else 511 {// Ok, this is really a match, set paddr 512 // hits++; 513 if(!Dirty) 514 { 515 TLBModifiedFault *Flt = new TLBModifiedFault(); 516 /* EntryHi VPN, ASID fields must be set */ 517 Flt->EntryHi_Asid = Asid; 518 Flt->EntryHi_VPN2 = (VPN>>2); 519 Flt->EntryHi_VPN2X = (VPN & 0x3); 520 521 522 /* BadVAddr must be set */ 523 Flt->BadVAddr = req->getVaddr(); 524 525 /* Context must be set */ 526 Flt->Context_BadVPN2 = (VPN >> 2); 527 return Flt; 528 529 } 530 Addr PAddr; 531 if(EvenOdd == 0){ 532 PAddr = pte->PFN0; 533 }else{ 534 PAddr = pte->PFN1; 535 } 536 PAddr >>= (pte->AddrShiftAmount-12); 537 PAddr <<= pte->AddrShiftAmount; 538 PAddr |= ((req->getVaddr()) & pte->OffsetMask); 539 req->setPaddr(PAddr); 540 } 541 } 542 else 543 { // Didn't find any match, return a TLB Refill Exception 544 // misses++; 545 DtbRefillFault *Flt=new DtbRefillFault(); 546 /* EntryHi VPN, ASID fields must be set */ 547 Flt->EntryHi_Asid = Asid; 548 Flt->EntryHi_VPN2 = (VPN>>2); 549 Flt->EntryHi_VPN2X = (VPN & 0x3); 550 551 552 /* BadVAddr must be set */ 553 Flt->BadVAddr = req->getVaddr(); 554 555 /* Context must be set */ 556 Flt->Context_BadVPN2 = (VPN >> 2); 557 return Flt; 558 } 559 } 560 return checkCacheability(req); 561#endif 562} 563 564Fault 565TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode) 566{ 567 if (mode == Execute) 568 return translateInst(req, tc); 569 else 570 return translateData(req, tc, mode == Write); 571} 572 573void 574TLB::translateTiming(RequestPtr req, ThreadContext *tc, 575 Translation *translation, Mode mode) 576{ 577 assert(translation); 578 translation->finish(translateAtomic(req, tc, mode), req, tc, mode); 579} 580 581 582MipsISA::PTE & 583TLB::index(bool advance) 584{ 585 MipsISA::PTE *pte = &table[nlu]; 586 587 if (advance) 588 nextnlu(); 589 590 return *pte; 591} 592 593MipsISA::TLB * 594MipsTLBParams::create() 595{ 596 return new MipsISA::TLB(this); 597} 598