pagetable_walker.cc revision 8975
17404SAli.Saidi@ARM.com/* 211574SCurtis.Dunham@arm.com * Copyright (c) 2012 ARM Limited 37404SAli.Saidi@ARM.com * All rights reserved. 47404SAli.Saidi@ARM.com * 57404SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall 67404SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual 77404SAli.Saidi@ARM.com * property including but not limited to intellectual property relating 87404SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software 97404SAli.Saidi@ARM.com * licensed hereunder. You may use the software subject to the license 107404SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated 117404SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software, 127404SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form. 137404SAli.Saidi@ARM.com * 147404SAli.Saidi@ARM.com * Copyright (c) 2007 The Hewlett-Packard Development Company 157404SAli.Saidi@ARM.com * All rights reserved. 167404SAli.Saidi@ARM.com * 177404SAli.Saidi@ARM.com * The license below extends only to copyright in the software and shall 187404SAli.Saidi@ARM.com * not be construed as granting a license to any other intellectual 197404SAli.Saidi@ARM.com * property including but not limited to intellectual property relating 207404SAli.Saidi@ARM.com * to a hardware implementation of the functionality of the software 217404SAli.Saidi@ARM.com * licensed hereunder. You may use the software subject to the license 227404SAli.Saidi@ARM.com * terms below provided that you ensure that this notice is replicated 237404SAli.Saidi@ARM.com * unmodified and in its entirety in all distributions of the software, 247404SAli.Saidi@ARM.com * modified or unmodified, in source code or in binary form. 257404SAli.Saidi@ARM.com * 267404SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 277404SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 287404SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright 297404SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer; 307404SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright 317404SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the 327404SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution; 337404SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its 347404SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from 357404SAli.Saidi@ARM.com * this software without specific prior written permission. 367404SAli.Saidi@ARM.com * 377404SAli.Saidi@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3810037SARM gem5 Developers * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 397404SAli.Saidi@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 4010873Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 417404SAli.Saidi@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4210474Sandreas.hansson@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 4310474Sandreas.hansson@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 447404SAli.Saidi@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 4510037SARM gem5 Developers * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 4610037SARM gem5 Developers * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 477404SAli.Saidi@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 487728SAli.Saidi@ARM.com * 497404SAli.Saidi@ARM.com * Authors: Gabe Black 508245Snate@binkert.org */ 519152Satgutier@umich.edu 528245Snate@binkert.org#include "arch/x86/pagetable.hh" 538245Snate@binkert.org#include "arch/x86/pagetable_walker.hh" 5410873Sandreas.sandberg@arm.com#include "arch/x86/tlb.hh" 557748SAli.Saidi@ARM.com#include "arch/x86/vtophys.hh" 567404SAli.Saidi@ARM.com#include "base/bitfield.hh" 577404SAli.Saidi@ARM.com#include "base/trie.hh" 587404SAli.Saidi@ARM.com#include "cpu/base.hh" 597404SAli.Saidi@ARM.com#include "cpu/thread_context.hh" 6010913Sandreas.sandberg@arm.com#include "debug/PageTableWalker.hh" 6110717Sandreas.hansson@arm.com#include "mem/packet_access.hh" 6210717Sandreas.hansson@arm.com#include "mem/request.hh" 6310717Sandreas.hansson@arm.com 649258SAli.Saidi@ARM.comnamespace X86ISA { 6510621SCurtis.Dunham@arm.com 6610621SCurtis.Dunham@arm.com// Unfortunately, the placement of the base field in a page table entry is 6710037SARM gem5 Developers// very erratic and would make a mess here. It might be moved here at some 6810037SARM gem5 Developers// point in the future. 6910037SARM gem5 DevelopersBitUnion64(PageTableEntry) 7010037SARM gem5 Developers Bitfield<63> nx; 717439Sdam.sunwoo@arm.com Bitfield<11, 9> avl; 727576SAli.Saidi@ARM.com Bitfield<8> g; 7310037SARM gem5 Developers Bitfield<7> ps; 7410037SARM gem5 Developers Bitfield<6> d; 7510037SARM gem5 Developers Bitfield<5> a; 7610717Sandreas.hansson@arm.com Bitfield<4> pcd; 7710037SARM gem5 Developers Bitfield<3> pwt; 7810037SARM gem5 Developers Bitfield<2> u; 7910037SARM gem5 Developers Bitfield<1> w; 8010037SARM gem5 Developers Bitfield<0> p; 8110037SARM gem5 DevelopersEndBitUnion(PageTableEntry) 8210037SARM gem5 Developers 8310037SARM gem5 DevelopersFault 8410037SARM gem5 DevelopersWalker::start(ThreadContext * _tc, BaseTLB::Translation *_translation, 8510037SARM gem5 Developers RequestPtr _req, BaseTLB::Mode _mode) 8610037SARM gem5 Developers{ 8710037SARM gem5 Developers // TODO: in timing mode, instead of blocking when there are other 8810037SARM gem5 Developers // outstanding requests, see if this request can be coalesced with 897439Sdam.sunwoo@arm.com // another one (i.e. either coalesce or start walk) 907404SAli.Saidi@ARM.com WalkerState * newState = new WalkerState(this, _translation, _req); 917404SAli.Saidi@ARM.com newState->initState(_tc, _mode, sys->getMemoryMode() == Enums::timing); 927404SAli.Saidi@ARM.com if (currStates.size()) { 937404SAli.Saidi@ARM.com assert(newState->isTiming()); 947404SAli.Saidi@ARM.com DPRINTF(PageTableWalker, "Walks in progress: %d\n", currStates.size()); 957404SAli.Saidi@ARM.com currStates.push_back(newState); 9610717Sandreas.hansson@arm.com return NoFault; 9710717Sandreas.hansson@arm.com } else { 9810717Sandreas.hansson@arm.com currStates.push_back(newState); 9910717Sandreas.hansson@arm.com Fault fault = newState->startWalk(); 10010717Sandreas.hansson@arm.com if (!newState->isTiming()) { 10110717Sandreas.hansson@arm.com currStates.pop_front(); 10210717Sandreas.hansson@arm.com delete newState; 10310717Sandreas.hansson@arm.com } 10410717Sandreas.hansson@arm.com return fault; 10510717Sandreas.hansson@arm.com } 10610717Sandreas.hansson@arm.com} 10710717Sandreas.hansson@arm.com 10810717Sandreas.hansson@arm.comFault 10910717Sandreas.hansson@arm.comWalker::startFunctional(ThreadContext * _tc, Addr &addr, unsigned &logBytes, 11010717Sandreas.hansson@arm.com BaseTLB::Mode _mode) 11110717Sandreas.hansson@arm.com{ 11210717Sandreas.hansson@arm.com funcState.initState(_tc, _mode); 11310717Sandreas.hansson@arm.com return funcState.startFunctional(addr, logBytes); 11410717Sandreas.hansson@arm.com} 11510717Sandreas.hansson@arm.com 11610717Sandreas.hansson@arm.combool 11710717Sandreas.hansson@arm.comWalker::WalkerPort::recvTimingResp(PacketPtr pkt) 11810717Sandreas.hansson@arm.com{ 11910717Sandreas.hansson@arm.com return walker->recvTimingResp(pkt); 12010717Sandreas.hansson@arm.com} 12110717Sandreas.hansson@arm.com 12210717Sandreas.hansson@arm.combool 12310717Sandreas.hansson@arm.comWalker::recvTimingResp(PacketPtr pkt) 12410717Sandreas.hansson@arm.com{ 12510537Sandreas.hansson@arm.com WalkerSenderState * senderState = 12610537Sandreas.hansson@arm.com dynamic_cast<WalkerSenderState *>(pkt->senderState); 12710537Sandreas.hansson@arm.com pkt->senderState = senderState->saved; 12810537Sandreas.hansson@arm.com WalkerState * senderWalk = senderState->senderWalk; 12910537Sandreas.hansson@arm.com bool walkComplete = senderWalk->recvPacket(pkt); 13010537Sandreas.hansson@arm.com delete senderState; 13110537Sandreas.hansson@arm.com if (walkComplete) { 13210537Sandreas.hansson@arm.com std::list<WalkerState *>::iterator iter; 13310537Sandreas.hansson@arm.com for (iter = currStates.begin(); iter != currStates.end(); iter++) { 13410037SARM gem5 Developers WalkerState * walkerState = *(iter); 13510037SARM gem5 Developers if (walkerState == senderWalk) { 13610037SARM gem5 Developers iter = currStates.erase(iter); 1379152Satgutier@umich.edu break; 1389152Satgutier@umich.edu } 1399152Satgutier@umich.edu } 14010913Sandreas.sandberg@arm.com delete senderWalk; 14110913Sandreas.sandberg@arm.com // Since we block requests when another is outstanding, we 1429152Satgutier@umich.edu // need to check if there is a waiting request to be serviced 14310913Sandreas.sandberg@arm.com if (currStates.size()) { 1449152Satgutier@umich.edu WalkerState * newState = currStates.front(); 14510913Sandreas.sandberg@arm.com if (!newState->wasStarted()) 1469152Satgutier@umich.edu newState->startWalk(); 1479152Satgutier@umich.edu } 1489152Satgutier@umich.edu } 14910913Sandreas.sandberg@arm.com return true; 15010913Sandreas.sandberg@arm.com} 1517404SAli.Saidi@ARM.com 15210037SARM gem5 Developersvoid 1539152Satgutier@umich.eduWalker::WalkerPort::recvRetry() 15410037SARM gem5 Developers{ 15510037SARM gem5 Developers walker->recvRetry(); 15610037SARM gem5 Developers} 15710037SARM gem5 Developers 15810037SARM gem5 Developersvoid 15910037SARM gem5 DevelopersWalker::recvRetry() 16010037SARM gem5 Developers{ 16110037SARM gem5 Developers std::list<WalkerState *>::iterator iter; 1629152Satgutier@umich.edu for (iter = currStates.begin(); iter != currStates.end(); iter++) { 16310913Sandreas.sandberg@arm.com WalkerState * walkerState = *(iter); 16410037SARM gem5 Developers if (walkerState->isRetrying()) { 16510037SARM gem5 Developers walkerState->retry(); 16610913Sandreas.sandberg@arm.com } 1677733SAli.Saidi@ARM.com } 1687404SAli.Saidi@ARM.com} 1697404SAli.Saidi@ARM.com 1707748SAli.Saidi@ARM.combool Walker::sendTiming(WalkerState* sendingState, PacketPtr pkt) 1719342SAndreas.Sandberg@arm.com{ 1727748SAli.Saidi@ARM.com pkt->senderState = new WalkerSenderState(sendingState, pkt->senderState); 1739524SAndreas.Sandberg@ARM.com return port.sendTimingReq(pkt); 1749152Satgutier@umich.edu} 1759152Satgutier@umich.edu 17610621SCurtis.Dunham@arm.comMasterPort & 1777748SAli.Saidi@ARM.comWalker::getMasterPort(const std::string &if_name, int idx) 1787748SAli.Saidi@ARM.com{ 1797748SAli.Saidi@ARM.com if (if_name == "port") 1807404SAli.Saidi@ARM.com return port; 18110037SARM gem5 Developers else 18210037SARM gem5 Developers return MemObject::getMasterPort(if_name, idx); 18310037SARM gem5 Developers} 18411580SDylan.Johnson@ARM.com 18511580SDylan.Johnson@ARM.comvoid 1867404SAli.Saidi@ARM.comWalker::WalkerState::initState(ThreadContext * _tc, 1878733Sgeoffrey.blake@arm.com BaseTLB::Mode _mode, bool _isTiming) 18810621SCurtis.Dunham@arm.com{ 18910621SCurtis.Dunham@arm.com assert(state == Ready); 19010109SGeoffrey.Blake@arm.com started = false; 19110037SARM gem5 Developers tc = _tc; 19210109SGeoffrey.Blake@arm.com mode = _mode; 1937439Sdam.sunwoo@arm.com timing = _isTiming; 1947439Sdam.sunwoo@arm.com} 1957439Sdam.sunwoo@arm.com 1967439Sdam.sunwoo@arm.comFault 1977404SAli.Saidi@ARM.comWalker::WalkerState::startWalk() 1987439Sdam.sunwoo@arm.com{ 1997439Sdam.sunwoo@arm.com Fault fault = NoFault; 20010109SGeoffrey.Blake@arm.com assert(started == false); 20110109SGeoffrey.Blake@arm.com started = true; 20210109SGeoffrey.Blake@arm.com setupWalk(req->getVaddr()); 20310109SGeoffrey.Blake@arm.com if (timing) { 20410109SGeoffrey.Blake@arm.com nextState = state; 20510109SGeoffrey.Blake@arm.com state = Waiting; 20610109SGeoffrey.Blake@arm.com timingFault = NoFault; 20710109SGeoffrey.Blake@arm.com sendPackets(); 2088202SAli.Saidi@ARM.com } else { 2098202SAli.Saidi@ARM.com do { 2108202SAli.Saidi@ARM.com walker->port.sendAtomic(read); 2118202SAli.Saidi@ARM.com PacketPtr write = NULL; 2128202SAli.Saidi@ARM.com fault = stepWalk(write); 2138202SAli.Saidi@ARM.com assert(fault == NoFault || read == NULL); 2148202SAli.Saidi@ARM.com state = nextState; 21510037SARM gem5 Developers nextState = Ready; 21610621SCurtis.Dunham@arm.com if (write) 21710474Sandreas.hansson@arm.com walker->port.sendAtomic(write); 2188202SAli.Saidi@ARM.com } while(read); 2197439Sdam.sunwoo@arm.com state = Ready; 22010621SCurtis.Dunham@arm.com nextState = Waiting; 2217439Sdam.sunwoo@arm.com } 22210621SCurtis.Dunham@arm.com return fault; 2237439Sdam.sunwoo@arm.com} 22411517SCurtis.Dunham@arm.com 22511517SCurtis.Dunham@arm.comFault 22611517SCurtis.Dunham@arm.comWalker::WalkerState::startFunctional(Addr &addr, unsigned &logBytes) 22711574SCurtis.Dunham@arm.com{ 22811517SCurtis.Dunham@arm.com Fault fault = NoFault; 22910037SARM gem5 Developers assert(started == false); 2307439Sdam.sunwoo@arm.com started = true; 2317439Sdam.sunwoo@arm.com setupWalk(addr); 2327439Sdam.sunwoo@arm.com 23310037SARM gem5 Developers do { 23410037SARM gem5 Developers walker->port.sendFunctional(read); 23510037SARM gem5 Developers // On a functional access (page table lookup), writes should 2367439Sdam.sunwoo@arm.com // not happen so this pointer is ignored after stepWalk 2378733Sgeoffrey.blake@arm.com PacketPtr write = NULL; 2387439Sdam.sunwoo@arm.com fault = stepWalk(write); 23910037SARM gem5 Developers assert(fault == NoFault || read == NULL); 24010037SARM gem5 Developers state = nextState; 24110037SARM gem5 Developers nextState = Ready; 2427404SAli.Saidi@ARM.com } while(read); 2437436Sdam.sunwoo@arm.com logBytes = entry.logBytes; 2447436Sdam.sunwoo@arm.com addr = entry.paddr; 24510037SARM gem5 Developers 24610037SARM gem5 Developers return fault; 24710037SARM gem5 Developers} 24810037SARM gem5 Developers 24910037SARM gem5 DevelopersFault 25010037SARM gem5 DevelopersWalker::WalkerState::stepWalk(PacketPtr &write) 25110037SARM gem5 Developers{ 25210037SARM gem5 Developers assert(state != Ready && state != Waiting); 25311575SDylan.Johnson@ARM.com Fault fault = NoFault; 25411575SDylan.Johnson@ARM.com write = NULL; 25511575SDylan.Johnson@ARM.com PageTableEntry pte; 25611575SDylan.Johnson@ARM.com if (dataSize == 8) 25710037SARM gem5 Developers pte = read->get<uint64_t>(); 25810037SARM gem5 Developers else 25910037SARM gem5 Developers pte = read->get<uint32_t>(); 26010324SCurtis.Dunham@arm.com VAddr vaddr = entry.vaddr; 26110037SARM gem5 Developers bool uncacheable = pte.pcd; 26211574SCurtis.Dunham@arm.com Addr nextRead = 0; 26311574SCurtis.Dunham@arm.com bool doWrite = false; 26411574SCurtis.Dunham@arm.com bool doTLBInsert = false; 26511574SCurtis.Dunham@arm.com bool doEndWalk = false; 26611574SCurtis.Dunham@arm.com bool badNX = pte.nx && mode == BaseTLB::Execute && enableNX; 26710037SARM gem5 Developers switch(state) { 26810037SARM gem5 Developers case LongPML4: 26910037SARM gem5 Developers DPRINTF(PageTableWalker, 27010324SCurtis.Dunham@arm.com "Got long mode PML4 entry %#016x.\n", (uint64_t)pte); 27110037SARM gem5 Developers nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * dataSize; 27210037SARM gem5 Developers doWrite = !pte.a; 27310037SARM gem5 Developers pte.a = 1; 27410037SARM gem5 Developers entry.writable = pte.w; 27510037SARM gem5 Developers entry.user = pte.u; 27611575SDylan.Johnson@ARM.com if (badNX || !pte.p) { 27710037SARM gem5 Developers doEndWalk = true; 27810037SARM gem5 Developers fault = pageFault(pte.p); 27910037SARM gem5 Developers break; 28010037SARM gem5 Developers } 28110037SARM gem5 Developers entry.noExec = pte.nx; 28210037SARM gem5 Developers nextState = LongPDP; 28310037SARM gem5 Developers break; 28410037SARM gem5 Developers case LongPDP: 28510037SARM gem5 Developers DPRINTF(PageTableWalker, 2867439Sdam.sunwoo@arm.com "Got long mode PDP entry %#016x.\n", (uint64_t)pte); 2877439Sdam.sunwoo@arm.com nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * dataSize; 2887439Sdam.sunwoo@arm.com doWrite = !pte.a; 2897439Sdam.sunwoo@arm.com pte.a = 1; 2907439Sdam.sunwoo@arm.com entry.writable = entry.writable && pte.w; 29110621SCurtis.Dunham@arm.com entry.user = entry.user && pte.u; 29210621SCurtis.Dunham@arm.com if (badNX || !pte.p) { 29310037SARM gem5 Developers doEndWalk = true; 29410037SARM gem5 Developers fault = pageFault(pte.p); 29510037SARM gem5 Developers break; 29611580SDylan.Johnson@ARM.com } 29710037SARM gem5 Developers nextState = LongPD; 29811580SDylan.Johnson@ARM.com break; 2997728SAli.Saidi@ARM.com case LongPD: 30011517SCurtis.Dunham@arm.com DPRINTF(PageTableWalker, 30111517SCurtis.Dunham@arm.com "Got long mode PD entry %#016x.\n", (uint64_t)pte); 30210037SARM gem5 Developers doWrite = !pte.a; 30310037SARM gem5 Developers pte.a = 1; 30410037SARM gem5 Developers entry.writable = entry.writable && pte.w; 30510037SARM gem5 Developers entry.user = entry.user && pte.u; 30610037SARM gem5 Developers if (badNX || !pte.p) { 30710037SARM gem5 Developers doEndWalk = true; 30810037SARM gem5 Developers fault = pageFault(pte.p); 30910037SARM gem5 Developers break; 31010621SCurtis.Dunham@arm.com } 31110621SCurtis.Dunham@arm.com if (!pte.ps) { 31210621SCurtis.Dunham@arm.com // 4 KB page 31310621SCurtis.Dunham@arm.com entry.logBytes = 12; 31410037SARM gem5 Developers nextRead = 31510037SARM gem5 Developers ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * dataSize; 31610037SARM gem5 Developers nextState = LongPTE; 31710109SGeoffrey.Blake@arm.com break; 31810037SARM gem5 Developers } else { 31910109SGeoffrey.Blake@arm.com // 2 MB page 32010037SARM gem5 Developers entry.logBytes = 21; 32110109SGeoffrey.Blake@arm.com entry.paddr = (uint64_t)pte & (mask(31) << 21); 32210037SARM gem5 Developers entry.uncacheable = uncacheable; 32310109SGeoffrey.Blake@arm.com entry.global = pte.g; 32410109SGeoffrey.Blake@arm.com entry.patBit = bits(pte, 12); 32510109SGeoffrey.Blake@arm.com entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 32610109SGeoffrey.Blake@arm.com doTLBInsert = true; 32710109SGeoffrey.Blake@arm.com doEndWalk = true; 32810109SGeoffrey.Blake@arm.com break; 32910109SGeoffrey.Blake@arm.com } 33010109SGeoffrey.Blake@arm.com case LongPTE: 33110109SGeoffrey.Blake@arm.com DPRINTF(PageTableWalker, 33210037SARM gem5 Developers "Got long mode PTE entry %#016x.\n", (uint64_t)pte); 3337728SAli.Saidi@ARM.com doWrite = !pte.a; 3348067SAli.Saidi@ARM.com pte.a = 1; 3357728SAli.Saidi@ARM.com entry.writable = entry.writable && pte.w; 3367728SAli.Saidi@ARM.com entry.user = entry.user && pte.u; 33710621SCurtis.Dunham@arm.com if (badNX || !pte.p) { 3387728SAli.Saidi@ARM.com doEndWalk = true; 3397728SAli.Saidi@ARM.com fault = pageFault(pte.p); 34010621SCurtis.Dunham@arm.com break; 34110037SARM gem5 Developers } 34210037SARM gem5 Developers entry.paddr = (uint64_t)pte & (mask(40) << 12); 34310037SARM gem5 Developers entry.uncacheable = uncacheable; 34410037SARM gem5 Developers entry.global = pte.g; 34510037SARM gem5 Developers entry.patBit = bits(pte, 12); 34610037SARM gem5 Developers entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 3477728SAli.Saidi@ARM.com doTLBInsert = true; 3487728SAli.Saidi@ARM.com doEndWalk = true; 3497728SAli.Saidi@ARM.com break; 3507728SAli.Saidi@ARM.com case PAEPDP: 3517728SAli.Saidi@ARM.com DPRINTF(PageTableWalker, 3527728SAli.Saidi@ARM.com "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte); 3537728SAli.Saidi@ARM.com nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * dataSize; 3547728SAli.Saidi@ARM.com if (!pte.p) { 3557728SAli.Saidi@ARM.com doEndWalk = true; 3567728SAli.Saidi@ARM.com fault = pageFault(pte.p); 35710621SCurtis.Dunham@arm.com break; 3587728SAli.Saidi@ARM.com } 3599258SAli.Saidi@ARM.com nextState = PAEPD; 36010037SARM gem5 Developers break; 36110037SARM gem5 Developers case PAEPD: 36210037SARM gem5 Developers DPRINTF(PageTableWalker, 36310037SARM gem5 Developers "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte); 36410037SARM gem5 Developers doWrite = !pte.a; 36510037SARM gem5 Developers pte.a = 1; 3669535Smrinmoy.ghosh@arm.com entry.writable = pte.w; 36710037SARM gem5 Developers entry.user = pte.u; 36810037SARM gem5 Developers if (badNX || !pte.p) { 36910037SARM gem5 Developers doEndWalk = true; 37010037SARM gem5 Developers fault = pageFault(pte.p); 3719258SAli.Saidi@ARM.com break; 3729535Smrinmoy.ghosh@arm.com } 3739535Smrinmoy.ghosh@arm.com if (!pte.ps) { 3749535Smrinmoy.ghosh@arm.com // 4 KB page 3759535Smrinmoy.ghosh@arm.com entry.logBytes = 12; 3769535Smrinmoy.ghosh@arm.com nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * dataSize; 3779535Smrinmoy.ghosh@arm.com nextState = PAEPTE; 3789258SAli.Saidi@ARM.com break; 3799258SAli.Saidi@ARM.com } else { 3809258SAli.Saidi@ARM.com // 2 MB page 38110579SAndrew.Bardsley@arm.com entry.logBytes = 21; 38210579SAndrew.Bardsley@arm.com entry.paddr = (uint64_t)pte & (mask(31) << 21); 38310579SAndrew.Bardsley@arm.com entry.uncacheable = uncacheable; 38410037SARM gem5 Developers entry.global = pte.g; 38510579SAndrew.Bardsley@arm.com entry.patBit = bits(pte, 12); 38611517SCurtis.Dunham@arm.com entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 38711517SCurtis.Dunham@arm.com doTLBInsert = true; 38810579SAndrew.Bardsley@arm.com doEndWalk = true; 38910037SARM gem5 Developers break; 39010579SAndrew.Bardsley@arm.com } 39110579SAndrew.Bardsley@arm.com case PAEPTE: 39210579SAndrew.Bardsley@arm.com DPRINTF(PageTableWalker, 39310579SAndrew.Bardsley@arm.com "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte); 39410579SAndrew.Bardsley@arm.com doWrite = !pte.a; 39510579SAndrew.Bardsley@arm.com pte.a = 1; 39610579SAndrew.Bardsley@arm.com entry.writable = entry.writable && pte.w; 39710579SAndrew.Bardsley@arm.com entry.user = entry.user && pte.u; 3989258SAli.Saidi@ARM.com if (badNX || !pte.p) { 3999258SAli.Saidi@ARM.com doEndWalk = true; 4009258SAli.Saidi@ARM.com fault = pageFault(pte.p); 4019258SAli.Saidi@ARM.com break; 4029258SAli.Saidi@ARM.com } 4039258SAli.Saidi@ARM.com entry.paddr = (uint64_t)pte & (mask(40) << 12); 4049258SAli.Saidi@ARM.com entry.uncacheable = uncacheable; 4059258SAli.Saidi@ARM.com entry.global = pte.g; 4069258SAli.Saidi@ARM.com entry.patBit = bits(pte, 7); 4079535Smrinmoy.ghosh@arm.com entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 4089258SAli.Saidi@ARM.com doTLBInsert = true; 4099258SAli.Saidi@ARM.com doEndWalk = true; 41010621SCurtis.Dunham@arm.com break; 4119258SAli.Saidi@ARM.com case PSEPD: 41210037SARM gem5 Developers DPRINTF(PageTableWalker, 41310037SARM gem5 Developers "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte); 4149258SAli.Saidi@ARM.com doWrite = !pte.a; 4159535Smrinmoy.ghosh@arm.com pte.a = 1; 4169535Smrinmoy.ghosh@arm.com entry.writable = pte.w; 41710474Sandreas.hansson@arm.com entry.user = pte.u; 41810474Sandreas.hansson@arm.com if (!pte.p) { 41910474Sandreas.hansson@arm.com doEndWalk = true; 4209535Smrinmoy.ghosh@arm.com fault = pageFault(pte.p); 4219535Smrinmoy.ghosh@arm.com break; 42210621SCurtis.Dunham@arm.com } 42310037SARM gem5 Developers if (!pte.ps) { 42410037SARM gem5 Developers // 4 KB page 42510037SARM gem5 Developers entry.logBytes = 12; 4269535Smrinmoy.ghosh@arm.com nextRead = 4279258SAli.Saidi@ARM.com ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 4289258SAli.Saidi@ARM.com nextState = PTE; 4299258SAli.Saidi@ARM.com break; 4309258SAli.Saidi@ARM.com } else { 4319258SAli.Saidi@ARM.com // 4 MB page 4329535Smrinmoy.ghosh@arm.com entry.logBytes = 21; 4339258SAli.Saidi@ARM.com entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22; 43410037SARM gem5 Developers entry.uncacheable = uncacheable; 43510037SARM gem5 Developers entry.global = pte.g; 43610037SARM gem5 Developers entry.patBit = bits(pte, 12); 4379535Smrinmoy.ghosh@arm.com entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1); 4389535Smrinmoy.ghosh@arm.com doTLBInsert = true; 4399258SAli.Saidi@ARM.com doEndWalk = true; 4409535Smrinmoy.ghosh@arm.com break; 4419258SAli.Saidi@ARM.com } 44210621SCurtis.Dunham@arm.com case PD: 4439258SAli.Saidi@ARM.com DPRINTF(PageTableWalker, 44410621SCurtis.Dunham@arm.com "Got legacy mode PD entry %#08x.\n", (uint32_t)pte); 4459258SAli.Saidi@ARM.com doWrite = !pte.a; 4469258SAli.Saidi@ARM.com pte.a = 1; 4477728SAli.Saidi@ARM.com entry.writable = pte.w; 4487728SAli.Saidi@ARM.com entry.user = pte.u; 4497728SAli.Saidi@ARM.com if (!pte.p) { 4507728SAli.Saidi@ARM.com doEndWalk = true; 4517728SAli.Saidi@ARM.com fault = pageFault(pte.p); 4527404SAli.Saidi@ARM.com break; 4537404SAli.Saidi@ARM.com } 4547404SAli.Saidi@ARM.com // 4 KB page 45510037SARM gem5 Developers entry.logBytes = 12; 4567404SAli.Saidi@ARM.com nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * dataSize; 45710037SARM gem5 Developers nextState = PTE; 45810037SARM gem5 Developers break; 45910037SARM gem5 Developers case PTE: 4607406SAli.Saidi@ARM.com DPRINTF(PageTableWalker, 46110621SCurtis.Dunham@arm.com "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte); 46210621SCurtis.Dunham@arm.com doWrite = !pte.a; 46310037SARM gem5 Developers pte.a = 1; 46410037SARM gem5 Developers entry.writable = pte.w; 4657406SAli.Saidi@ARM.com entry.user = pte.u; 46610037SARM gem5 Developers if (!pte.p) { 46710037SARM gem5 Developers doEndWalk = true; 46810037SARM gem5 Developers fault = pageFault(pte.p); 46910474Sandreas.hansson@arm.com break; 47010474Sandreas.hansson@arm.com } 47110474Sandreas.hansson@arm.com entry.paddr = (uint64_t)pte & (mask(20) << 12); 47210474Sandreas.hansson@arm.com entry.uncacheable = uncacheable; 47310474Sandreas.hansson@arm.com entry.global = pte.g; 47410037SARM gem5 Developers entry.patBit = bits(pte, 7); 47510474Sandreas.hansson@arm.com entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 47610474Sandreas.hansson@arm.com doTLBInsert = true; 47710474Sandreas.hansson@arm.com doEndWalk = true; 47810474Sandreas.hansson@arm.com break; 47910474Sandreas.hansson@arm.com default: 48010037SARM gem5 Developers panic("Unknown page table walker state %d!\n"); 48110037SARM gem5 Developers } 48210037SARM gem5 Developers if (doEndWalk) { 4837404SAli.Saidi@ARM.com if (doTLBInsert) 4847406SAli.Saidi@ARM.com if (!functional) 48510037SARM gem5 Developers walker->tlb->insert(entry.vaddr, entry); 48610037SARM gem5 Developers endWalk(); 48710037SARM gem5 Developers } else { 48810474Sandreas.hansson@arm.com PacketPtr oldRead = read; 48910474Sandreas.hansson@arm.com //If we didn't return, we're setting up another read. 49010474Sandreas.hansson@arm.com Request::Flags flags = oldRead->req->getFlags(); 49110474Sandreas.hansson@arm.com flags.set(Request::UNCACHEABLE, uncacheable); 49210474Sandreas.hansson@arm.com RequestPtr request = 49310037SARM gem5 Developers new Request(nextRead, oldRead->getSize(), flags, walker->masterId); 49410474Sandreas.hansson@arm.com read = new Packet(request, MemCmd::ReadReq); 49510474Sandreas.hansson@arm.com read->allocate(); 49610474Sandreas.hansson@arm.com // If we need to write, adjust the read packet to write the modified 49710474Sandreas.hansson@arm.com // value back to memory. 49810474Sandreas.hansson@arm.com if (doWrite) { 49910037SARM gem5 Developers write = oldRead; 50010037SARM gem5 Developers write->set<uint64_t>(pte); 50110037SARM gem5 Developers write->cmd = MemCmd::WriteReq; 50210037SARM gem5 Developers write->clearDest(); 5037404SAli.Saidi@ARM.com } else { 5047404SAli.Saidi@ARM.com write = NULL; 50510037SARM gem5 Developers delete oldRead->req; 50610037SARM gem5 Developers delete oldRead; 50710037SARM gem5 Developers } 50810037SARM gem5 Developers } 5097404SAli.Saidi@ARM.com return fault; 5107404SAli.Saidi@ARM.com} 5117439Sdam.sunwoo@arm.com 51211395Sandreas.sandberg@arm.comvoid 51311395Sandreas.sandberg@arm.comWalker::WalkerState::endWalk() 5147439Sdam.sunwoo@arm.com{ 51510037SARM gem5 Developers nextState = Ready; 5167579Sminkyu.jeong@arm.com delete read->req; 5177728SAli.Saidi@ARM.com delete read; 5187728SAli.Saidi@ARM.com read = NULL; 5197579Sminkyu.jeong@arm.com} 5207579Sminkyu.jeong@arm.com 5217579Sminkyu.jeong@arm.comvoid 5227579Sminkyu.jeong@arm.comWalker::WalkerState::setupWalk(Addr vaddr) 5237579Sminkyu.jeong@arm.com{ 5247579Sminkyu.jeong@arm.com VAddr addr = vaddr; 5257404SAli.Saidi@ARM.com CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3); 5267404SAli.Saidi@ARM.com // Check if we're in long mode or not 52710836Sandreas.hansson@arm.com Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); 5287946SGiacomo.Gabrielli@arm.com dataSize = 8; 52910836Sandreas.hansson@arm.com Addr topAddr; 5307946SGiacomo.Gabrielli@arm.com if (efer.lma) { 5317946SGiacomo.Gabrielli@arm.com // Do long mode. 53211181Snathananel.premillieu@arm.com state = LongPML4; 53311181Snathananel.premillieu@arm.com topAddr = (cr3.longPdtb << 12) + addr.longl4 * dataSize; 53411181Snathananel.premillieu@arm.com enableNX = efer.nxe; 53511181Snathananel.premillieu@arm.com } else { 53610037SARM gem5 Developers // We're in some flavor of legacy mode. 53710037SARM gem5 Developers CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); 53810037SARM gem5 Developers if (cr4.pae) { 53910037SARM gem5 Developers // Do legacy PAE. 54010037SARM gem5 Developers state = PAEPDP; 54110037SARM gem5 Developers topAddr = (cr3.paePdtb << 5) + addr.pael3 * dataSize; 54210037SARM gem5 Developers enableNX = efer.nxe; 54310037SARM gem5 Developers } else { 54410037SARM gem5 Developers dataSize = 4; 54510037SARM gem5 Developers topAddr = (cr3.pdtb << 12) + addr.norml2 * dataSize; 54610037SARM gem5 Developers if (cr4.pse) { 54710037SARM gem5 Developers // Do legacy PSE. 54810037SARM gem5 Developers state = PSEPD; 54910037SARM gem5 Developers } else { 55010037SARM gem5 Developers // Do legacy non PSE. 55110037SARM gem5 Developers state = PD; 55210037SARM gem5 Developers } 55310037SARM gem5 Developers enableNX = false; 55410037SARM gem5 Developers } 55510037SARM gem5 Developers } 55610037SARM gem5 Developers 55710621SCurtis.Dunham@arm.com nextState = Ready; 55810621SCurtis.Dunham@arm.com entry.vaddr = vaddr; 55910836Sandreas.hansson@arm.com 56010037SARM gem5 Developers Request::Flags flags = Request::PHYSICAL; 56110037SARM gem5 Developers if (cr3.pcd) 56210037SARM gem5 Developers flags.set(Request::UNCACHEABLE); 56310037SARM gem5 Developers RequestPtr request = new Request(topAddr, dataSize, flags, 56410037SARM gem5 Developers walker->masterId); 56510037SARM gem5 Developers read = new Packet(request, MemCmd::ReadReq); 56610037SARM gem5 Developers read->allocate(); 56710037SARM gem5 Developers} 56810037SARM gem5 Developers 56910037SARM gem5 Developersbool 57010037SARM gem5 DevelopersWalker::WalkerState::recvPacket(PacketPtr pkt) 57110037SARM gem5 Developers{ 57210037SARM gem5 Developers assert(pkt->isResponse()); 57310037SARM gem5 Developers if (!pkt->wasNacked()) { 57410037SARM gem5 Developers assert(inflight); 57511517SCurtis.Dunham@arm.com assert(state == Waiting); 57610037SARM gem5 Developers assert(!read); 57710037SARM gem5 Developers inflight--; 57810037SARM gem5 Developers if (pkt->isRead()) { 57910037SARM gem5 Developers state = nextState; 58010037SARM gem5 Developers nextState = Ready; 58110037SARM gem5 Developers PacketPtr write = NULL; 58210037SARM gem5 Developers read = pkt; 58310037SARM gem5 Developers timingFault = stepWalk(write); 58410037SARM gem5 Developers state = Waiting; 58510037SARM gem5 Developers assert(timingFault == NoFault || read == NULL); 58610037SARM gem5 Developers if (write) { 58710037SARM gem5 Developers writes.push_back(write); 58810037SARM gem5 Developers } 58910037SARM gem5 Developers sendPackets(); 59010037SARM gem5 Developers } else { 59110037SARM gem5 Developers sendPackets(); 59210037SARM gem5 Developers } 59310037SARM gem5 Developers if (inflight == 0 && read == NULL && writes.size() == 0) { 59410037SARM gem5 Developers state = Ready; 59510037SARM gem5 Developers nextState = Waiting; 59610037SARM gem5 Developers if (timingFault == NoFault) { 59710037SARM gem5 Developers /* 59810037SARM gem5 Developers * Finish the translation. Now that we now the right entry is 59910474Sandreas.hansson@arm.com * in the TLB, this should work with no memory accesses. 60010474Sandreas.hansson@arm.com * There could be new faults unrelated to the table walk like 60110474Sandreas.hansson@arm.com * permissions violations, so we'll need the return value as 60210474Sandreas.hansson@arm.com * well. 60310474Sandreas.hansson@arm.com */ 60410037SARM gem5 Developers bool delayedResponse; 60510474Sandreas.hansson@arm.com Fault fault = walker->tlb->translate(req, tc, NULL, mode, 60610474Sandreas.hansson@arm.com delayedResponse, true); 60710474Sandreas.hansson@arm.com assert(!delayedResponse); 60810474Sandreas.hansson@arm.com // Let the CPU continue. 60910474Sandreas.hansson@arm.com translation->finish(fault, req, tc, mode); 61010474Sandreas.hansson@arm.com } else { 61110474Sandreas.hansson@arm.com // There was a fault during the walk. Let the CPU know. 61210037SARM gem5 Developers translation->finish(timingFault, req, tc, mode); 61310037SARM gem5 Developers } 61410037SARM gem5 Developers return true; 61510037SARM gem5 Developers } 61610037SARM gem5 Developers } else { 61710037SARM gem5 Developers DPRINTF(PageTableWalker, "Request was nacked. Entering retry state\n"); 61810037SARM gem5 Developers pkt->reinitNacked(); 61910037SARM gem5 Developers if (!walker->sendTiming(this, pkt)) { 62010037SARM gem5 Developers inflight--; 62110037SARM gem5 Developers retrying = true; 62210037SARM gem5 Developers if (pkt->isWrite()) { 62310474Sandreas.hansson@arm.com writes.push_back(pkt); 62410474Sandreas.hansson@arm.com } else { 62510474Sandreas.hansson@arm.com assert(!read); 62610474Sandreas.hansson@arm.com read = pkt; 62710474Sandreas.hansson@arm.com } 62810037SARM gem5 Developers } 62910474Sandreas.hansson@arm.com } 63010474Sandreas.hansson@arm.com return false; 63110474Sandreas.hansson@arm.com} 63210474Sandreas.hansson@arm.com 63310474Sandreas.hansson@arm.comvoid 63410474Sandreas.hansson@arm.comWalker::WalkerState::sendPackets() 63510474Sandreas.hansson@arm.com{ 63610037SARM gem5 Developers //If we're already waiting for the port to become available, just return. 63710037SARM gem5 Developers if (retrying) 63810037SARM gem5 Developers return; 63910037SARM gem5 Developers 64010037SARM gem5 Developers //Reads always have priority 64110037SARM gem5 Developers if (read) { 64210037SARM gem5 Developers PacketPtr pkt = read; 64310037SARM gem5 Developers read = NULL; 64410037SARM gem5 Developers inflight++; 64510474Sandreas.hansson@arm.com if (!walker->sendTiming(this, pkt)) { 64610474Sandreas.hansson@arm.com retrying = true; 64710474Sandreas.hansson@arm.com read = pkt; 64810474Sandreas.hansson@arm.com inflight--; 64910474Sandreas.hansson@arm.com return; 65010037SARM gem5 Developers } 65110474Sandreas.hansson@arm.com } 65210474Sandreas.hansson@arm.com //Send off as many of the writes as we can. 65310474Sandreas.hansson@arm.com while (writes.size()) { 65410474Sandreas.hansson@arm.com PacketPtr write = writes.back(); 65510474Sandreas.hansson@arm.com writes.pop_back(); 65610037SARM gem5 Developers inflight++; 65710037SARM gem5 Developers if (!walker->sendTiming(this, write)) { 65810037SARM gem5 Developers retrying = true; 65910037SARM gem5 Developers writes.push_back(write); 66010037SARM gem5 Developers inflight--; 66110037SARM gem5 Developers return; 66210037SARM gem5 Developers } 66310037SARM gem5 Developers } 66410037SARM gem5 Developers} 66510037SARM gem5 Developers 66610037SARM gem5 Developersbool 66710037SARM gem5 DevelopersWalker::WalkerState::isRetrying() 66810037SARM gem5 Developers{ 66910037SARM gem5 Developers return retrying; 67010037SARM gem5 Developers} 67110037SARM gem5 Developers 67210037SARM gem5 Developersbool 67310037SARM gem5 DevelopersWalker::WalkerState::isTiming() 67410037SARM gem5 Developers{ 67510037SARM gem5 Developers return timing; 67610037SARM gem5 Developers} 67711395Sandreas.sandberg@arm.com 67811395Sandreas.sandberg@arm.combool 67910037SARM gem5 DevelopersWalker::WalkerState::wasStarted() 68010037SARM gem5 Developers{ 68110037SARM gem5 Developers return started; 68210037SARM gem5 Developers} 68310037SARM gem5 Developers 68410037SARM gem5 Developersvoid 68510037SARM gem5 DevelopersWalker::WalkerState::retry() 68610037SARM gem5 Developers{ 68710037SARM gem5 Developers retrying = false; 68810037SARM gem5 Developers sendPackets(); 68910037SARM gem5 Developers} 69010037SARM gem5 Developers 69110037SARM gem5 DevelopersFault 69210037SARM gem5 DevelopersWalker::WalkerState::pageFault(bool present) 69310836Sandreas.hansson@arm.com{ 69410037SARM gem5 Developers DPRINTF(PageTableWalker, "Raising page fault.\n"); 69510037SARM gem5 Developers HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); 69610037SARM gem5 Developers if (mode == BaseTLB::Execute && !enableNX) 69710037SARM gem5 Developers mode = BaseTLB::Read; 69810324SCurtis.Dunham@arm.com return new PageFault(entry.vaddr, present, mode, m5reg.cpl == 3, false); 69910037SARM gem5 Developers} 70010037SARM gem5 Developers 70110037SARM gem5 Developers/* end namespace X86ISA */ } 70210037SARM gem5 Developers 70310037SARM gem5 DevelopersX86ISA::Walker * 70410037SARM gem5 DevelopersX86PagetableWalkerParams::create() 70510037SARM gem5 Developers{ 70610037SARM gem5 Developers return new X86ISA::Walker(this); 70710037SARM gem5 Developers} 70810037SARM gem5 Developers