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