pagetable_walker.cc revision 10474:799c8ee4ecba
16313Sgblack@eecs.umich.edu/* 26313Sgblack@eecs.umich.edu * Copyright (c) 2012 ARM Limited 36313Sgblack@eecs.umich.edu * All rights reserved. 46313Sgblack@eecs.umich.edu * 56313Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 66313Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 76313Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 86313Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 96313Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 106313Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 116313Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 126313Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 136313Sgblack@eecs.umich.edu * 146313Sgblack@eecs.umich.edu * Copyright (c) 2007 The Hewlett-Packard Development Company 156313Sgblack@eecs.umich.edu * All rights reserved. 166313Sgblack@eecs.umich.edu * 176313Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 186313Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 196313Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 206313Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 216313Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 226313Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 236313Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 246313Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 256313Sgblack@eecs.umich.edu * 266313Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 276313Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 286313Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 296313Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 306313Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 316313Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 326313Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 336313Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 348229Snate@binkert.org * contributors may be used to endorse or promote products derived from 358229Snate@binkert.org * this software without specific prior written permission. 368229Snate@binkert.org * 376335Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 386313Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 396335Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 409384SAndreas.Sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 416335Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 426313Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 436313Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 449384SAndreas.Sandberg@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 456335Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 466313Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 476313Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 486313Sgblack@eecs.umich.edu * 499384SAndreas.Sandberg@arm.com * Authors: Gabe Black 507741Sgblack@eecs.umich.edu */ 517741Sgblack@eecs.umich.edu 526335Sgblack@eecs.umich.edu#include <memory> 537741Sgblack@eecs.umich.edu 547741Sgblack@eecs.umich.edu#include "arch/x86/pagetable.hh" 557741Sgblack@eecs.umich.edu#include "arch/x86/pagetable_walker.hh" 567741Sgblack@eecs.umich.edu#include "arch/x86/tlb.hh" 577741Sgblack@eecs.umich.edu#include "arch/x86/vtophys.hh" 587741Sgblack@eecs.umich.edu#include "base/bitfield.hh" 597741Sgblack@eecs.umich.edu#include "base/trie.hh" 607741Sgblack@eecs.umich.edu#include "cpu/base.hh" 617741Sgblack@eecs.umich.edu#include "cpu/thread_context.hh" 627741Sgblack@eecs.umich.edu#include "debug/PageTableWalker.hh" 637741Sgblack@eecs.umich.edu#include "mem/packet_access.hh" 646335Sgblack@eecs.umich.edu#include "mem/request.hh" 656335Sgblack@eecs.umich.edu 667741Sgblack@eecs.umich.edunamespace X86ISA { 677741Sgblack@eecs.umich.edu 687741Sgblack@eecs.umich.eduFault 697741Sgblack@eecs.umich.eduWalker::start(ThreadContext * _tc, BaseTLB::Translation *_translation, 707741Sgblack@eecs.umich.edu RequestPtr _req, BaseTLB::Mode _mode) 717741Sgblack@eecs.umich.edu{ 727741Sgblack@eecs.umich.edu // TODO: in timing mode, instead of blocking when there are other 737741Sgblack@eecs.umich.edu // outstanding requests, see if this request can be coalesced with 747741Sgblack@eecs.umich.edu // another one (i.e. either coalesce or start walk) 756335Sgblack@eecs.umich.edu WalkerState * newState = new WalkerState(this, _translation, _req); 768829Sgblack@eecs.umich.edu newState->initState(_tc, _mode, sys->isTimingMode()); 777741Sgblack@eecs.umich.edu if (currStates.size()) { 787741Sgblack@eecs.umich.edu assert(newState->isTiming()); 797741Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, "Walks in progress: %d\n", currStates.size()); 807741Sgblack@eecs.umich.edu currStates.push_back(newState); 817741Sgblack@eecs.umich.edu return NoFault; 827741Sgblack@eecs.umich.edu } else { 837741Sgblack@eecs.umich.edu currStates.push_back(newState); 847741Sgblack@eecs.umich.edu Fault fault = newState->startWalk(); 857741Sgblack@eecs.umich.edu if (!newState->isTiming()) { 866335Sgblack@eecs.umich.edu currStates.pop_front(); 877741Sgblack@eecs.umich.edu delete newState; 888829Sgblack@eecs.umich.edu } 897741Sgblack@eecs.umich.edu return fault; 907741Sgblack@eecs.umich.edu } 917741Sgblack@eecs.umich.edu} 927741Sgblack@eecs.umich.edu 936335Sgblack@eecs.umich.eduFault 947741Sgblack@eecs.umich.eduWalker::startFunctional(ThreadContext * _tc, Addr &addr, unsigned &logBytes, 956335Sgblack@eecs.umich.edu BaseTLB::Mode _mode) 967741Sgblack@eecs.umich.edu{ 977741Sgblack@eecs.umich.edu funcState.initState(_tc, _mode); 986335Sgblack@eecs.umich.edu return funcState.startFunctional(addr, logBytes); 997741Sgblack@eecs.umich.edu} 1007741Sgblack@eecs.umich.edu 1017741Sgblack@eecs.umich.edubool 1027741Sgblack@eecs.umich.eduWalker::WalkerPort::recvTimingResp(PacketPtr pkt) 1037741Sgblack@eecs.umich.edu{ 1046335Sgblack@eecs.umich.edu return walker->recvTimingResp(pkt); 1057741Sgblack@eecs.umich.edu} 1066335Sgblack@eecs.umich.edu 1077741Sgblack@eecs.umich.edubool 1087741Sgblack@eecs.umich.eduWalker::recvTimingResp(PacketPtr pkt) 1097741Sgblack@eecs.umich.edu{ 1107741Sgblack@eecs.umich.edu WalkerSenderState * senderState = 1117741Sgblack@eecs.umich.edu dynamic_cast<WalkerSenderState *>(pkt->popSenderState()); 1127741Sgblack@eecs.umich.edu WalkerState * senderWalk = senderState->senderWalk; 1137741Sgblack@eecs.umich.edu bool walkComplete = senderWalk->recvPacket(pkt); 1147741Sgblack@eecs.umich.edu delete senderState; 1156335Sgblack@eecs.umich.edu if (walkComplete) { 1167741Sgblack@eecs.umich.edu std::list<WalkerState *>::iterator iter; 1177741Sgblack@eecs.umich.edu for (iter = currStates.begin(); iter != currStates.end(); iter++) { 1187741Sgblack@eecs.umich.edu WalkerState * walkerState = *(iter); 1197741Sgblack@eecs.umich.edu if (walkerState == senderWalk) { 1206335Sgblack@eecs.umich.edu iter = currStates.erase(iter); 1217741Sgblack@eecs.umich.edu break; 1227741Sgblack@eecs.umich.edu } 1236335Sgblack@eecs.umich.edu } 1247741Sgblack@eecs.umich.edu delete senderWalk; 1257741Sgblack@eecs.umich.edu // Since we block requests when another is outstanding, we 1267741Sgblack@eecs.umich.edu // need to check if there is a waiting request to be serviced 1277741Sgblack@eecs.umich.edu if (currStates.size()) 1287741Sgblack@eecs.umich.edu startWalkWrapper(); 1296335Sgblack@eecs.umich.edu } 1307741Sgblack@eecs.umich.edu return true; 1317741Sgblack@eecs.umich.edu} 1327741Sgblack@eecs.umich.edu 1336335Sgblack@eecs.umich.eduvoid 1347741Sgblack@eecs.umich.eduWalker::WalkerPort::recvRetry() 1357741Sgblack@eecs.umich.edu{ 1367741Sgblack@eecs.umich.edu walker->recvRetry(); 1376335Sgblack@eecs.umich.edu} 1387741Sgblack@eecs.umich.edu 1397741Sgblack@eecs.umich.eduvoid 1407741Sgblack@eecs.umich.eduWalker::recvRetry() 1416337Sgblack@eecs.umich.edu{ 1427741Sgblack@eecs.umich.edu std::list<WalkerState *>::iterator iter; 1437741Sgblack@eecs.umich.edu for (iter = currStates.begin(); iter != currStates.end(); iter++) { 1447741Sgblack@eecs.umich.edu WalkerState * walkerState = *(iter); 1456337Sgblack@eecs.umich.edu if (walkerState->isRetrying()) { 1467741Sgblack@eecs.umich.edu walkerState->retry(); 1477741Sgblack@eecs.umich.edu } 1487741Sgblack@eecs.umich.edu } 1496337Sgblack@eecs.umich.edu} 1507741Sgblack@eecs.umich.edu 1517741Sgblack@eecs.umich.edubool Walker::sendTiming(WalkerState* sendingState, PacketPtr pkt) 1527741Sgblack@eecs.umich.edu{ 1537741Sgblack@eecs.umich.edu WalkerSenderState* walker_state = new WalkerSenderState(sendingState); 1547741Sgblack@eecs.umich.edu pkt->pushSenderState(walker_state); 1557741Sgblack@eecs.umich.edu if (port.sendTimingReq(pkt)) { 1567741Sgblack@eecs.umich.edu return true; 1577741Sgblack@eecs.umich.edu } else { 1587741Sgblack@eecs.umich.edu // undo the adding of the sender state and delete it, as we 1597741Sgblack@eecs.umich.edu // will do it again the next time we attempt to send it 1606337Sgblack@eecs.umich.edu pkt->popSenderState(); 1617741Sgblack@eecs.umich.edu delete walker_state; 1627741Sgblack@eecs.umich.edu return false; 1637741Sgblack@eecs.umich.edu } 1647741Sgblack@eecs.umich.edu 1656337Sgblack@eecs.umich.edu} 1667741Sgblack@eecs.umich.edu 1676335Sgblack@eecs.umich.eduBaseMasterPort & 1687741Sgblack@eecs.umich.eduWalker::getMasterPort(const std::string &if_name, PortID idx) 1696335Sgblack@eecs.umich.edu{ 1709425SAndreas.Sandberg@ARM.com if (if_name == "port") 1716335Sgblack@eecs.umich.edu return port; 1729425SAndreas.Sandberg@ARM.com else 1736335Sgblack@eecs.umich.edu return MemObject::getMasterPort(if_name, idx); 1749461Snilay@cs.wisc.edu} 1759461Snilay@cs.wisc.edu 1769553Sandreas.hansson@arm.comvoid 1779553Sandreas.hansson@arm.comWalker::WalkerState::initState(ThreadContext * _tc, 1789553Sandreas.hansson@arm.com BaseTLB::Mode _mode, bool _isTiming) 1797741Sgblack@eecs.umich.edu{ 1808829Sgblack@eecs.umich.edu assert(state == Ready); 1818829Sgblack@eecs.umich.edu started = false; 1827741Sgblack@eecs.umich.edu tc = _tc; 1836313Sgblack@eecs.umich.edu mode = _mode; 1847741Sgblack@eecs.umich.edu timing = _isTiming; 1856313Sgblack@eecs.umich.edu} 1867741Sgblack@eecs.umich.edu 1877741Sgblack@eecs.umich.eduvoid 1886313Sgblack@eecs.umich.eduWalker::startWalkWrapper() 1897741Sgblack@eecs.umich.edu{ 1907741Sgblack@eecs.umich.edu unsigned num_squashed = 0; 1917741Sgblack@eecs.umich.edu WalkerState *currState = currStates.front(); 1926313Sgblack@eecs.umich.edu while ((num_squashed < numSquashable) && currState && 1937741Sgblack@eecs.umich.edu currState->translation->squashed()) { 1947741Sgblack@eecs.umich.edu currStates.pop_front(); 1957741Sgblack@eecs.umich.edu num_squashed++; 1967741Sgblack@eecs.umich.edu 1977741Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, "Squashing table walk for address %#x\n", 1987741Sgblack@eecs.umich.edu currState->req->getVaddr()); 1997741Sgblack@eecs.umich.edu 2007741Sgblack@eecs.umich.edu // finish the translation which will delete the translation object 2016313Sgblack@eecs.umich.edu currState->translation->finish( 2027741Sgblack@eecs.umich.edu std::make_shared<UnimpFault>("Squashed Inst"), 2037741Sgblack@eecs.umich.edu currState->req, currState->tc, currState->mode); 2047741Sgblack@eecs.umich.edu 2057741Sgblack@eecs.umich.edu // delete the current request 2067741Sgblack@eecs.umich.edu delete currState; 2076313Sgblack@eecs.umich.edu 2089920Syasuko.eckert@amd.com // check the next translation request, if it exists 2099920Syasuko.eckert@amd.com if (currStates.size()) 2109920Syasuko.eckert@amd.com currState = currStates.front(); 2119920Syasuko.eckert@amd.com else 2129920Syasuko.eckert@amd.com currState = NULL; 2139920Syasuko.eckert@amd.com } 2149920Syasuko.eckert@amd.com if (currState && !currState->wasStarted()) 21510033SAli.Saidi@ARM.com currState->startWalk(); 21610033SAli.Saidi@ARM.com} 21710033SAli.Saidi@ARM.com 21810033SAli.Saidi@ARM.comFault 21910033SAli.Saidi@ARM.comWalker::WalkerState::startWalk() 22010033SAli.Saidi@ARM.com{ 22110033SAli.Saidi@ARM.com Fault fault = NoFault; 2229384SAndreas.Sandberg@arm.com assert(!started); 2239384SAndreas.Sandberg@arm.com started = true; 2247703Sgblack@eecs.umich.edu setupWalk(req->getVaddr()); 2259384SAndreas.Sandberg@arm.com if (timing) { 2267741Sgblack@eecs.umich.edu nextState = state; 2276313Sgblack@eecs.umich.edu state = Waiting; 2286313Sgblack@eecs.umich.edu timingFault = NoFault; 2296313Sgblack@eecs.umich.edu sendPackets(); 230 } else { 231 do { 232 walker->port.sendAtomic(read); 233 PacketPtr write = NULL; 234 fault = stepWalk(write); 235 assert(fault == NoFault || read == NULL); 236 state = nextState; 237 nextState = Ready; 238 if (write) 239 walker->port.sendAtomic(write); 240 } while(read); 241 state = Ready; 242 nextState = Waiting; 243 } 244 return fault; 245} 246 247Fault 248Walker::WalkerState::startFunctional(Addr &addr, unsigned &logBytes) 249{ 250 Fault fault = NoFault; 251 assert(!started); 252 started = true; 253 setupWalk(addr); 254 255 do { 256 walker->port.sendFunctional(read); 257 // On a functional access (page table lookup), writes should 258 // not happen so this pointer is ignored after stepWalk 259 PacketPtr write = NULL; 260 fault = stepWalk(write); 261 assert(fault == NoFault || read == NULL); 262 state = nextState; 263 nextState = Ready; 264 } while(read); 265 logBytes = entry.logBytes; 266 addr = entry.paddr; 267 268 return fault; 269} 270 271Fault 272Walker::WalkerState::stepWalk(PacketPtr &write) 273{ 274 assert(state != Ready && state != Waiting); 275 Fault fault = NoFault; 276 write = NULL; 277 PageTableEntry pte; 278 if (dataSize == 8) 279 pte = read->get<uint64_t>(); 280 else 281 pte = read->get<uint32_t>(); 282 VAddr vaddr = entry.vaddr; 283 bool uncacheable = pte.pcd; 284 Addr nextRead = 0; 285 bool doWrite = false; 286 bool doTLBInsert = false; 287 bool doEndWalk = false; 288 bool badNX = pte.nx && mode == BaseTLB::Execute && enableNX; 289 switch(state) { 290 case LongPML4: 291 DPRINTF(PageTableWalker, 292 "Got long mode PML4 entry %#016x.\n", (uint64_t)pte); 293 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * dataSize; 294 doWrite = !pte.a; 295 pte.a = 1; 296 entry.writable = pte.w; 297 entry.user = pte.u; 298 if (badNX || !pte.p) { 299 doEndWalk = true; 300 fault = pageFault(pte.p); 301 break; 302 } 303 entry.noExec = pte.nx; 304 nextState = LongPDP; 305 break; 306 case LongPDP: 307 DPRINTF(PageTableWalker, 308 "Got long mode PDP entry %#016x.\n", (uint64_t)pte); 309 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * dataSize; 310 doWrite = !pte.a; 311 pte.a = 1; 312 entry.writable = entry.writable && pte.w; 313 entry.user = entry.user && pte.u; 314 if (badNX || !pte.p) { 315 doEndWalk = true; 316 fault = pageFault(pte.p); 317 break; 318 } 319 nextState = LongPD; 320 break; 321 case LongPD: 322 DPRINTF(PageTableWalker, 323 "Got long mode PD entry %#016x.\n", (uint64_t)pte); 324 doWrite = !pte.a; 325 pte.a = 1; 326 entry.writable = entry.writable && pte.w; 327 entry.user = entry.user && pte.u; 328 if (badNX || !pte.p) { 329 doEndWalk = true; 330 fault = pageFault(pte.p); 331 break; 332 } 333 if (!pte.ps) { 334 // 4 KB page 335 entry.logBytes = 12; 336 nextRead = 337 ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * dataSize; 338 nextState = LongPTE; 339 break; 340 } else { 341 // 2 MB page 342 entry.logBytes = 21; 343 entry.paddr = (uint64_t)pte & (mask(31) << 21); 344 entry.uncacheable = uncacheable; 345 entry.global = pte.g; 346 entry.patBit = bits(pte, 12); 347 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 348 doTLBInsert = true; 349 doEndWalk = true; 350 break; 351 } 352 case LongPTE: 353 DPRINTF(PageTableWalker, 354 "Got long mode PTE entry %#016x.\n", (uint64_t)pte); 355 doWrite = !pte.a; 356 pte.a = 1; 357 entry.writable = entry.writable && pte.w; 358 entry.user = entry.user && pte.u; 359 if (badNX || !pte.p) { 360 doEndWalk = true; 361 fault = pageFault(pte.p); 362 break; 363 } 364 entry.paddr = (uint64_t)pte & (mask(40) << 12); 365 entry.uncacheable = uncacheable; 366 entry.global = pte.g; 367 entry.patBit = bits(pte, 12); 368 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 369 doTLBInsert = true; 370 doEndWalk = true; 371 break; 372 case PAEPDP: 373 DPRINTF(PageTableWalker, 374 "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte); 375 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * dataSize; 376 if (!pte.p) { 377 doEndWalk = true; 378 fault = pageFault(pte.p); 379 break; 380 } 381 nextState = PAEPD; 382 break; 383 case PAEPD: 384 DPRINTF(PageTableWalker, 385 "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte); 386 doWrite = !pte.a; 387 pte.a = 1; 388 entry.writable = pte.w; 389 entry.user = pte.u; 390 if (badNX || !pte.p) { 391 doEndWalk = true; 392 fault = pageFault(pte.p); 393 break; 394 } 395 if (!pte.ps) { 396 // 4 KB page 397 entry.logBytes = 12; 398 nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * dataSize; 399 nextState = PAEPTE; 400 break; 401 } else { 402 // 2 MB page 403 entry.logBytes = 21; 404 entry.paddr = (uint64_t)pte & (mask(31) << 21); 405 entry.uncacheable = uncacheable; 406 entry.global = pte.g; 407 entry.patBit = bits(pte, 12); 408 entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 409 doTLBInsert = true; 410 doEndWalk = true; 411 break; 412 } 413 case PAEPTE: 414 DPRINTF(PageTableWalker, 415 "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte); 416 doWrite = !pte.a; 417 pte.a = 1; 418 entry.writable = entry.writable && pte.w; 419 entry.user = entry.user && pte.u; 420 if (badNX || !pte.p) { 421 doEndWalk = true; 422 fault = pageFault(pte.p); 423 break; 424 } 425 entry.paddr = (uint64_t)pte & (mask(40) << 12); 426 entry.uncacheable = uncacheable; 427 entry.global = pte.g; 428 entry.patBit = bits(pte, 7); 429 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 430 doTLBInsert = true; 431 doEndWalk = true; 432 break; 433 case PSEPD: 434 DPRINTF(PageTableWalker, 435 "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte); 436 doWrite = !pte.a; 437 pte.a = 1; 438 entry.writable = pte.w; 439 entry.user = pte.u; 440 if (!pte.p) { 441 doEndWalk = true; 442 fault = pageFault(pte.p); 443 break; 444 } 445 if (!pte.ps) { 446 // 4 KB page 447 entry.logBytes = 12; 448 nextRead = 449 ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 450 nextState = PTE; 451 break; 452 } else { 453 // 4 MB page 454 entry.logBytes = 21; 455 entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22; 456 entry.uncacheable = uncacheable; 457 entry.global = pte.g; 458 entry.patBit = bits(pte, 12); 459 entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1); 460 doTLBInsert = true; 461 doEndWalk = true; 462 break; 463 } 464 case PD: 465 DPRINTF(PageTableWalker, 466 "Got legacy mode PD entry %#08x.\n", (uint32_t)pte); 467 doWrite = !pte.a; 468 pte.a = 1; 469 entry.writable = pte.w; 470 entry.user = pte.u; 471 if (!pte.p) { 472 doEndWalk = true; 473 fault = pageFault(pte.p); 474 break; 475 } 476 // 4 KB page 477 entry.logBytes = 12; 478 nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 479 nextState = PTE; 480 break; 481 case PTE: 482 DPRINTF(PageTableWalker, 483 "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte); 484 doWrite = !pte.a; 485 pte.a = 1; 486 entry.writable = pte.w; 487 entry.user = pte.u; 488 if (!pte.p) { 489 doEndWalk = true; 490 fault = pageFault(pte.p); 491 break; 492 } 493 entry.paddr = (uint64_t)pte & (mask(20) << 12); 494 entry.uncacheable = uncacheable; 495 entry.global = pte.g; 496 entry.patBit = bits(pte, 7); 497 entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 498 doTLBInsert = true; 499 doEndWalk = true; 500 break; 501 default: 502 panic("Unknown page table walker state %d!\n"); 503 } 504 if (doEndWalk) { 505 if (doTLBInsert) 506 if (!functional) 507 walker->tlb->insert(entry.vaddr, entry); 508 endWalk(); 509 } else { 510 PacketPtr oldRead = read; 511 //If we didn't return, we're setting up another read. 512 Request::Flags flags = oldRead->req->getFlags(); 513 flags.set(Request::UNCACHEABLE, uncacheable); 514 RequestPtr request = 515 new Request(nextRead, oldRead->getSize(), flags, walker->masterId); 516 read = new Packet(request, MemCmd::ReadReq); 517 read->allocate(); 518 // If we need to write, adjust the read packet to write the modified 519 // value back to memory. 520 if (doWrite) { 521 write = oldRead; 522 write->set<uint64_t>(pte); 523 write->cmd = MemCmd::WriteReq; 524 write->clearDest(); 525 } else { 526 write = NULL; 527 delete oldRead->req; 528 delete oldRead; 529 } 530 } 531 return fault; 532} 533 534void 535Walker::WalkerState::endWalk() 536{ 537 nextState = Ready; 538 delete read->req; 539 delete read; 540 read = NULL; 541} 542 543void 544Walker::WalkerState::setupWalk(Addr vaddr) 545{ 546 VAddr addr = vaddr; 547 CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3); 548 // Check if we're in long mode or not 549 Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); 550 dataSize = 8; 551 Addr topAddr; 552 if (efer.lma) { 553 // Do long mode. 554 state = LongPML4; 555 topAddr = (cr3.longPdtb << 12) + addr.longl4 * dataSize; 556 enableNX = efer.nxe; 557 } else { 558 // We're in some flavor of legacy mode. 559 CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); 560 if (cr4.pae) { 561 // Do legacy PAE. 562 state = PAEPDP; 563 topAddr = (cr3.paePdtb << 5) + addr.pael3 * dataSize; 564 enableNX = efer.nxe; 565 } else { 566 dataSize = 4; 567 topAddr = (cr3.pdtb << 12) + addr.norml2 * dataSize; 568 if (cr4.pse) { 569 // Do legacy PSE. 570 state = PSEPD; 571 } else { 572 // Do legacy non PSE. 573 state = PD; 574 } 575 enableNX = false; 576 } 577 } 578 579 nextState = Ready; 580 entry.vaddr = vaddr; 581 582 Request::Flags flags = Request::PHYSICAL; 583 if (cr3.pcd) 584 flags.set(Request::UNCACHEABLE); 585 RequestPtr request = new Request(topAddr, dataSize, flags, 586 walker->masterId); 587 read = new Packet(request, MemCmd::ReadReq); 588 read->allocate(); 589} 590 591bool 592Walker::WalkerState::recvPacket(PacketPtr pkt) 593{ 594 assert(pkt->isResponse()); 595 assert(inflight); 596 assert(state == Waiting); 597 inflight--; 598 if (pkt->isRead()) { 599 // should not have a pending read it we also had one outstanding 600 assert(!read); 601 602 // @todo someone should pay for this 603 pkt->firstWordDelay = pkt->lastWordDelay = 0; 604 605 state = nextState; 606 nextState = Ready; 607 PacketPtr write = NULL; 608 read = pkt; 609 timingFault = stepWalk(write); 610 state = Waiting; 611 assert(timingFault == NoFault || read == NULL); 612 if (write) { 613 writes.push_back(write); 614 } 615 sendPackets(); 616 } else { 617 sendPackets(); 618 } 619 if (inflight == 0 && read == NULL && writes.size() == 0) { 620 state = Ready; 621 nextState = Waiting; 622 if (timingFault == NoFault) { 623 /* 624 * Finish the translation. Now that we now the right entry is 625 * in the TLB, this should work with no memory accesses. 626 * There could be new faults unrelated to the table walk like 627 * permissions violations, so we'll need the return value as 628 * well. 629 */ 630 bool delayedResponse; 631 Fault fault = walker->tlb->translate(req, tc, NULL, mode, 632 delayedResponse, true); 633 assert(!delayedResponse); 634 // Let the CPU continue. 635 translation->finish(fault, req, tc, mode); 636 } else { 637 // There was a fault during the walk. Let the CPU know. 638 translation->finish(timingFault, req, tc, mode); 639 } 640 return true; 641 } 642 643 return false; 644} 645 646void 647Walker::WalkerState::sendPackets() 648{ 649 //If we're already waiting for the port to become available, just return. 650 if (retrying) 651 return; 652 653 //Reads always have priority 654 if (read) { 655 PacketPtr pkt = read; 656 read = NULL; 657 inflight++; 658 if (!walker->sendTiming(this, pkt)) { 659 retrying = true; 660 read = pkt; 661 inflight--; 662 return; 663 } 664 } 665 //Send off as many of the writes as we can. 666 while (writes.size()) { 667 PacketPtr write = writes.back(); 668 writes.pop_back(); 669 inflight++; 670 if (!walker->sendTiming(this, write)) { 671 retrying = true; 672 writes.push_back(write); 673 inflight--; 674 return; 675 } 676 } 677} 678 679bool 680Walker::WalkerState::isRetrying() 681{ 682 return retrying; 683} 684 685bool 686Walker::WalkerState::isTiming() 687{ 688 return timing; 689} 690 691bool 692Walker::WalkerState::wasStarted() 693{ 694 return started; 695} 696 697void 698Walker::WalkerState::retry() 699{ 700 retrying = false; 701 sendPackets(); 702} 703 704Fault 705Walker::WalkerState::pageFault(bool present) 706{ 707 DPRINTF(PageTableWalker, "Raising page fault.\n"); 708 HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); 709 if (mode == BaseTLB::Execute && !enableNX) 710 mode = BaseTLB::Read; 711 return std::make_shared<PageFault>(entry.vaddr, present, mode, 712 m5reg.cpl == 3, false); 713} 714 715/* end namespace X86ISA */ } 716 717X86ISA::Walker * 718X86PagetableWalkerParams::create() 719{ 720 return new X86ISA::Walker(this); 721} 722