pagetable_walker.cc revision 5736:426510e758ad
1/*
2 * Copyright (c) 2007 The Hewlett-Packard Development Company
3 * All rights reserved.
4 *
5 * Redistribution and use of this software in source and binary forms,
6 * with or without modification, are permitted provided that the
7 * following conditions are met:
8 *
9 * The software must be used only for Non-Commercial Use which means any
10 * use which is NOT directed to receiving any direct monetary
11 * compensation for, or commercial advantage from such use.  Illustrative
12 * examples of non-commercial use are academic research, personal study,
13 * teaching, education and corporate research & development.
14 * Illustrative examples of commercial use are distributing products for
15 * commercial advantage and providing services using the software for
16 * commercial advantage.
17 *
18 * If you wish to use this software or functionality therein that may be
19 * covered by patents for commercial use, please contact:
20 *     Director of Intellectual Property Licensing
21 *     Office of Strategy and Technology
22 *     Hewlett-Packard Company
23 *     1501 Page Mill Road
24 *     Palo Alto, California  94304
25 *
26 * Redistributions of source code must retain the above copyright notice,
27 * this list of conditions and the following disclaimer.  Redistributions
28 * in binary form must reproduce the above copyright notice, this list of
29 * conditions and the following disclaimer in the documentation and/or
30 * other materials provided with the distribution.  Neither the name of
31 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
32 * contributors may be used to endorse or promote products derived from
33 * this software without specific prior written permission.  No right of
34 * sublicense is granted herewith.  Derivatives of the software and
35 * output created using the software may be prepared, but only for
36 * Non-Commercial Uses.  Derivatives of the software may be shared with
37 * others provided: (i) the others agree to abide by the list of
38 * conditions herein which includes the Non-Commercial Use restrictions;
39 * and (ii) such Derivatives of the software include the above copyright
40 * notice to acknowledge the contribution from this software where
41 * applicable, this list of conditions and the disclaimer below.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 *
55 * Authors: Gabe Black
56 */
57
58#include "arch/x86/pagetable.hh"
59#include "arch/x86/pagetable_walker.hh"
60#include "arch/x86/tlb.hh"
61#include "base/bitfield.hh"
62#include "cpu/thread_context.hh"
63#include "cpu/base.hh"
64#include "mem/packet_access.hh"
65#include "mem/request.hh"
66#include "sim/system.hh"
67
68namespace X86ISA {
69
70// Unfortunately, the placement of the base field in a page table entry is
71// very erratic and would make a mess here. It might be moved here at some
72// point in the future.
73BitUnion64(PageTableEntry)
74    Bitfield<63> nx;
75    Bitfield<11, 9> avl;
76    Bitfield<8> g;
77    Bitfield<7> ps;
78    Bitfield<6> d;
79    Bitfield<5> a;
80    Bitfield<4> pcd;
81    Bitfield<3> pwt;
82    Bitfield<2> u;
83    Bitfield<1> w;
84    Bitfield<0> p;
85EndBitUnion(PageTableEntry)
86
87void
88Walker::doNext(PacketPtr &read, PacketPtr &write)
89{
90    assert(state != Ready && state != Waiting);
91    write = NULL;
92    PageTableEntry pte;
93    if (size == 8)
94        pte = read->get<uint64_t>();
95    else
96        pte = read->get<uint32_t>();
97    VAddr vaddr = entry.vaddr;
98    bool uncacheable = pte.pcd;
99    Addr nextRead = 0;
100    bool doWrite = false;
101    bool badNX = pte.nx && (!tlb->allowNX() || !enableNX);
102    switch(state) {
103      case LongPML4:
104        nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * size;
105        doWrite = !pte.a;
106        pte.a = 1;
107        entry.writable = pte.w;
108        entry.user = pte.u;
109        if (badNX)
110            panic("NX violation!\n");
111        entry.noExec = pte.nx;
112        if (!pte.p)
113            panic("Page at %#x not present!\n", entry.vaddr);
114        nextState = LongPDP;
115        break;
116      case LongPDP:
117        nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * size;
118        doWrite = !pte.a;
119        pte.a = 1;
120        entry.writable = entry.writable && pte.w;
121        entry.user = entry.user && pte.u;
122        if (badNX)
123            panic("NX violation!\n");
124        if (!pte.p)
125            panic("Page at %#x not present!\n", entry.vaddr);
126        nextState = LongPD;
127        break;
128      case LongPD:
129        doWrite = !pte.a;
130        pte.a = 1;
131        entry.writable = entry.writable && pte.w;
132        entry.user = entry.user && pte.u;
133        if (badNX)
134            panic("NX violation!\n");
135        if (!pte.p)
136            panic("Page at %#x not present!\n", entry.vaddr);
137        if (!pte.ps) {
138            // 4 KB page
139            entry.size = 4 * (1 << 10);
140            nextRead =
141                ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * size;
142            nextState = LongPTE;
143            break;
144        } else {
145            // 2 MB page
146            entry.size = 2 * (1 << 20);
147            entry.paddr = (uint64_t)pte & (mask(31) << 21);
148            entry.uncacheable = uncacheable;
149            entry.global = pte.g;
150            entry.patBit = bits(pte, 12);
151            entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
152            tlb->insert(entry.vaddr, entry);
153            nextState = Ready;
154            delete read->req;
155            delete read;
156            read = NULL;
157            return;
158        }
159      case LongPTE:
160        doWrite = !pte.a;
161        pte.a = 1;
162        entry.writable = entry.writable && pte.w;
163        entry.user = entry.user && pte.u;
164        if (badNX)
165            panic("NX violation!\n");
166        if (!pte.p)
167            panic("Page at %#x not present!\n", entry.vaddr);
168        entry.paddr = (uint64_t)pte & (mask(40) << 12);
169        entry.uncacheable = uncacheable;
170        entry.global = pte.g;
171        entry.patBit = bits(pte, 12);
172        entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
173        tlb->insert(entry.vaddr, entry);
174        nextState = Ready;
175        delete read->req;
176        delete read;
177        read = NULL;
178        return;
179      case PAEPDP:
180        nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size;
181        if (!pte.p)
182            panic("Page at %#x not present!\n", entry.vaddr);
183        nextState = PAEPD;
184        break;
185      case PAEPD:
186        doWrite = !pte.a;
187        pte.a = 1;
188        entry.writable = pte.w;
189        entry.user = pte.u;
190        if (badNX)
191            panic("NX violation!\n");
192        if (!pte.p)
193            panic("Page at %#x not present!\n", entry.vaddr);
194        if (!pte.ps) {
195            // 4 KB page
196            entry.size = 4 * (1 << 10);
197            nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * size;
198            nextState = PAEPTE;
199            break;
200        } else {
201            // 2 MB page
202            entry.size = 2 * (1 << 20);
203            entry.paddr = (uint64_t)pte & (mask(31) << 21);
204            entry.uncacheable = uncacheable;
205            entry.global = pte.g;
206            entry.patBit = bits(pte, 12);
207            entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
208            tlb->insert(entry.vaddr, entry);
209            nextState = Ready;
210            delete read->req;
211            delete read;
212            read = NULL;
213            return;
214        }
215      case PAEPTE:
216        doWrite = !pte.a;
217        pte.a = 1;
218        entry.writable = entry.writable && pte.w;
219        entry.user = entry.user && pte.u;
220        if (badNX)
221            panic("NX violation!\n");
222        if (!pte.p)
223            panic("Page at %#x not present!\n", entry.vaddr);
224        entry.paddr = (uint64_t)pte & (mask(40) << 12);
225        entry.uncacheable = uncacheable;
226        entry.global = pte.g;
227        entry.patBit = bits(pte, 7);
228        entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
229        tlb->insert(entry.vaddr, entry);
230        nextState = Ready;
231        delete read->req;
232        delete read;
233        read = NULL;
234        return;
235      case PSEPD:
236        doWrite = !pte.a;
237        pte.a = 1;
238        entry.writable = pte.w;
239        entry.user = pte.u;
240        if (!pte.p)
241            panic("Page at %#x not present!\n", entry.vaddr);
242        if (!pte.ps) {
243            // 4 KB page
244            entry.size = 4 * (1 << 10);
245            nextRead =
246                ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
247            nextState = PTE;
248            break;
249        } else {
250            // 4 MB page
251            entry.size = 4 * (1 << 20);
252            entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22;
253            entry.uncacheable = uncacheable;
254            entry.global = pte.g;
255            entry.patBit = bits(pte, 12);
256            entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1);
257            tlb->insert(entry.vaddr, entry);
258            nextState = Ready;
259            delete read->req;
260            delete read;
261            read = NULL;
262            return;
263        }
264      case PD:
265        doWrite = !pte.a;
266        pte.a = 1;
267        entry.writable = pte.w;
268        entry.user = pte.u;
269        if (!pte.p)
270            panic("Page at %#x not present!\n", entry.vaddr);
271        // 4 KB page
272        entry.size = 4 * (1 << 10);
273        nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
274        nextState = PTE;
275        break;
276        nextState = PTE;
277        break;
278      case PTE:
279        doWrite = !pte.a;
280        pte.a = 1;
281        entry.writable = pte.w;
282        entry.user = pte.u;
283        if (!pte.p)
284            panic("Page at %#x not present!\n", entry.vaddr);
285        entry.paddr = (uint64_t)pte & (mask(20) << 12);
286        entry.uncacheable = uncacheable;
287        entry.global = pte.g;
288        entry.patBit = bits(pte, 7);
289        entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
290        tlb->insert(entry.vaddr, entry);
291        nextState = Ready;
292        delete read->req;
293        delete read;
294        read = NULL;
295        return;
296      default:
297        panic("Unknown page table walker state %d!\n");
298    }
299    PacketPtr oldRead = read;
300    //If we didn't return, we're setting up another read.
301    Request::Flags flags = oldRead->req->getFlags();
302    flags.set(Request::UNCACHEABLE, uncacheable);
303    RequestPtr request =
304        new Request(nextRead, oldRead->getSize(), flags);
305    read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
306    read->allocate();
307    //If we need to write, adjust the read packet to write the modified value
308    //back to memory.
309    if (doWrite) {
310        write = oldRead;
311        write->set<uint64_t>(pte);
312        write->cmd = MemCmd::WriteReq;
313        write->setDest(Packet::Broadcast);
314    } else {
315        write = NULL;
316        delete oldRead->req;
317        delete oldRead;
318    }
319}
320
321void
322Walker::start(ThreadContext * _tc, Addr vaddr)
323{
324    assert(state == Ready);
325    assert(!tc);
326    tc = _tc;
327
328    VAddr addr = vaddr;
329
330    //Figure out what we're doing.
331    CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3);
332    Addr top = 0;
333    // Check if we're in long mode or not
334    Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
335    size = 8;
336    if (efer.lma) {
337        // Do long mode.
338        state = LongPML4;
339        top = (cr3.longPdtb << 12) + addr.longl4 * size;
340    } else {
341        // We're in some flavor of legacy mode.
342        CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
343        if (cr4.pae) {
344            // Do legacy PAE.
345            state = PAEPDP;
346            top = (cr3.paePdtb << 5) + addr.pael3 * size;
347        } else {
348            size = 4;
349            top = (cr3.pdtb << 12) + addr.norml2 * size;
350            if (cr4.pse) {
351                // Do legacy PSE.
352                state = PSEPD;
353            } else {
354                // Do legacy non PSE.
355                state = PD;
356            }
357        }
358    }
359
360    nextState = Ready;
361    entry.vaddr = vaddr;
362
363    enableNX = efer.nxe;
364
365    Request::Flags flags = Request::PHYSICAL;
366    if (cr3.pcd)
367        flags.set(Request::UNCACHEABLE);
368    RequestPtr request = new Request(top, size, flags);
369    read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
370    read->allocate();
371    Enums::MemoryMode memMode = sys->getMemoryMode();
372    if (memMode == Enums::timing) {
373        tc->suspend();
374        port.sendTiming(read);
375    } else if (memMode == Enums::atomic) {
376        do {
377            port.sendAtomic(read);
378            PacketPtr write = NULL;
379            doNext(read, write);
380            state = nextState;
381            nextState = Ready;
382            if (write)
383                port.sendAtomic(write);
384        } while(read);
385        tc = NULL;
386        state = Ready;
387        nextState = Waiting;
388    } else {
389        panic("Unrecognized memory system mode.\n");
390    }
391}
392
393bool
394Walker::WalkerPort::recvTiming(PacketPtr pkt)
395{
396    return walker->recvTiming(pkt);
397}
398
399bool
400Walker::recvTiming(PacketPtr pkt)
401{
402    inflight--;
403    if (pkt->isResponse() && !pkt->wasNacked()) {
404        if (pkt->isRead()) {
405            assert(inflight);
406            assert(state == Waiting);
407            assert(!read);
408            state = nextState;
409            nextState = Ready;
410            PacketPtr write = NULL;
411            doNext(pkt, write);
412            state = Waiting;
413            read = pkt;
414            if (write) {
415                writes.push_back(write);
416            }
417            sendPackets();
418        } else {
419            sendPackets();
420        }
421        if (inflight == 0 && read == NULL && writes.size() == 0) {
422            tc->activate(0);
423            tc = NULL;
424            state = Ready;
425            nextState = Waiting;
426        }
427    } else if (pkt->wasNacked()) {
428        pkt->reinitNacked();
429        if (!port.sendTiming(pkt)) {
430            retrying = true;
431            if (pkt->isWrite()) {
432                writes.push_back(pkt);
433            } else {
434                assert(!read);
435                read = pkt;
436            }
437        } else {
438            inflight++;
439        }
440    }
441    return true;
442}
443
444Tick
445Walker::WalkerPort::recvAtomic(PacketPtr pkt)
446{
447    return 0;
448}
449
450void
451Walker::WalkerPort::recvFunctional(PacketPtr pkt)
452{
453    return;
454}
455
456void
457Walker::WalkerPort::recvStatusChange(Status status)
458{
459    if (status == RangeChange) {
460        if (!snoopRangeSent) {
461            snoopRangeSent = true;
462            sendStatusChange(Port::RangeChange);
463        }
464        return;
465    }
466
467    panic("Unexpected recvStatusChange.\n");
468}
469
470void
471Walker::WalkerPort::recvRetry()
472{
473    walker->recvRetry();
474}
475
476void
477Walker::recvRetry()
478{
479    retrying = false;
480    sendPackets();
481}
482
483void
484Walker::sendPackets()
485{
486    //If we're already waiting for the port to become available, just return.
487    if (retrying)
488        return;
489
490    //Reads always have priority
491    if (read) {
492        if (!port.sendTiming(read)) {
493            retrying = true;
494            return;
495        } else {
496            inflight++;
497            delete read->req;
498            delete read;
499            read = NULL;
500        }
501    }
502    //Send off as many of the writes as we can.
503    while (writes.size()) {
504        PacketPtr write = writes.back();
505        if (!port.sendTiming(write)) {
506            retrying = true;
507            return;
508        } else {
509            inflight++;
510            delete write->req;
511            delete write;
512            writes.pop_back();
513        }
514    }
515}
516
517Port *
518Walker::getPort(const std::string &if_name, int idx)
519{
520    if (if_name == "port")
521        return &port;
522    else
523        panic("No page table walker port named %s!\n", if_name);
524}
525
526}
527
528X86ISA::Walker *
529X86PagetableWalkerParams::create()
530{
531    return new X86ISA::Walker(this);
532}
533