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