2 * Copyright (c) 2010 ARM Limited
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.
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.
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.
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"
48 using namespace ArmISA
;
50 TableWalker::TableWalker(const Params
*p
)
51 : MemObject(p
), port(NULL
), tlb(NULL
), currState(NULL
), pending(false),
52 doL1DescEvent(this), doL2DescEvent(this), doProcessEvent(this)
57 TableWalker::~TableWalker()
64 TableWalker::drain(Event
*de
)
66 if (stateQueueL1
.size() || stateQueueL2
.size() || pendingQueue
.size())
68 changeState(Draining
);
69 DPRINTF(Checkpoint
, "TableWalker busy, wait to drain\n");
75 DPRINTF(Checkpoint
, "TableWalker free, no need to drain\n");
84 if ((params()->sys
->getMemoryMode() == Enums::timing
) && currState
) {
91 TableWalker::getPort(const std::string
&if_name
, int idx
)
93 if (if_name
== "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
);
106 TableWalker::walk(RequestPtr _req
, ThreadContext
*_tc
, uint8_t _cid
, TLB::Mode _mode
,
107 TLB::Translation
*_trans
, bool _timing
)
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
113 DPRINTF(TLBVerbose
, "creating new instance of WalkerState\n");
115 currState
= new WalkerState();
116 currState
->tableWalker
= this;
119 panic("currState should always be empty in timing mode!\n");
123 currState
->transState
= _trans
;
124 currState
->req
= _req
;
125 currState
->fault
= NoFault
;
126 currState
->contextId
= _cid
;
127 currState
->timing
= _timing
;
128 currState
->mode
= _mode
;
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
);
137 currState
->isFetch
= (currState
->mode
== TLB::Execute
);
138 currState
->isWrite
= (currState
->mode
== TLB::Write
);
141 if (!currState
->timing
)
142 return processWalk();
145 pendingQueue
.push_back(currState
);
156 TableWalker::processWalkWrapper()
159 assert(pendingQueue
.size());
160 currState
= pendingQueue
.front();
161 pendingQueue
.pop_front();
167 TableWalker::processWalk()
171 // If translation isn't enabled, we shouldn't be here
172 assert(currState
->sctlr
.m
);
174 DPRINTF(TLB
, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n",
175 currState
->vaddr
, currState
->N
, mbits(currState
->vaddr
, 31,
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
);
182 DPRINTF(TLB
, " - Selecting TTBR1\n");
183 ttbr
= currState
->tc
->readMiscReg(MISCREG_TTBR1
);
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
);
192 // Trickbox address check
194 f
= tlb
->walkTrickBoxCheck(l1desc_addr
, currState
->vaddr
, sizeof(uint32_t),
195 currState
->isFetch
, currState
->isWrite
, 0, true);
197 if (currState
->timing
) {
198 currState
->transState
->finish(f
, currState
->req
,
199 currState
->tc
, currState
->mode
);
202 nextWalk(currState
->tc
);
205 currState
->tc
= NULL
;
206 currState
->req
= NULL
;
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
);
220 Request::Flags flag
= 0;
221 if (currState
->sctlr
.c
== 0){
222 flag
= Request::UNCACHEABLE
;
224 port
->dmaAction(MemCmd::ReadReq
, l1desc_addr
, sizeof(uint32_t),
225 NULL
, (uint8_t*)&currState
->l1Desc
.data
,
226 currState
->tc
->getCpuPtr()->ticks(1), flag
);
228 f
= currState
->fault
;
235 TableWalker::memAttrs(ThreadContext
*tc
, TlbEntry
&te
, SCTLR sctlr
,
236 uint8_t texcb
, bool s
)
238 // Note: tc and sctlr local variables are hiding tc and sctrl class
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))) {
246 case 0: // Stongly-ordered
247 te
.nonCacheable
= true;
248 te
.mtype
= TlbEntry::StronglyOrdered
;
253 case 1: // Shareable Device
254 te
.nonCacheable
= true;
255 te
.mtype
= TlbEntry::Device
;
260 case 2: // Outer and Inner Write-Through, no Write-Allocate
261 te
.mtype
= TlbEntry::Normal
;
264 te
.outerAttrs
= bits(texcb
, 1, 0);
266 case 3: // Outer and Inner Write-Back, no Write-Allocate
267 te
.mtype
= TlbEntry::Normal
;
270 te
.outerAttrs
= bits(texcb
, 1, 0);
272 case 4: // Outer and Inner Non-cacheable
273 te
.nonCacheable
= true;
274 te
.mtype
= TlbEntry::Normal
;
277 te
.outerAttrs
= bits(texcb
, 1, 0);
280 panic("Reserved texcb value!\n");
282 case 6: // Implementation Defined
283 panic("Implementation-defined texcb value!\n");
285 case 7: // Outer and Inner Write-Back, Write-Allocate
286 te
.mtype
= TlbEntry::Normal
;
291 case 8: // Non-shareable Device
292 te
.nonCacheable
= true;
293 te
.mtype
= TlbEntry::Device
;
294 te
.shareable
= false;
298 case 9 ... 15: // Reserved
299 panic("Reserved texcb value!\n");
301 case 16 ... 31: // Cacheable Memory
302 te
.mtype
= TlbEntry::Normal
;
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);
310 panic("More than 32 states for 5 bits?\n");
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)) {
323 outer_shareable
= (prrr
.nos0
== 0);
329 outer_shareable
= (prrr
.nos1
== 0);
335 outer_shareable
= (prrr
.nos2
== 0);
341 outer_shareable
= (prrr
.nos3
== 0);
347 outer_shareable
= (prrr
.nos4
== 0);
353 outer_shareable
= (prrr
.nos5
== 0);
356 panic("Imp defined type\n");
361 outer_shareable
= (prrr
.nos7
== 0);
367 DPRINTF(TLBVerbose
, "StronglyOrdered\n");
368 te
.mtype
= TlbEntry::StronglyOrdered
;
369 te
.nonCacheable
= true;
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;
387 DPRINTF(TLBVerbose
, "Normal ns1:%d ns0:%d s:%d\n",
388 prrr
.ns1
, prrr
.ns0
, s
);
389 te
.mtype
= TlbEntry::Normal
;
396 panic("Reserved type");
399 if (te
.mtype
== TlbEntry::Normal
){
402 te
.nonCacheable
= true;
418 te
.nonCacheable
= true;
433 DPRINTF(TLBVerbose
, "memAttrs: shareable: %d, innerAttrs: %d, \
435 te
.shareable
, te
.innerAttrs
, te
.outerAttrs
);
437 /** Formatting for Physical Address Register (PAR)
438 * Only including lower bits (TLB info here)
443 * NOS [10] (Not Outer Sharable)
444 * NS [9] (Non-Secure)
445 * -- [8] (Implementation Defined)
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)
453 ((outer_shareable
? 0:1) << 10) |
455 ((te
.shareable
? 1:0) << 7) |
456 (te
.innerAttrs
<< 4) |
458 // TODO: Supersection bit
466 TableWalker::doL1Descriptor()
468 DPRINTF(TLB
, "L1 descriptor for %#x is %#x\n",
469 currState
->vaddr
, currState
->l1Desc
.data
);
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
;
479 DPRINTF(TLB
, "L1 Descriptor Reserved/Ignore, causing fault\n");
480 if (currState
->isFetch
)
482 new PrefetchAbort(currState
->vaddr
, ArmFault::Translation0
);
485 new DataAbort(currState
->vaddr
, 0, currState
->isWrite
,
486 ArmFault::Translation0
);
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
495 currState
->fault
= new DataAbort(currState
->vaddr
,
496 currState
->l1Desc
.domain(), currState
->isWrite
,
497 ArmFault::AccessFlag0
);
499 if (currState
->l1Desc
.supersection()) {
500 panic("Haven't implemented supersections\n");
503 te
.pfn
= currState
->l1Desc
.pfn();
504 te
.size
= (1<<te
.N
) - 1;
505 te
.global
= !currState
->l1Desc
.global();
507 te
.vpn
= currState
->vaddr
>> te
.N
;
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());
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
,
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 );
526 if (!currState
->timing
) {
527 currState
->tc
= NULL
;
528 currState
->req
= NULL
;
530 tlb
->insert(currState
->vaddr
, te
);
533 case L1Descriptor::PageTable
:
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",
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);
545 if (currState
->fault
) {
546 if (!currState
->timing
) {
547 currState
->tc
= NULL
;
548 currState
->req
= NULL
;
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));
560 port
->dmaAction(MemCmd::ReadReq
, l2desc_addr
, sizeof(uint32_t),
561 NULL
, (uint8_t*)&currState
->l2Desc
.data
,
562 currState
->tc
->getCpuPtr()->ticks(1));
567 panic("A new type in a 2 bit field?\n");
572 TableWalker::doL2Descriptor()
574 DPRINTF(TLB
, "L2 descriptor for %#x is %#x\n",
575 currState
->vaddr
, currState
->l2Desc
.data
);
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
;
584 if (currState
->isFetch
)
586 new PrefetchAbort(currState
->vaddr
, ArmFault::Translation1
);
589 new DataAbort(currState
->vaddr
, currState
->l1Desc
.domain(),
590 currState
->isWrite
, ArmFault::Translation1
);
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
600 new DataAbort(currState
->vaddr
, 0, currState
->isWrite
,
601 ArmFault::AccessFlag1
);
605 if (currState
->l2Desc
.large()) {
607 te
.pfn
= currState
->l2Desc
.pfn();
610 te
.pfn
= currState
->l2Desc
.pfn();
614 te
.size
= (1 << te
.N
) - 1;
615 te
.asid
= currState
->contextId
;
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());
625 if (!currState
->delayed
) {
626 currState
->tc
= NULL
;
627 currState
->req
= NULL
;
629 tlb
->insert(currState
->vaddr
, te
);
633 TableWalker::doL1DescriptorWrapper()
635 currState
= stateQueueL1
.front();
636 currState
->delayed
= false;
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
);
641 DPRINTF(TLBVerbose
, "calling doL1Descriptor for vaddr:%#x\n", currState
->vaddr
);
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
);
651 nextWalk(currState
->tc
);
653 currState
->req
= NULL
;
654 currState
->tc
= NULL
;
655 currState
->delayed
= false;
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
);
665 nextWalk(currState
->tc
);
667 currState
->req
= NULL
;
668 currState
->tc
= NULL
;
669 currState
->delayed
= false;
672 // need to do L2 descriptor
673 stateQueueL2
.push_back(currState
);
679 TableWalker::doL2DescriptorWrapper()
681 currState
= stateQueueL2
.front();
682 assert(currState
->delayed
);
684 DPRINTF(TLBVerbose
, "calling doL2Descriptor for vaddr:%#x\n",
688 // Check if fault was generated
689 if (currState
->fault
!= NoFault
) {
690 currState
->transState
->finish(currState
->fault
, currState
->req
,
691 currState
->tc
, currState
->mode
);
694 DPRINTF(TLBVerbose
, "calling translateTiming again\n");
695 currState
->fault
= tlb
->translateTiming(currState
->req
, currState
->tc
,
696 currState
->transState
, currState
->mode
);
700 stateQueueL2
.pop_front();
702 nextWalk(currState
->tc
);
704 currState
->req
= NULL
;
705 currState
->tc
= NULL
;
706 currState
->delayed
= false;
713 TableWalker::nextWalk(ThreadContext
*tc
)
715 if (pendingQueue
.size())
716 schedule(doProcessEvent
, tc
->getCpuPtr()->nextCycle(curTick()+1));
721 ArmISA::TableWalker
*
722 ArmTableWalkerParams::create()
724 return new ArmISA::TableWalker(this);