tlb.cc revision 555
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 { 286 // verify that this is a good virtual address 287 if (!validVirtualAddress(req->vaddr)) { 288 fault(req->vaddr, req->xc); 289 acv++; 290 return Itb_Acv_Fault; 291 } 292 293 // Check for "superpage" mapping: when SP<1> is set, and 294 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>. 295 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && 296 VA_SPACE(req->vaddr) == 2) { 297 298 // only valid in kernel mode 299 if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) { 300 fault(req->vaddr, req->xc); 301 acv++; 302 return Itb_Acv_Fault; 303 } 304 305 req->paddr = req->vaddr & PA_IMPL_MASK; 306 } else { 307 // not a physical address: need to look up pte 308 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr), 309 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); 310 311 if (!pte) { 312 fault(req->vaddr, req->xc); 313 misses++; 314 return Itb_Fault_Fault; 315 } 316 317 req->paddr = PA_PFN2PA(pte->ppn) + VA_POFS(req->vaddr & ~3); 318 319 // check permissions for this access 320 if (!(pte->xre & (1 << ICM_CM(ipr[AlphaISA::IPR_ICM])))) { 321 // instruction access fault 322 fault(req->vaddr, req->xc); 323 acv++; 324 return Itb_Acv_Fault; 325 } 326 327 hits++; 328 } 329 } 330 331 // check that the physical address is ok (catch bad physical addresses) 332 if (req->paddr & ~PA_IMPL_MASK) 333 return Machine_Check_Fault; 334 335 checkCacheability(req); 336 337 return No_Fault; 338} 339 340/////////////////////////////////////////////////////////////////////// 341// 342// Alpha DTB 343// 344AlphaDtb::AlphaDtb(const std::string &name, int size) 345 : AlphaTlb(name, size) 346{} 347 348void 349AlphaDtb::regStats() 350{ 351 read_hits 352 .name(name() + ".read_hits") 353 .desc("DTB read hits") 354 ; 355 356 read_misses 357 .name(name() + ".read_misses") 358 .desc("DTB read misses") 359 ; 360 361 read_acv 362 .name(name() + ".read_acv") 363 .desc("DTB read access violations") 364 ; 365 366 read_accesses 367 .name(name() + ".read_accesses") 368 .desc("DTB read accesses") 369 ; 370 371 write_hits 372 .name(name() + ".write_hits") 373 .desc("DTB write hits") 374 ; 375 376 write_misses 377 .name(name() + ".write_misses") 378 .desc("DTB write misses") 379 ; 380 381 write_acv 382 .name(name() + ".write_acv") 383 .desc("DTB write access violations") 384 ; 385 386 write_accesses 387 .name(name() + ".write_accesses") 388 .desc("DTB write accesses") 389 ; 390 391 hits 392 .name(name() + ".hits") 393 .desc("DTB hits") 394 ; 395 396 misses 397 .name(name() + ".misses") 398 .desc("DTB misses") 399 ; 400 401 acv 402 .name(name() + ".acv") 403 .desc("DTB access violations") 404 ; 405 406 accesses 407 .name(name() + ".accesses") 408 .desc("DTB accesses") 409 ; 410 411 hits = read_hits + write_hits; 412 misses = read_misses + write_misses; 413 acv = read_acv + write_acv; 414 accesses = read_accesses + write_accesses; 415} 416 417void 418AlphaDtb::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const 419{ 420 uint64_t *ipr = xc->regs.ipr; 421 422 // set fault address and flags 423 if (!xc->misspeculating() && !xc->regs.intrlock) { 424 // set VA register with faulting address 425 ipr[AlphaISA::IPR_VA] = vaddr; 426 427 // set MM_STAT register flags 428 ipr[AlphaISA::IPR_MM_STAT] = (((xc->regs.opcode & 0x3f) << 11) 429 | ((xc->regs.ra & 0x1f) << 6) 430 | (flags & 0x3f)); 431 432 // set VA_FORM register with faulting formatted address 433 ipr[AlphaISA::IPR_VA_FORM] = 434 ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3); 435 436 // lock these registers until the VA register is read 437 xc->regs.intrlock = true; 438 } 439} 440 441Fault 442AlphaDtb::translate(MemReqPtr &req, bool write) const 443{ 444 RegFile *regs = &req->xc->regs; 445 Addr pc = regs->pc; 446 InternalProcReg *ipr = regs->ipr; 447 448 AlphaISA::mode_type mode = 449 (AlphaISA::mode_type)DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]); 450 451 if (PC_PAL(pc)) { 452 mode = (req->flags & ALTMODE) ? 453 (AlphaISA::mode_type)ALT_MODE_AM(ipr[AlphaISA::IPR_ALT_MODE]) 454 : AlphaISA::mode_kernel; 455 } 456 457 if (req->flags & PHYSICAL) { 458 req->paddr = req->vaddr; 459 } else { 460 // verify that this is a good virtual address 461 if (!validVirtualAddress(req->vaddr)) { 462 fault(req->vaddr, 463 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK | 464 MM_STAT_ACV_MASK), 465 req->xc); 466 467 if (write) { write_acv++; } else { read_acv++; } 468 return Dtb_Fault_Fault; 469 } 470 471 // Check for "superpage" mapping: when SP<1> is set, and 472 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>. 473 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && 474 VA_SPACE(req->vaddr) == 2) { 475 476 // only valid in kernel mode 477 if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) != 478 AlphaISA::mode_kernel) { 479 fault(req->vaddr, 480 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK), 481 req->xc); 482 if (write) { write_acv++; } else { read_acv++; } 483 return Dtb_Acv_Fault; 484 } 485 486 req->paddr = req->vaddr & PA_IMPL_MASK; 487 } else { 488 if (write) 489 write_accesses++; 490 else 491 read_accesses++; 492 493 // not a physical address: need to look up pte 494 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr), 495 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); 496 497 if (!pte) { 498 // page fault 499 fault(req->vaddr, 500 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK), 501 req->xc); 502 if (write) { write_misses++; } else { read_misses++; } 503 return (req->flags & VPTE) ? Pdtb_Miss_Fault : Ndtb_Miss_Fault; 504 } 505 506 req->paddr = PA_PFN2PA(pte->ppn) | VA_POFS(req->vaddr); 507 508 if (write) { 509 if (!(pte->xwe & MODE2MASK(mode))) { 510 // declare the instruction access fault 511 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_ACV_MASK | 512 (pte->fonw ? MM_STAT_FONW_MASK : 0), 513 req->xc); 514 write_acv++; 515 return Dtb_Fault_Fault; 516 } 517 if (pte->fonw) { 518 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_FONW_MASK, 519 req->xc); 520 write_acv++; 521 return Dtb_Fault_Fault; 522 } 523 } else { 524 if (!(pte->xre & MODE2MASK(mode))) { 525 fault(req->vaddr, 526 MM_STAT_ACV_MASK | 527 (pte->fonr ? MM_STAT_FONR_MASK : 0), 528 req->xc); 529 read_acv++; 530 return Dtb_Acv_Fault; 531 } 532 if (pte->fonr) { 533 fault(req->vaddr, MM_STAT_FONR_MASK, req->xc); 534 read_acv++; 535 return Dtb_Fault_Fault; 536 } 537 } 538 } 539 540 if (write) 541 write_hits++; 542 else 543 read_hits++; 544 } 545 546 // check that the physical address is ok (catch bad physical addresses) 547 if (req->paddr & ~PA_IMPL_MASK) 548 return Machine_Check_Fault; 549 550 checkCacheability(req); 551 552 return No_Fault; 553} 554 555AlphaISA::PTE & 556AlphaTlb::index(bool advance) 557{ 558 AlphaISA::PTE *pte = &table[nlu]; 559 560 if (advance) 561 nextnlu(); 562 563 return *pte; 564} 565 566BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaItb) 567 568 Param<int> size; 569 570END_DECLARE_SIM_OBJECT_PARAMS(AlphaItb) 571 572BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaItb) 573 574 INIT_PARAM_DFLT(size, "TLB size", 48) 575 576END_INIT_SIM_OBJECT_PARAMS(AlphaItb) 577 578 579CREATE_SIM_OBJECT(AlphaItb) 580{ 581 return new AlphaItb(getInstanceName(), size); 582} 583 584REGISTER_SIM_OBJECT("AlphaITB", AlphaItb) 585 586BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb) 587 588 Param<int> size; 589 590END_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb) 591 592BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDtb) 593 594 INIT_PARAM_DFLT(size, "TLB size", 64) 595 596END_INIT_SIM_OBJECT_PARAMS(AlphaDtb) 597 598 599CREATE_SIM_OBJECT(AlphaDtb) 600{ 601 return new AlphaDtb(getInstanceName(), size); 602} 603 604REGISTER_SIM_OBJECT("AlphaDTB", AlphaDtb) 605 606