pagetable_walker.cc revision 7087
15245Sgblack@eecs.umich.edu/* 25245Sgblack@eecs.umich.edu * Copyright (c) 2007 The Hewlett-Packard Development Company 35245Sgblack@eecs.umich.edu * All rights reserved. 45245Sgblack@eecs.umich.edu * 57087Snate@binkert.org * The license below extends only to copyright in the software and shall 67087Snate@binkert.org * not be construed as granting a license to any other intellectual 77087Snate@binkert.org * property including but not limited to intellectual property relating 87087Snate@binkert.org * to a hardware implementation of the functionality of the software 97087Snate@binkert.org * licensed hereunder. You may use the software subject to the license 107087Snate@binkert.org * terms below provided that you ensure that this notice is replicated 117087Snate@binkert.org * unmodified and in its entirety in all distributions of the software, 127087Snate@binkert.org * modified or unmodified, in source code or in binary form. 135245Sgblack@eecs.umich.edu * 147087Snate@binkert.org * Redistribution and use in source and binary forms, with or without 157087Snate@binkert.org * modification, are permitted provided that the following conditions are 167087Snate@binkert.org * met: redistributions of source code must retain the above copyright 177087Snate@binkert.org * notice, this list of conditions and the following disclaimer; 187087Snate@binkert.org * redistributions in binary form must reproduce the above copyright 197087Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 207087Snate@binkert.org * documentation and/or other materials provided with the distribution; 217087Snate@binkert.org * neither the name of the copyright holders nor the names of its 225245Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 237087Snate@binkert.org * this software without specific prior written permission. 245245Sgblack@eecs.umich.edu * 255245Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 265245Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 275245Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 285245Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 295245Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 305245Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 315245Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 325245Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 335245Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 345245Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 355245Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 365245Sgblack@eecs.umich.edu * 375245Sgblack@eecs.umich.edu * Authors: Gabe Black 385245Sgblack@eecs.umich.edu */ 395245Sgblack@eecs.umich.edu 405245Sgblack@eecs.umich.edu#include "arch/x86/pagetable.hh" 415245Sgblack@eecs.umich.edu#include "arch/x86/pagetable_walker.hh" 425245Sgblack@eecs.umich.edu#include "arch/x86/tlb.hh" 435245Sgblack@eecs.umich.edu#include "base/bitfield.hh" 445245Sgblack@eecs.umich.edu#include "cpu/thread_context.hh" 455245Sgblack@eecs.umich.edu#include "cpu/base.hh" 465245Sgblack@eecs.umich.edu#include "mem/packet_access.hh" 475245Sgblack@eecs.umich.edu#include "mem/request.hh" 485245Sgblack@eecs.umich.edu#include "sim/system.hh" 495245Sgblack@eecs.umich.edu 505245Sgblack@eecs.umich.edunamespace X86ISA { 515245Sgblack@eecs.umich.edu 525245Sgblack@eecs.umich.edu// Unfortunately, the placement of the base field in a page table entry is 535245Sgblack@eecs.umich.edu// very erratic and would make a mess here. It might be moved here at some 545245Sgblack@eecs.umich.edu// point in the future. 555245Sgblack@eecs.umich.eduBitUnion64(PageTableEntry) 565245Sgblack@eecs.umich.edu Bitfield<63> nx; 575245Sgblack@eecs.umich.edu Bitfield<11, 9> avl; 585245Sgblack@eecs.umich.edu Bitfield<8> g; 595245Sgblack@eecs.umich.edu Bitfield<7> ps; 605245Sgblack@eecs.umich.edu Bitfield<6> d; 615245Sgblack@eecs.umich.edu Bitfield<5> a; 625245Sgblack@eecs.umich.edu Bitfield<4> pcd; 635245Sgblack@eecs.umich.edu Bitfield<3> pwt; 645245Sgblack@eecs.umich.edu Bitfield<2> u; 655245Sgblack@eecs.umich.edu Bitfield<1> w; 665245Sgblack@eecs.umich.edu Bitfield<0> p; 675245Sgblack@eecs.umich.eduEndBitUnion(PageTableEntry) 685245Sgblack@eecs.umich.edu 695895Sgblack@eecs.umich.eduFault 705897Sgblack@eecs.umich.eduWalker::doNext(PacketPtr &write) 715245Sgblack@eecs.umich.edu{ 725245Sgblack@eecs.umich.edu assert(state != Ready && state != Waiting); 735245Sgblack@eecs.umich.edu write = NULL; 745245Sgblack@eecs.umich.edu PageTableEntry pte; 755245Sgblack@eecs.umich.edu if (size == 8) 765245Sgblack@eecs.umich.edu pte = read->get<uint64_t>(); 775245Sgblack@eecs.umich.edu else 785245Sgblack@eecs.umich.edu pte = read->get<uint32_t>(); 795245Sgblack@eecs.umich.edu VAddr vaddr = entry.vaddr; 805245Sgblack@eecs.umich.edu bool uncacheable = pte.pcd; 815245Sgblack@eecs.umich.edu Addr nextRead = 0; 825245Sgblack@eecs.umich.edu bool doWrite = false; 836027Sgblack@eecs.umich.edu bool badNX = pte.nx && mode == BaseTLB::Execute && enableNX; 845245Sgblack@eecs.umich.edu switch(state) { 855245Sgblack@eecs.umich.edu case LongPML4: 865904Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, 875904Sgblack@eecs.umich.edu "Got long mode PML4 entry %#016x.\n", (uint64_t)pte); 885245Sgblack@eecs.umich.edu nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * size; 895245Sgblack@eecs.umich.edu doWrite = !pte.a; 905245Sgblack@eecs.umich.edu pte.a = 1; 915245Sgblack@eecs.umich.edu entry.writable = pte.w; 925245Sgblack@eecs.umich.edu entry.user = pte.u; 935895Sgblack@eecs.umich.edu if (badNX || !pte.p) { 945895Sgblack@eecs.umich.edu stop(); 955895Sgblack@eecs.umich.edu return pageFault(pte.p); 965895Sgblack@eecs.umich.edu } 975245Sgblack@eecs.umich.edu entry.noExec = pte.nx; 985245Sgblack@eecs.umich.edu nextState = LongPDP; 995245Sgblack@eecs.umich.edu break; 1005245Sgblack@eecs.umich.edu case LongPDP: 1015904Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, 1025904Sgblack@eecs.umich.edu "Got long mode PDP entry %#016x.\n", (uint64_t)pte); 1035245Sgblack@eecs.umich.edu nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * size; 1045245Sgblack@eecs.umich.edu doWrite = !pte.a; 1055245Sgblack@eecs.umich.edu pte.a = 1; 1065245Sgblack@eecs.umich.edu entry.writable = entry.writable && pte.w; 1075245Sgblack@eecs.umich.edu entry.user = entry.user && pte.u; 1085895Sgblack@eecs.umich.edu if (badNX || !pte.p) { 1095895Sgblack@eecs.umich.edu stop(); 1105895Sgblack@eecs.umich.edu return pageFault(pte.p); 1115895Sgblack@eecs.umich.edu } 1125245Sgblack@eecs.umich.edu nextState = LongPD; 1135245Sgblack@eecs.umich.edu break; 1145245Sgblack@eecs.umich.edu case LongPD: 1155904Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, 1165904Sgblack@eecs.umich.edu "Got long mode PD entry %#016x.\n", (uint64_t)pte); 1175245Sgblack@eecs.umich.edu doWrite = !pte.a; 1185245Sgblack@eecs.umich.edu pte.a = 1; 1195245Sgblack@eecs.umich.edu entry.writable = entry.writable && pte.w; 1205245Sgblack@eecs.umich.edu entry.user = entry.user && pte.u; 1215895Sgblack@eecs.umich.edu if (badNX || !pte.p) { 1225895Sgblack@eecs.umich.edu stop(); 1235895Sgblack@eecs.umich.edu return pageFault(pte.p); 1245895Sgblack@eecs.umich.edu } 1255245Sgblack@eecs.umich.edu if (!pte.ps) { 1265245Sgblack@eecs.umich.edu // 4 KB page 1275245Sgblack@eecs.umich.edu entry.size = 4 * (1 << 10); 1285245Sgblack@eecs.umich.edu nextRead = 1295245Sgblack@eecs.umich.edu ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * size; 1305245Sgblack@eecs.umich.edu nextState = LongPTE; 1315245Sgblack@eecs.umich.edu break; 1325245Sgblack@eecs.umich.edu } else { 1335245Sgblack@eecs.umich.edu // 2 MB page 1345245Sgblack@eecs.umich.edu entry.size = 2 * (1 << 20); 1355245Sgblack@eecs.umich.edu entry.paddr = (uint64_t)pte & (mask(31) << 21); 1365245Sgblack@eecs.umich.edu entry.uncacheable = uncacheable; 1375245Sgblack@eecs.umich.edu entry.global = pte.g; 1385245Sgblack@eecs.umich.edu entry.patBit = bits(pte, 12); 1395245Sgblack@eecs.umich.edu entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 1405245Sgblack@eecs.umich.edu tlb->insert(entry.vaddr, entry); 1415895Sgblack@eecs.umich.edu stop(); 1425895Sgblack@eecs.umich.edu return NoFault; 1435245Sgblack@eecs.umich.edu } 1445245Sgblack@eecs.umich.edu case LongPTE: 1455904Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, 1465904Sgblack@eecs.umich.edu "Got long mode PTE entry %#016x.\n", (uint64_t)pte); 1475245Sgblack@eecs.umich.edu doWrite = !pte.a; 1485245Sgblack@eecs.umich.edu pte.a = 1; 1495245Sgblack@eecs.umich.edu entry.writable = entry.writable && pte.w; 1505245Sgblack@eecs.umich.edu entry.user = entry.user && pte.u; 1515895Sgblack@eecs.umich.edu if (badNX || !pte.p) { 1525895Sgblack@eecs.umich.edu stop(); 1535895Sgblack@eecs.umich.edu return pageFault(pte.p); 1545895Sgblack@eecs.umich.edu } 1555245Sgblack@eecs.umich.edu entry.paddr = (uint64_t)pte & (mask(40) << 12); 1565245Sgblack@eecs.umich.edu entry.uncacheable = uncacheable; 1575245Sgblack@eecs.umich.edu entry.global = pte.g; 1585245Sgblack@eecs.umich.edu entry.patBit = bits(pte, 12); 1595245Sgblack@eecs.umich.edu entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 1605245Sgblack@eecs.umich.edu tlb->insert(entry.vaddr, entry); 1615895Sgblack@eecs.umich.edu stop(); 1625895Sgblack@eecs.umich.edu return NoFault; 1635245Sgblack@eecs.umich.edu case PAEPDP: 1645904Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, 1655904Sgblack@eecs.umich.edu "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte); 1665245Sgblack@eecs.umich.edu nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size; 1675895Sgblack@eecs.umich.edu if (!pte.p) { 1685895Sgblack@eecs.umich.edu stop(); 1695895Sgblack@eecs.umich.edu return pageFault(pte.p); 1705895Sgblack@eecs.umich.edu } 1715245Sgblack@eecs.umich.edu nextState = PAEPD; 1725245Sgblack@eecs.umich.edu break; 1735245Sgblack@eecs.umich.edu case PAEPD: 1745904Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, 1755904Sgblack@eecs.umich.edu "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte); 1765245Sgblack@eecs.umich.edu doWrite = !pte.a; 1775245Sgblack@eecs.umich.edu pte.a = 1; 1785245Sgblack@eecs.umich.edu entry.writable = pte.w; 1795245Sgblack@eecs.umich.edu entry.user = pte.u; 1805895Sgblack@eecs.umich.edu if (badNX || !pte.p) { 1815895Sgblack@eecs.umich.edu stop(); 1825895Sgblack@eecs.umich.edu return pageFault(pte.p); 1835895Sgblack@eecs.umich.edu } 1845245Sgblack@eecs.umich.edu if (!pte.ps) { 1855245Sgblack@eecs.umich.edu // 4 KB page 1865245Sgblack@eecs.umich.edu entry.size = 4 * (1 << 10); 1875245Sgblack@eecs.umich.edu nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * size; 1885245Sgblack@eecs.umich.edu nextState = PAEPTE; 1895245Sgblack@eecs.umich.edu break; 1905245Sgblack@eecs.umich.edu } else { 1915245Sgblack@eecs.umich.edu // 2 MB page 1925245Sgblack@eecs.umich.edu entry.size = 2 * (1 << 20); 1935245Sgblack@eecs.umich.edu entry.paddr = (uint64_t)pte & (mask(31) << 21); 1945245Sgblack@eecs.umich.edu entry.uncacheable = uncacheable; 1955245Sgblack@eecs.umich.edu entry.global = pte.g; 1965245Sgblack@eecs.umich.edu entry.patBit = bits(pte, 12); 1975245Sgblack@eecs.umich.edu entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1); 1985245Sgblack@eecs.umich.edu tlb->insert(entry.vaddr, entry); 1995895Sgblack@eecs.umich.edu stop(); 2005895Sgblack@eecs.umich.edu return NoFault; 2015245Sgblack@eecs.umich.edu } 2025245Sgblack@eecs.umich.edu case PAEPTE: 2035904Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, 2045904Sgblack@eecs.umich.edu "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte); 2055245Sgblack@eecs.umich.edu doWrite = !pte.a; 2065245Sgblack@eecs.umich.edu pte.a = 1; 2075245Sgblack@eecs.umich.edu entry.writable = entry.writable && pte.w; 2085245Sgblack@eecs.umich.edu entry.user = entry.user && pte.u; 2095895Sgblack@eecs.umich.edu if (badNX || !pte.p) { 2105895Sgblack@eecs.umich.edu stop(); 2115895Sgblack@eecs.umich.edu return pageFault(pte.p); 2125895Sgblack@eecs.umich.edu } 2135245Sgblack@eecs.umich.edu entry.paddr = (uint64_t)pte & (mask(40) << 12); 2145245Sgblack@eecs.umich.edu entry.uncacheable = uncacheable; 2155245Sgblack@eecs.umich.edu entry.global = pte.g; 2165245Sgblack@eecs.umich.edu entry.patBit = bits(pte, 7); 2175245Sgblack@eecs.umich.edu entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 2185245Sgblack@eecs.umich.edu tlb->insert(entry.vaddr, entry); 2195895Sgblack@eecs.umich.edu stop(); 2205895Sgblack@eecs.umich.edu return NoFault; 2215245Sgblack@eecs.umich.edu case PSEPD: 2225904Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, 2235904Sgblack@eecs.umich.edu "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte); 2245245Sgblack@eecs.umich.edu doWrite = !pte.a; 2255245Sgblack@eecs.umich.edu pte.a = 1; 2265245Sgblack@eecs.umich.edu entry.writable = pte.w; 2275245Sgblack@eecs.umich.edu entry.user = pte.u; 2285895Sgblack@eecs.umich.edu if (!pte.p) { 2295895Sgblack@eecs.umich.edu stop(); 2305895Sgblack@eecs.umich.edu return pageFault(pte.p); 2315895Sgblack@eecs.umich.edu } 2325245Sgblack@eecs.umich.edu if (!pte.ps) { 2335245Sgblack@eecs.umich.edu // 4 KB page 2345245Sgblack@eecs.umich.edu entry.size = 4 * (1 << 10); 2355245Sgblack@eecs.umich.edu nextRead = 2365245Sgblack@eecs.umich.edu ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size; 2375245Sgblack@eecs.umich.edu nextState = PTE; 2385245Sgblack@eecs.umich.edu break; 2395245Sgblack@eecs.umich.edu } else { 2405245Sgblack@eecs.umich.edu // 4 MB page 2415245Sgblack@eecs.umich.edu entry.size = 4 * (1 << 20); 2425245Sgblack@eecs.umich.edu entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22; 2435245Sgblack@eecs.umich.edu entry.uncacheable = uncacheable; 2445245Sgblack@eecs.umich.edu entry.global = pte.g; 2455245Sgblack@eecs.umich.edu entry.patBit = bits(pte, 12); 2465245Sgblack@eecs.umich.edu entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1); 2475245Sgblack@eecs.umich.edu tlb->insert(entry.vaddr, entry); 2485895Sgblack@eecs.umich.edu stop(); 2495895Sgblack@eecs.umich.edu return NoFault; 2505245Sgblack@eecs.umich.edu } 2515245Sgblack@eecs.umich.edu case PD: 2525904Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, 2535904Sgblack@eecs.umich.edu "Got legacy mode PD entry %#08x.\n", (uint32_t)pte); 2545245Sgblack@eecs.umich.edu doWrite = !pte.a; 2555245Sgblack@eecs.umich.edu pte.a = 1; 2565245Sgblack@eecs.umich.edu entry.writable = pte.w; 2575245Sgblack@eecs.umich.edu entry.user = pte.u; 2585895Sgblack@eecs.umich.edu if (!pte.p) { 2595895Sgblack@eecs.umich.edu stop(); 2605895Sgblack@eecs.umich.edu return pageFault(pte.p); 2615895Sgblack@eecs.umich.edu } 2625245Sgblack@eecs.umich.edu // 4 KB page 2635245Sgblack@eecs.umich.edu entry.size = 4 * (1 << 10); 2645245Sgblack@eecs.umich.edu nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size; 2655245Sgblack@eecs.umich.edu nextState = PTE; 2665245Sgblack@eecs.umich.edu break; 2675245Sgblack@eecs.umich.edu case PTE: 2685904Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, 2695904Sgblack@eecs.umich.edu "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte); 2705245Sgblack@eecs.umich.edu doWrite = !pte.a; 2715245Sgblack@eecs.umich.edu pte.a = 1; 2725245Sgblack@eecs.umich.edu entry.writable = pte.w; 2735245Sgblack@eecs.umich.edu entry.user = pte.u; 2745895Sgblack@eecs.umich.edu if (!pte.p) { 2755895Sgblack@eecs.umich.edu stop(); 2765895Sgblack@eecs.umich.edu return pageFault(pte.p); 2775895Sgblack@eecs.umich.edu } 2785245Sgblack@eecs.umich.edu entry.paddr = (uint64_t)pte & (mask(20) << 12); 2795245Sgblack@eecs.umich.edu entry.uncacheable = uncacheable; 2805245Sgblack@eecs.umich.edu entry.global = pte.g; 2815245Sgblack@eecs.umich.edu entry.patBit = bits(pte, 7); 2825245Sgblack@eecs.umich.edu entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1); 2835245Sgblack@eecs.umich.edu tlb->insert(entry.vaddr, entry); 2845895Sgblack@eecs.umich.edu stop(); 2855895Sgblack@eecs.umich.edu return NoFault; 2865245Sgblack@eecs.umich.edu default: 2875245Sgblack@eecs.umich.edu panic("Unknown page table walker state %d!\n"); 2885245Sgblack@eecs.umich.edu } 2895245Sgblack@eecs.umich.edu PacketPtr oldRead = read; 2905245Sgblack@eecs.umich.edu //If we didn't return, we're setting up another read. 2915736Snate@binkert.org Request::Flags flags = oldRead->req->getFlags(); 2925736Snate@binkert.org flags.set(Request::UNCACHEABLE, uncacheable); 2935245Sgblack@eecs.umich.edu RequestPtr request = 2945245Sgblack@eecs.umich.edu new Request(nextRead, oldRead->getSize(), flags); 2955245Sgblack@eecs.umich.edu read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast); 2965245Sgblack@eecs.umich.edu read->allocate(); 2975245Sgblack@eecs.umich.edu //If we need to write, adjust the read packet to write the modified value 2985245Sgblack@eecs.umich.edu //back to memory. 2995245Sgblack@eecs.umich.edu if (doWrite) { 3005245Sgblack@eecs.umich.edu write = oldRead; 3015245Sgblack@eecs.umich.edu write->set<uint64_t>(pte); 3025245Sgblack@eecs.umich.edu write->cmd = MemCmd::WriteReq; 3035245Sgblack@eecs.umich.edu write->setDest(Packet::Broadcast); 3045245Sgblack@eecs.umich.edu } else { 3055245Sgblack@eecs.umich.edu write = NULL; 3065245Sgblack@eecs.umich.edu delete oldRead->req; 3075245Sgblack@eecs.umich.edu delete oldRead; 3085245Sgblack@eecs.umich.edu } 3095895Sgblack@eecs.umich.edu return NoFault; 3105245Sgblack@eecs.umich.edu} 3115245Sgblack@eecs.umich.edu 3125895Sgblack@eecs.umich.eduFault 3135895Sgblack@eecs.umich.eduWalker::start(ThreadContext * _tc, BaseTLB::Translation *_translation, 3146023Snate@binkert.org RequestPtr _req, BaseTLB::Mode _mode) 3155245Sgblack@eecs.umich.edu{ 3165245Sgblack@eecs.umich.edu assert(state == Ready); 3175245Sgblack@eecs.umich.edu tc = _tc; 3185895Sgblack@eecs.umich.edu req = _req; 3195895Sgblack@eecs.umich.edu Addr vaddr = req->getVaddr(); 3206023Snate@binkert.org mode = _mode; 3215895Sgblack@eecs.umich.edu translation = _translation; 3225245Sgblack@eecs.umich.edu 3235245Sgblack@eecs.umich.edu VAddr addr = vaddr; 3245245Sgblack@eecs.umich.edu 3255245Sgblack@eecs.umich.edu //Figure out what we're doing. 3265245Sgblack@eecs.umich.edu CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3); 3275245Sgblack@eecs.umich.edu Addr top = 0; 3285245Sgblack@eecs.umich.edu // Check if we're in long mode or not 3295245Sgblack@eecs.umich.edu Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); 3305245Sgblack@eecs.umich.edu size = 8; 3315245Sgblack@eecs.umich.edu if (efer.lma) { 3325245Sgblack@eecs.umich.edu // Do long mode. 3335245Sgblack@eecs.umich.edu state = LongPML4; 3345245Sgblack@eecs.umich.edu top = (cr3.longPdtb << 12) + addr.longl4 * size; 3355895Sgblack@eecs.umich.edu enableNX = efer.nxe; 3365245Sgblack@eecs.umich.edu } else { 3375245Sgblack@eecs.umich.edu // We're in some flavor of legacy mode. 3385245Sgblack@eecs.umich.edu CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); 3395245Sgblack@eecs.umich.edu if (cr4.pae) { 3405245Sgblack@eecs.umich.edu // Do legacy PAE. 3415245Sgblack@eecs.umich.edu state = PAEPDP; 3425245Sgblack@eecs.umich.edu top = (cr3.paePdtb << 5) + addr.pael3 * size; 3435895Sgblack@eecs.umich.edu enableNX = efer.nxe; 3445245Sgblack@eecs.umich.edu } else { 3455245Sgblack@eecs.umich.edu size = 4; 3465245Sgblack@eecs.umich.edu top = (cr3.pdtb << 12) + addr.norml2 * size; 3475245Sgblack@eecs.umich.edu if (cr4.pse) { 3485245Sgblack@eecs.umich.edu // Do legacy PSE. 3495245Sgblack@eecs.umich.edu state = PSEPD; 3505245Sgblack@eecs.umich.edu } else { 3515245Sgblack@eecs.umich.edu // Do legacy non PSE. 3525245Sgblack@eecs.umich.edu state = PD; 3535245Sgblack@eecs.umich.edu } 3545895Sgblack@eecs.umich.edu enableNX = false; 3555245Sgblack@eecs.umich.edu } 3565245Sgblack@eecs.umich.edu } 3575245Sgblack@eecs.umich.edu 3585245Sgblack@eecs.umich.edu nextState = Ready; 3595245Sgblack@eecs.umich.edu entry.vaddr = vaddr; 3605245Sgblack@eecs.umich.edu 3615736Snate@binkert.org Request::Flags flags = Request::PHYSICAL; 3625736Snate@binkert.org if (cr3.pcd) 3635736Snate@binkert.org flags.set(Request::UNCACHEABLE); 3645736Snate@binkert.org RequestPtr request = new Request(top, size, flags); 3655245Sgblack@eecs.umich.edu read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast); 3665245Sgblack@eecs.umich.edu read->allocate(); 3675245Sgblack@eecs.umich.edu Enums::MemoryMode memMode = sys->getMemoryMode(); 3685245Sgblack@eecs.umich.edu if (memMode == Enums::timing) { 3695897Sgblack@eecs.umich.edu nextState = state; 3705897Sgblack@eecs.umich.edu state = Waiting; 3715895Sgblack@eecs.umich.edu timingFault = NoFault; 3725897Sgblack@eecs.umich.edu sendPackets(); 3735245Sgblack@eecs.umich.edu } else if (memMode == Enums::atomic) { 3745895Sgblack@eecs.umich.edu Fault fault; 3755245Sgblack@eecs.umich.edu do { 3765245Sgblack@eecs.umich.edu port.sendAtomic(read); 3775245Sgblack@eecs.umich.edu PacketPtr write = NULL; 3785897Sgblack@eecs.umich.edu fault = doNext(write); 3795895Sgblack@eecs.umich.edu assert(fault == NoFault || read == NULL); 3805245Sgblack@eecs.umich.edu state = nextState; 3815245Sgblack@eecs.umich.edu nextState = Ready; 3825245Sgblack@eecs.umich.edu if (write) 3835245Sgblack@eecs.umich.edu port.sendAtomic(write); 3845245Sgblack@eecs.umich.edu } while(read); 3855245Sgblack@eecs.umich.edu state = Ready; 3865245Sgblack@eecs.umich.edu nextState = Waiting; 3875895Sgblack@eecs.umich.edu return fault; 3885245Sgblack@eecs.umich.edu } else { 3895245Sgblack@eecs.umich.edu panic("Unrecognized memory system mode.\n"); 3905245Sgblack@eecs.umich.edu } 3915895Sgblack@eecs.umich.edu return NoFault; 3925245Sgblack@eecs.umich.edu} 3935245Sgblack@eecs.umich.edu 3945245Sgblack@eecs.umich.edubool 3955245Sgblack@eecs.umich.eduWalker::WalkerPort::recvTiming(PacketPtr pkt) 3965245Sgblack@eecs.umich.edu{ 3975245Sgblack@eecs.umich.edu return walker->recvTiming(pkt); 3985245Sgblack@eecs.umich.edu} 3995245Sgblack@eecs.umich.edu 4005245Sgblack@eecs.umich.edubool 4015245Sgblack@eecs.umich.eduWalker::recvTiming(PacketPtr pkt) 4025245Sgblack@eecs.umich.edu{ 4035245Sgblack@eecs.umich.edu if (pkt->isResponse() && !pkt->wasNacked()) { 4045897Sgblack@eecs.umich.edu assert(inflight); 4055897Sgblack@eecs.umich.edu assert(state == Waiting); 4065897Sgblack@eecs.umich.edu assert(!read); 4075897Sgblack@eecs.umich.edu inflight--; 4085245Sgblack@eecs.umich.edu if (pkt->isRead()) { 4095245Sgblack@eecs.umich.edu state = nextState; 4105245Sgblack@eecs.umich.edu nextState = Ready; 4115245Sgblack@eecs.umich.edu PacketPtr write = NULL; 4125897Sgblack@eecs.umich.edu read = pkt; 4135897Sgblack@eecs.umich.edu timingFault = doNext(write); 4145245Sgblack@eecs.umich.edu state = Waiting; 4155895Sgblack@eecs.umich.edu assert(timingFault == NoFault || read == NULL); 4165245Sgblack@eecs.umich.edu if (write) { 4175245Sgblack@eecs.umich.edu writes.push_back(write); 4185245Sgblack@eecs.umich.edu } 4195245Sgblack@eecs.umich.edu sendPackets(); 4205245Sgblack@eecs.umich.edu } else { 4215245Sgblack@eecs.umich.edu sendPackets(); 4225245Sgblack@eecs.umich.edu } 4235245Sgblack@eecs.umich.edu if (inflight == 0 && read == NULL && writes.size() == 0) { 4245245Sgblack@eecs.umich.edu state = Ready; 4255245Sgblack@eecs.umich.edu nextState = Waiting; 4265895Sgblack@eecs.umich.edu if (timingFault == NoFault) { 4275895Sgblack@eecs.umich.edu /* 4285895Sgblack@eecs.umich.edu * Finish the translation. Now that we now the right entry is 4295895Sgblack@eecs.umich.edu * in the TLB, this should work with no memory accesses. 4305895Sgblack@eecs.umich.edu * There could be new faults unrelated to the table walk like 4315895Sgblack@eecs.umich.edu * permissions violations, so we'll need the return value as 4325895Sgblack@eecs.umich.edu * well. 4335895Sgblack@eecs.umich.edu */ 4345895Sgblack@eecs.umich.edu bool delayedResponse; 4356023Snate@binkert.org Fault fault = tlb->translate(req, tc, NULL, mode, 4365895Sgblack@eecs.umich.edu delayedResponse, true); 4375895Sgblack@eecs.umich.edu assert(!delayedResponse); 4385895Sgblack@eecs.umich.edu // Let the CPU continue. 4396023Snate@binkert.org translation->finish(fault, req, tc, mode); 4405895Sgblack@eecs.umich.edu } else { 4415895Sgblack@eecs.umich.edu // There was a fault during the walk. Let the CPU know. 4426023Snate@binkert.org translation->finish(timingFault, req, tc, mode); 4435895Sgblack@eecs.umich.edu } 4445245Sgblack@eecs.umich.edu } 4455245Sgblack@eecs.umich.edu } else if (pkt->wasNacked()) { 4465245Sgblack@eecs.umich.edu pkt->reinitNacked(); 4475245Sgblack@eecs.umich.edu if (!port.sendTiming(pkt)) { 4485897Sgblack@eecs.umich.edu inflight--; 4495245Sgblack@eecs.umich.edu retrying = true; 4505245Sgblack@eecs.umich.edu if (pkt->isWrite()) { 4515245Sgblack@eecs.umich.edu writes.push_back(pkt); 4525245Sgblack@eecs.umich.edu } else { 4535245Sgblack@eecs.umich.edu assert(!read); 4545245Sgblack@eecs.umich.edu read = pkt; 4555245Sgblack@eecs.umich.edu } 4565245Sgblack@eecs.umich.edu } 4575245Sgblack@eecs.umich.edu } 4585245Sgblack@eecs.umich.edu return true; 4595245Sgblack@eecs.umich.edu} 4605245Sgblack@eecs.umich.edu 4615245Sgblack@eecs.umich.eduTick 4625245Sgblack@eecs.umich.eduWalker::WalkerPort::recvAtomic(PacketPtr pkt) 4635245Sgblack@eecs.umich.edu{ 4645245Sgblack@eecs.umich.edu return 0; 4655245Sgblack@eecs.umich.edu} 4665245Sgblack@eecs.umich.edu 4675245Sgblack@eecs.umich.eduvoid 4685245Sgblack@eecs.umich.eduWalker::WalkerPort::recvFunctional(PacketPtr pkt) 4695245Sgblack@eecs.umich.edu{ 4705245Sgblack@eecs.umich.edu return; 4715245Sgblack@eecs.umich.edu} 4725245Sgblack@eecs.umich.edu 4735245Sgblack@eecs.umich.eduvoid 4745245Sgblack@eecs.umich.eduWalker::WalkerPort::recvStatusChange(Status status) 4755245Sgblack@eecs.umich.edu{ 4765245Sgblack@eecs.umich.edu if (status == RangeChange) { 4775245Sgblack@eecs.umich.edu if (!snoopRangeSent) { 4785245Sgblack@eecs.umich.edu snoopRangeSent = true; 4795245Sgblack@eecs.umich.edu sendStatusChange(Port::RangeChange); 4805245Sgblack@eecs.umich.edu } 4815245Sgblack@eecs.umich.edu return; 4825245Sgblack@eecs.umich.edu } 4835245Sgblack@eecs.umich.edu 4845245Sgblack@eecs.umich.edu panic("Unexpected recvStatusChange.\n"); 4855245Sgblack@eecs.umich.edu} 4865245Sgblack@eecs.umich.edu 4875245Sgblack@eecs.umich.eduvoid 4885245Sgblack@eecs.umich.eduWalker::WalkerPort::recvRetry() 4895245Sgblack@eecs.umich.edu{ 4905245Sgblack@eecs.umich.edu walker->recvRetry(); 4915245Sgblack@eecs.umich.edu} 4925245Sgblack@eecs.umich.edu 4935245Sgblack@eecs.umich.eduvoid 4945245Sgblack@eecs.umich.eduWalker::recvRetry() 4955245Sgblack@eecs.umich.edu{ 4965245Sgblack@eecs.umich.edu retrying = false; 4975245Sgblack@eecs.umich.edu sendPackets(); 4985245Sgblack@eecs.umich.edu} 4995245Sgblack@eecs.umich.edu 5005245Sgblack@eecs.umich.eduvoid 5015245Sgblack@eecs.umich.eduWalker::sendPackets() 5025245Sgblack@eecs.umich.edu{ 5035245Sgblack@eecs.umich.edu //If we're already waiting for the port to become available, just return. 5045245Sgblack@eecs.umich.edu if (retrying) 5055245Sgblack@eecs.umich.edu return; 5065245Sgblack@eecs.umich.edu 5075245Sgblack@eecs.umich.edu //Reads always have priority 5085245Sgblack@eecs.umich.edu if (read) { 5095897Sgblack@eecs.umich.edu PacketPtr pkt = read; 5105897Sgblack@eecs.umich.edu read = NULL; 5115897Sgblack@eecs.umich.edu inflight++; 5125897Sgblack@eecs.umich.edu if (!port.sendTiming(pkt)) { 5135245Sgblack@eecs.umich.edu retrying = true; 5145897Sgblack@eecs.umich.edu read = pkt; 5155897Sgblack@eecs.umich.edu inflight--; 5165245Sgblack@eecs.umich.edu return; 5175245Sgblack@eecs.umich.edu } 5185245Sgblack@eecs.umich.edu } 5195245Sgblack@eecs.umich.edu //Send off as many of the writes as we can. 5205245Sgblack@eecs.umich.edu while (writes.size()) { 5215245Sgblack@eecs.umich.edu PacketPtr write = writes.back(); 5225897Sgblack@eecs.umich.edu writes.pop_back(); 5235897Sgblack@eecs.umich.edu inflight++; 5245245Sgblack@eecs.umich.edu if (!port.sendTiming(write)) { 5255245Sgblack@eecs.umich.edu retrying = true; 5265897Sgblack@eecs.umich.edu writes.push_back(write); 5275897Sgblack@eecs.umich.edu inflight--; 5285245Sgblack@eecs.umich.edu return; 5295245Sgblack@eecs.umich.edu } 5305245Sgblack@eecs.umich.edu } 5315245Sgblack@eecs.umich.edu} 5325245Sgblack@eecs.umich.edu 5335245Sgblack@eecs.umich.eduPort * 5345245Sgblack@eecs.umich.eduWalker::getPort(const std::string &if_name, int idx) 5355245Sgblack@eecs.umich.edu{ 5365245Sgblack@eecs.umich.edu if (if_name == "port") 5375245Sgblack@eecs.umich.edu return &port; 5385245Sgblack@eecs.umich.edu else 5395245Sgblack@eecs.umich.edu panic("No page table walker port named %s!\n", if_name); 5405245Sgblack@eecs.umich.edu} 5415245Sgblack@eecs.umich.edu 5425895Sgblack@eecs.umich.eduFault 5435895Sgblack@eecs.umich.eduWalker::pageFault(bool present) 5445895Sgblack@eecs.umich.edu{ 5455904Sgblack@eecs.umich.edu DPRINTF(PageTableWalker, "Raising page fault.\n"); 5465895Sgblack@eecs.umich.edu HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG); 5476023Snate@binkert.org if (mode == BaseTLB::Execute && !enableNX) 5486023Snate@binkert.org mode = BaseTLB::Read; 5496023Snate@binkert.org return new PageFault(entry.vaddr, present, mode, m5reg.cpl == 3, false); 5505895Sgblack@eecs.umich.edu} 5515895Sgblack@eecs.umich.edu 5525245Sgblack@eecs.umich.edu} 5535245Sgblack@eecs.umich.edu 5545245Sgblack@eecs.umich.eduX86ISA::Walker * 5555245Sgblack@eecs.umich.eduX86PagetableWalkerParams::create() 5565245Sgblack@eecs.umich.edu{ 5575245Sgblack@eecs.umich.edu return new X86ISA::Walker(this); 5585245Sgblack@eecs.umich.edu} 559