table_walker.cc revision 7436:b578349f9371
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
99    /** @todo These should be cached or grabbed from cached copies in
100     the TLB, all these miscreg reads are expensive */
101    vaddr = req->getVaddr() & ~PcModeMask;
102    sctlr = tc->readMiscReg(MISCREG_SCTLR);
103    cpsr = tc->readMiscReg(MISCREG_CPSR);
104    N = tc->readMiscReg(MISCREG_TTBCR);
105    Addr ttbr = 0;
106
107    isFetch = (mode == TLB::Execute);
108    isWrite = (mode == TLB::Write);
109    isPriv = (cpsr.mode != MODE_USER);
110
111    // If translation isn't enabled, we shouldn't be here
112    assert(sctlr.m);
113
114    DPRINTF(TLB, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n",
115            vaddr, N, mbits(vaddr, 31, 32-N));
116
117    if (N == 0 || !mbits(vaddr, 31, 32-N)) {
118        DPRINTF(TLB, " - Selecting TTBR0\n");
119        ttbr = tc->readMiscReg(MISCREG_TTBR0);
120    } else {
121        DPRINTF(TLB, " - Selecting TTBR1\n");
122        ttbr = tc->readMiscReg(MISCREG_TTBR1);
123        N = 0;
124    }
125
126    Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(vaddr,31-N,20) << 2);
127    DPRINTF(TLB, " - Descriptor at address %#x\n", l1desc_addr);
128
129
130    // Trickbox address check
131    fault = tlb->walkTrickBoxCheck(l1desc_addr, vaddr, sizeof(uint32_t),
132            isFetch, isWrite, 0, true);
133    if (fault) {
134       tc = NULL;
135       req = NULL;
136       return fault;
137    }
138
139    if (timing) {
140        port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
141                &doL1DescEvent, (uint8_t*)&l1Desc.data, (Tick)0);
142    } else {
143        port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
144                NULL, (uint8_t*)&l1Desc.data, (Tick)0);
145        doL1Descriptor();
146    }
147
148    return fault;
149}
150
151void
152TableWalker::memAttrs(TlbEntry &te, uint8_t texcb, bool s)
153{
154    DPRINTF(TLBVerbose, "memAttrs texcb:%d s:%d\n", texcb, s);
155    te.shareable = false; // default value
156    bool outer_shareable = false;
157    if (sctlr.tre == 0) {
158        switch(texcb) {
159          case 0: // Stongly-ordered
160            te.nonCacheable = true;
161            te.mtype = TlbEntry::StronglyOrdered;
162            te.shareable = true;
163            te.innerAttrs = 1;
164            te.outerAttrs = 0;
165            break;
166          case 1: // Shareable Device
167            te.nonCacheable = true;
168            te.mtype = TlbEntry::Device;
169            te.shareable = true;
170            te.innerAttrs = 3;
171            te.outerAttrs = 0;
172            break;
173          case 2: // Outer and Inner Write-Through, no Write-Allocate
174            te.mtype = TlbEntry::Normal;
175            te.shareable = s;
176            te.innerAttrs = 6;
177            te.outerAttrs = bits(texcb, 1, 0);
178            break;
179          case 3: // Outer and Inner Write-Back, no Write-Allocate
180            te.mtype = TlbEntry::Normal;
181            te.shareable = s;
182            te.innerAttrs = 7;
183            te.outerAttrs = bits(texcb, 1, 0);
184            break;
185          case 4: // Outer and Inner Non-cacheable
186            te.nonCacheable = true;
187            te.mtype = TlbEntry::Normal;
188            te.shareable = s;
189            te.innerAttrs = 0;
190            te.outerAttrs = bits(texcb, 1, 0);
191            break;
192          case 5: // Reserved
193            break;
194          case 6: // Implementation Defined
195            break;
196          case 7: // Outer and Inner Write-Back, Write-Allocate
197            te.mtype = TlbEntry::Normal;
198            te.shareable = s;
199            te.innerAttrs = 5;
200            te.outerAttrs = 1;
201            break;
202          case 8: // Non-shareable Device
203            te.nonCacheable = true;
204            te.mtype = TlbEntry::Device;
205            te.shareable = false;
206            te.innerAttrs = 3;
207            te.outerAttrs = 0;
208            break;
209          case 9 ... 15:  // Reserved
210            break;
211          case 16 ... 31: // Cacheable Memory
212            te.mtype = TlbEntry::Normal;
213            te.shareable = s;
214            if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0)
215                te.nonCacheable = true;
216            te.innerAttrs = bits(texcb, 1, 0);
217            te.outerAttrs = bits(texcb, 3, 2);
218            break;
219          default:
220            panic("More than 32 states for 5 bits?\n");
221        }
222    } else {
223        PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
224        NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
225        DPRINTF(TLBVerbose, "memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr);
226        uint8_t curr_tr, curr_ir, curr_or;
227        switch(bits(texcb, 2,0)) {
228          case 0:
229            curr_tr = prrr.tr0;
230            curr_ir = nmrr.ir0;
231            curr_or = nmrr.or0;
232            outer_shareable = (prrr.nos0 == 0);
233            break;
234          case 1:
235            curr_tr = prrr.tr1;
236            curr_ir = nmrr.ir1;
237            curr_or = nmrr.or1;
238            outer_shareable = (prrr.nos1 == 0);
239            break;
240          case 2:
241            curr_tr = prrr.tr2;
242            curr_ir = nmrr.ir2;
243            curr_or = nmrr.or2;
244            outer_shareable = (prrr.nos2 == 0);
245            break;
246          case 3:
247            curr_tr = prrr.tr3;
248            curr_ir = nmrr.ir3;
249            curr_or = nmrr.or3;
250            outer_shareable = (prrr.nos3 == 0);
251            break;
252          case 4:
253            curr_tr = prrr.tr4;
254            curr_ir = nmrr.ir4;
255            curr_or = nmrr.or4;
256            outer_shareable = (prrr.nos4 == 0);
257            break;
258          case 5:
259            curr_tr = prrr.tr5;
260            curr_ir = nmrr.ir5;
261            curr_or = nmrr.or5;
262            outer_shareable = (prrr.nos5 == 0);
263            break;
264          case 6:
265            panic("Imp defined type\n");
266          case 7:
267            curr_tr = prrr.tr7;
268            curr_ir = nmrr.ir7;
269            curr_or = nmrr.or7;
270            outer_shareable = (prrr.nos7 == 0);
271            break;
272        }
273
274        switch(curr_tr) {
275          case 0:
276            DPRINTF(TLBVerbose, "StronglyOrdered\n");
277            te.mtype = TlbEntry::StronglyOrdered;
278            te.nonCacheable = true;
279            te.innerAttrs = 1;
280            te.outerAttrs = 0;
281            te.shareable = true;
282            break;
283          case 1:
284            DPRINTF(TLBVerbose, "Device ds1:%d ds0:%d s:%d\n",
285                    prrr.ds1, prrr.ds0, s);
286            te.mtype = TlbEntry::Device;
287            te.nonCacheable = true;
288            te.innerAttrs = 3;
289            te.outerAttrs = 0;
290            if (prrr.ds1 && s)
291                te.shareable = true;
292            if (prrr.ds0 && !s)
293                te.shareable = true;
294            break;
295          case 2:
296            DPRINTF(TLBVerbose, "Normal ns1:%d ns0:%d s:%d\n",
297                    prrr.ns1, prrr.ns0, s);
298            te.mtype = TlbEntry::Normal;
299            if (prrr.ns1 && s)
300                te.shareable = true;
301            if (prrr.ns0 && !s)
302                te.shareable = true;
303            //te.shareable = outer_shareable;
304            break;
305          case 3:
306            panic("Reserved type");
307        }
308
309        if (te.mtype == TlbEntry::Normal){
310            switch(curr_ir) {
311              case 0:
312                te.nonCacheable = true;
313                te.innerAttrs = 0;
314                break;
315              case 1:
316                te.innerAttrs = 5;
317                break;
318              case 2:
319                te.innerAttrs = 6;
320                break;
321              case 3:
322                te.innerAttrs = 7;
323                break;
324            }
325
326            switch(curr_or) {
327              case 0:
328                te.nonCacheable = true;
329                te.outerAttrs = 0;
330                break;
331              case 1:
332                te.outerAttrs = 1;
333                break;
334              case 2:
335                te.outerAttrs = 2;
336                break;
337              case 3:
338                te.outerAttrs = 3;
339                break;
340            }
341        }
342    }
343
344    /** Formatting for Physical Address Register (PAR)
345     *  Only including lower bits (TLB info here)
346     *  PAR:
347     *  PA [31:12]
348     *  Reserved [11]
349     *  TLB info [10:1]
350     *      NOS  [10] (Not Outer Sharable)
351     *      NS   [9]  (Non-Secure)
352     *      --   [8]  (Implementation Defined)
353     *      SH   [7]  (Sharable)
354     *      Inner[6:4](Inner memory attributes)
355     *      Outer[3:2](Outer memory attributes)
356     *      SS   [1]  (SuperSection)
357     *      F    [0]  (Fault, Fault Status in [6:1] if faulted)
358     */
359    te.attributes = (
360                ((outer_shareable ? 0:1) << 10) |
361                // TODO: NS Bit
362                ((te.shareable ? 1:0) << 7) |
363                (te.innerAttrs << 4) |
364                (te.outerAttrs << 2)
365                // TODO: Supersection bit
366                // TODO: Fault bit
367                );
368
369
370}
371
372void
373TableWalker::doL1Descriptor()
374{
375    DPRINTF(TLB, "L1 descriptor for %#x is %#x\n", vaddr, l1Desc.data);
376    TlbEntry te;
377
378    switch (l1Desc.type()) {
379      case L1Descriptor::Ignore:
380      case L1Descriptor::Reserved:
381        tc = NULL;
382        req = NULL;
383        DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n");
384        if (isFetch)
385            fault = new PrefetchAbort(vaddr, ArmFault::Translation0);
386        else
387            fault = new DataAbort(vaddr, NULL, isWrite,
388                                  ArmFault::Translation0);
389        return;
390      case L1Descriptor::Section:
391        if (sctlr.afe && bits(l1Desc.ap(), 0) == 0) {
392            /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is
393              * enabled if set, do l1.Desc.setAp0() instead of generating
394              * AccessFlag0
395              */
396
397            fault = new DataAbort(vaddr, NULL, isWrite,
398                                    ArmFault::AccessFlag0);
399        }
400
401        if (l1Desc.supersection()) {
402            panic("Haven't implemented supersections\n");
403        }
404        te.N = 20;
405        te.pfn = l1Desc.pfn();
406        te.size = (1<<te.N) - 1;
407        te.global = !l1Desc.global();
408        te.valid = true;
409        te.vpn = vaddr >> te.N;
410        te.sNp = true;
411        te.xn = l1Desc.xn();
412        te.ap =  l1Desc.ap();
413        te.domain = l1Desc.domain();
414        te.asid = contextId;
415        memAttrs(te, l1Desc.texcb(), l1Desc.shareable());
416
417        DPRINTF(TLB, "Inserting Section Descriptor into TLB\n");
418        DPRINTF(TLB, " - N%d pfn:%#x size: %#x global:%d valid: %d\n",
419                te.N, te.pfn, te.size, te.global, te.valid);
420        DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d\n",
421                te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid);
422        DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n",
423                l1Desc.domain(), l1Desc.data, (l1Desc.data >> 5) & 0xF );
424
425        tc = NULL;
426        req = NULL;
427        tlb->insert(vaddr, te);
428
429        return;
430      case L1Descriptor::PageTable:
431        Addr l2desc_addr;
432        l2desc_addr = l1Desc.l2Addr() | (bits(vaddr, 19,12) << 2);
433        DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n",
434                l2desc_addr);
435
436        // Trickbox address check
437        fault = tlb->walkTrickBoxCheck(l2desc_addr, vaddr, sizeof(uint32_t),
438                isFetch, isWrite, l1Desc.domain(), false);
439        if (fault) {
440           tc = NULL;
441           req = NULL;
442           return;
443        }
444
445
446        if (timing) {
447            port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
448                    &doL2DescEvent, (uint8_t*)&l2Desc.data, 0);
449        } else {
450            port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
451                    NULL, (uint8_t*)&l2Desc.data, 0);
452            doL2Descriptor();
453        }
454        return;
455      default:
456        panic("A new type in a 2 bit field?\n");
457    }
458}
459
460void
461TableWalker::doL2Descriptor()
462{
463    DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", vaddr, l2Desc.data);
464    TlbEntry te;
465
466    if (l2Desc.invalid()) {
467        DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
468        tc = NULL;
469        req = NULL;
470        if (isFetch)
471            fault = new PrefetchAbort(vaddr, ArmFault::Translation1);
472        else
473            fault = new DataAbort(vaddr, l1Desc.domain(), isWrite,
474                                    ArmFault::Translation1);
475        return;
476    }
477
478    if (sctlr.afe && bits(l2Desc.ap(), 0) == 0) {
479        /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled
480          * if set, do l2.Desc.setAp0() instead of generating AccessFlag0
481          */
482
483        fault = new DataAbort(vaddr, NULL, isWrite, ArmFault::AccessFlag1);
484    }
485
486    if (l2Desc.large()) {
487      te.N = 16;
488      te.pfn = l2Desc.pfn();
489    } else {
490      te.N = 12;
491      te.pfn = l2Desc.pfn();
492    }
493
494    te.valid = true;
495    te.size =  (1 << te.N) - 1;
496    te.asid = contextId;
497    te.sNp = false;
498    te.vpn = vaddr >> te.N;
499    te.global = l2Desc.global();
500    te.xn = l2Desc.xn();
501    te.ap = l2Desc.ap();
502    te.domain = l1Desc.domain();
503    memAttrs(te, l2Desc.texcb(), l2Desc.shareable());
504
505    tc = NULL;
506    req = NULL;
507    tlb->insert(vaddr, te);
508}
509
510ArmISA::TableWalker *
511ArmTableWalkerParams::create()
512{
513    return new ArmISA::TableWalker(this);
514}
515
516