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