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 "cpu/base.hh"
44 #include "cpu/thread_context.hh"
45 #include "debug/Checkpoint.hh"
46 #include "debug/TLB.hh"
47 #include "debug/TLBVerbose.hh"
48 #include "sim/system.hh"
50 using namespace ArmISA
;
52 TableWalker::TableWalker(const Params
*p
)
53 : MemObject(p
), port(this, params()->sys
, params()->min_backoff
,
54 params()->max_backoff
, true),
55 tlb(NULL
), currState(NULL
), pending(false),
56 masterId(p
->sys
->getMasterId(name())),
57 doL1DescEvent(this), doL2DescEvent(this), doProcessEvent(this)
62 TableWalker::~TableWalker()
68 TableWalker::drain(Event
*de
)
70 if (stateQueueL1
.size() || stateQueueL2
.size() || pendingQueue
.size())
72 changeState(Draining
);
73 DPRINTF(Checkpoint
, "TableWalker busy, wait to drain\n");
79 DPRINTF(Checkpoint
, "TableWalker free, no need to drain\n");
88 if ((params()->sys
->getMemoryMode() == Enums::timing
) && currState
) {
95 TableWalker::getMasterPort(const std::string
&if_name
, int idx
)
97 if (if_name
== "port") {
100 return MemObject::getMasterPort(if_name
, idx
);
104 TableWalker::walk(RequestPtr _req
, ThreadContext
*_tc
, uint8_t _cid
, TLB::Mode _mode
,
105 TLB::Translation
*_trans
, bool _timing
, bool _functional
)
107 assert(!(_functional
&& _timing
));
109 // For atomic mode, a new WalkerState instance should be only created
110 // once per TLB. For timing mode, a new instance is generated for every
112 DPRINTF(TLBVerbose
, "creating new instance of WalkerState\n");
114 currState
= new WalkerState();
115 currState
->tableWalker
= this;
116 } else if (_timing
) {
117 // This is a translation that was completed and then faulted again
118 // because some underlying parameters that affect the translation
119 // changed out from under us (e.g. asid). It will either be a
120 // misprediction, in which case nothing will happen or we'll use
121 // this fault to re-execute the faulting instruction which should clean
123 if (currState
->vaddr
== _req
->getVaddr()) {
126 panic("currState should always be empty in timing mode!\n");
130 currState
->transState
= _trans
;
131 currState
->req
= _req
;
132 currState
->fault
= NoFault
;
133 currState
->contextId
= _cid
;
134 currState
->timing
= _timing
;
135 currState
->functional
= _functional
;
136 currState
->mode
= _mode
;
138 /** @todo These should be cached or grabbed from cached copies in
139 the TLB, all these miscreg reads are expensive */
140 currState
->vaddr
= currState
->req
->getVaddr();
141 currState
->sctlr
= currState
->tc
->readMiscReg(MISCREG_SCTLR
);
142 sctlr
= currState
->sctlr
;
143 currState
->N
= currState
->tc
->readMiscReg(MISCREG_TTBCR
);
145 currState
->isFetch
= (currState
->mode
== TLB::Execute
);
146 currState
->isWrite
= (currState
->mode
== TLB::Write
);
149 if (!currState
->timing
)
150 return processWalk();
152 if (pending
|| pendingQueue
.size()) {
153 pendingQueue
.push_back(currState
);
157 return processWalk();
164 TableWalker::processWalkWrapper()
167 assert(pendingQueue
.size());
168 currState
= pendingQueue
.front();
169 pendingQueue
.pop_front();
175 TableWalker::processWalk()
179 // If translation isn't enabled, we shouldn't be here
180 assert(currState
->sctlr
.m
);
182 DPRINTF(TLB
, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n",
183 currState
->vaddr
, currState
->N
, mbits(currState
->vaddr
, 31,
186 if (currState
->N
== 0 || !mbits(currState
->vaddr
, 31, 32-currState
->N
)) {
187 DPRINTF(TLB
, " - Selecting TTBR0\n");
188 ttbr
= currState
->tc
->readMiscReg(MISCREG_TTBR0
);
190 DPRINTF(TLB
, " - Selecting TTBR1\n");
191 ttbr
= currState
->tc
->readMiscReg(MISCREG_TTBR1
);
195 Addr l1desc_addr
= mbits(ttbr
, 31, 14-currState
->N
) |
196 (bits(currState
->vaddr
,31-currState
->N
,20) << 2);
197 DPRINTF(TLB
, " - Descriptor at address %#x\n", l1desc_addr
);
200 // Trickbox address check
202 f
= tlb
->walkTrickBoxCheck(l1desc_addr
, currState
->vaddr
, sizeof(uint32_t),
203 currState
->isFetch
, currState
->isWrite
, 0, true);
205 DPRINTF(TLB
, "Trickbox check caused fault on %#x\n", currState
->vaddr
);
206 if (currState
->timing
) {
208 nextWalk(currState
->tc
);
211 currState
->tc
= NULL
;
212 currState
->req
= NULL
;
217 Request::Flags flag
= 0;
218 if (currState
->sctlr
.c
== 0) {
219 flag
= Request::UNCACHEABLE
;
222 if (currState
->timing
) {
223 port
.dmaAction(MemCmd::ReadReq
, l1desc_addr
, sizeof(uint32_t),
224 &doL1DescEvent
, (uint8_t*)&currState
->l1Desc
.data
,
225 currState
->tc
->getCpuPtr()->ticks(1), flag
);
226 DPRINTF(TLBVerbose
, "Adding to walker fifo: queue size before adding: %d\n",
227 stateQueueL1
.size());
228 stateQueueL1
.push_back(currState
);
230 } else if (!currState
->functional
) {
231 port
.dmaAction(MemCmd::ReadReq
, l1desc_addr
, sizeof(uint32_t),
232 NULL
, (uint8_t*)&currState
->l1Desc
.data
,
233 currState
->tc
->getCpuPtr()->ticks(1), flag
);
235 f
= currState
->fault
;
237 RequestPtr req
= new Request(l1desc_addr
, sizeof(uint32_t), flag
, masterId
);
238 PacketPtr pkt
= new Packet(req
, MemCmd::ReadReq
, Packet::Broadcast
);
239 pkt
->dataStatic((uint8_t*)&currState
->l1Desc
.data
);
240 port
.sendFunctional(pkt
);
244 f
= currState
->fault
;
251 TableWalker::memAttrs(ThreadContext
*tc
, TlbEntry
&te
, SCTLR sctlr
,
252 uint8_t texcb
, bool s
)
254 // Note: tc and sctlr local variables are hiding tc and sctrl class
256 DPRINTF(TLBVerbose
, "memAttrs texcb:%d s:%d\n", texcb
, s
);
257 te
.shareable
= false; // default value
258 te
.nonCacheable
= false;
259 bool outer_shareable
= false;
260 if (sctlr
.tre
== 0 || ((sctlr
.tre
== 1) && (sctlr
.m
== 0))) {
262 case 0: // Stongly-ordered
263 te
.nonCacheable
= true;
264 te
.mtype
= TlbEntry::StronglyOrdered
;
269 case 1: // Shareable Device
270 te
.nonCacheable
= true;
271 te
.mtype
= TlbEntry::Device
;
276 case 2: // Outer and Inner Write-Through, no Write-Allocate
277 te
.mtype
= TlbEntry::Normal
;
280 te
.outerAttrs
= bits(texcb
, 1, 0);
282 case 3: // Outer and Inner Write-Back, no Write-Allocate
283 te
.mtype
= TlbEntry::Normal
;
286 te
.outerAttrs
= bits(texcb
, 1, 0);
288 case 4: // Outer and Inner Non-cacheable
289 te
.nonCacheable
= true;
290 te
.mtype
= TlbEntry::Normal
;
293 te
.outerAttrs
= bits(texcb
, 1, 0);
296 panic("Reserved texcb value!\n");
298 case 6: // Implementation Defined
299 panic("Implementation-defined texcb value!\n");
301 case 7: // Outer and Inner Write-Back, Write-Allocate
302 te
.mtype
= TlbEntry::Normal
;
307 case 8: // Non-shareable Device
308 te
.nonCacheable
= true;
309 te
.mtype
= TlbEntry::Device
;
310 te
.shareable
= false;
314 case 9 ... 15: // Reserved
315 panic("Reserved texcb value!\n");
317 case 16 ... 31: // Cacheable Memory
318 te
.mtype
= TlbEntry::Normal
;
320 if (bits(texcb
, 1,0) == 0 || bits(texcb
, 3,2) == 0)
321 te
.nonCacheable
= true;
322 te
.innerAttrs
= bits(texcb
, 1, 0);
323 te
.outerAttrs
= bits(texcb
, 3, 2);
326 panic("More than 32 states for 5 bits?\n");
330 PRRR prrr
= tc
->readMiscReg(MISCREG_PRRR
);
331 NMRR nmrr
= tc
->readMiscReg(MISCREG_NMRR
);
332 DPRINTF(TLBVerbose
, "memAttrs PRRR:%08x NMRR:%08x\n", prrr
, nmrr
);
333 uint8_t curr_tr
= 0, curr_ir
= 0, curr_or
= 0;
334 switch(bits(texcb
, 2,0)) {
339 outer_shareable
= (prrr
.nos0
== 0);
345 outer_shareable
= (prrr
.nos1
== 0);
351 outer_shareable
= (prrr
.nos2
== 0);
357 outer_shareable
= (prrr
.nos3
== 0);
363 outer_shareable
= (prrr
.nos4
== 0);
369 outer_shareable
= (prrr
.nos5
== 0);
372 panic("Imp defined type\n");
377 outer_shareable
= (prrr
.nos7
== 0);
383 DPRINTF(TLBVerbose
, "StronglyOrdered\n");
384 te
.mtype
= TlbEntry::StronglyOrdered
;
385 te
.nonCacheable
= true;
391 DPRINTF(TLBVerbose
, "Device ds1:%d ds0:%d s:%d\n",
392 prrr
.ds1
, prrr
.ds0
, s
);
393 te
.mtype
= TlbEntry::Device
;
394 te
.nonCacheable
= true;
403 DPRINTF(TLBVerbose
, "Normal ns1:%d ns0:%d s:%d\n",
404 prrr
.ns1
, prrr
.ns0
, s
);
405 te
.mtype
= TlbEntry::Normal
;
412 panic("Reserved type");
415 if (te
.mtype
== TlbEntry::Normal
){
418 te
.nonCacheable
= true;
434 te
.nonCacheable
= true;
449 DPRINTF(TLBVerbose
, "memAttrs: shareable: %d, innerAttrs: %d, \
451 te
.shareable
, te
.innerAttrs
, te
.outerAttrs
);
453 /** Formatting for Physical Address Register (PAR)
454 * Only including lower bits (TLB info here)
459 * NOS [10] (Not Outer Sharable)
460 * NS [9] (Non-Secure)
461 * -- [8] (Implementation Defined)
463 * Inner[6:4](Inner memory attributes)
464 * Outer[3:2](Outer memory attributes)
465 * SS [1] (SuperSection)
466 * F [0] (Fault, Fault Status in [6:1] if faulted)
469 ((outer_shareable
? 0:1) << 10) |
471 ((te
.shareable
? 1:0) << 7) |
472 (te
.innerAttrs
<< 4) |
474 // TODO: Supersection bit
482 TableWalker::doL1Descriptor()
484 DPRINTF(TLB
, "L1 descriptor for %#x is %#x\n",
485 currState
->vaddr
, currState
->l1Desc
.data
);
488 switch (currState
->l1Desc
.type()) {
489 case L1Descriptor::Ignore
:
490 case L1Descriptor::Reserved
:
491 if (!currState
->timing
) {
492 currState
->tc
= NULL
;
493 currState
->req
= NULL
;
495 DPRINTF(TLB
, "L1 Descriptor Reserved/Ignore, causing fault\n");
496 if (currState
->isFetch
)
498 new PrefetchAbort(currState
->vaddr
, ArmFault::Translation0
);
501 new DataAbort(currState
->vaddr
, 0, currState
->isWrite
,
502 ArmFault::Translation0
);
504 case L1Descriptor::Section
:
505 if (currState
->sctlr
.afe
&& bits(currState
->l1Desc
.ap(), 0) == 0) {
506 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is
507 * enabled if set, do l1.Desc.setAp0() instead of generating
511 currState
->fault
= new DataAbort(currState
->vaddr
,
512 currState
->l1Desc
.domain(), currState
->isWrite
,
513 ArmFault::AccessFlag0
);
515 if (currState
->l1Desc
.supersection()) {
516 panic("Haven't implemented supersections\n");
519 te
.pfn
= currState
->l1Desc
.pfn();
520 te
.size
= (1<<te
.N
) - 1;
521 te
.global
= !currState
->l1Desc
.global();
523 te
.vpn
= currState
->vaddr
>> te
.N
;
525 te
.xn
= currState
->l1Desc
.xn();
526 te
.ap
= currState
->l1Desc
.ap();
527 te
.domain
= currState
->l1Desc
.domain();
528 te
.asid
= currState
->contextId
;
529 memAttrs(currState
->tc
, te
, currState
->sctlr
,
530 currState
->l1Desc
.texcb(), currState
->l1Desc
.shareable());
532 DPRINTF(TLB
, "Inserting Section Descriptor into TLB\n");
533 DPRINTF(TLB
, " - N:%d pfn:%#x size: %#x global:%d valid: %d\n",
534 te
.N
, te
.pfn
, te
.size
, te
.global
, te
.valid
);
535 DPRINTF(TLB
, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d nc:%d\n",
536 te
.vpn
, te
.sNp
, te
.xn
, te
.ap
, te
.domain
, te
.asid
,
538 DPRINTF(TLB
, " - domain from l1 desc: %d data: %#x bits:%d\n",
539 currState
->l1Desc
.domain(), currState
->l1Desc
.data
,
540 (currState
->l1Desc
.data
>> 5) & 0xF );
542 if (!currState
->timing
) {
543 currState
->tc
= NULL
;
544 currState
->req
= NULL
;
546 tlb
->insert(currState
->vaddr
, te
);
549 case L1Descriptor::PageTable
:
551 l2desc_addr
= currState
->l1Desc
.l2Addr() |
552 (bits(currState
->vaddr
, 19,12) << 2);
553 DPRINTF(TLB
, "L1 descriptor points to page table at: %#x\n",
556 // Trickbox address check
557 currState
->fault
= tlb
->walkTrickBoxCheck(l2desc_addr
, currState
->vaddr
,
558 sizeof(uint32_t), currState
->isFetch
, currState
->isWrite
,
559 currState
->l1Desc
.domain(), false);
561 if (currState
->fault
) {
562 if (!currState
->timing
) {
563 currState
->tc
= NULL
;
564 currState
->req
= NULL
;
570 if (currState
->timing
) {
571 currState
->delayed
= true;
572 port
.dmaAction(MemCmd::ReadReq
, l2desc_addr
, sizeof(uint32_t),
573 &doL2DescEvent
, (uint8_t*)&currState
->l2Desc
.data
,
574 currState
->tc
->getCpuPtr()->ticks(1));
575 } else if (!currState
->functional
) {
576 port
.dmaAction(MemCmd::ReadReq
, l2desc_addr
, sizeof(uint32_t),
577 NULL
, (uint8_t*)&currState
->l2Desc
.data
,
578 currState
->tc
->getCpuPtr()->ticks(1));
581 RequestPtr req
= new Request(l2desc_addr
, sizeof(uint32_t), 0, masterId
);
582 PacketPtr pkt
= new Packet(req
, MemCmd::ReadReq
, Packet::Broadcast
);
583 pkt
->dataStatic((uint8_t*)&currState
->l2Desc
.data
);
584 port
.sendFunctional(pkt
);
591 panic("A new type in a 2 bit field?\n");
596 TableWalker::doL2Descriptor()
598 DPRINTF(TLB
, "L2 descriptor for %#x is %#x\n",
599 currState
->vaddr
, currState
->l2Desc
.data
);
602 if (currState
->l2Desc
.invalid()) {
603 DPRINTF(TLB
, "L2 descriptor invalid, causing fault\n");
604 if (!currState
->timing
) {
605 currState
->tc
= NULL
;
606 currState
->req
= NULL
;
608 if (currState
->isFetch
)
610 new PrefetchAbort(currState
->vaddr
, ArmFault::Translation1
);
613 new DataAbort(currState
->vaddr
, currState
->l1Desc
.domain(),
614 currState
->isWrite
, ArmFault::Translation1
);
618 if (currState
->sctlr
.afe
&& bits(currState
->l2Desc
.ap(), 0) == 0) {
619 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled
620 * if set, do l2.Desc.setAp0() instead of generating AccessFlag0
624 new DataAbort(currState
->vaddr
, 0, currState
->isWrite
,
625 ArmFault::AccessFlag1
);
629 if (currState
->l2Desc
.large()) {
631 te
.pfn
= currState
->l2Desc
.pfn();
634 te
.pfn
= currState
->l2Desc
.pfn();
638 te
.size
= (1 << te
.N
) - 1;
639 te
.asid
= currState
->contextId
;
641 te
.vpn
= currState
->vaddr
>> te
.N
;
642 te
.global
= currState
->l2Desc
.global();
643 te
.xn
= currState
->l2Desc
.xn();
644 te
.ap
= currState
->l2Desc
.ap();
645 te
.domain
= currState
->l1Desc
.domain();
646 memAttrs(currState
->tc
, te
, currState
->sctlr
, currState
->l2Desc
.texcb(),
647 currState
->l2Desc
.shareable());
649 if (!currState
->timing
) {
650 currState
->tc
= NULL
;
651 currState
->req
= NULL
;
653 tlb
->insert(currState
->vaddr
, te
);
657 TableWalker::doL1DescriptorWrapper()
659 currState
= stateQueueL1
.front();
660 currState
->delayed
= false;
662 DPRINTF(TLBVerbose
, "L1 Desc object host addr: %p\n",&currState
->l1Desc
.data
);
663 DPRINTF(TLBVerbose
, "L1 Desc object data: %08x\n",currState
->l1Desc
.data
);
665 DPRINTF(TLBVerbose
, "calling doL1Descriptor for vaddr:%#x\n", currState
->vaddr
);
668 stateQueueL1
.pop_front();
669 // Check if fault was generated
670 if (currState
->fault
!= NoFault
) {
671 currState
->transState
->finish(currState
->fault
, currState
->req
,
672 currState
->tc
, currState
->mode
);
675 nextWalk(currState
->tc
);
677 currState
->req
= NULL
;
678 currState
->tc
= NULL
;
679 currState
->delayed
= false;
682 else if (!currState
->delayed
) {
683 // delay is not set so there is no L2 to do
684 DPRINTF(TLBVerbose
, "calling translateTiming again\n");
685 currState
->fault
= tlb
->translateTiming(currState
->req
, currState
->tc
,
686 currState
->transState
, currState
->mode
);
689 nextWalk(currState
->tc
);
691 currState
->req
= NULL
;
692 currState
->tc
= NULL
;
693 currState
->delayed
= false;
696 // need to do L2 descriptor
697 stateQueueL2
.push_back(currState
);
703 TableWalker::doL2DescriptorWrapper()
705 currState
= stateQueueL2
.front();
706 assert(currState
->delayed
);
708 DPRINTF(TLBVerbose
, "calling doL2Descriptor for vaddr:%#x\n",
712 // Check if fault was generated
713 if (currState
->fault
!= NoFault
) {
714 currState
->transState
->finish(currState
->fault
, currState
->req
,
715 currState
->tc
, currState
->mode
);
718 DPRINTF(TLBVerbose
, "calling translateTiming again\n");
719 currState
->fault
= tlb
->translateTiming(currState
->req
, currState
->tc
,
720 currState
->transState
, currState
->mode
);
724 stateQueueL2
.pop_front();
726 nextWalk(currState
->tc
);
728 currState
->req
= NULL
;
729 currState
->tc
= NULL
;
730 currState
->delayed
= false;
737 TableWalker::nextWalk(ThreadContext
*tc
)
739 if (pendingQueue
.size())
740 schedule(doProcessEvent
, tc
->getCpuPtr()->nextCycle(curTick()+1));
745 ArmISA::TableWalker
*
746 ArmTableWalkerParams::create()
748 return new ArmISA::TableWalker(this);