pagetable_walker.cc revision 5881
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, bool _write, bool _execute)
323{
324    assert(state == Ready);
325    assert(!tc);
326    tc = _tc;
327    execute = _execute;
328    write = _write;
329
330    VAddr addr = vaddr;
331
332    //Figure out what we're doing.
333    CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3);
334    Addr top = 0;
335    // Check if we're in long mode or not
336    Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
337    size = 8;
338    if (efer.lma) {
339        // Do long mode.
340        state = LongPML4;
341        top = (cr3.longPdtb << 12) + addr.longl4 * size;
342    } else {
343        // We're in some flavor of legacy mode.
344        CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
345        if (cr4.pae) {
346            // Do legacy PAE.
347            state = PAEPDP;
348            top = (cr3.paePdtb << 5) + addr.pael3 * size;
349        } else {
350            size = 4;
351            top = (cr3.pdtb << 12) + addr.norml2 * size;
352            if (cr4.pse) {
353                // Do legacy PSE.
354                state = PSEPD;
355            } else {
356                // Do legacy non PSE.
357                state = PD;
358            }
359        }
360    }
361
362    nextState = Ready;
363    entry.vaddr = vaddr;
364
365    enableNX = efer.nxe;
366
367    Request::Flags flags = Request::PHYSICAL;
368    if (cr3.pcd)
369        flags.set(Request::UNCACHEABLE);
370    RequestPtr request = new Request(top, size, flags);
371    read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
372    read->allocate();
373    Enums::MemoryMode memMode = sys->getMemoryMode();
374    if (memMode == Enums::timing) {
375        tc->suspend();
376        port.sendTiming(read);
377    } else if (memMode == Enums::atomic) {
378        do {
379            port.sendAtomic(read);
380            PacketPtr write = NULL;
381            doNext(read, write);
382            state = nextState;
383            nextState = Ready;
384            if (write)
385                port.sendAtomic(write);
386        } while(read);
387        tc = NULL;
388        state = Ready;
389        nextState = Waiting;
390    } else {
391        panic("Unrecognized memory system mode.\n");
392    }
393}
394
395bool
396Walker::WalkerPort::recvTiming(PacketPtr pkt)
397{
398    return walker->recvTiming(pkt);
399}
400
401bool
402Walker::recvTiming(PacketPtr pkt)
403{
404    inflight--;
405    if (pkt->isResponse() && !pkt->wasNacked()) {
406        if (pkt->isRead()) {
407            assert(inflight);
408            assert(state == Waiting);
409            assert(!read);
410            state = nextState;
411            nextState = Ready;
412            PacketPtr write = NULL;
413            doNext(pkt, write);
414            state = Waiting;
415            read = pkt;
416            if (write) {
417                writes.push_back(write);
418            }
419            sendPackets();
420        } else {
421            sendPackets();
422        }
423        if (inflight == 0 && read == NULL && writes.size() == 0) {
424            tc->activate(0);
425            tc = NULL;
426            state = Ready;
427            nextState = Waiting;
428        }
429    } else if (pkt->wasNacked()) {
430        pkt->reinitNacked();
431        if (!port.sendTiming(pkt)) {
432            retrying = true;
433            if (pkt->isWrite()) {
434                writes.push_back(pkt);
435            } else {
436                assert(!read);
437                read = pkt;
438            }
439        } else {
440            inflight++;
441        }
442    }
443    return true;
444}
445
446Tick
447Walker::WalkerPort::recvAtomic(PacketPtr pkt)
448{
449    return 0;
450}
451
452void
453Walker::WalkerPort::recvFunctional(PacketPtr pkt)
454{
455    return;
456}
457
458void
459Walker::WalkerPort::recvStatusChange(Status status)
460{
461    if (status == RangeChange) {
462        if (!snoopRangeSent) {
463            snoopRangeSent = true;
464            sendStatusChange(Port::RangeChange);
465        }
466        return;
467    }
468
469    panic("Unexpected recvStatusChange.\n");
470}
471
472void
473Walker::WalkerPort::recvRetry()
474{
475    walker->recvRetry();
476}
477
478void
479Walker::recvRetry()
480{
481    retrying = false;
482    sendPackets();
483}
484
485void
486Walker::sendPackets()
487{
488    //If we're already waiting for the port to become available, just return.
489    if (retrying)
490        return;
491
492    //Reads always have priority
493    if (read) {
494        if (!port.sendTiming(read)) {
495            retrying = true;
496            return;
497        } else {
498            inflight++;
499            delete read->req;
500            delete read;
501            read = NULL;
502        }
503    }
504    //Send off as many of the writes as we can.
505    while (writes.size()) {
506        PacketPtr write = writes.back();
507        if (!port.sendTiming(write)) {
508            retrying = true;
509            return;
510        } else {
511            inflight++;
512            delete write->req;
513            delete write;
514            writes.pop_back();
515        }
516    }
517}
518
519Port *
520Walker::getPort(const std::string &if_name, int idx)
521{
522    if (if_name == "port")
523        return &port;
524    else
525        panic("No page table walker port named %s!\n", if_name);
526}
527
528}
529
530X86ISA::Walker *
531X86PagetableWalkerParams::create()
532{
533    return new X86ISA::Walker(this);
534}
535