tlb.cc revision 5236:0050ad4fb3ef
1/* 2 * Copyright (c) 2007 The Hewlett-Packard Development Company 3 * All rights reserved. 4 * 5 * Redistribution and use of this software in source and binary forms, 6 * with or without modification, are permitted provided that the 7 * following conditions are met: 8 * 9 * The software must be used only for Non-Commercial Use which means any 10 * use which is NOT directed to receiving any direct monetary 11 * compensation for, or commercial advantage from such use. Illustrative 12 * examples of non-commercial use are academic research, personal study, 13 * teaching, education and corporate research & development. 14 * Illustrative examples of commercial use are distributing products for 15 * commercial advantage and providing services using the software for 16 * commercial advantage. 17 * 18 * If you wish to use this software or functionality therein that may be 19 * covered by patents for commercial use, please contact: 20 * Director of Intellectual Property Licensing 21 * Office of Strategy and Technology 22 * Hewlett-Packard Company 23 * 1501 Page Mill Road 24 * Palo Alto, California 94304 25 * 26 * Redistributions of source code must retain the above copyright notice, 27 * this list of conditions and the following disclaimer. Redistributions 28 * in binary form must reproduce the above copyright notice, this list of 29 * conditions and the following disclaimer in the documentation and/or 30 * other materials provided with the distribution. Neither the name of 31 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its 32 * contributors may be used to endorse or promote products derived from 33 * this software without specific prior written permission. No right of 34 * sublicense is granted herewith. Derivatives of the software and 35 * output created using the software may be prepared, but only for 36 * Non-Commercial Uses. Derivatives of the software may be shared with 37 * others provided: (i) the others agree to abide by the list of 38 * conditions herein which includes the Non-Commercial Use restrictions; 39 * and (ii) such Derivatives of the software include the above copyright 40 * notice to acknowledge the contribution from this software where 41 * applicable, this list of conditions and the disclaimer below. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 * 55 * Authors: Gabe Black 56 */ 57 58#include <cstring> 59 60#include "config/full_system.hh" 61 62#include "arch/x86/pagetable.hh" 63#include "arch/x86/tlb.hh" 64#include "arch/x86/x86_traits.hh" 65#include "base/bitfield.hh" 66#include "base/trace.hh" 67#include "cpu/thread_context.hh" 68#include "cpu/base.hh" 69#include "mem/packet_access.hh" 70#include "mem/request.hh" 71#include "sim/system.hh" 72 73namespace X86ISA { 74 75TLB::TLB(const Params *p) : MemObject(p), walker(name(), this), size(p->size) 76{ 77 tlb = new TlbEntry[size]; 78 std::memset(tlb, 0, sizeof(TlbEntry) * size); 79 80 for (int x = 0; x < size; x++) 81 freeList.push_back(&tlb[x]); 82} 83 84bool 85TLB::Walker::doNext(uint64_t data, PacketPtr &write) 86{ 87 assert(state != Ready && state != Waiting); 88 write = NULL; 89 switch(state) { 90 case LongPML4: 91 nextState = LongPDP; 92 break; 93 case LongPDP: 94 nextState = LongPD; 95 break; 96 case LongPD: 97 nextState = LongPTE; 98 break; 99 case LongPTE: 100 nextState = Ready; 101 return false; 102 case PAEPDP: 103 nextState = PAEPD; 104 break; 105 case PAEPD: 106 break; 107 case PAEPTE: 108 nextState = Ready; 109 return false; 110 case PSEPD: 111 break; 112 case PD: 113 nextState = PTE; 114 break; 115 case PTE: 116 nextState = Ready; 117 return false; 118 default: 119 panic("Unknown page table walker state %d!\n"); 120 } 121 return true; 122} 123 124void 125TLB::Walker::buildReadPacket(Addr addr) 126{ 127 readRequest.setPhys(addr, size, PHYSICAL | uncachable ? UNCACHEABLE : 0); 128 readPacket.reinitFromRequest(); 129} 130 131TLB::walker::buildWritePacket(Addr addr) 132{ 133 writeRequest.setPhys(addr, size, PHYSICAL | uncachable ? UNCACHEABLE : 0); 134 writePacket.reinitFromRequest(); 135 136bool 137TLB::Walker::WalkerPort::recvTiming(PacketPtr pkt) 138{ 139 if (pkt->isResponse() && !pkt->wasNacked()) { 140 if (pkt->isRead()) { 141 assert(packet); 142 assert(walker->state == Waiting); 143 packet = NULL; 144 walker->state = walker->nextState; 145 walker->nextState = Ready; 146 PacketPtr write; 147 if (walker->doNext(pkt, write)) { 148 packet = &walker->packet; 149 port->sendTiming(packet); 150 } 151 if (write) { 152 writes.push_back(write); 153 } 154 while (!port->blocked() && writes.size()) { 155 if (port->sendTiming(writes.front())) { 156 writes.pop_front(); 157 outstandingWrites++; 158 } 159 } 160 } else { 161 outstandingWrites--; 162 } 163 } else if (pkt->wasNacked()) { 164 pkt->reinitNacked(); 165 if (!sendTiming(pkt)) { 166 if (pkt->isWrite()) { 167 writes.push_front(pkt); 168 } 169 } 170 } 171 return true; 172} 173 174Tick 175TLB::Walker::WalkerPort::recvAtomic(PacketPtr pkt) 176{ 177 return 0; 178} 179 180void 181TLB::Walker::WalkerPort::recvFunctional(PacketPtr pkt) 182{ 183 return; 184} 185 186void 187TLB::Walker::WalkerPort::recvStatusChange(Status status) 188{ 189 if (status == RangeChange) { 190 if (!snoopRangeSent) { 191 snoopRangeSent = true; 192 sendStatusChange(Port::RangeChange); 193 } 194 return; 195 } 196 197 panic("Unexpected recvStatusChange.\n"); 198} 199 200void 201TLB::Walker::WalkerPort::recvRetry() 202{ 203 retrying = false; 204 if (!sendTiming(packet)) { 205 retrying = true; 206 } 207} 208 209Port * 210TLB::getPort(const std::string &if_name, int idx) 211{ 212 if (if_name == "walker_port") 213 return &walker.port; 214 else 215 panic("No tlb port named %s!\n", if_name); 216} 217 218void 219TLB::insert(Addr vpn, TlbEntry &entry) 220{ 221 //TODO Deal with conflicting entries 222 223 TlbEntry *newEntry = NULL; 224 if (!freeList.empty()) { 225 newEntry = freeList.front(); 226 freeList.pop_front(); 227 } else { 228 newEntry = entryList.back(); 229 entryList.pop_back(); 230 } 231 *newEntry = entry; 232 newEntry->vaddr = vpn; 233 entryList.push_front(newEntry); 234} 235 236TlbEntry * 237TLB::lookup(Addr va, bool update_lru) 238{ 239 //TODO make this smarter at some point 240 EntryList::iterator entry; 241 for (entry = entryList.begin(); entry != entryList.end(); entry++) { 242 if ((*entry)->vaddr <= va && (*entry)->vaddr + (*entry)->size > va) { 243 DPRINTF(TLB, "Matched vaddr %#x to entry starting at %#x " 244 "with size %#x.\n", va, (*entry)->vaddr, (*entry)->size); 245 TlbEntry *e = *entry; 246 if (update_lru) { 247 entryList.erase(entry); 248 entryList.push_front(e); 249 } 250 return e; 251 } 252 } 253 return NULL; 254} 255 256void 257TLB::invalidateAll() 258{ 259} 260 261void 262TLB::invalidateNonGlobal() 263{ 264} 265 266void 267TLB::demapPage(Addr va) 268{ 269} 270 271template<class TlbFault> 272Fault 273TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute) 274{ 275 Addr vaddr = req->getVaddr(); 276 DPRINTF(TLB, "Translating vaddr %#x.\n", vaddr); 277 uint32_t flags = req->getFlags(); 278 bool storeCheck = flags & StoreCheck; 279 280 int seg = flags & mask(3); 281 282 //XXX Junk code to surpress the warning 283 if (storeCheck); 284 285 // If this is true, we're dealing with a request to read an internal 286 // value. 287 if (seg == SEGMENT_REG_INT) { 288 Addr prefix = vaddr & IntAddrPrefixMask; 289 if (prefix == IntAddrPrefixCPUID) { 290 panic("CPUID memory space not yet implemented!\n"); 291 } else if (prefix == IntAddrPrefixMSR) { 292 req->setMmapedIpr(true); 293 Addr regNum = 0; 294 switch (vaddr & ~IntAddrPrefixMask) { 295 case 0x10: 296 regNum = MISCREG_TSC; 297 break; 298 case 0xFE: 299 regNum = MISCREG_MTRRCAP; 300 break; 301 case 0x174: 302 regNum = MISCREG_SYSENTER_CS; 303 break; 304 case 0x175: 305 regNum = MISCREG_SYSENTER_ESP; 306 break; 307 case 0x176: 308 regNum = MISCREG_SYSENTER_EIP; 309 break; 310 case 0x179: 311 regNum = MISCREG_MCG_CAP; 312 break; 313 case 0x17A: 314 regNum = MISCREG_MCG_STATUS; 315 break; 316 case 0x17B: 317 regNum = MISCREG_MCG_CTL; 318 break; 319 case 0x1D9: 320 regNum = MISCREG_DEBUG_CTL_MSR; 321 break; 322 case 0x1DB: 323 regNum = MISCREG_LAST_BRANCH_FROM_IP; 324 break; 325 case 0x1DC: 326 regNum = MISCREG_LAST_BRANCH_TO_IP; 327 break; 328 case 0x1DD: 329 regNum = MISCREG_LAST_EXCEPTION_FROM_IP; 330 break; 331 case 0x1DE: 332 regNum = MISCREG_LAST_EXCEPTION_TO_IP; 333 break; 334 case 0x200: 335 regNum = MISCREG_MTRR_PHYS_BASE_0; 336 break; 337 case 0x201: 338 regNum = MISCREG_MTRR_PHYS_MASK_0; 339 break; 340 case 0x202: 341 regNum = MISCREG_MTRR_PHYS_BASE_1; 342 break; 343 case 0x203: 344 regNum = MISCREG_MTRR_PHYS_MASK_1; 345 break; 346 case 0x204: 347 regNum = MISCREG_MTRR_PHYS_BASE_2; 348 break; 349 case 0x205: 350 regNum = MISCREG_MTRR_PHYS_MASK_2; 351 break; 352 case 0x206: 353 regNum = MISCREG_MTRR_PHYS_BASE_3; 354 break; 355 case 0x207: 356 regNum = MISCREG_MTRR_PHYS_MASK_3; 357 break; 358 case 0x208: 359 regNum = MISCREG_MTRR_PHYS_BASE_4; 360 break; 361 case 0x209: 362 regNum = MISCREG_MTRR_PHYS_MASK_4; 363 break; 364 case 0x20A: 365 regNum = MISCREG_MTRR_PHYS_BASE_5; 366 break; 367 case 0x20B: 368 regNum = MISCREG_MTRR_PHYS_MASK_5; 369 break; 370 case 0x20C: 371 regNum = MISCREG_MTRR_PHYS_BASE_6; 372 break; 373 case 0x20D: 374 regNum = MISCREG_MTRR_PHYS_MASK_6; 375 break; 376 case 0x20E: 377 regNum = MISCREG_MTRR_PHYS_BASE_7; 378 break; 379 case 0x20F: 380 regNum = MISCREG_MTRR_PHYS_MASK_7; 381 break; 382 case 0x250: 383 regNum = MISCREG_MTRR_FIX_64K_00000; 384 break; 385 case 0x258: 386 regNum = MISCREG_MTRR_FIX_16K_80000; 387 break; 388 case 0x259: 389 regNum = MISCREG_MTRR_FIX_16K_A0000; 390 break; 391 case 0x268: 392 regNum = MISCREG_MTRR_FIX_4K_C0000; 393 break; 394 case 0x269: 395 regNum = MISCREG_MTRR_FIX_4K_C8000; 396 break; 397 case 0x26A: 398 regNum = MISCREG_MTRR_FIX_4K_D0000; 399 break; 400 case 0x26B: 401 regNum = MISCREG_MTRR_FIX_4K_D8000; 402 break; 403 case 0x26C: 404 regNum = MISCREG_MTRR_FIX_4K_E0000; 405 break; 406 case 0x26D: 407 regNum = MISCREG_MTRR_FIX_4K_E8000; 408 break; 409 case 0x26E: 410 regNum = MISCREG_MTRR_FIX_4K_F0000; 411 break; 412 case 0x26F: 413 regNum = MISCREG_MTRR_FIX_4K_F8000; 414 break; 415 case 0x277: 416 regNum = MISCREG_PAT; 417 break; 418 case 0x2FF: 419 regNum = MISCREG_DEF_TYPE; 420 break; 421 case 0x400: 422 regNum = MISCREG_MC0_CTL; 423 break; 424 case 0x404: 425 regNum = MISCREG_MC1_CTL; 426 break; 427 case 0x408: 428 regNum = MISCREG_MC2_CTL; 429 break; 430 case 0x40C: 431 regNum = MISCREG_MC3_CTL; 432 break; 433 case 0x410: 434 regNum = MISCREG_MC4_CTL; 435 break; 436 case 0x401: 437 regNum = MISCREG_MC0_STATUS; 438 break; 439 case 0x405: 440 regNum = MISCREG_MC1_STATUS; 441 break; 442 case 0x409: 443 regNum = MISCREG_MC2_STATUS; 444 break; 445 case 0x40D: 446 regNum = MISCREG_MC3_STATUS; 447 break; 448 case 0x411: 449 regNum = MISCREG_MC4_STATUS; 450 break; 451 case 0x402: 452 regNum = MISCREG_MC0_ADDR; 453 break; 454 case 0x406: 455 regNum = MISCREG_MC1_ADDR; 456 break; 457 case 0x40A: 458 regNum = MISCREG_MC2_ADDR; 459 break; 460 case 0x40E: 461 regNum = MISCREG_MC3_ADDR; 462 break; 463 case 0x412: 464 regNum = MISCREG_MC4_ADDR; 465 break; 466 case 0x403: 467 regNum = MISCREG_MC0_MISC; 468 break; 469 case 0x407: 470 regNum = MISCREG_MC1_MISC; 471 break; 472 case 0x40B: 473 regNum = MISCREG_MC2_MISC; 474 break; 475 case 0x40F: 476 regNum = MISCREG_MC3_MISC; 477 break; 478 case 0x413: 479 regNum = MISCREG_MC4_MISC; 480 break; 481 case 0xC0000080: 482 regNum = MISCREG_EFER; 483 break; 484 case 0xC0000081: 485 regNum = MISCREG_STAR; 486 break; 487 case 0xC0000082: 488 regNum = MISCREG_LSTAR; 489 break; 490 case 0xC0000083: 491 regNum = MISCREG_CSTAR; 492 break; 493 case 0xC0000084: 494 regNum = MISCREG_SF_MASK; 495 break; 496 case 0xC0000100: 497 regNum = MISCREG_FS_BASE; 498 break; 499 case 0xC0000101: 500 regNum = MISCREG_GS_BASE; 501 break; 502 case 0xC0000102: 503 regNum = MISCREG_KERNEL_GS_BASE; 504 break; 505 case 0xC0000103: 506 regNum = MISCREG_TSC_AUX; 507 break; 508 case 0xC0010000: 509 regNum = MISCREG_PERF_EVT_SEL0; 510 break; 511 case 0xC0010001: 512 regNum = MISCREG_PERF_EVT_SEL1; 513 break; 514 case 0xC0010002: 515 regNum = MISCREG_PERF_EVT_SEL2; 516 break; 517 case 0xC0010003: 518 regNum = MISCREG_PERF_EVT_SEL3; 519 break; 520 case 0xC0010004: 521 regNum = MISCREG_PERF_EVT_CTR0; 522 break; 523 case 0xC0010005: 524 regNum = MISCREG_PERF_EVT_CTR1; 525 break; 526 case 0xC0010006: 527 regNum = MISCREG_PERF_EVT_CTR2; 528 break; 529 case 0xC0010007: 530 regNum = MISCREG_PERF_EVT_CTR3; 531 break; 532 case 0xC0010010: 533 regNum = MISCREG_SYSCFG; 534 break; 535 case 0xC0010016: 536 regNum = MISCREG_IORR_BASE0; 537 break; 538 case 0xC0010017: 539 regNum = MISCREG_IORR_BASE1; 540 break; 541 case 0xC0010018: 542 regNum = MISCREG_IORR_MASK0; 543 break; 544 case 0xC0010019: 545 regNum = MISCREG_IORR_MASK1; 546 break; 547 case 0xC001001A: 548 regNum = MISCREG_TOP_MEM; 549 break; 550 case 0xC001001D: 551 regNum = MISCREG_TOP_MEM2; 552 break; 553 case 0xC0010114: 554 regNum = MISCREG_VM_CR; 555 break; 556 case 0xC0010115: 557 regNum = MISCREG_IGNNE; 558 break; 559 case 0xC0010116: 560 regNum = MISCREG_SMM_CTL; 561 break; 562 case 0xC0010117: 563 regNum = MISCREG_VM_HSAVE_PA; 564 break; 565 default: 566 return new GeneralProtection(0); 567 } 568 //The index is multiplied by the size of a MiscReg so that 569 //any memory dependence calculations will not see these as 570 //overlapping. 571 req->setPaddr(regNum * sizeof(MiscReg)); 572 return NoFault; 573 } else { 574 panic("Access to unrecognized internal address space %#x.\n", 575 prefix); 576 } 577 } 578 579 // Get cr0. This will tell us how to do translation. We'll assume it was 580 // verified to be correct and consistent when set. 581 CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0); 582 583 // If protected mode has been enabled... 584 if (cr0.pe) { 585 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); 586 SegAttr csAttr = tc->readMiscRegNoEffect(MISCREG_CS_ATTR); 587 // If we're not in 64-bit mode, do protection/limit checks 588 if (!efer.lma || !csAttr.longMode) { 589 SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg)); 590 if (!attr.writable && write) 591 return new GeneralProtection(0); 592 if (!attr.readable && !write && !execute) 593 return new GeneralProtection(0); 594 Addr base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(seg)); 595 Addr limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg)); 596 if (!attr.expandDown) { 597 // We don't have to worry about the access going around the 598 // end of memory because accesses will be broken up into 599 // pieces at boundaries aligned on sizes smaller than an 600 // entire address space. We do have to worry about the limit 601 // being less than the base. 602 if (limit < base) { 603 if (limit < vaddr + req->getSize() && vaddr < base) 604 return new GeneralProtection(0); 605 } else { 606 if (limit < vaddr + req->getSize()) 607 return new GeneralProtection(0); 608 } 609 } else { 610 if (limit < base) { 611 if (vaddr <= limit || vaddr + req->getSize() >= base) 612 return new GeneralProtection(0); 613 } else { 614 if (vaddr <= limit && vaddr + req->getSize() >= base) 615 return new GeneralProtection(0); 616 } 617 } 618 } 619 // If paging is enabled, do the translation. 620 if (cr0.pg) { 621 // The vaddr already has the segment base applied. 622 TlbEntry *entry = lookup(vaddr); 623 if (!entry) { 624#if FULL_SYSTEM 625 return new TlbFault(); 626#else 627 return new TlbFault(vaddr); 628#endif 629 } else { 630 // Do paging protection checks. 631 Addr paddr = entry->paddr | (vaddr & mask(12)); 632 req->setPaddr(paddr); 633 } 634 } else { 635 //Use the address which already has segmentation applied. 636 req->setPaddr(vaddr); 637 } 638 } else { 639 // Real mode 640 req->setPaddr(vaddr); 641 } 642 return NoFault; 643}; 644 645Fault 646DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) 647{ 648 return TLB::translate<FakeDTLBFault>(req, tc, write, false); 649} 650 651Fault 652ITB::translate(RequestPtr &req, ThreadContext *tc) 653{ 654 return TLB::translate<FakeITLBFault>(req, tc, false, true); 655} 656 657#if FULL_SYSTEM 658 659Tick 660DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) 661{ 662 return tc->getCpuPtr()->ticks(1); 663} 664 665Tick 666DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt) 667{ 668 return tc->getCpuPtr()->ticks(1); 669} 670 671#endif 672 673void 674TLB::serialize(std::ostream &os) 675{ 676} 677 678void 679TLB::unserialize(Checkpoint *cp, const std::string §ion) 680{ 681} 682 683void 684DTB::serialize(std::ostream &os) 685{ 686 TLB::serialize(os); 687} 688 689void 690DTB::unserialize(Checkpoint *cp, const std::string §ion) 691{ 692 TLB::unserialize(cp, section); 693} 694 695/* end namespace X86ISA */ } 696 697X86ISA::ITB * 698X86ITBParams::create() 699{ 700 return new X86ISA::ITB(this); 701} 702 703X86ISA::DTB * 704X86DTBParams::create() 705{ 706 return new X86ISA::DTB(this); 707} 708