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