table_walker.cc revision 7438
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/thread_context.hh"
45
46
47using namespace ArmISA;
48
49TableWalker::TableWalker(const Params *p)
50    : MemObject(p), port(NULL), tlb(NULL), tc(NULL), req(NULL),
51      doL1DescEvent(this), doL2DescEvent(this)
52{}
53
54TableWalker::~TableWalker()
55{
56    ;
57}
58
59
60unsigned int
61drain(Event *de)
62{
63    panic("Not implemented\n");
64}
65
66Port*
67TableWalker::getPort(const std::string &if_name, int idx)
68{
69    if (if_name == "port") {
70        if (port != NULL)
71            fatal("%s: port already connected to %s",
72                  name(), port->getPeer()->name());
73        System *sys = params()->sys;
74        Tick minb = params()->min_backoff;
75        Tick maxb = params()->max_backoff;
76        port = new DmaPort(this, sys, minb, maxb);
77        return port;
78    }
79    return NULL;
80}
81
82Fault
83TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _mode,
84            TLB::Translation *_trans, bool _timing)
85{
86    // Right now 1 CPU == 1 TLB == 1 TLB walker
87    // In the future we might want to change this as multiple
88    // threads/contexts could share a walker and/or a TLB
89    if (tc || req)
90        panic("Overlapping TLB walks attempted\n");
91
92    tc = _tc;
93    transState = _trans;
94    req = _req;
95    fault = NoFault;
96    contextId = _cid;
97    timing = _timing;
98    mode = _mode;
99
100    /** @todo These should be cached or grabbed from cached copies in
101     the TLB, all these miscreg reads are expensive */
102    vaddr = req->getVaddr() & ~PcModeMask;
103    sctlr = tc->readMiscReg(MISCREG_SCTLR);
104    cpsr = tc->readMiscReg(MISCREG_CPSR);
105    N = tc->readMiscReg(MISCREG_TTBCR);
106    Addr ttbr = 0;
107
108    isFetch = (mode == TLB::Execute);
109    isWrite = (mode == TLB::Write);
110    isPriv = (cpsr.mode != MODE_USER);
111
112    // If translation isn't enabled, we shouldn't be here
113    assert(sctlr.m);
114
115    DPRINTF(TLB, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n",
116            vaddr, N, mbits(vaddr, 31, 32-N));
117
118    if (N == 0 || !mbits(vaddr, 31, 32-N)) {
119        DPRINTF(TLB, " - Selecting TTBR0\n");
120        ttbr = tc->readMiscReg(MISCREG_TTBR0);
121    } else {
122        DPRINTF(TLB, " - Selecting TTBR1\n");
123        ttbr = tc->readMiscReg(MISCREG_TTBR1);
124        N = 0;
125    }
126
127    Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(vaddr,31-N,20) << 2);
128    DPRINTF(TLB, " - Descriptor at address %#x\n", l1desc_addr);
129
130
131    // Trickbox address check
132    fault = tlb->walkTrickBoxCheck(l1desc_addr, vaddr, sizeof(uint32_t),
133            isFetch, isWrite, 0, true);
134    if (fault) {
135       tc = NULL;
136       req = NULL;
137       return fault;
138    }
139
140    if (timing) {
141        port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
142                &doL1DescEvent, (uint8_t*)&l1Desc.data, (Tick)0);
143    } else {
144        port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
145                NULL, (uint8_t*)&l1Desc.data, (Tick)0);
146        doL1Descriptor();
147    }
148
149    return fault;
150}
151
152void
153TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, uint8_t texcb, bool s)
154{
155    // Note: tc local variable is hiding tc class variable
156    DPRINTF(TLBVerbose, "memAttrs texcb:%d s:%d\n", texcb, s);
157    te.shareable = false; // default value
158    bool outer_shareable = false;
159    if (sctlr.tre == 0) {
160        switch(texcb) {
161          case 0: // Stongly-ordered
162            te.nonCacheable = true;
163            te.mtype = TlbEntry::StronglyOrdered;
164            te.shareable = true;
165            te.innerAttrs = 1;
166            te.outerAttrs = 0;
167            break;
168          case 1: // Shareable Device
169            te.nonCacheable = true;
170            te.mtype = TlbEntry::Device;
171            te.shareable = true;
172            te.innerAttrs = 3;
173            te.outerAttrs = 0;
174            break;
175          case 2: // Outer and Inner Write-Through, no Write-Allocate
176            te.mtype = TlbEntry::Normal;
177            te.shareable = s;
178            te.innerAttrs = 6;
179            te.outerAttrs = bits(texcb, 1, 0);
180            break;
181          case 3: // Outer and Inner Write-Back, no Write-Allocate
182            te.mtype = TlbEntry::Normal;
183            te.shareable = s;
184            te.innerAttrs = 7;
185            te.outerAttrs = bits(texcb, 1, 0);
186            break;
187          case 4: // Outer and Inner Non-cacheable
188            te.nonCacheable = true;
189            te.mtype = TlbEntry::Normal;
190            te.shareable = s;
191            te.innerAttrs = 0;
192            te.outerAttrs = bits(texcb, 1, 0);
193            break;
194          case 5: // Reserved
195            break;
196          case 6: // Implementation Defined
197            break;
198          case 7: // Outer and Inner Write-Back, Write-Allocate
199            te.mtype = TlbEntry::Normal;
200            te.shareable = s;
201            te.innerAttrs = 5;
202            te.outerAttrs = 1;
203            break;
204          case 8: // Non-shareable Device
205            te.nonCacheable = true;
206            te.mtype = TlbEntry::Device;
207            te.shareable = false;
208            te.innerAttrs = 3;
209            te.outerAttrs = 0;
210            break;
211          case 9 ... 15:  // Reserved
212            break;
213          case 16 ... 31: // Cacheable Memory
214            te.mtype = TlbEntry::Normal;
215            te.shareable = s;
216            if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0)
217                te.nonCacheable = true;
218            te.innerAttrs = bits(texcb, 1, 0);
219            te.outerAttrs = bits(texcb, 3, 2);
220            break;
221          default:
222            panic("More than 32 states for 5 bits?\n");
223        }
224    } else {
225        assert(tc);
226        PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
227        NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
228        DPRINTF(TLBVerbose, "memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr);
229        uint8_t curr_tr, curr_ir, curr_or;
230        switch(bits(texcb, 2,0)) {
231          case 0:
232            curr_tr = prrr.tr0;
233            curr_ir = nmrr.ir0;
234            curr_or = nmrr.or0;
235            outer_shareable = (prrr.nos0 == 0);
236            break;
237          case 1:
238            curr_tr = prrr.tr1;
239            curr_ir = nmrr.ir1;
240            curr_or = nmrr.or1;
241            outer_shareable = (prrr.nos1 == 0);
242            break;
243          case 2:
244            curr_tr = prrr.tr2;
245            curr_ir = nmrr.ir2;
246            curr_or = nmrr.or2;
247            outer_shareable = (prrr.nos2 == 0);
248            break;
249          case 3:
250            curr_tr = prrr.tr3;
251            curr_ir = nmrr.ir3;
252            curr_or = nmrr.or3;
253            outer_shareable = (prrr.nos3 == 0);
254            break;
255          case 4:
256            curr_tr = prrr.tr4;
257            curr_ir = nmrr.ir4;
258            curr_or = nmrr.or4;
259            outer_shareable = (prrr.nos4 == 0);
260            break;
261          case 5:
262            curr_tr = prrr.tr5;
263            curr_ir = nmrr.ir5;
264            curr_or = nmrr.or5;
265            outer_shareable = (prrr.nos5 == 0);
266            break;
267          case 6:
268            panic("Imp defined type\n");
269          case 7:
270            curr_tr = prrr.tr7;
271            curr_ir = nmrr.ir7;
272            curr_or = nmrr.or7;
273            outer_shareable = (prrr.nos7 == 0);
274            break;
275        }
276
277        switch(curr_tr) {
278          case 0:
279            DPRINTF(TLBVerbose, "StronglyOrdered\n");
280            te.mtype = TlbEntry::StronglyOrdered;
281            te.nonCacheable = true;
282            te.innerAttrs = 1;
283            te.outerAttrs = 0;
284            te.shareable = true;
285            break;
286          case 1:
287            DPRINTF(TLBVerbose, "Device ds1:%d ds0:%d s:%d\n",
288                    prrr.ds1, prrr.ds0, s);
289            te.mtype = TlbEntry::Device;
290            te.nonCacheable = true;
291            te.innerAttrs = 3;
292            te.outerAttrs = 0;
293            if (prrr.ds1 && s)
294                te.shareable = true;
295            if (prrr.ds0 && !s)
296                te.shareable = true;
297            break;
298          case 2:
299            DPRINTF(TLBVerbose, "Normal ns1:%d ns0:%d s:%d\n",
300                    prrr.ns1, prrr.ns0, s);
301            te.mtype = TlbEntry::Normal;
302            if (prrr.ns1 && s)
303                te.shareable = true;
304            if (prrr.ns0 && !s)
305                te.shareable = true;
306            //te.shareable = outer_shareable;
307            break;
308          case 3:
309            panic("Reserved type");
310        }
311
312        if (te.mtype == TlbEntry::Normal){
313            switch(curr_ir) {
314              case 0:
315                te.nonCacheable = true;
316                te.innerAttrs = 0;
317                break;
318              case 1:
319                te.innerAttrs = 5;
320                break;
321              case 2:
322                te.innerAttrs = 6;
323                break;
324              case 3:
325                te.innerAttrs = 7;
326                break;
327            }
328
329            switch(curr_or) {
330              case 0:
331                te.nonCacheable = true;
332                te.outerAttrs = 0;
333                break;
334              case 1:
335                te.outerAttrs = 1;
336                break;
337              case 2:
338                te.outerAttrs = 2;
339                break;
340              case 3:
341                te.outerAttrs = 3;
342                break;
343            }
344        }
345    }
346
347    /** Formatting for Physical Address Register (PAR)
348     *  Only including lower bits (TLB info here)
349     *  PAR:
350     *  PA [31:12]
351     *  Reserved [11]
352     *  TLB info [10:1]
353     *      NOS  [10] (Not Outer Sharable)
354     *      NS   [9]  (Non-Secure)
355     *      --   [8]  (Implementation Defined)
356     *      SH   [7]  (Sharable)
357     *      Inner[6:4](Inner memory attributes)
358     *      Outer[3:2](Outer memory attributes)
359     *      SS   [1]  (SuperSection)
360     *      F    [0]  (Fault, Fault Status in [6:1] if faulted)
361     */
362    te.attributes = (
363                ((outer_shareable ? 0:1) << 10) |
364                // TODO: NS Bit
365                ((te.shareable ? 1:0) << 7) |
366                (te.innerAttrs << 4) |
367                (te.outerAttrs << 2)
368                // TODO: Supersection bit
369                // TODO: Fault bit
370                );
371
372
373}
374
375void
376TableWalker::doL1Descriptor()
377{
378    DPRINTF(TLB, "L1 descriptor for %#x is %#x\n", vaddr, l1Desc.data);
379    TlbEntry te;
380
381    switch (l1Desc.type()) {
382      case L1Descriptor::Ignore:
383      case L1Descriptor::Reserved:
384        if (!delayed) {
385            tc = NULL;
386            req = NULL;
387        }
388        DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n");
389        if (isFetch)
390            fault = new PrefetchAbort(vaddr, ArmFault::Translation0);
391        else
392            fault = new DataAbort(vaddr, NULL, isWrite,
393                                  ArmFault::Translation0);
394        return;
395      case L1Descriptor::Section:
396        if (sctlr.afe && bits(l1Desc.ap(), 0) == 0) {
397            /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is
398              * enabled if set, do l1.Desc.setAp0() instead of generating
399              * AccessFlag0
400              */
401
402            fault = new DataAbort(vaddr, NULL, isWrite,
403                                    ArmFault::AccessFlag0);
404        }
405
406        if (l1Desc.supersection()) {
407            panic("Haven't implemented supersections\n");
408        }
409        te.N = 20;
410        te.pfn = l1Desc.pfn();
411        te.size = (1<<te.N) - 1;
412        te.global = !l1Desc.global();
413        te.valid = true;
414        te.vpn = vaddr >> te.N;
415        te.sNp = true;
416        te.xn = l1Desc.xn();
417        te.ap =  l1Desc.ap();
418        te.domain = l1Desc.domain();
419        te.asid = contextId;
420        memAttrs(tc, te, l1Desc.texcb(), l1Desc.shareable());
421
422        DPRINTF(TLB, "Inserting Section Descriptor into TLB\n");
423        DPRINTF(TLB, " - N%d pfn:%#x size: %#x global:%d valid: %d\n",
424                te.N, te.pfn, te.size, te.global, te.valid);
425        DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d\n",
426                te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid);
427        DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n",
428                l1Desc.domain(), l1Desc.data, (l1Desc.data >> 5) & 0xF );
429
430        if (!timing) {
431            tc = NULL;
432            req = NULL;
433        }
434        tlb->insert(vaddr, te);
435
436        return;
437      case L1Descriptor::PageTable:
438        Addr l2desc_addr;
439        l2desc_addr = l1Desc.l2Addr() | (bits(vaddr, 19,12) << 2);
440        DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n",
441                l2desc_addr);
442
443        // Trickbox address check
444        fault = tlb->walkTrickBoxCheck(l2desc_addr, vaddr, sizeof(uint32_t),
445                isFetch, isWrite, l1Desc.domain(), false);
446        if (fault) {
447            if (!timing) {
448                tc = NULL;
449                req = NULL;
450            }
451            return;
452        }
453
454
455        if (timing) {
456            delayed = true;
457            port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
458                    &doL2DescEvent, (uint8_t*)&l2Desc.data, 0);
459        } else {
460            port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
461                    NULL, (uint8_t*)&l2Desc.data, 0);
462            doL2Descriptor();
463        }
464        return;
465      default:
466        panic("A new type in a 2 bit field?\n");
467    }
468}
469
470void
471TableWalker::doL2Descriptor()
472{
473    DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", vaddr, l2Desc.data);
474    TlbEntry te;
475
476    if (l2Desc.invalid()) {
477        DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
478        if (!delayed) {
479            tc = NULL;
480            req = NULL;
481        }
482        if (isFetch)
483            fault = new PrefetchAbort(vaddr, ArmFault::Translation1);
484        else
485            fault = new DataAbort(vaddr, l1Desc.domain(), isWrite,
486                                    ArmFault::Translation1);
487        return;
488    }
489
490    if (sctlr.afe && bits(l2Desc.ap(), 0) == 0) {
491        /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled
492          * if set, do l2.Desc.setAp0() instead of generating AccessFlag0
493          */
494
495        fault = new DataAbort(vaddr, NULL, isWrite, ArmFault::AccessFlag1);
496    }
497
498    if (l2Desc.large()) {
499      te.N = 16;
500      te.pfn = l2Desc.pfn();
501    } else {
502      te.N = 12;
503      te.pfn = l2Desc.pfn();
504    }
505
506    te.valid = true;
507    te.size =  (1 << te.N) - 1;
508    te.asid = contextId;
509    te.sNp = false;
510    te.vpn = vaddr >> te.N;
511    te.global = l2Desc.global();
512    te.xn = l2Desc.xn();
513    te.ap = l2Desc.ap();
514    te.domain = l1Desc.domain();
515    memAttrs(tc, te, l2Desc.texcb(), l2Desc.shareable());
516
517    if (!delayed) {
518        tc = NULL;
519        req = NULL;
520    }
521    tlb->insert(vaddr, te);
522}
523
524void
525TableWalker::doL1DescriptorWrapper()
526{
527    delayed = false;
528
529    DPRINTF(TLBVerbose, "calling doL1Descriptor\n");
530    doL1Descriptor();
531
532    // Check if fault was generated
533    if (fault != NoFault) {
534        transState->finish(fault, req, tc, mode);
535
536        req = NULL;
537        tc = NULL;
538        delayed = false;
539    }
540    else if (!delayed) {
541        DPRINTF(TLBVerbose, "calling translateTiming again\n");
542        fault = tlb->translateTiming(req, tc, transState, mode);
543
544        req = NULL;
545        tc = NULL;
546        delayed = false;
547    }
548}
549
550void
551TableWalker::doL2DescriptorWrapper()
552{
553    assert(delayed);
554
555    DPRINTF(TLBVerbose, "calling doL2Descriptor\n");
556    doL2Descriptor();
557
558    // Check if fault was generated
559    if (fault != NoFault) {
560        transState->finish(fault, req, tc, mode);
561    }
562    else {
563        DPRINTF(TLBVerbose, "calling translateTiming again\n");
564        fault = tlb->translateTiming(req, tc, transState, mode);
565    }
566
567    req = NULL;
568    tc = NULL;
569    delayed = false;
570}
571
572ArmISA::TableWalker *
573ArmTableWalkerParams::create()
574{
575    return new ArmISA::TableWalker(this);
576}
577
578