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