tlb.cc revision 860
1/* 2 * Copyright (c) 2003 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sstream> 30#include <string> 31#include <vector> 32 33#include "base/inifile.hh" 34#include "base/str.hh" 35#include "base/trace.hh" 36#include "cpu/exec_context.hh" 37#include "sim/builder.hh" 38#include "targetarch/alpha_memory.hh" 39#include "targetarch/ev5.hh" 40 41using namespace std; 42 43/////////////////////////////////////////////////////////////////////// 44// 45// Alpha TLB 46// 47#ifdef DEBUG 48bool uncacheBit39 = false; 49bool uncacheBit40 = false; 50#endif 51 52AlphaTLB::AlphaTLB(const string &name, int s) 53 : SimObject(name), size(s), nlu(0) 54{ 55 table = new AlphaISA::PTE[size]; 56 memset(table, 0, sizeof(AlphaISA::PTE[size])); 57} 58 59AlphaTLB::~AlphaTLB() 60{ 61 if (table) 62 delete [] table; 63} 64 65// look up an entry in the TLB 66AlphaISA::PTE * 67AlphaTLB::lookup(Addr vpn, uint8_t asn) const 68{ 69 DPRINTF(TLB, "lookup %#x\n", vpn); 70 71 PageTable::const_iterator i = lookupTable.find(vpn); 72 if (i == lookupTable.end()) 73 return NULL; 74 75 while (i->first == vpn) { 76 int index = i->second; 77 AlphaISA::PTE *pte = &table[index]; 78 assert(pte->valid); 79 if (vpn == pte->tag && (pte->asma || pte->asn == asn)) 80 return pte; 81 82 ++i; 83 } 84 85 // not found... 86 return NULL; 87} 88 89 90void 91AlphaTLB::checkCacheability(MemReqPtr &req) 92{ 93 // in Alpha, cacheability is controlled by upper-level bits of the 94 // physical address 95 96 /* 97 * We support having the uncacheable bit in either bit 39 or bit 40. 98 * The Turbolaser platform (and EV5) support having the bit in 39, but 99 * Tsunami (which Linux assumes uses an EV6) generates accesses with 100 * the bit in 40. So we must check for both, but we have debug flags 101 * to catch a weird case where both are used, which shouldn't happen. 102 */ 103 104 if (req->paddr & PA_UNCACHED_BIT_40 || 105 req->paddr & PA_UNCACHED_BIT_39) { 106 107#ifdef DEBUG 108 if (req->paddr & PA_UNCACHED_BIT_40) { 109 if(uncacheBit39) 110 panic("Bit 40 access follows bit 39 access, PA=%x\n", 111 req->paddr); 112 113 uncacheBit40 = true; 114 } else if (req->paddr & PA_UNCACHED_BIT_39) { 115 if(uncacheBit40) 116 panic("Bit 39 acceess follows bit 40 access, PA=%x\n", 117 req->paddr); 118 119 uncacheBit39 = true; 120 } 121#endif 122 123 // IPR memory space not implemented 124 if (PA_IPR_SPACE(req->paddr)) 125 if (!req->xc->misspeculating()) 126 panic("IPR memory space not implemented! PA=%x\n", 127 req->paddr); 128 129 // mark request as uncacheable 130 req->flags |= UNCACHEABLE; 131 } 132} 133 134 135// insert a new TLB entry 136void 137AlphaTLB::insert(Addr vaddr, AlphaISA::PTE &pte) 138{ 139 if (table[nlu].valid) { 140 Addr oldvpn = table[nlu].tag; 141 PageTable::iterator i = lookupTable.find(oldvpn); 142 143 if (i == lookupTable.end()) 144 panic("TLB entry not found in lookupTable"); 145 146 int index; 147 while ((index = i->second) != nlu) { 148 if (table[index].tag != oldvpn) 149 panic("TLB entry not found in lookupTable"); 150 151 ++i; 152 } 153 154 DPRINTF(TLB, "remove @%d: %#x -> %#x\n", nlu, oldvpn, table[nlu].ppn); 155 156 lookupTable.erase(i); 157 } 158 159 Addr vpn = VA_VPN(vaddr); 160 DPRINTF(TLB, "insert @%d: %#x -> %#x\n", nlu, vpn, pte.ppn); 161 162 table[nlu] = pte; 163 table[nlu].tag = vpn; 164 table[nlu].valid = true; 165 166 lookupTable.insert(make_pair(vpn, nlu)); 167 nextnlu(); 168} 169 170void 171AlphaTLB::flushAll() 172{ 173 memset(table, 0, sizeof(AlphaISA::PTE[size])); 174 lookupTable.clear(); 175 nlu = 0; 176} 177 178void 179AlphaTLB::flushProcesses() 180{ 181 PageTable::iterator i = lookupTable.begin(); 182 PageTable::iterator end = lookupTable.end(); 183 while (i != end) { 184 int index = i->second; 185 AlphaISA::PTE *pte = &table[index]; 186 assert(pte->valid); 187 188 if (!pte->asma) { 189 DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, pte->tag, pte->ppn); 190 pte->valid = false; 191 lookupTable.erase(i); 192 } 193 194 ++i; 195 } 196} 197 198void 199AlphaTLB::flushAddr(Addr vaddr, uint8_t asn) 200{ 201 Addr vpn = VA_VPN(vaddr); 202 203 PageTable::iterator i = lookupTable.find(vpn); 204 if (i == lookupTable.end()) 205 return; 206 207 while (i->first == vpn) { 208 int index = i->second; 209 AlphaISA::PTE *pte = &table[index]; 210 assert(pte->valid); 211 212 if (vpn == pte->tag && (pte->asma || pte->asn == asn)) { 213 DPRINTF(TLB, "flushaddr @%d: %#x -> %#x\n", index, vpn, pte->ppn); 214 215 // invalidate this entry 216 pte->valid = false; 217 218 lookupTable.erase(i); 219 } 220 221 ++i; 222 } 223} 224 225 226void 227AlphaTLB::serialize(ostream &os) 228{ 229 SERIALIZE_SCALAR(size); 230 SERIALIZE_SCALAR(nlu); 231 232 for (int i = 0; i < size; i++) { 233 nameOut(os, csprintf("%s.PTE%d", name(), i)); 234 table[i].serialize(os); 235 } 236} 237 238void 239AlphaTLB::unserialize(Checkpoint *cp, const string §ion) 240{ 241 UNSERIALIZE_SCALAR(size); 242 UNSERIALIZE_SCALAR(nlu); 243 244 for (int i = 0; i < size; i++) { 245 table[i].unserialize(cp, csprintf("%s.PTE%d", section, i)); 246 if (table[i].valid) { 247 lookupTable.insert(make_pair(table[i].tag, i)); 248 } 249 } 250} 251 252 253/////////////////////////////////////////////////////////////////////// 254// 255// Alpha ITB 256// 257AlphaITB::AlphaITB(const std::string &name, int size) 258 : AlphaTLB(name, size) 259{} 260 261 262void 263AlphaITB::regStats() 264{ 265 hits 266 .name(name() + ".hits") 267 .desc("ITB hits"); 268 misses 269 .name(name() + ".misses") 270 .desc("ITB misses"); 271 acv 272 .name(name() + ".acv") 273 .desc("ITB acv"); 274 accesses 275 .name(name() + ".accesses") 276 .desc("ITB accesses"); 277 278 accesses = hits + misses; 279} 280 281void 282AlphaITB::fault(Addr pc, ExecContext *xc) const 283{ 284 uint64_t *ipr = xc->regs.ipr; 285 286 if (!xc->misspeculating()) { 287 ipr[AlphaISA::IPR_ITB_TAG] = pc; 288 ipr[AlphaISA::IPR_IFAULT_VA_FORM] = 289 ipr[AlphaISA::IPR_IVPTBR] | (VA_VPN(pc) << 3); 290 } 291} 292 293 294Fault 295AlphaITB::translate(MemReqPtr &req) const 296{ 297 InternalProcReg *ipr = req->xc->regs.ipr; 298 299 if (PC_PAL(req->vaddr)) { 300 // strip off PAL PC marker (lsb is 1) 301 req->paddr = (req->vaddr & ~3) & PA_IMPL_MASK; 302 hits++; 303 return No_Fault; 304 } 305 306 if (req->flags & PHYSICAL) { 307 req->paddr = req->vaddr; 308 } else { 309 // verify that this is a good virtual address 310 if (!validVirtualAddress(req->vaddr)) { 311 fault(req->vaddr, req->xc); 312 acv++; 313 return ITB_Acv_Fault; 314 } 315 316 // Check for "superpage" mapping: when SP<1> is set, and 317 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>. 318 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && 319 VA_SPACE(req->vaddr) == 2) { 320 321 // only valid in kernel mode 322 if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) { 323 fault(req->vaddr, req->xc); 324 acv++; 325 return ITB_Acv_Fault; 326 } 327 328 req->paddr = req->vaddr & PA_IMPL_MASK; 329 330 // sign extend the physical address properly 331 if (req->paddr & PA_UNCACHED_BIT_39 || 332 req->paddr & PA_UNCACHED_BIT_40) 333 req->paddr |= 0xf0000000000ULL; 334 else 335 req->paddr &= 0xffffffffffULL; 336 337 } else { 338 // not a physical address: need to look up pte 339 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr), 340 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); 341 342 if (!pte) { 343 fault(req->vaddr, req->xc); 344 misses++; 345 return ITB_Fault_Fault; 346 } 347 348 req->paddr = PA_PFN2PA(pte->ppn) + VA_POFS(req->vaddr & ~3); 349 350 // check permissions for this access 351 if (!(pte->xre & (1 << ICM_CM(ipr[AlphaISA::IPR_ICM])))) { 352 // instruction access fault 353 fault(req->vaddr, req->xc); 354 acv++; 355 return ITB_Acv_Fault; 356 } 357 358 hits++; 359 } 360 } 361 362 // check that the physical address is ok (catch bad physical addresses) 363 if (req->paddr & ~PA_IMPL_MASK) 364 return Machine_Check_Fault; 365 366 checkCacheability(req); 367 368 return No_Fault; 369} 370 371/////////////////////////////////////////////////////////////////////// 372// 373// Alpha DTB 374// 375AlphaDTB::AlphaDTB(const std::string &name, int size) 376 : AlphaTLB(name, size) 377{} 378 379void 380AlphaDTB::regStats() 381{ 382 read_hits 383 .name(name() + ".read_hits") 384 .desc("DTB read hits") 385 ; 386 387 read_misses 388 .name(name() + ".read_misses") 389 .desc("DTB read misses") 390 ; 391 392 read_acv 393 .name(name() + ".read_acv") 394 .desc("DTB read access violations") 395 ; 396 397 read_accesses 398 .name(name() + ".read_accesses") 399 .desc("DTB read accesses") 400 ; 401 402 write_hits 403 .name(name() + ".write_hits") 404 .desc("DTB write hits") 405 ; 406 407 write_misses 408 .name(name() + ".write_misses") 409 .desc("DTB write misses") 410 ; 411 412 write_acv 413 .name(name() + ".write_acv") 414 .desc("DTB write access violations") 415 ; 416 417 write_accesses 418 .name(name() + ".write_accesses") 419 .desc("DTB write accesses") 420 ; 421 422 hits 423 .name(name() + ".hits") 424 .desc("DTB hits") 425 ; 426 427 misses 428 .name(name() + ".misses") 429 .desc("DTB misses") 430 ; 431 432 acv 433 .name(name() + ".acv") 434 .desc("DTB access violations") 435 ; 436 437 accesses 438 .name(name() + ".accesses") 439 .desc("DTB accesses") 440 ; 441 442 hits = read_hits + write_hits; 443 misses = read_misses + write_misses; 444 acv = read_acv + write_acv; 445 accesses = read_accesses + write_accesses; 446} 447 448void 449AlphaDTB::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const 450{ 451 uint64_t *ipr = xc->regs.ipr; 452 453 // set fault address and flags 454 if (!xc->misspeculating() && !xc->regs.intrlock) { 455 // set VA register with faulting address 456 ipr[AlphaISA::IPR_VA] = vaddr; 457 458 // set MM_STAT register flags 459 ipr[AlphaISA::IPR_MM_STAT] = (((xc->regs.opcode & 0x3f) << 11) 460 | ((xc->regs.ra & 0x1f) << 6) 461 | (flags & 0x3f)); 462 463 // set VA_FORM register with faulting formatted address 464 ipr[AlphaISA::IPR_VA_FORM] = 465 ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3); 466 467 // lock these registers until the VA register is read 468 xc->regs.intrlock = true; 469 } 470} 471 472Fault 473AlphaDTB::translate(MemReqPtr &req, bool write) const 474{ 475 RegFile *regs = &req->xc->regs; 476 Addr pc = regs->pc; 477 InternalProcReg *ipr = regs->ipr; 478 479 AlphaISA::mode_type mode = 480 (AlphaISA::mode_type)DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]); 481 482 if (PC_PAL(pc)) { 483 mode = (req->flags & ALTMODE) ? 484 (AlphaISA::mode_type)ALT_MODE_AM(ipr[AlphaISA::IPR_ALT_MODE]) 485 : AlphaISA::mode_kernel; 486 } 487 488 if (req->flags & PHYSICAL) { 489 req->paddr = req->vaddr; 490 } else { 491 // verify that this is a good virtual address 492 if (!validVirtualAddress(req->vaddr)) { 493 fault(req->vaddr, 494 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK | 495 MM_STAT_ACV_MASK), 496 req->xc); 497 498 if (write) { write_acv++; } else { read_acv++; } 499 return DTB_Fault_Fault; 500 } 501 502 // Check for "superpage" mapping: when SP<1> is set, and 503 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>. 504 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && 505 VA_SPACE(req->vaddr) == 2) { 506 507 // only valid in kernel mode 508 if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) != 509 AlphaISA::mode_kernel) { 510 fault(req->vaddr, 511 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK), 512 req->xc); 513 if (write) { write_acv++; } else { read_acv++; } 514 return DTB_Acv_Fault; 515 } 516 517 req->paddr = req->vaddr & PA_IMPL_MASK; 518 519 // sign extend the physical address properly 520 if (req->paddr & PA_UNCACHED_BIT_39 || 521 req->paddr & PA_UNCACHED_BIT_40) 522 req->paddr |= 0xf0000000000ULL; 523 else 524 req->paddr &= 0xffffffffffULL; 525 526 } else { 527 if (write) 528 write_accesses++; 529 else 530 read_accesses++; 531 532 // not a physical address: need to look up pte 533 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr), 534 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); 535 536 if (!pte) { 537 // page fault 538 fault(req->vaddr, 539 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK), 540 req->xc); 541 if (write) { write_misses++; } else { read_misses++; } 542 return (req->flags & VPTE) ? Pdtb_Miss_Fault : Ndtb_Miss_Fault; 543 } 544 545 req->paddr = PA_PFN2PA(pte->ppn) | VA_POFS(req->vaddr); 546 547 if (write) { 548 if (!(pte->xwe & MODE2MASK(mode))) { 549 // declare the instruction access fault 550 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_ACV_MASK | 551 (pte->fonw ? MM_STAT_FONW_MASK : 0), 552 req->xc); 553 write_acv++; 554 return DTB_Fault_Fault; 555 } 556 if (pte->fonw) { 557 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_FONW_MASK, 558 req->xc); 559 write_acv++; 560 return DTB_Fault_Fault; 561 } 562 } else { 563 if (!(pte->xre & MODE2MASK(mode))) { 564 fault(req->vaddr, 565 MM_STAT_ACV_MASK | 566 (pte->fonr ? MM_STAT_FONR_MASK : 0), 567 req->xc); 568 read_acv++; 569 return DTB_Acv_Fault; 570 } 571 if (pte->fonr) { 572 fault(req->vaddr, MM_STAT_FONR_MASK, req->xc); 573 read_acv++; 574 return DTB_Fault_Fault; 575 } 576 } 577 } 578 579 if (write) 580 write_hits++; 581 else 582 read_hits++; 583 } 584 585 // check that the physical address is ok (catch bad physical addresses) 586 if (req->paddr & ~PA_IMPL_MASK) 587 return Machine_Check_Fault; 588 589 checkCacheability(req); 590 591 return No_Fault; 592} 593 594AlphaISA::PTE & 595AlphaTLB::index(bool advance) 596{ 597 AlphaISA::PTE *pte = &table[nlu]; 598 599 if (advance) 600 nextnlu(); 601 602 return *pte; 603} 604 605DEFINE_SIM_OBJECT_CLASS_NAME("AlphaTLB", AlphaTLB) 606 607BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) 608 609 Param<int> size; 610 611END_DECLARE_SIM_OBJECT_PARAMS(AlphaITB) 612 613BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaITB) 614 615 INIT_PARAM_DFLT(size, "TLB size", 48) 616 617END_INIT_SIM_OBJECT_PARAMS(AlphaITB) 618 619 620CREATE_SIM_OBJECT(AlphaITB) 621{ 622 return new AlphaITB(getInstanceName(), size); 623} 624 625REGISTER_SIM_OBJECT("AlphaITB", AlphaITB) 626 627BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) 628 629 Param<int> size; 630 631END_DECLARE_SIM_OBJECT_PARAMS(AlphaDTB) 632 633BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDTB) 634 635 INIT_PARAM_DFLT(size, "TLB size", 64) 636 637END_INIT_SIM_OBJECT_PARAMS(AlphaDTB) 638 639 640CREATE_SIM_OBJECT(AlphaDTB) 641{ 642 return new AlphaDTB(getInstanceName(), size); 643} 644 645REGISTER_SIM_OBJECT("AlphaDTB", AlphaDTB) 646 647