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