tlb.cc revision 6383:31c067ae3331
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 invalids 285 .name(name() + ".invalids") 286 .desc("DTB access violations") 287 ; 288 289 accesses 290 .name(name() + ".accesses") 291 .desc("DTB accesses") 292 ; 293 294 hits = read_hits + write_hits; 295 misses = read_misses + write_misses; 296 accesses = read_accesses + write_accesses; 297} 298 299Fault 300TLB::translateInst(RequestPtr req, ThreadContext *tc) 301{ 302#if !FULL_SYSTEM 303 Process * p = tc->getProcessPtr(); 304 305 Fault fault = p->pTable->translate(req); 306 if (fault != NoFault) 307 return fault; 308 309 return NoFault; 310#else 311 if (IsKSeg0(req->getVaddr())) { 312 // Address will not be translated through TLB, set response, and go! 313 req->setPaddr(KSeg02Phys(req->getVaddr())); 314 if (getOperatingMode(tc->readMiscReg(MISCREG_STATUS)) != mode_kernel || 315 req->isMisaligned()) { 316 AddressErrorFault *Flt = new AddressErrorFault(); 317 /* BadVAddr must be set */ 318 Flt->badVAddr = req->getVaddr(); 319 return Flt; 320 } 321 } else if(IsKSeg1(req->getVaddr())) { 322 // Address will not be translated through TLB, set response, and go! 323 req->setPaddr(KSeg02Phys(req->getVaddr())); 324 } else { 325 /* 326 * This is an optimization - smallPages is updated every time a TLB 327 * operation is performed. That way, we don't need to look at 328 * Config3 _ SP and PageGrain _ ESP every time we do a TLB lookup 329 */ 330 Addr VPN; 331 if (smallPages == 1) { 332 VPN = ((req->getVaddr() >> 11)); 333 } else { 334 VPN = ((req->getVaddr() >> 11) & 0xFFFFFFFC); 335 } 336 uint8_t Asid = req->getAsid(); 337 if (req->isMisaligned()) { 338 // Unaligned address! 339 AddressErrorFault *Flt = new AddressErrorFault(); 340 /* BadVAddr must be set */ 341 Flt->badVAddr = req->getVaddr(); 342 return Flt; 343 } 344 PTE *pte = lookup(VPN,Asid); 345 if (pte != NULL) { 346 // Ok, found something 347 /* Check for valid bits */ 348 int EvenOdd; 349 bool Valid; 350 if ((((req->getVaddr()) >> pte->AddrShiftAmount) & 1) == 0) { 351 // Check even bits 352 Valid = pte->V0; 353 EvenOdd = 0; 354 } else { 355 // Check odd bits 356 Valid = pte->V1; 357 EvenOdd = 1; 358 } 359 360 if (Valid == false) { 361 //Invalid entry 362 ItbInvalidFault *Flt = new ItbInvalidFault(); 363 /* EntryHi VPN, ASID fields must be set */ 364 Flt->entryHiAsid = Asid; 365 Flt->entryHiVPN2 = (VPN >> 2); 366 Flt->entryHiVPN2X = (VPN & 0x3); 367 368 /* BadVAddr must be set */ 369 Flt->badVAddr = req->getVaddr(); 370 371 /* Context must be set */ 372 Flt->contextBadVPN2 = (VPN >> 2); 373 return Flt; 374 } else { 375 // Ok, this is really a match, set paddr 376 Addr PAddr; 377 if (EvenOdd == 0) { 378 PAddr = pte->PFN0; 379 } else { 380 PAddr = pte->PFN1; 381 } 382 PAddr >>= (pte->AddrShiftAmount - 12); 383 PAddr <<= pte->AddrShiftAmount; 384 PAddr |= ((req->getVaddr()) & pte->OffsetMask); 385 req->setPaddr(PAddr); 386 } 387 } else { 388 // Didn't find any match, return a TLB Refill Exception 389 ItbRefillFault *Flt = new ItbRefillFault(); 390 /* EntryHi VPN, ASID fields must be set */ 391 Flt->entryHiAsid = Asid; 392 Flt->entryHiVPN2 = (VPN >> 2); 393 Flt->entryHiVPN2X = (VPN & 0x3); 394 395 /* BadVAddr must be set */ 396 Flt->badVAddr = req->getVaddr(); 397 398 /* Context must be set */ 399 Flt->contextBadVPN2 = (VPN >> 2); 400 return Flt; 401 } 402 } 403 return checkCacheability(req); 404#endif 405} 406 407Fault 408TLB::translateData(RequestPtr req, ThreadContext *tc, bool write) 409{ 410#if !FULL_SYSTEM 411 //@TODO: This should actually use TLB instead of going directly 412 // to the page table in syscall mode. 413 /** 414 * Check for alignment faults 415 */ 416 if (req->getVaddr() & (req->getSize() - 1)) { 417 DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->getVaddr(), 418 req->getSize()); 419 return new AlignmentFault(); 420 } 421 422 423 Process * p = tc->getProcessPtr(); 424 425 Fault fault = p->pTable->translate(req); 426 if (fault != NoFault) 427 return fault; 428 429 return NoFault; 430#else 431 if (IsKSeg0(req->getVaddr())) { 432 // Address will not be translated through TLB, set response, and go! 433 req->setPaddr(KSeg02Phys(req->getVaddr())); 434 if (getOperatingMode(tc->readMiscReg(MISCREG_STATUS)) != mode_kernel || 435 req->isMisaligned()) { 436 StoreAddressErrorFault *Flt = new StoreAddressErrorFault(); 437 /* BadVAddr must be set */ 438 Flt->badVAddr = req->getVaddr(); 439 440 return Flt; 441 } 442 } else if(IsKSeg1(req->getVaddr())) { 443 // Address will not be translated through TLB, set response, and go! 444 req->setPaddr(KSeg02Phys(req->getVaddr())); 445 } else { 446 /* 447 * This is an optimization - smallPages is updated every time a TLB 448 * operation is performed. That way, we don't need to look at 449 * Config3 _ SP and PageGrain _ ESP every time we do a TLB lookup 450 */ 451 Addr VPN = ((req->getVaddr() >> 11) & 0xFFFFFFFC); 452 if (smallPages == 1) { 453 VPN = ((req->getVaddr() >> 11)); 454 } 455 uint8_t Asid = req->getAsid(); 456 PTE *pte = lookup(VPN, Asid); 457 if (req->isMisaligned()) { 458 // Unaligned address! 459 StoreAddressErrorFault *Flt = new StoreAddressErrorFault(); 460 /* BadVAddr must be set */ 461 Flt->badVAddr = req->getVaddr(); 462 return Flt; 463 } 464 if (pte != NULL) { 465 // Ok, found something 466 /* Check for valid bits */ 467 int EvenOdd; 468 bool Valid; 469 bool Dirty; 470 if (((((req->getVaddr()) >> pte->AddrShiftAmount) & 1)) == 0) { 471 // Check even bits 472 Valid = pte->V0; 473 Dirty = pte->D0; 474 EvenOdd = 0; 475 } else { 476 // Check odd bits 477 Valid = pte->V1; 478 Dirty = pte->D1; 479 EvenOdd = 1; 480 } 481 482 if (Valid == false) { 483 //Invalid entry 484 DtbInvalidFault *Flt = new DtbInvalidFault(); 485 /* EntryHi VPN, ASID fields must be set */ 486 Flt->entryHiAsid = Asid; 487 Flt->entryHiVPN2 = (VPN>>2); 488 Flt->entryHiVPN2X = (VPN & 0x3); 489 490 /* BadVAddr must be set */ 491 Flt->badVAddr = req->getVaddr(); 492 493 /* Context must be set */ 494 Flt->contextBadVPN2 = (VPN >> 2); 495 496 return Flt; 497 } else { 498 // Ok, this is really a match, set paddr 499 if (!Dirty) { 500 TLBModifiedFault *Flt = new TLBModifiedFault(); 501 /* EntryHi VPN, ASID fields must be set */ 502 Flt->entryHiAsid = Asid; 503 Flt->entryHiVPN2 = (VPN >> 2); 504 Flt->entryHiVPN2X = (VPN & 0x3); 505 506 /* BadVAddr must be set */ 507 Flt->badVAddr = req->getVaddr(); 508 509 /* Context must be set */ 510 Flt->contextBadVPN2 = (VPN >> 2); 511 return Flt; 512 } 513 Addr PAddr; 514 if (EvenOdd == 0) { 515 PAddr = pte->PFN0; 516 } else { 517 PAddr = pte->PFN1; 518 } 519 PAddr >>= (pte->AddrShiftAmount - 12); 520 PAddr <<= pte->AddrShiftAmount; 521 PAddr |= ((req->getVaddr()) & pte->OffsetMask); 522 req->setPaddr(PAddr); 523 } 524 } else { 525 // Didn't find any match, return a TLB Refill Exception 526 DtbRefillFault *Flt = new DtbRefillFault(); 527 /* EntryHi VPN, ASID fields must be set */ 528 Flt->entryHiAsid = Asid; 529 Flt->entryHiVPN2 = (VPN >> 2); 530 Flt->entryHiVPN2X = (VPN & 0x3); 531 532 /* BadVAddr must be set */ 533 Flt->badVAddr = req->getVaddr(); 534 535 /* Context must be set */ 536 Flt->contextBadVPN2 = (VPN >> 2); 537 return Flt; 538 } 539 } 540 return checkCacheability(req); 541#endif 542} 543 544Fault 545TLB::translateAtomic(RequestPtr req, ThreadContext *tc, Mode mode) 546{ 547 if (mode == Execute) 548 return translateInst(req, tc); 549 else 550 return translateData(req, tc, mode == Write); 551} 552 553void 554TLB::translateTiming(RequestPtr req, ThreadContext *tc, 555 Translation *translation, Mode mode) 556{ 557 assert(translation); 558 translation->finish(translateAtomic(req, tc, mode), req, tc, mode); 559} 560 561 562MipsISA::PTE & 563TLB::index(bool advance) 564{ 565 PTE *pte = &table[nlu]; 566 567 if (advance) 568 nextnlu(); 569 570 return *pte; 571} 572 573MipsISA::TLB * 574MipsTLBParams::create() 575{ 576 return new TLB(this); 577} 578