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