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