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