table_walker.cc revision 7823:dac01f14f20f
1/*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Ali Saidi
38 */
39
40#include "arch/arm/faults.hh"
41#include "arch/arm/table_walker.hh"
42#include "arch/arm/tlb.hh"
43#include "dev/io_device.hh"
44#include "cpu/base.hh"
45#include "cpu/thread_context.hh"
46#include "sim/system.hh"
47
48using namespace ArmISA;
49
50TableWalker::TableWalker(const Params *p)
51    : MemObject(p), port(NULL), tlb(NULL), currState(NULL), pending(false),
52      doL1DescEvent(this), doL2DescEvent(this), doProcessEvent(this)
53{
54    sctlr = 0;
55}
56
57TableWalker::~TableWalker()
58{
59    ;
60}
61
62
63unsigned int
64TableWalker::drain(Event *de)
65{
66    if (stateQueueL1.size() || stateQueueL2.size() || pendingQueue.size())
67    {
68        changeState(Draining);
69        DPRINTF(Checkpoint, "TableWalker busy, wait to drain\n");
70        return 1;
71    }
72    else
73    {
74        changeState(Drained);
75        DPRINTF(Checkpoint, "TableWalker free, no need to drain\n");
76        return 0;
77    }
78}
79
80void
81TableWalker::resume()
82{
83    MemObject::resume();
84    if ((params()->sys->getMemoryMode() == Enums::timing) && currState) {
85            delete currState;
86            currState = NULL;
87    }
88}
89
90Port*
91TableWalker::getPort(const std::string &if_name, int idx)
92{
93    if (if_name == "port") {
94        if (port != NULL)
95            return port;
96        System *sys = params()->sys;
97        Tick minb = params()->min_backoff;
98        Tick maxb = params()->max_backoff;
99        port = new DmaPort(this, sys, minb, maxb);
100        return port;
101    }
102    return NULL;
103}
104
105Fault
106TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _mode,
107            TLB::Translation *_trans, bool _timing)
108{
109    if (!currState) {
110        // For atomic mode, a new WalkerState instance should be only created
111        // once per TLB. For timing mode, a new instance is generated for every
112        // TLB miss.
113        DPRINTF(TLBVerbose, "creating new instance of WalkerState\n");
114
115        currState = new WalkerState();
116        currState->tableWalker = this;
117    }
118    else if (_timing) {
119        panic("currState should always be empty in timing mode!\n");
120    }
121
122    currState->tc = _tc;
123    currState->transState = _trans;
124    currState->req = _req;
125    currState->fault = NoFault;
126    currState->contextId = _cid;
127    currState->timing = _timing;
128    currState->mode = _mode;
129
130    /** @todo These should be cached or grabbed from cached copies in
131     the TLB, all these miscreg reads are expensive */
132    currState->vaddr = currState->req->getVaddr();
133    currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR);
134    sctlr = currState->sctlr;
135    currState->N = currState->tc->readMiscReg(MISCREG_TTBCR);
136
137    currState->isFetch = (currState->mode == TLB::Execute);
138    currState->isWrite = (currState->mode == TLB::Write);
139
140
141    if (!currState->timing)
142        return processWalk();
143
144    if (pending) {
145        pendingQueue.push_back(currState);
146        currState = NULL;
147    } else {
148        pending = true;
149        processWalk();
150    }
151
152    return NoFault;
153}
154
155void
156TableWalker::processWalkWrapper()
157{
158    assert(!currState);
159    assert(pendingQueue.size());
160    currState = pendingQueue.front();
161    pendingQueue.pop_front();
162    pending = true;
163    processWalk();
164}
165
166Fault
167TableWalker::processWalk()
168{
169    Addr ttbr = 0;
170
171    // If translation isn't enabled, we shouldn't be here
172    assert(currState->sctlr.m);
173
174    DPRINTF(TLB, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n",
175            currState->vaddr, currState->N, mbits(currState->vaddr, 31,
176            32-currState->N));
177
178    if (currState->N == 0 || !mbits(currState->vaddr, 31, 32-currState->N)) {
179        DPRINTF(TLB, " - Selecting TTBR0\n");
180        ttbr = currState->tc->readMiscReg(MISCREG_TTBR0);
181    } else {
182        DPRINTF(TLB, " - Selecting TTBR1\n");
183        ttbr = currState->tc->readMiscReg(MISCREG_TTBR1);
184        currState->N = 0;
185    }
186
187    Addr l1desc_addr = mbits(ttbr, 31, 14-currState->N) |
188                       (bits(currState->vaddr,31-currState->N,20) << 2);
189    DPRINTF(TLB, " - Descriptor at address %#x\n", l1desc_addr);
190
191
192    // Trickbox address check
193    Fault f;
194    f = tlb->walkTrickBoxCheck(l1desc_addr, currState->vaddr, sizeof(uint32_t),
195            currState->isFetch, currState->isWrite, 0, true);
196    if (f) {
197        if (currState->timing) {
198            currState->transState->finish(f, currState->req,
199                                          currState->tc, currState->mode);
200
201            pending = false;
202            nextWalk(currState->tc);
203            currState = NULL;
204        } else {
205            currState->tc = NULL;
206            currState->req = NULL;
207        }
208        return f;
209    }
210
211    if (currState->timing) {
212        port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
213                &doL1DescEvent, (uint8_t*)&currState->l1Desc.data,
214                currState->tc->getCpuPtr()->ticks(1));
215        DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n",
216                stateQueueL1.size());
217        stateQueueL1.push_back(currState);
218        currState = NULL;
219    } else {
220        Request::Flags flag = 0;
221        if (currState->sctlr.c == 0){
222           flag = Request::UNCACHEABLE;
223        }
224        port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
225                NULL, (uint8_t*)&currState->l1Desc.data,
226                currState->tc->getCpuPtr()->ticks(1), flag);
227        doL1Descriptor();
228        f = currState->fault;
229    }
230
231    return f;
232}
233
234void
235TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr,
236                      uint8_t texcb, bool s)
237{
238    // Note: tc and sctlr local variables are hiding tc and sctrl class
239    // variables
240    DPRINTF(TLBVerbose, "memAttrs texcb:%d s:%d\n", texcb, s);
241    te.shareable = false; // default value
242    te.nonCacheable = false;
243    bool outer_shareable = false;
244    if (sctlr.tre == 0 || ((sctlr.tre == 1) && (sctlr.m == 0))) {
245        switch(texcb) {
246          case 0: // Stongly-ordered
247            te.nonCacheable = true;
248            te.mtype = TlbEntry::StronglyOrdered;
249            te.shareable = true;
250            te.innerAttrs = 1;
251            te.outerAttrs = 0;
252            break;
253          case 1: // Shareable Device
254            te.nonCacheable = true;
255            te.mtype = TlbEntry::Device;
256            te.shareable = true;
257            te.innerAttrs = 3;
258            te.outerAttrs = 0;
259            break;
260          case 2: // Outer and Inner Write-Through, no Write-Allocate
261            te.mtype = TlbEntry::Normal;
262            te.shareable = s;
263            te.innerAttrs = 6;
264            te.outerAttrs = bits(texcb, 1, 0);
265            break;
266          case 3: // Outer and Inner Write-Back, no Write-Allocate
267            te.mtype = TlbEntry::Normal;
268            te.shareable = s;
269            te.innerAttrs = 7;
270            te.outerAttrs = bits(texcb, 1, 0);
271            break;
272          case 4: // Outer and Inner Non-cacheable
273            te.nonCacheable = true;
274            te.mtype = TlbEntry::Normal;
275            te.shareable = s;
276            te.innerAttrs = 0;
277            te.outerAttrs = bits(texcb, 1, 0);
278            break;
279          case 5: // Reserved
280            panic("Reserved texcb value!\n");
281            break;
282          case 6: // Implementation Defined
283            panic("Implementation-defined texcb value!\n");
284            break;
285          case 7: // Outer and Inner Write-Back, Write-Allocate
286            te.mtype = TlbEntry::Normal;
287            te.shareable = s;
288            te.innerAttrs = 5;
289            te.outerAttrs = 1;
290            break;
291          case 8: // Non-shareable Device
292            te.nonCacheable = true;
293            te.mtype = TlbEntry::Device;
294            te.shareable = false;
295            te.innerAttrs = 3;
296            te.outerAttrs = 0;
297            break;
298          case 9 ... 15:  // Reserved
299            panic("Reserved texcb value!\n");
300            break;
301          case 16 ... 31: // Cacheable Memory
302            te.mtype = TlbEntry::Normal;
303            te.shareable = s;
304            if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0)
305                te.nonCacheable = true;
306            te.innerAttrs = bits(texcb, 1, 0);
307            te.outerAttrs = bits(texcb, 3, 2);
308            break;
309          default:
310            panic("More than 32 states for 5 bits?\n");
311        }
312    } else {
313        assert(tc);
314        PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
315        NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
316        DPRINTF(TLBVerbose, "memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr);
317        uint8_t curr_tr = 0, curr_ir = 0, curr_or = 0;
318        switch(bits(texcb, 2,0)) {
319          case 0:
320            curr_tr = prrr.tr0;
321            curr_ir = nmrr.ir0;
322            curr_or = nmrr.or0;
323            outer_shareable = (prrr.nos0 == 0);
324            break;
325          case 1:
326            curr_tr = prrr.tr1;
327            curr_ir = nmrr.ir1;
328            curr_or = nmrr.or1;
329            outer_shareable = (prrr.nos1 == 0);
330            break;
331          case 2:
332            curr_tr = prrr.tr2;
333            curr_ir = nmrr.ir2;
334            curr_or = nmrr.or2;
335            outer_shareable = (prrr.nos2 == 0);
336            break;
337          case 3:
338            curr_tr = prrr.tr3;
339            curr_ir = nmrr.ir3;
340            curr_or = nmrr.or3;
341            outer_shareable = (prrr.nos3 == 0);
342            break;
343          case 4:
344            curr_tr = prrr.tr4;
345            curr_ir = nmrr.ir4;
346            curr_or = nmrr.or4;
347            outer_shareable = (prrr.nos4 == 0);
348            break;
349          case 5:
350            curr_tr = prrr.tr5;
351            curr_ir = nmrr.ir5;
352            curr_or = nmrr.or5;
353            outer_shareable = (prrr.nos5 == 0);
354            break;
355          case 6:
356            panic("Imp defined type\n");
357          case 7:
358            curr_tr = prrr.tr7;
359            curr_ir = nmrr.ir7;
360            curr_or = nmrr.or7;
361            outer_shareable = (prrr.nos7 == 0);
362            break;
363        }
364
365        switch(curr_tr) {
366          case 0:
367            DPRINTF(TLBVerbose, "StronglyOrdered\n");
368            te.mtype = TlbEntry::StronglyOrdered;
369            te.nonCacheable = true;
370            te.innerAttrs = 1;
371            te.outerAttrs = 0;
372            te.shareable = true;
373            break;
374          case 1:
375            DPRINTF(TLBVerbose, "Device ds1:%d ds0:%d s:%d\n",
376                    prrr.ds1, prrr.ds0, s);
377            te.mtype = TlbEntry::Device;
378            te.nonCacheable = true;
379            te.innerAttrs = 3;
380            te.outerAttrs = 0;
381            if (prrr.ds1 && s)
382                te.shareable = true;
383            if (prrr.ds0 && !s)
384                te.shareable = true;
385            break;
386          case 2:
387            DPRINTF(TLBVerbose, "Normal ns1:%d ns0:%d s:%d\n",
388                    prrr.ns1, prrr.ns0, s);
389            te.mtype = TlbEntry::Normal;
390            if (prrr.ns1 && s)
391                te.shareable = true;
392            if (prrr.ns0 && !s)
393                te.shareable = true;
394            break;
395          case 3:
396            panic("Reserved type");
397        }
398
399        if (te.mtype == TlbEntry::Normal){
400            switch(curr_ir) {
401              case 0:
402                te.nonCacheable = true;
403                te.innerAttrs = 0;
404                break;
405              case 1:
406                te.innerAttrs = 5;
407                break;
408              case 2:
409                te.innerAttrs = 6;
410                break;
411              case 3:
412                te.innerAttrs = 7;
413                break;
414            }
415
416            switch(curr_or) {
417              case 0:
418                te.nonCacheable = true;
419                te.outerAttrs = 0;
420                break;
421              case 1:
422                te.outerAttrs = 1;
423                break;
424              case 2:
425                te.outerAttrs = 2;
426                break;
427              case 3:
428                te.outerAttrs = 3;
429                break;
430            }
431        }
432    }
433    DPRINTF(TLBVerbose, "memAttrs: shareable: %d, innerAttrs: %d, \
434            outerAttrs: %d\n",
435            te.shareable, te.innerAttrs, te.outerAttrs);
436
437    /** Formatting for Physical Address Register (PAR)
438     *  Only including lower bits (TLB info here)
439     *  PAR:
440     *  PA [31:12]
441     *  Reserved [11]
442     *  TLB info [10:1]
443     *      NOS  [10] (Not Outer Sharable)
444     *      NS   [9]  (Non-Secure)
445     *      --   [8]  (Implementation Defined)
446     *      SH   [7]  (Sharable)
447     *      Inner[6:4](Inner memory attributes)
448     *      Outer[3:2](Outer memory attributes)
449     *      SS   [1]  (SuperSection)
450     *      F    [0]  (Fault, Fault Status in [6:1] if faulted)
451     */
452    te.attributes = (
453                ((outer_shareable ? 0:1) << 10) |
454                // TODO: NS Bit
455                ((te.shareable ? 1:0) << 7) |
456                (te.innerAttrs << 4) |
457                (te.outerAttrs << 2)
458                // TODO: Supersection bit
459                // TODO: Fault bit
460                );
461
462
463}
464
465void
466TableWalker::doL1Descriptor()
467{
468    DPRINTF(TLB, "L1 descriptor for %#x is %#x\n",
469            currState->vaddr, currState->l1Desc.data);
470    TlbEntry te;
471
472    switch (currState->l1Desc.type()) {
473      case L1Descriptor::Ignore:
474      case L1Descriptor::Reserved:
475        if (!currState->delayed) {
476            currState->tc = NULL;
477            currState->req = NULL;
478        }
479        DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n");
480        if (currState->isFetch)
481            currState->fault =
482                new PrefetchAbort(currState->vaddr, ArmFault::Translation0);
483        else
484            currState->fault =
485                new DataAbort(currState->vaddr, 0, currState->isWrite,
486                                  ArmFault::Translation0);
487        return;
488      case L1Descriptor::Section:
489        if (currState->sctlr.afe && bits(currState->l1Desc.ap(), 0) == 0) {
490            /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is
491              * enabled if set, do l1.Desc.setAp0() instead of generating
492              * AccessFlag0
493              */
494
495            currState->fault = new DataAbort(currState->vaddr,
496                                    currState->l1Desc.domain(), currState->isWrite,
497                                    ArmFault::AccessFlag0);
498        }
499        if (currState->l1Desc.supersection()) {
500            panic("Haven't implemented supersections\n");
501        }
502        te.N = 20;
503        te.pfn = currState->l1Desc.pfn();
504        te.size = (1<<te.N) - 1;
505        te.global = !currState->l1Desc.global();
506        te.valid = true;
507        te.vpn = currState->vaddr >> te.N;
508        te.sNp = true;
509        te.xn = currState->l1Desc.xn();
510        te.ap = currState->l1Desc.ap();
511        te.domain = currState->l1Desc.domain();
512        te.asid = currState->contextId;
513        memAttrs(currState->tc, te, currState->sctlr,
514                currState->l1Desc.texcb(), currState->l1Desc.shareable());
515
516        DPRINTF(TLB, "Inserting Section Descriptor into TLB\n");
517        DPRINTF(TLB, " - N:%d pfn:%#x size: %#x global:%d valid: %d\n",
518                te.N, te.pfn, te.size, te.global, te.valid);
519        DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d nc:%d\n",
520                te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid,
521                te.nonCacheable);
522        DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n",
523                currState->l1Desc.domain(), currState->l1Desc.data,
524                (currState->l1Desc.data >> 5) & 0xF );
525
526        if (!currState->timing) {
527            currState->tc = NULL;
528            currState->req = NULL;
529        }
530        tlb->insert(currState->vaddr, te);
531
532        return;
533      case L1Descriptor::PageTable:
534        Addr l2desc_addr;
535        l2desc_addr = currState->l1Desc.l2Addr() |
536                      (bits(currState->vaddr, 19,12) << 2);
537        DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n",
538                l2desc_addr);
539
540        // Trickbox address check
541        currState->fault = tlb->walkTrickBoxCheck(l2desc_addr, currState->vaddr,
542                sizeof(uint32_t), currState->isFetch, currState->isWrite,
543                currState->l1Desc.domain(), false);
544
545        if (currState->fault) {
546            if (!currState->timing) {
547                currState->tc = NULL;
548                currState->req = NULL;
549            }
550            return;
551        }
552
553
554        if (currState->timing) {
555            currState->delayed = true;
556            port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
557                    &doL2DescEvent, (uint8_t*)&currState->l2Desc.data,
558                    currState->tc->getCpuPtr()->ticks(1));
559        } else {
560            port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
561                    NULL, (uint8_t*)&currState->l2Desc.data,
562                    currState->tc->getCpuPtr()->ticks(1));
563            doL2Descriptor();
564        }
565        return;
566      default:
567        panic("A new type in a 2 bit field?\n");
568    }
569}
570
571void
572TableWalker::doL2Descriptor()
573{
574    DPRINTF(TLB, "L2 descriptor for %#x is %#x\n",
575            currState->vaddr, currState->l2Desc.data);
576    TlbEntry te;
577
578    if (currState->l2Desc.invalid()) {
579        DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
580        if (!currState->delayed) {
581            currState->tc = NULL;
582            currState->req = NULL;
583        }
584        if (currState->isFetch)
585            currState->fault =
586                new PrefetchAbort(currState->vaddr, ArmFault::Translation1);
587        else
588            currState->fault =
589                new DataAbort(currState->vaddr, currState->l1Desc.domain(),
590                              currState->isWrite, ArmFault::Translation1);
591        return;
592    }
593
594    if (currState->sctlr.afe && bits(currState->l2Desc.ap(), 0) == 0) {
595        /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled
596          * if set, do l2.Desc.setAp0() instead of generating AccessFlag0
597          */
598
599        currState->fault =
600            new DataAbort(currState->vaddr, 0, currState->isWrite,
601                          ArmFault::AccessFlag1);
602
603    }
604
605    if (currState->l2Desc.large()) {
606      te.N = 16;
607      te.pfn = currState->l2Desc.pfn();
608    } else {
609      te.N = 12;
610      te.pfn = currState->l2Desc.pfn();
611    }
612
613    te.valid = true;
614    te.size =  (1 << te.N) - 1;
615    te.asid = currState->contextId;
616    te.sNp = false;
617    te.vpn = currState->vaddr >> te.N;
618    te.global = currState->l2Desc.global();
619    te.xn = currState->l2Desc.xn();
620    te.ap = currState->l2Desc.ap();
621    te.domain = currState->l1Desc.domain();
622    memAttrs(currState->tc, te, currState->sctlr, currState->l2Desc.texcb(),
623             currState->l2Desc.shareable());
624
625    if (!currState->delayed) {
626        currState->tc = NULL;
627        currState->req = NULL;
628    }
629    tlb->insert(currState->vaddr, te);
630}
631
632void
633TableWalker::doL1DescriptorWrapper()
634{
635    currState = stateQueueL1.front();
636    currState->delayed = false;
637
638    DPRINTF(TLBVerbose, "L1 Desc object host addr: %p\n",&currState->l1Desc.data);
639    DPRINTF(TLBVerbose, "L1 Desc object      data: %08x\n",currState->l1Desc.data);
640
641    DPRINTF(TLBVerbose, "calling doL1Descriptor for vaddr:%#x\n", currState->vaddr);
642    doL1Descriptor();
643
644    stateQueueL1.pop_front();
645    // Check if fault was generated
646    if (currState->fault != NoFault) {
647        currState->transState->finish(currState->fault, currState->req,
648                                      currState->tc, currState->mode);
649
650        pending = false;
651        nextWalk(currState->tc);
652
653        currState->req = NULL;
654        currState->tc = NULL;
655        currState->delayed = false;
656
657    }
658    else if (!currState->delayed) {
659        // delay is not set so there is no L2 to do
660        DPRINTF(TLBVerbose, "calling translateTiming again\n");
661        currState->fault = tlb->translateTiming(currState->req, currState->tc,
662                                       currState->transState, currState->mode);
663
664        pending = false;
665        nextWalk(currState->tc);
666
667        currState->req = NULL;
668        currState->tc = NULL;
669        currState->delayed = false;
670        delete currState;
671    } else {
672        // need to do L2 descriptor
673        stateQueueL2.push_back(currState);
674    }
675    currState = NULL;
676}
677
678void
679TableWalker::doL2DescriptorWrapper()
680{
681    currState = stateQueueL2.front();
682    assert(currState->delayed);
683
684    DPRINTF(TLBVerbose, "calling doL2Descriptor for vaddr:%#x\n",
685            currState->vaddr);
686    doL2Descriptor();
687
688    // Check if fault was generated
689    if (currState->fault != NoFault) {
690        currState->transState->finish(currState->fault, currState->req,
691                                      currState->tc, currState->mode);
692    }
693    else {
694        DPRINTF(TLBVerbose, "calling translateTiming again\n");
695        currState->fault = tlb->translateTiming(currState->req, currState->tc,
696                                      currState->transState, currState->mode);
697    }
698
699
700    stateQueueL2.pop_front();
701    pending = false;
702    nextWalk(currState->tc);
703
704    currState->req = NULL;
705    currState->tc = NULL;
706    currState->delayed = false;
707
708    delete currState;
709    currState = NULL;
710}
711
712void
713TableWalker::nextWalk(ThreadContext *tc)
714{
715    if (pendingQueue.size())
716        schedule(doProcessEvent, tc->getCpuPtr()->nextCycle(curTick()+1));
717}
718
719
720
721ArmISA::TableWalker *
722ArmTableWalkerParams::create()
723{
724    return new ArmISA::TableWalker(this);
725}
726
727