1/* 2 * Copyright (c) 2012 ARM Limited 3 * All rights reserved. 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2007 The Hewlett-Packard Development Company 15 * All rights reserved. 16 * 17 * The license below extends only to copyright in the software and shall 18 * not be construed as granting a license to any other intellectual 19 * property including but not limited to intellectual property relating 20 * to a hardware implementation of the functionality of the software 21 * licensed hereunder. You may use the software subject to the license 22 * terms below provided that you ensure that this notice is replicated 23 * unmodified and in its entirety in all distributions of the software, 24 * modified or unmodified, in source code or in binary form. 25 * 26 * Redistribution and use in source and binary forms, with or without 27 * modification, are permitted provided that the following conditions are 28 * met: redistributions of source code must retain the above copyright 29 * notice, this list of conditions and the following disclaimer; 30 * redistributions in binary form must reproduce the above copyright 31 * notice, this list of conditions and the following disclaimer in the 32 * documentation and/or other materials provided with the distribution; 33 * neither the name of the copyright holders nor the names of its 34 * contributors may be used to endorse or promote products derived from 35 * this software without specific prior written permission. 36 * 37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 38 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 39 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 40 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 41 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 * 49 * Authors: Gabe Black 50 */ 51 52#include "arch/x86/pagetable.hh" 53#include "arch/x86/pagetable_walker.hh" 54#include "arch/x86/tlb.hh" 55#include "arch/x86/vtophys.hh" 56#include "base/bitfield.hh" 57#include "base/trie.hh" 58#include "cpu/base.hh" 59#include "cpu/thread_context.hh" 60#include "debug/PageTableWalker.hh" 61#include "mem/packet_access.hh" 62#include "mem/request.hh" 63 64namespace X86ISA { 65 66// Unfortunately, the placement of the base field in a page table entry is 67// very erratic and would make a mess here. It might be moved here at some 68// point in the future. 69BitUnion64(PageTableEntry) 70 Bitfield<63> nx; 71 Bitfield<11, 9> avl; 72 Bitfield<8> g; 73 Bitfield<7> ps; 74 Bitfield<6> d; 75 Bitfield<5> a; 76 Bitfield<4> pcd; 77 Bitfield<3> pwt; 78 Bitfield<2> u; 79 Bitfield<1> w; 80 Bitfield<0> p; 81EndBitUnion(PageTableEntry) 82 83Fault 84Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation, 85 RequestPtr _req, BaseTLB::Mode _mode) 86{ 87 // TODO: in timing mode, instead of blocking when there are other 88 // outstanding requests, see if this request can be coalesced with 89 // another one (i.e. either coalesce or start walk) 90 WalkerState * newState = new WalkerState(this, _translation, _req); 91 newState->initState(_tc, _mode, sys->isTimingMode()); 92 if (currStates.size()) { 93 assert(newState->isTiming()); 94 DPRINTF(PageTableWalker, "Walks in progress: %d\n", currStates.size()); 95 currStates.push_back(newState); 96 return NoFault; 97 } else { 98 currStates.push_back(newState); 99 Fault fault = newState->startWalk(); 100 if (!newState->isTiming()) { 101 currStates.pop_front(); 102 delete newState; 103 } 104 return fault; 105 } 106} 107 108Fault 109Walker::startFunctional(ThreadContext * _tc, Addr &addr, unsigned &logBytes, 110 BaseTLB::Mode _mode) 111{ 112 funcState.initState(_tc, _mode); 113 return funcState.startFunctional(addr, logBytes); 114} 115 116bool 117Walker::WalkerPort::recvTimingResp(PacketPtr pkt) 118{ 119 return walker->recvTimingResp(pkt); 120} 121 122bool 123Walker::recvTimingResp(PacketPtr pkt) 124{ 125 WalkerSenderState * senderState = 126 dynamic_cast<WalkerSenderState *>(pkt->popSenderState()); 127 WalkerState * senderWalk = senderState->senderWalk; 128 bool walkComplete = senderWalk->recvPacket(pkt); 129 delete senderState; 130 if (walkComplete) { 131 std::list<WalkerState *>::iterator iter; 132 for (iter = currStates.begin(); iter != currStates.end(); iter++) { 133 WalkerState * walkerState = *(iter); 134 if (walkerState == senderWalk) { 135 iter = currStates.erase(iter); 136 break; 137 } 138 } 139 delete senderWalk; 140 // Since we block requests when another is outstanding, we 141 // need to check if there is a waiting request to be serviced
| 1/* 2 * Copyright (c) 2012 ARM Limited 3 * All rights reserved. 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2007 The Hewlett-Packard Development Company 15 * All rights reserved. 16 * 17 * The license below extends only to copyright in the software and shall 18 * not be construed as granting a license to any other intellectual 19 * property including but not limited to intellectual property relating 20 * to a hardware implementation of the functionality of the software 21 * licensed hereunder. You may use the software subject to the license 22 * terms below provided that you ensure that this notice is replicated 23 * unmodified and in its entirety in all distributions of the software, 24 * modified or unmodified, in source code or in binary form. 25 * 26 * Redistribution and use in source and binary forms, with or without 27 * modification, are permitted provided that the following conditions are 28 * met: redistributions of source code must retain the above copyright 29 * notice, this list of conditions and the following disclaimer; 30 * redistributions in binary form must reproduce the above copyright 31 * notice, this list of conditions and the following disclaimer in the 32 * documentation and/or other materials provided with the distribution; 33 * neither the name of the copyright holders nor the names of its 34 * contributors may be used to endorse or promote products derived from 35 * this software without specific prior written permission. 36 * 37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 38 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 39 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 40 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 41 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 * 49 * Authors: Gabe Black 50 */ 51 52#include "arch/x86/pagetable.hh" 53#include "arch/x86/pagetable_walker.hh" 54#include "arch/x86/tlb.hh" 55#include "arch/x86/vtophys.hh" 56#include "base/bitfield.hh" 57#include "base/trie.hh" 58#include "cpu/base.hh" 59#include "cpu/thread_context.hh" 60#include "debug/PageTableWalker.hh" 61#include "mem/packet_access.hh" 62#include "mem/request.hh" 63 64namespace X86ISA { 65 66// Unfortunately, the placement of the base field in a page table entry is 67// very erratic and would make a mess here. It might be moved here at some 68// point in the future. 69BitUnion64(PageTableEntry) 70 Bitfield<63> nx; 71 Bitfield<11, 9> avl; 72 Bitfield<8> g; 73 Bitfield<7> ps; 74 Bitfield<6> d; 75 Bitfield<5> a; 76 Bitfield<4> pcd; 77 Bitfield<3> pwt; 78 Bitfield<2> u; 79 Bitfield<1> w; 80 Bitfield<0> p; 81EndBitUnion(PageTableEntry) 82 83Fault 84Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation, 85 RequestPtr _req, BaseTLB::Mode _mode) 86{ 87 // TODO: in timing mode, instead of blocking when there are other 88 // outstanding requests, see if this request can be coalesced with 89 // another one (i.e. either coalesce or start walk) 90 WalkerState * newState = new WalkerState(this, _translation, _req); 91 newState->initState(_tc, _mode, sys->isTimingMode()); 92 if (currStates.size()) { 93 assert(newState->isTiming()); 94 DPRINTF(PageTableWalker, "Walks in progress: %d\n", currStates.size()); 95 currStates.push_back(newState); 96 return NoFault; 97 } else { 98 currStates.push_back(newState); 99 Fault fault = newState->startWalk(); 100 if (!newState->isTiming()) { 101 currStates.pop_front(); 102 delete newState; 103 } 104 return fault; 105 } 106} 107 108Fault 109Walker::startFunctional(ThreadContext * _tc, Addr &addr, unsigned &logBytes, 110 BaseTLB::Mode _mode) 111{ 112 funcState.initState(_tc, _mode); 113 return funcState.startFunctional(addr, logBytes); 114} 115 116bool 117Walker::WalkerPort::recvTimingResp(PacketPtr pkt) 118{ 119 return walker->recvTimingResp(pkt); 120} 121 122bool 123Walker::recvTimingResp(PacketPtr pkt) 124{ 125 WalkerSenderState * senderState = 126 dynamic_cast<WalkerSenderState *>(pkt->popSenderState()); 127 WalkerState * senderWalk = senderState->senderWalk; 128 bool walkComplete = senderWalk->recvPacket(pkt); 129 delete senderState; 130 if (walkComplete) { 131 std::list<WalkerState *>::iterator iter; 132 for (iter = currStates.begin(); iter != currStates.end(); iter++) { 133 WalkerState * walkerState = *(iter); 134 if (walkerState == senderWalk) { 135 iter = currStates.erase(iter); 136 break; 137 } 138 } 139 delete senderWalk; 140 // Since we block requests when another is outstanding, we 141 // need to check if there is a waiting request to be serviced
|
195Fault 196Walker::WalkerState::startWalk() 197{ 198 Fault fault = NoFault; 199 assert(started == false); 200 started = true; 201 setupWalk(req->getVaddr()); 202 if (timing) { 203 nextState = state; 204 state = Waiting; 205 timingFault = NoFault; 206 sendPackets(); 207 } else { 208 do { 209 walker->port.sendAtomic(read); 210 PacketPtr write = NULL; 211 fault = stepWalk(write); 212 assert(fault == NoFault || read == NULL); 213 state = nextState; 214 nextState = Ready; 215 if (write) 216 walker->port.sendAtomic(write); 217 } while(read); 218 state = Ready; 219 nextState = Waiting; 220 } 221 return fault; 222} 223 224Fault 225Walker::WalkerState::startFunctional(Addr &addr, unsigned &logBytes) 226{ 227 Fault fault = NoFault; 228 assert(started == false); 229 started = true; 230 setupWalk(addr); 231 232 do { 233 walker->port.sendFunctional(read); 234 // On a functional access (page table lookup), writes should 235 // not happen so this pointer is ignored after stepWalk 236 PacketPtr write = NULL; 237 fault = stepWalk(write); 238 assert(fault == NoFault || read == NULL); 239 state = nextState; 240 nextState = Ready; 241 } while(read); 242 logBytes = entry.logBytes; 243 addr = entry.paddr; 244 245 return fault; 246} 247 248Fault 249Walker::WalkerState::stepWalk(PacketPtr &write) 250{ 251 assert(state != Ready && state != Waiting); 252 Fault fault = NoFault; 253 write = NULL; 254 PageTableEntry pte; 255 if (dataSize == 8) 256 pte = read->get<uint64_t>(); 257 else 258 pte = read->get<uint32_t>(); 259 VAddr vaddr = entry.vaddr; 260 bool uncacheable = pte.pcd; 261 Addr nextRead = 0; 262 bool doWrite = false; 263 bool doTLBInsert = false; 264 bool doEndWalk = false; 265 bool badNX = pte.nx && mode == BaseTLB::Execute && enableNX; 266 switch(state) { 267 case LongPML4: 268 DPRINTF(PageTableWalker, 269 "Got long mode PML4 entry %#016x.\n", (uint64_t)pte); 270 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * dataSize; 271 doWrite = !pte.a; 272 pte.a = 1; 273 entry.writable = pte.w; 274 entry.user = pte.u; 275 if (badNX || !pte.p) { 276 doEndWalk = true; 277 fault = pageFault(pte.p); 278 break; 279 } 280 entry.noExec = pte.nx; 281 nextState = LongPDP; 282 break; 283 case LongPDP: 284 DPRINTF(PageTableWalker, 285 "Got long mode PDP entry %#016x.\n", (uint64_t)pte); 286 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * dataSize; 287 doWrite = !pte.a; 288 pte.a = 1; 289 entry.writable = entry.writable && pte.w; 290 entry.user = entry.user && pte.u; 291 if (badNX || !pte.p) { 292 doEndWalk = true; 293 fault = pageFault(pte.p); 294 break; 295 } 296 nextState = LongPD; 297 break; 298 case LongPD: 299 DPRINTF(PageTableWalker, 300 "Got long mode PD entry %#016x.\n", (uint64_t)pte); 301 doWrite = !pte.a; 302 pte.a = 1; 303 entry.writable = entry.writable && pte.w; 304 entry.user = entry.user && pte.u; 305 if (badNX || !pte.p) { 306 doEndWalk = true; 307 fault = pageFault(pte.p); 308 break; 309 } 310 if (!pte.ps) { 311 // 4 KB page 312 entry.logBytes = 12; 313 nextRead = 314 ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * dataSize; 315 nextState = LongPTE; 316 break; 317 } else { 318 // 2 MB page 319 entry.logBytes = 21; 320 entry.paddr = (uint64_t)pte & (mask(31) << 21); 321 entry.uncacheable = uncacheable; 322 entry.global = pte.g; 323 entry.patBit = bits(pte, 12); 324 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 325 doTLBInsert = true; 326 doEndWalk = true; 327 break; 328 } 329 case LongPTE: 330 DPRINTF(PageTableWalker, 331 "Got long mode PTE entry %#016x.\n", (uint64_t)pte); 332 doWrite = !pte.a; 333 pte.a = 1; 334 entry.writable = entry.writable && pte.w; 335 entry.user = entry.user && pte.u; 336 if (badNX || !pte.p) { 337 doEndWalk = true; 338 fault = pageFault(pte.p); 339 break; 340 } 341 entry.paddr = (uint64_t)pte & (mask(40) << 12); 342 entry.uncacheable = uncacheable; 343 entry.global = pte.g; 344 entry.patBit = bits(pte, 12); 345 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 346 doTLBInsert = true; 347 doEndWalk = true; 348 break; 349 case PAEPDP: 350 DPRINTF(PageTableWalker, 351 "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte); 352 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * dataSize; 353 if (!pte.p) { 354 doEndWalk = true; 355 fault = pageFault(pte.p); 356 break; 357 } 358 nextState = PAEPD; 359 break; 360 case PAEPD: 361 DPRINTF(PageTableWalker, 362 "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte); 363 doWrite = !pte.a; 364 pte.a = 1; 365 entry.writable = pte.w; 366 entry.user = pte.u; 367 if (badNX || !pte.p) { 368 doEndWalk = true; 369 fault = pageFault(pte.p); 370 break; 371 } 372 if (!pte.ps) { 373 // 4 KB page 374 entry.logBytes = 12; 375 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * dataSize; 376 nextState = PAEPTE; 377 break; 378 } else { 379 // 2 MB page 380 entry.logBytes = 21; 381 entry.paddr = (uint64_t)pte & (mask(31) << 21); 382 entry.uncacheable = uncacheable; 383 entry.global = pte.g; 384 entry.patBit = bits(pte, 12); 385 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 386 doTLBInsert = true; 387 doEndWalk = true; 388 break; 389 } 390 case PAEPTE: 391 DPRINTF(PageTableWalker, 392 "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte); 393 doWrite = !pte.a; 394 pte.a = 1; 395 entry.writable = entry.writable && pte.w; 396 entry.user = entry.user && pte.u; 397 if (badNX || !pte.p) { 398 doEndWalk = true; 399 fault = pageFault(pte.p); 400 break; 401 } 402 entry.paddr = (uint64_t)pte & (mask(40) << 12); 403 entry.uncacheable = uncacheable; 404 entry.global = pte.g; 405 entry.patBit = bits(pte, 7); 406 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 407 doTLBInsert = true; 408 doEndWalk = true; 409 break; 410 case PSEPD: 411 DPRINTF(PageTableWalker, 412 "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte); 413 doWrite = !pte.a; 414 pte.a = 1; 415 entry.writable = pte.w; 416 entry.user = pte.u; 417 if (!pte.p) { 418 doEndWalk = true; 419 fault = pageFault(pte.p); 420 break; 421 } 422 if (!pte.ps) { 423 // 4 KB page 424 entry.logBytes = 12; 425 nextRead = 426 ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 427 nextState = PTE; 428 break; 429 } else { 430 // 4 MB page 431 entry.logBytes = 21; 432 entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22; 433 entry.uncacheable = uncacheable; 434 entry.global = pte.g; 435 entry.patBit = bits(pte, 12); 436 entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1); 437 doTLBInsert = true; 438 doEndWalk = true; 439 break; 440 } 441 case PD: 442 DPRINTF(PageTableWalker, 443 "Got legacy mode PD entry %#08x.\n", (uint32_t)pte); 444 doWrite = !pte.a; 445 pte.a = 1; 446 entry.writable = pte.w; 447 entry.user = pte.u; 448 if (!pte.p) { 449 doEndWalk = true; 450 fault = pageFault(pte.p); 451 break; 452 } 453 // 4 KB page 454 entry.logBytes = 12; 455 nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 456 nextState = PTE; 457 break; 458 case PTE: 459 DPRINTF(PageTableWalker, 460 "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte); 461 doWrite = !pte.a; 462 pte.a = 1; 463 entry.writable = pte.w; 464 entry.user = pte.u; 465 if (!pte.p) { 466 doEndWalk = true; 467 fault = pageFault(pte.p); 468 break; 469 } 470 entry.paddr = (uint64_t)pte & (mask(20) << 12); 471 entry.uncacheable = uncacheable; 472 entry.global = pte.g; 473 entry.patBit = bits(pte, 7); 474 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 475 doTLBInsert = true; 476 doEndWalk = true; 477 break; 478 default: 479 panic("Unknown page table walker state %d!\n"); 480 } 481 if (doEndWalk) { 482 if (doTLBInsert) 483 if (!functional) 484 walker->tlb->insert(entry.vaddr, entry); 485 endWalk(); 486 } else { 487 PacketPtr oldRead = read; 488 //If we didn't return, we're setting up another read. 489 Request::Flags flags = oldRead->req->getFlags(); 490 flags.set(Request::UNCACHEABLE, uncacheable); 491 RequestPtr request = 492 new Request(nextRead, oldRead->getSize(), flags, walker->masterId); 493 read = new Packet(request, MemCmd::ReadReq); 494 read->allocate(); 495 // If we need to write, adjust the read packet to write the modified 496 // value back to memory. 497 if (doWrite) { 498 write = oldRead; 499 write->set<uint64_t>(pte); 500 write->cmd = MemCmd::WriteReq; 501 write->clearDest(); 502 } else { 503 write = NULL; 504 delete oldRead->req; 505 delete oldRead; 506 } 507 } 508 return fault; 509} 510 511void 512Walker::WalkerState::endWalk() 513{ 514 nextState = Ready; 515 delete read->req; 516 delete read; 517 read = NULL; 518} 519 520void 521Walker::WalkerState::setupWalk(Addr vaddr) 522{ 523 VAddr addr = vaddr; 524 CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3); 525 // Check if we're in long mode or not 526 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); 527 dataSize = 8; 528 Addr topAddr; 529 if (efer.lma) { 530 // Do long mode. 531 state = LongPML4; 532 topAddr = (cr3.longPdtb << 12) + addr.longl4 * dataSize; 533 enableNX = efer.nxe; 534 } else { 535 // We're in some flavor of legacy mode. 536 CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); 537 if (cr4.pae) { 538 // Do legacy PAE. 539 state = PAEPDP; 540 topAddr = (cr3.paePdtb << 5) + addr.pael3 * dataSize; 541 enableNX = efer.nxe; 542 } else { 543 dataSize = 4; 544 topAddr = (cr3.pdtb << 12) + addr.norml2 * dataSize; 545 if (cr4.pse) { 546 // Do legacy PSE. 547 state = PSEPD; 548 } else { 549 // Do legacy non PSE. 550 state = PD; 551 } 552 enableNX = false; 553 } 554 } 555 556 nextState = Ready; 557 entry.vaddr = vaddr; 558 559 Request::Flags flags = Request::PHYSICAL; 560 if (cr3.pcd) 561 flags.set(Request::UNCACHEABLE); 562 RequestPtr request = new Request(topAddr, dataSize, flags, 563 walker->masterId); 564 read = new Packet(request, MemCmd::ReadReq); 565 read->allocate(); 566} 567 568bool 569Walker::WalkerState::recvPacket(PacketPtr pkt) 570{ 571 assert(pkt->isResponse()); 572 assert(inflight); 573 assert(state == Waiting); 574 assert(!read); 575 inflight--; 576 if (pkt->isRead()) { 577 // @todo someone should pay for this 578 pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; 579 580 state = nextState; 581 nextState = Ready; 582 PacketPtr write = NULL; 583 read = pkt; 584 timingFault = stepWalk(write); 585 state = Waiting; 586 assert(timingFault == NoFault || read == NULL); 587 if (write) { 588 writes.push_back(write); 589 } 590 sendPackets(); 591 } else { 592 sendPackets(); 593 } 594 if (inflight == 0 && read == NULL && writes.size() == 0) { 595 state = Ready; 596 nextState = Waiting; 597 if (timingFault == NoFault) { 598 /* 599 * Finish the translation. Now that we now the right entry is 600 * in the TLB, this should work with no memory accesses. 601 * There could be new faults unrelated to the table walk like 602 * permissions violations, so we'll need the return value as 603 * well. 604 */ 605 bool delayedResponse; 606 Fault fault = walker->tlb->translate(req, tc, NULL, mode, 607 delayedResponse, true); 608 assert(!delayedResponse); 609 // Let the CPU continue. 610 translation->finish(fault, req, tc, mode); 611 } else { 612 // There was a fault during the walk. Let the CPU know. 613 translation->finish(timingFault, req, tc, mode); 614 } 615 return true; 616 } 617 618 return false; 619} 620 621void 622Walker::WalkerState::sendPackets() 623{ 624 //If we're already waiting for the port to become available, just return. 625 if (retrying) 626 return; 627 628 //Reads always have priority 629 if (read) { 630 PacketPtr pkt = read; 631 read = NULL; 632 inflight++; 633 if (!walker->sendTiming(this, pkt)) { 634 retrying = true; 635 read = pkt; 636 inflight--; 637 return; 638 } 639 } 640 //Send off as many of the writes as we can. 641 while (writes.size()) { 642 PacketPtr write = writes.back(); 643 writes.pop_back(); 644 inflight++; 645 if (!walker->sendTiming(this, write)) { 646 retrying = true; 647 writes.push_back(write); 648 inflight--; 649 return; 650 } 651 } 652} 653 654bool 655Walker::WalkerState::isRetrying() 656{ 657 return retrying; 658} 659 660bool 661Walker::WalkerState::isTiming() 662{ 663 return timing; 664} 665 666bool 667Walker::WalkerState::wasStarted() 668{ 669 return started; 670} 671 672void 673Walker::WalkerState::retry() 674{ 675 retrying = false; 676 sendPackets(); 677} 678 679Fault 680Walker::WalkerState::pageFault(bool present) 681{ 682 DPRINTF(PageTableWalker, "Raising page fault.\n"); 683 HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); 684 if (mode == BaseTLB::Execute && !enableNX) 685 mode = BaseTLB::Read; 686 return new PageFault(entry.vaddr, present, mode, m5reg.cpl == 3, false); 687} 688 689/* end namespace X86ISA */ } 690 691X86ISA::Walker * 692X86PagetableWalkerParams::create() 693{ 694 return new X86ISA::Walker(this); 695}
| 222Fault 223Walker::WalkerState::startWalk() 224{ 225 Fault fault = NoFault; 226 assert(started == false); 227 started = true; 228 setupWalk(req->getVaddr()); 229 if (timing) { 230 nextState = state; 231 state = Waiting; 232 timingFault = NoFault; 233 sendPackets(); 234 } else { 235 do { 236 walker->port.sendAtomic(read); 237 PacketPtr write = NULL; 238 fault = stepWalk(write); 239 assert(fault == NoFault || read == NULL); 240 state = nextState; 241 nextState = Ready; 242 if (write) 243 walker->port.sendAtomic(write); 244 } while(read); 245 state = Ready; 246 nextState = Waiting; 247 } 248 return fault; 249} 250 251Fault 252Walker::WalkerState::startFunctional(Addr &addr, unsigned &logBytes) 253{ 254 Fault fault = NoFault; 255 assert(started == false); 256 started = true; 257 setupWalk(addr); 258 259 do { 260 walker->port.sendFunctional(read); 261 // On a functional access (page table lookup), writes should 262 // not happen so this pointer is ignored after stepWalk 263 PacketPtr write = NULL; 264 fault = stepWalk(write); 265 assert(fault == NoFault || read == NULL); 266 state = nextState; 267 nextState = Ready; 268 } while(read); 269 logBytes = entry.logBytes; 270 addr = entry.paddr; 271 272 return fault; 273} 274 275Fault 276Walker::WalkerState::stepWalk(PacketPtr &write) 277{ 278 assert(state != Ready && state != Waiting); 279 Fault fault = NoFault; 280 write = NULL; 281 PageTableEntry pte; 282 if (dataSize == 8) 283 pte = read->get<uint64_t>(); 284 else 285 pte = read->get<uint32_t>(); 286 VAddr vaddr = entry.vaddr; 287 bool uncacheable = pte.pcd; 288 Addr nextRead = 0; 289 bool doWrite = false; 290 bool doTLBInsert = false; 291 bool doEndWalk = false; 292 bool badNX = pte.nx && mode == BaseTLB::Execute && enableNX; 293 switch(state) { 294 case LongPML4: 295 DPRINTF(PageTableWalker, 296 "Got long mode PML4 entry %#016x.\n", (uint64_t)pte); 297 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * dataSize; 298 doWrite = !pte.a; 299 pte.a = 1; 300 entry.writable = pte.w; 301 entry.user = pte.u; 302 if (badNX || !pte.p) { 303 doEndWalk = true; 304 fault = pageFault(pte.p); 305 break; 306 } 307 entry.noExec = pte.nx; 308 nextState = LongPDP; 309 break; 310 case LongPDP: 311 DPRINTF(PageTableWalker, 312 "Got long mode PDP entry %#016x.\n", (uint64_t)pte); 313 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * dataSize; 314 doWrite = !pte.a; 315 pte.a = 1; 316 entry.writable = entry.writable && pte.w; 317 entry.user = entry.user && pte.u; 318 if (badNX || !pte.p) { 319 doEndWalk = true; 320 fault = pageFault(pte.p); 321 break; 322 } 323 nextState = LongPD; 324 break; 325 case LongPD: 326 DPRINTF(PageTableWalker, 327 "Got long mode PD entry %#016x.\n", (uint64_t)pte); 328 doWrite = !pte.a; 329 pte.a = 1; 330 entry.writable = entry.writable && pte.w; 331 entry.user = entry.user && pte.u; 332 if (badNX || !pte.p) { 333 doEndWalk = true; 334 fault = pageFault(pte.p); 335 break; 336 } 337 if (!pte.ps) { 338 // 4 KB page 339 entry.logBytes = 12; 340 nextRead = 341 ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * dataSize; 342 nextState = LongPTE; 343 break; 344 } else { 345 // 2 MB page 346 entry.logBytes = 21; 347 entry.paddr = (uint64_t)pte & (mask(31) << 21); 348 entry.uncacheable = uncacheable; 349 entry.global = pte.g; 350 entry.patBit = bits(pte, 12); 351 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 352 doTLBInsert = true; 353 doEndWalk = true; 354 break; 355 } 356 case LongPTE: 357 DPRINTF(PageTableWalker, 358 "Got long mode PTE entry %#016x.\n", (uint64_t)pte); 359 doWrite = !pte.a; 360 pte.a = 1; 361 entry.writable = entry.writable && pte.w; 362 entry.user = entry.user && pte.u; 363 if (badNX || !pte.p) { 364 doEndWalk = true; 365 fault = pageFault(pte.p); 366 break; 367 } 368 entry.paddr = (uint64_t)pte & (mask(40) << 12); 369 entry.uncacheable = uncacheable; 370 entry.global = pte.g; 371 entry.patBit = bits(pte, 12); 372 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 373 doTLBInsert = true; 374 doEndWalk = true; 375 break; 376 case PAEPDP: 377 DPRINTF(PageTableWalker, 378 "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte); 379 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * dataSize; 380 if (!pte.p) { 381 doEndWalk = true; 382 fault = pageFault(pte.p); 383 break; 384 } 385 nextState = PAEPD; 386 break; 387 case PAEPD: 388 DPRINTF(PageTableWalker, 389 "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte); 390 doWrite = !pte.a; 391 pte.a = 1; 392 entry.writable = pte.w; 393 entry.user = pte.u; 394 if (badNX || !pte.p) { 395 doEndWalk = true; 396 fault = pageFault(pte.p); 397 break; 398 } 399 if (!pte.ps) { 400 // 4 KB page 401 entry.logBytes = 12; 402 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * dataSize; 403 nextState = PAEPTE; 404 break; 405 } else { 406 // 2 MB page 407 entry.logBytes = 21; 408 entry.paddr = (uint64_t)pte & (mask(31) << 21); 409 entry.uncacheable = uncacheable; 410 entry.global = pte.g; 411 entry.patBit = bits(pte, 12); 412 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 413 doTLBInsert = true; 414 doEndWalk = true; 415 break; 416 } 417 case PAEPTE: 418 DPRINTF(PageTableWalker, 419 "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte); 420 doWrite = !pte.a; 421 pte.a = 1; 422 entry.writable = entry.writable && pte.w; 423 entry.user = entry.user && pte.u; 424 if (badNX || !pte.p) { 425 doEndWalk = true; 426 fault = pageFault(pte.p); 427 break; 428 } 429 entry.paddr = (uint64_t)pte & (mask(40) << 12); 430 entry.uncacheable = uncacheable; 431 entry.global = pte.g; 432 entry.patBit = bits(pte, 7); 433 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 434 doTLBInsert = true; 435 doEndWalk = true; 436 break; 437 case PSEPD: 438 DPRINTF(PageTableWalker, 439 "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte); 440 doWrite = !pte.a; 441 pte.a = 1; 442 entry.writable = pte.w; 443 entry.user = pte.u; 444 if (!pte.p) { 445 doEndWalk = true; 446 fault = pageFault(pte.p); 447 break; 448 } 449 if (!pte.ps) { 450 // 4 KB page 451 entry.logBytes = 12; 452 nextRead = 453 ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 454 nextState = PTE; 455 break; 456 } else { 457 // 4 MB page 458 entry.logBytes = 21; 459 entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22; 460 entry.uncacheable = uncacheable; 461 entry.global = pte.g; 462 entry.patBit = bits(pte, 12); 463 entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1); 464 doTLBInsert = true; 465 doEndWalk = true; 466 break; 467 } 468 case PD: 469 DPRINTF(PageTableWalker, 470 "Got legacy mode PD entry %#08x.\n", (uint32_t)pte); 471 doWrite = !pte.a; 472 pte.a = 1; 473 entry.writable = pte.w; 474 entry.user = pte.u; 475 if (!pte.p) { 476 doEndWalk = true; 477 fault = pageFault(pte.p); 478 break; 479 } 480 // 4 KB page 481 entry.logBytes = 12; 482 nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 483 nextState = PTE; 484 break; 485 case PTE: 486 DPRINTF(PageTableWalker, 487 "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte); 488 doWrite = !pte.a; 489 pte.a = 1; 490 entry.writable = pte.w; 491 entry.user = pte.u; 492 if (!pte.p) { 493 doEndWalk = true; 494 fault = pageFault(pte.p); 495 break; 496 } 497 entry.paddr = (uint64_t)pte & (mask(20) << 12); 498 entry.uncacheable = uncacheable; 499 entry.global = pte.g; 500 entry.patBit = bits(pte, 7); 501 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 502 doTLBInsert = true; 503 doEndWalk = true; 504 break; 505 default: 506 panic("Unknown page table walker state %d!\n"); 507 } 508 if (doEndWalk) { 509 if (doTLBInsert) 510 if (!functional) 511 walker->tlb->insert(entry.vaddr, entry); 512 endWalk(); 513 } else { 514 PacketPtr oldRead = read; 515 //If we didn't return, we're setting up another read. 516 Request::Flags flags = oldRead->req->getFlags(); 517 flags.set(Request::UNCACHEABLE, uncacheable); 518 RequestPtr request = 519 new Request(nextRead, oldRead->getSize(), flags, walker->masterId); 520 read = new Packet(request, MemCmd::ReadReq); 521 read->allocate(); 522 // If we need to write, adjust the read packet to write the modified 523 // value back to memory. 524 if (doWrite) { 525 write = oldRead; 526 write->set<uint64_t>(pte); 527 write->cmd = MemCmd::WriteReq; 528 write->clearDest(); 529 } else { 530 write = NULL; 531 delete oldRead->req; 532 delete oldRead; 533 } 534 } 535 return fault; 536} 537 538void 539Walker::WalkerState::endWalk() 540{ 541 nextState = Ready; 542 delete read->req; 543 delete read; 544 read = NULL; 545} 546 547void 548Walker::WalkerState::setupWalk(Addr vaddr) 549{ 550 VAddr addr = vaddr; 551 CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3); 552 // Check if we're in long mode or not 553 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); 554 dataSize = 8; 555 Addr topAddr; 556 if (efer.lma) { 557 // Do long mode. 558 state = LongPML4; 559 topAddr = (cr3.longPdtb << 12) + addr.longl4 * dataSize; 560 enableNX = efer.nxe; 561 } else { 562 // We're in some flavor of legacy mode. 563 CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); 564 if (cr4.pae) { 565 // Do legacy PAE. 566 state = PAEPDP; 567 topAddr = (cr3.paePdtb << 5) + addr.pael3 * dataSize; 568 enableNX = efer.nxe; 569 } else { 570 dataSize = 4; 571 topAddr = (cr3.pdtb << 12) + addr.norml2 * dataSize; 572 if (cr4.pse) { 573 // Do legacy PSE. 574 state = PSEPD; 575 } else { 576 // Do legacy non PSE. 577 state = PD; 578 } 579 enableNX = false; 580 } 581 } 582 583 nextState = Ready; 584 entry.vaddr = vaddr; 585 586 Request::Flags flags = Request::PHYSICAL; 587 if (cr3.pcd) 588 flags.set(Request::UNCACHEABLE); 589 RequestPtr request = new Request(topAddr, dataSize, flags, 590 walker->masterId); 591 read = new Packet(request, MemCmd::ReadReq); 592 read->allocate(); 593} 594 595bool 596Walker::WalkerState::recvPacket(PacketPtr pkt) 597{ 598 assert(pkt->isResponse()); 599 assert(inflight); 600 assert(state == Waiting); 601 assert(!read); 602 inflight--; 603 if (pkt->isRead()) { 604 // @todo someone should pay for this 605 pkt->busFirstWordDelay = pkt->busLastWordDelay = 0; 606 607 state = nextState; 608 nextState = Ready; 609 PacketPtr write = NULL; 610 read = pkt; 611 timingFault = stepWalk(write); 612 state = Waiting; 613 assert(timingFault == NoFault || read == NULL); 614 if (write) { 615 writes.push_back(write); 616 } 617 sendPackets(); 618 } else { 619 sendPackets(); 620 } 621 if (inflight == 0 && read == NULL && writes.size() == 0) { 622 state = Ready; 623 nextState = Waiting; 624 if (timingFault == NoFault) { 625 /* 626 * Finish the translation. Now that we now the right entry is 627 * in the TLB, this should work with no memory accesses. 628 * There could be new faults unrelated to the table walk like 629 * permissions violations, so we'll need the return value as 630 * well. 631 */ 632 bool delayedResponse; 633 Fault fault = walker->tlb->translate(req, tc, NULL, mode, 634 delayedResponse, true); 635 assert(!delayedResponse); 636 // Let the CPU continue. 637 translation->finish(fault, req, tc, mode); 638 } else { 639 // There was a fault during the walk. Let the CPU know. 640 translation->finish(timingFault, req, tc, mode); 641 } 642 return true; 643 } 644 645 return false; 646} 647 648void 649Walker::WalkerState::sendPackets() 650{ 651 //If we're already waiting for the port to become available, just return. 652 if (retrying) 653 return; 654 655 //Reads always have priority 656 if (read) { 657 PacketPtr pkt = read; 658 read = NULL; 659 inflight++; 660 if (!walker->sendTiming(this, pkt)) { 661 retrying = true; 662 read = pkt; 663 inflight--; 664 return; 665 } 666 } 667 //Send off as many of the writes as we can. 668 while (writes.size()) { 669 PacketPtr write = writes.back(); 670 writes.pop_back(); 671 inflight++; 672 if (!walker->sendTiming(this, write)) { 673 retrying = true; 674 writes.push_back(write); 675 inflight--; 676 return; 677 } 678 } 679} 680 681bool 682Walker::WalkerState::isRetrying() 683{ 684 return retrying; 685} 686 687bool 688Walker::WalkerState::isTiming() 689{ 690 return timing; 691} 692 693bool 694Walker::WalkerState::wasStarted() 695{ 696 return started; 697} 698 699void 700Walker::WalkerState::retry() 701{ 702 retrying = false; 703 sendPackets(); 704} 705 706Fault 707Walker::WalkerState::pageFault(bool present) 708{ 709 DPRINTF(PageTableWalker, "Raising page fault.\n"); 710 HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); 711 if (mode == BaseTLB::Execute && !enableNX) 712 mode = BaseTLB::Read; 713 return new PageFault(entry.vaddr, present, mode, m5reg.cpl == 3, false); 714} 715 716/* end namespace X86ISA */ } 717 718X86ISA::Walker * 719X86PagetableWalkerParams::create() 720{ 721 return new X86ISA::Walker(this); 722}
|