tlb.cc revision 224
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 for (int i = 0; i < size; i++) { 201 nameOut(os, csprintf("%s.PTE%d", name(), i)); 202 table[i].serialize(os); 203 } 204} 205 206void 207AlphaTlb::unserialize(const IniFile *db, const string §ion) 208{ 209 UNSERIALIZE_SCALAR(size); 210 UNSERIALIZE_SCALAR(nlu); 211 212 for (int i = 0; i < size; i++) { 213 table[i].unserialize(db, csprintf("%s.PTE%d", section, i)); 214 if (table[i].valid) { 215 lookupTable.insert(make_pair(table[i].tag, i)); 216 } 217 } 218} 219 220 221/////////////////////////////////////////////////////////////////////// 222// 223// Alpha ITB 224// 225AlphaItb::AlphaItb(const std::string &name, int size) 226 : AlphaTlb(name, size) 227{} 228 229 230void 231AlphaItb::regStats() 232{ 233 hits 234 .name(name() + ".hits") 235 .desc("ITB hits"); 236 misses 237 .name(name() + ".misses") 238 .desc("ITB misses"); 239 acv 240 .name(name() + ".acv") 241 .desc("ITB acv"); 242 accesses 243 .name(name() + ".accesses") 244 .desc("ITB accesses"); 245 246 accesses = hits + misses; 247} 248 249void 250AlphaItb::fault(Addr pc, ExecContext *xc) const 251{ 252 uint64_t *ipr = xc->regs.ipr; 253 254 if (!xc->misspeculating()) { 255 ipr[AlphaISA::IPR_ITB_TAG] = pc; 256 ipr[AlphaISA::IPR_IFAULT_VA_FORM] = 257 ipr[AlphaISA::IPR_IVPTBR] | (VA_VPN(pc) << 3); 258 } 259} 260 261 262Fault 263AlphaItb::translate(MemReqPtr req) const 264{ 265 InternalProcReg *ipr = req->xc->regs.ipr; 266 267 if (PC_PAL(req->vaddr)) { 268 // strip off PAL PC marker (lsb is 1) 269 req->paddr = (req->vaddr & ~3) & PA_IMPL_MASK; 270 hits++; 271 return No_Fault; 272 } 273 274 // verify that this is a good virtual address 275 if (!validVirtualAddress(req->vaddr)) { 276 fault(req->vaddr, req->xc); 277 acv++; 278 return Itb_Acv_Fault; 279 } 280 281 // Check for "superpage" mapping: when SP<1> is set, and 282 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>. 283 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && 284 VA_SPACE(req->vaddr) == 2) { 285 // only valid in kernel mode 286 if (ICM_CM(ipr[AlphaISA::IPR_ICM]) != AlphaISA::mode_kernel) { 287 fault(req->vaddr, req->xc); 288 acv++; 289 return Itb_Acv_Fault; 290 } 291 292 req->flags |= PHYSICAL; 293 } 294 295 if (req->flags & PHYSICAL) { 296 req->paddr = req->vaddr & PA_IMPL_MASK; 297 } else { 298 // not a physical address: need to look up pte 299 300 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr), 301 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); 302 303 if (!pte) { 304 fault(req->vaddr, req->xc); 305 misses++; 306 return Itb_Fault_Fault; 307 } 308 309 req->paddr = PA_PFN2PA(pte->ppn) + VA_POFS(req->vaddr & ~3); 310 311 // check permissions for this access 312 if (!(pte->xre & (1 << ICM_CM(ipr[AlphaISA::IPR_ICM])))) { 313 // instruction access fault 314 fault(req->vaddr, req->xc); 315 acv++; 316 return Itb_Acv_Fault; 317 } 318 } 319 320 checkCacheability(req); 321 322 hits++; 323 return No_Fault; 324} 325 326/////////////////////////////////////////////////////////////////////// 327// 328// Alpha DTB 329// 330AlphaDtb::AlphaDtb(const std::string &name, int size) 331 : AlphaTlb(name, size) 332{} 333 334void 335AlphaDtb::regStats() 336{ 337 read_hits 338 .name(name() + ".read_hits") 339 .desc("DTB read hits") 340 ; 341 342 read_misses 343 .name(name() + ".read_misses") 344 .desc("DTB read misses") 345 ; 346 347 read_acv 348 .name(name() + ".read_acv") 349 .desc("DTB read access violations") 350 ; 351 352 read_accesses 353 .name(name() + ".read_accesses") 354 .desc("DTB read accesses") 355 ; 356 357 write_hits 358 .name(name() + ".write_hits") 359 .desc("DTB write hits") 360 ; 361 362 write_misses 363 .name(name() + ".write_misses") 364 .desc("DTB write misses") 365 ; 366 367 write_acv 368 .name(name() + ".write_acv") 369 .desc("DTB write access violations") 370 ; 371 372 write_accesses 373 .name(name() + ".write_accesses") 374 .desc("DTB write accesses") 375 ; 376 377 hits 378 .name(name() + ".hits") 379 .desc("DTB hits") 380 ; 381 382 misses 383 .name(name() + ".misses") 384 .desc("DTB misses") 385 ; 386 387 acv 388 .name(name() + ".acv") 389 .desc("DTB access violations") 390 ; 391 392 accesses 393 .name(name() + ".accesses") 394 .desc("DTB accesses") 395 ; 396 397 hits = read_hits + write_hits; 398 misses = read_misses + write_misses; 399 acv = read_acv + write_acv; 400 accesses = read_accesses + write_accesses; 401} 402 403void 404AlphaDtb::fault(Addr vaddr, uint64_t flags, ExecContext *xc) const 405{ 406 uint64_t *ipr = xc->regs.ipr; 407 408 // set fault address and flags 409 if (!xc->misspeculating() && !xc->regs.intrlock) { 410 // set VA register with faulting address 411 ipr[AlphaISA::IPR_VA] = vaddr; 412 413 // set MM_STAT register flags 414 ipr[AlphaISA::IPR_MM_STAT] = (((xc->regs.opcode & 0x3f) << 11) 415 | ((xc->regs.ra & 0x1f) << 6) 416 | (flags & 0x3f)); 417 418 // set VA_FORM register with faulting formatted address 419 ipr[AlphaISA::IPR_VA_FORM] = 420 ipr[AlphaISA::IPR_MVPTBR] | (VA_VPN(vaddr) << 3); 421 422 // lock these registers until the VA register is read 423 xc->regs.intrlock = true; 424 } 425} 426 427Fault 428AlphaDtb::translate(MemReqPtr req, bool write) const 429{ 430 RegFile *regs = &req->xc->regs; 431 Addr pc = regs->pc; 432 InternalProcReg *ipr = regs->ipr; 433 434 if (write) 435 write_accesses++; 436 else 437 read_accesses++; 438 439 AlphaISA::md_mode_type mode = 440 (AlphaISA::md_mode_type)DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]); 441 442 if (PC_PAL(pc)) { 443 mode = (req->flags & ALTMODE) ? (AlphaISA::md_mode_type) 444 (ALT_MODE_AM(ipr[AlphaISA::IPR_ALT_MODE])) 445 : AlphaISA::mode_kernel; 446 } 447 448 // verify that this is a good virtual address 449 if (!validVirtualAddress(req->vaddr)) { 450 fault(req->vaddr, 451 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_BAD_VA_MASK | 452 MM_STAT_ACV_MASK), 453 req->xc); 454 455 if (write) { write_acv++; } else { read_acv++; } 456 return Dtb_Fault_Fault; 457 } 458 459 // Check for "superpage" mapping: when SP<1> is set, and 460 // VA<42:41> == 2, VA<39:13> maps directly to PA<39:13>. 461 if ((MCSR_SP(ipr[AlphaISA::IPR_MCSR]) & 2) && VA_SPACE(req->vaddr) == 2) { 462 // only valid in kernel mode 463 if (DTB_CM_CM(ipr[AlphaISA::IPR_DTB_CM]) != AlphaISA::mode_kernel) { 464 fault(req->vaddr, 465 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_ACV_MASK), 466 req->xc); 467 if (write) { write_acv++; } else { read_acv++; } 468 return Dtb_Acv_Fault; 469 } 470 471 req->flags |= PHYSICAL; 472 } 473 474 if (req->flags & PHYSICAL) { 475 req->paddr = req->vaddr & PA_IMPL_MASK; 476 } else { 477 // not a physical address: need to look up pte 478 479 AlphaISA::PTE *pte = lookup(VA_VPN(req->vaddr), 480 DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN])); 481 482 if (!pte) { 483 // page fault 484 fault(req->vaddr, 485 ((write ? MM_STAT_WR_MASK : 0) | MM_STAT_DTB_MISS_MASK), 486 req->xc); 487 if (write) { write_misses++; } else { read_misses++; } 488 return (req->flags & VPTE) ? Pdtb_Miss_Fault : Ndtb_Miss_Fault; 489 } 490 491 req->paddr = PA_PFN2PA(pte->ppn) | VA_POFS(req->vaddr); 492 493 if (write) { 494 if (!(pte->xwe & MODE2MASK(mode))) { 495 // declare the instruction access fault 496 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_ACV_MASK | 497 (pte->fonw ? MM_STAT_FONW_MASK : 0), 498 req->xc); 499 write_acv++; 500 return Dtb_Fault_Fault; 501 } 502 if (pte->fonw) { 503 fault(req->vaddr, MM_STAT_WR_MASK | MM_STAT_FONW_MASK, 504 req->xc); 505 write_acv++; 506 return Dtb_Fault_Fault; 507 } 508 } else { 509 if (!(pte->xre & MODE2MASK(mode))) { 510 fault(req->vaddr, 511 MM_STAT_ACV_MASK | (pte->fonr ? MM_STAT_FONR_MASK : 0), 512 req->xc); 513 read_acv++; 514 return Dtb_Acv_Fault; 515 } 516 if (pte->fonr) { 517 fault(req->vaddr, MM_STAT_FONR_MASK, req->xc); 518 read_acv++; 519 return Dtb_Fault_Fault; 520 } 521 } 522 } 523 524 checkCacheability(req); 525 526 if (write) 527 write_hits++; 528 else 529 read_hits++; 530 531 return No_Fault; 532} 533 534AlphaISA::PTE & 535AlphaTlb::index() 536{ 537 AlphaISA::PTE *pte = &table[nlu]; 538 nextnlu(); 539 540 return *pte; 541} 542 543BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaItb) 544 545 Param<int> size; 546 547END_DECLARE_SIM_OBJECT_PARAMS(AlphaItb) 548 549BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaItb) 550 551 INIT_PARAM_DFLT(size, "TLB size", 48) 552 553END_INIT_SIM_OBJECT_PARAMS(AlphaItb) 554 555 556CREATE_SIM_OBJECT(AlphaItb) 557{ 558 return new AlphaItb(getInstanceName(), size); 559} 560 561REGISTER_SIM_OBJECT("AlphaITB", AlphaItb) 562 563BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb) 564 565 Param<int> size; 566 567END_DECLARE_SIM_OBJECT_PARAMS(AlphaDtb) 568 569BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaDtb) 570 571 INIT_PARAM_DFLT(size, "TLB size", 64) 572 573END_INIT_SIM_OBJECT_PARAMS(AlphaDtb) 574 575 576CREATE_SIM_OBJECT(AlphaDtb) 577{ 578 return new AlphaDtb(getInstanceName(), size); 579} 580 581REGISTER_SIM_OBJECT("AlphaDTB", AlphaDtb) 582 583