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