table_walker.cc (9152:86c0e6ca5e7c) table_walker.cc (9165:f9e3dac185ba)
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 "cpu/base.hh"
44#include "cpu/thread_context.hh"
45#include "debug/Checkpoint.hh"
46#include "debug/Drain.hh"
47#include "debug/TLB.hh"
48#include "debug/TLBVerbose.hh"
49#include "sim/system.hh"
50
51using namespace ArmISA;
52
53TableWalker::TableWalker(const Params *p)
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 "cpu/base.hh"
44#include "cpu/thread_context.hh"
45#include "debug/Checkpoint.hh"
46#include "debug/Drain.hh"
47#include "debug/TLB.hh"
48#include "debug/TLBVerbose.hh"
49#include "sim/system.hh"
50
51using namespace ArmISA;
52
53TableWalker::TableWalker(const Params *p)
54 : MemObject(p), port(this, params()->sys, params()->min_backoff,
55 params()->max_backoff), drainEvent(NULL),
54 : MemObject(p), port(this, params()->sys), drainEvent(NULL),
56 tlb(NULL), currState(NULL), pending(false),
57 masterId(p->sys->getMasterId(name())),
58 doL1DescEvent(this), doL2DescEvent(this), doProcessEvent(this)
59{
60 sctlr = 0;
61}
62
63TableWalker::~TableWalker()
64{
65 ;
66}
67
68void
69TableWalker::completeDrain()
70{
71 if (drainEvent && stateQueueL1.empty() && stateQueueL2.empty() &&
72 pendingQueue.empty()) {
73 changeState(Drained);
74 DPRINTF(Drain, "TableWalker done draining, processing drain event\n");
75 drainEvent->process();
76 drainEvent = NULL;
77 }
78}
79
80unsigned int
81TableWalker::drain(Event *de)
82{
83 unsigned int count = port.drain(de);
84
85 if (stateQueueL1.empty() && stateQueueL2.empty() &&
86 pendingQueue.empty()) {
87 changeState(Drained);
88 DPRINTF(Drain, "TableWalker free, no need to drain\n");
89
90 // table walker is drained, but its ports may still need to be drained
91 return count;
92 } else {
93 drainEvent = de;
94 changeState(Draining);
95 DPRINTF(Drain, "TableWalker not drained\n");
96
97 // return port drain count plus the table walker itself needs to drain
98 return count + 1;
99
100 }
101}
102
103void
104TableWalker::resume()
105{
106 MemObject::resume();
107 if ((params()->sys->getMemoryMode() == Enums::timing) && currState) {
108 delete currState;
109 currState = NULL;
110 }
111}
112
113MasterPort&
114TableWalker::getMasterPort(const std::string &if_name, int idx)
115{
116 if (if_name == "port") {
117 return port;
118 }
119 return MemObject::getMasterPort(if_name, idx);
120}
121
122Fault
123TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _mode,
124 TLB::Translation *_trans, bool _timing, bool _functional)
125{
126 assert(!(_functional && _timing));
127 if (!currState) {
128 // For atomic mode, a new WalkerState instance should be only created
129 // once per TLB. For timing mode, a new instance is generated for every
130 // TLB miss.
131 DPRINTF(TLBVerbose, "creating new instance of WalkerState\n");
132
133 currState = new WalkerState();
134 currState->tableWalker = this;
135 } else if (_timing) {
136 // This is a translation that was completed and then faulted again
137 // because some underlying parameters that affect the translation
138 // changed out from under us (e.g. asid). It will either be a
139 // misprediction, in which case nothing will happen or we'll use
140 // this fault to re-execute the faulting instruction which should clean
141 // up everything.
142 if (currState->vaddr == _req->getVaddr()) {
143 return new ReExec;
144 }
145 panic("currState should always be empty in timing mode!\n");
146 }
147
148 currState->tc = _tc;
149 currState->transState = _trans;
150 currState->req = _req;
151 currState->fault = NoFault;
152 currState->contextId = _cid;
153 currState->timing = _timing;
154 currState->functional = _functional;
155 currState->mode = _mode;
156
157 /** @todo These should be cached or grabbed from cached copies in
158 the TLB, all these miscreg reads are expensive */
159 currState->vaddr = currState->req->getVaddr();
160 currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR);
161 sctlr = currState->sctlr;
162 currState->N = currState->tc->readMiscReg(MISCREG_TTBCR);
163
164 currState->isFetch = (currState->mode == TLB::Execute);
165 currState->isWrite = (currState->mode == TLB::Write);
166
167
168 if (!currState->timing)
169 return processWalk();
170
171 if (pending || pendingQueue.size()) {
172 pendingQueue.push_back(currState);
173 currState = NULL;
174 } else {
175 pending = true;
176 return processWalk();
177 }
178
179 return NoFault;
180}
181
182void
183TableWalker::processWalkWrapper()
184{
185 assert(!currState);
186 assert(pendingQueue.size());
187 currState = pendingQueue.front();
188 pendingQueue.pop_front();
189 pending = true;
190 processWalk();
191}
192
193Fault
194TableWalker::processWalk()
195{
196 Addr ttbr = 0;
197
198 // If translation isn't enabled, we shouldn't be here
199 assert(currState->sctlr.m);
200
201 DPRINTF(TLB, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n",
202 currState->vaddr, currState->N, mbits(currState->vaddr, 31,
203 32-currState->N));
204
205 if (currState->N == 0 || !mbits(currState->vaddr, 31, 32-currState->N)) {
206 DPRINTF(TLB, " - Selecting TTBR0\n");
207 ttbr = currState->tc->readMiscReg(MISCREG_TTBR0);
208 } else {
209 DPRINTF(TLB, " - Selecting TTBR1\n");
210 ttbr = currState->tc->readMiscReg(MISCREG_TTBR1);
211 currState->N = 0;
212 }
213
214 Addr l1desc_addr = mbits(ttbr, 31, 14-currState->N) |
215 (bits(currState->vaddr,31-currState->N,20) << 2);
216 DPRINTF(TLB, " - Descriptor at address %#x\n", l1desc_addr);
217
218
219 // Trickbox address check
220 Fault f;
221 f = tlb->walkTrickBoxCheck(l1desc_addr, currState->vaddr, sizeof(uint32_t),
222 currState->isFetch, currState->isWrite, 0, true);
223 if (f) {
224 DPRINTF(TLB, "Trickbox check caused fault on %#x\n", currState->vaddr);
225 if (currState->timing) {
226 pending = false;
227 nextWalk(currState->tc);
228 currState = NULL;
229 } else {
230 currState->tc = NULL;
231 currState->req = NULL;
232 }
233 return f;
234 }
235
236 Request::Flags flag = 0;
237 if (currState->sctlr.c == 0) {
238 flag = Request::UNCACHEABLE;
239 }
240
241 if (currState->timing) {
242 port.dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
243 &doL1DescEvent, (uint8_t*)&currState->l1Desc.data,
244 currState->tc->getCpuPtr()->ticks(1), flag);
245 DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n",
246 stateQueueL1.size());
247 stateQueueL1.push_back(currState);
248 currState = NULL;
249 } else if (!currState->functional) {
250 port.dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
251 NULL, (uint8_t*)&currState->l1Desc.data,
252 currState->tc->getCpuPtr()->ticks(1), flag);
253 doL1Descriptor();
254 f = currState->fault;
255 } else {
256 RequestPtr req = new Request(l1desc_addr, sizeof(uint32_t), flag, masterId);
257 PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
258 pkt->dataStatic((uint8_t*)&currState->l1Desc.data);
259 port.sendFunctional(pkt);
260 doL1Descriptor();
261 delete req;
262 delete pkt;
263 f = currState->fault;
264 }
265
266 return f;
267}
268
269void
270TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr,
271 uint8_t texcb, bool s)
272{
273 // Note: tc and sctlr local variables are hiding tc and sctrl class
274 // variables
275 DPRINTF(TLBVerbose, "memAttrs texcb:%d s:%d\n", texcb, s);
276 te.shareable = false; // default value
277 te.nonCacheable = false;
278 bool outer_shareable = false;
279 if (sctlr.tre == 0 || ((sctlr.tre == 1) && (sctlr.m == 0))) {
280 switch(texcb) {
281 case 0: // Stongly-ordered
282 te.nonCacheable = true;
283 te.mtype = TlbEntry::StronglyOrdered;
284 te.shareable = true;
285 te.innerAttrs = 1;
286 te.outerAttrs = 0;
287 break;
288 case 1: // Shareable Device
289 te.nonCacheable = true;
290 te.mtype = TlbEntry::Device;
291 te.shareable = true;
292 te.innerAttrs = 3;
293 te.outerAttrs = 0;
294 break;
295 case 2: // Outer and Inner Write-Through, no Write-Allocate
296 te.mtype = TlbEntry::Normal;
297 te.shareable = s;
298 te.innerAttrs = 6;
299 te.outerAttrs = bits(texcb, 1, 0);
300 break;
301 case 3: // Outer and Inner Write-Back, no Write-Allocate
302 te.mtype = TlbEntry::Normal;
303 te.shareable = s;
304 te.innerAttrs = 7;
305 te.outerAttrs = bits(texcb, 1, 0);
306 break;
307 case 4: // Outer and Inner Non-cacheable
308 te.nonCacheable = true;
309 te.mtype = TlbEntry::Normal;
310 te.shareable = s;
311 te.innerAttrs = 0;
312 te.outerAttrs = bits(texcb, 1, 0);
313 break;
314 case 5: // Reserved
315 panic("Reserved texcb value!\n");
316 break;
317 case 6: // Implementation Defined
318 panic("Implementation-defined texcb value!\n");
319 break;
320 case 7: // Outer and Inner Write-Back, Write-Allocate
321 te.mtype = TlbEntry::Normal;
322 te.shareable = s;
323 te.innerAttrs = 5;
324 te.outerAttrs = 1;
325 break;
326 case 8: // Non-shareable Device
327 te.nonCacheable = true;
328 te.mtype = TlbEntry::Device;
329 te.shareable = false;
330 te.innerAttrs = 3;
331 te.outerAttrs = 0;
332 break;
333 case 9 ... 15: // Reserved
334 panic("Reserved texcb value!\n");
335 break;
336 case 16 ... 31: // Cacheable Memory
337 te.mtype = TlbEntry::Normal;
338 te.shareable = s;
339 if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0)
340 te.nonCacheable = true;
341 te.innerAttrs = bits(texcb, 1, 0);
342 te.outerAttrs = bits(texcb, 3, 2);
343 break;
344 default:
345 panic("More than 32 states for 5 bits?\n");
346 }
347 } else {
348 assert(tc);
349 PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
350 NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
351 DPRINTF(TLBVerbose, "memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr);
352 uint8_t curr_tr = 0, curr_ir = 0, curr_or = 0;
353 switch(bits(texcb, 2,0)) {
354 case 0:
355 curr_tr = prrr.tr0;
356 curr_ir = nmrr.ir0;
357 curr_or = nmrr.or0;
358 outer_shareable = (prrr.nos0 == 0);
359 break;
360 case 1:
361 curr_tr = prrr.tr1;
362 curr_ir = nmrr.ir1;
363 curr_or = nmrr.or1;
364 outer_shareable = (prrr.nos1 == 0);
365 break;
366 case 2:
367 curr_tr = prrr.tr2;
368 curr_ir = nmrr.ir2;
369 curr_or = nmrr.or2;
370 outer_shareable = (prrr.nos2 == 0);
371 break;
372 case 3:
373 curr_tr = prrr.tr3;
374 curr_ir = nmrr.ir3;
375 curr_or = nmrr.or3;
376 outer_shareable = (prrr.nos3 == 0);
377 break;
378 case 4:
379 curr_tr = prrr.tr4;
380 curr_ir = nmrr.ir4;
381 curr_or = nmrr.or4;
382 outer_shareable = (prrr.nos4 == 0);
383 break;
384 case 5:
385 curr_tr = prrr.tr5;
386 curr_ir = nmrr.ir5;
387 curr_or = nmrr.or5;
388 outer_shareable = (prrr.nos5 == 0);
389 break;
390 case 6:
391 panic("Imp defined type\n");
392 case 7:
393 curr_tr = prrr.tr7;
394 curr_ir = nmrr.ir7;
395 curr_or = nmrr.or7;
396 outer_shareable = (prrr.nos7 == 0);
397 break;
398 }
399
400 switch(curr_tr) {
401 case 0:
402 DPRINTF(TLBVerbose, "StronglyOrdered\n");
403 te.mtype = TlbEntry::StronglyOrdered;
404 te.nonCacheable = true;
405 te.innerAttrs = 1;
406 te.outerAttrs = 0;
407 te.shareable = true;
408 break;
409 case 1:
410 DPRINTF(TLBVerbose, "Device ds1:%d ds0:%d s:%d\n",
411 prrr.ds1, prrr.ds0, s);
412 te.mtype = TlbEntry::Device;
413 te.nonCacheable = true;
414 te.innerAttrs = 3;
415 te.outerAttrs = 0;
416 if (prrr.ds1 && s)
417 te.shareable = true;
418 if (prrr.ds0 && !s)
419 te.shareable = true;
420 break;
421 case 2:
422 DPRINTF(TLBVerbose, "Normal ns1:%d ns0:%d s:%d\n",
423 prrr.ns1, prrr.ns0, s);
424 te.mtype = TlbEntry::Normal;
425 if (prrr.ns1 && s)
426 te.shareable = true;
427 if (prrr.ns0 && !s)
428 te.shareable = true;
429 break;
430 case 3:
431 panic("Reserved type");
432 }
433
434 if (te.mtype == TlbEntry::Normal){
435 switch(curr_ir) {
436 case 0:
437 te.nonCacheable = true;
438 te.innerAttrs = 0;
439 break;
440 case 1:
441 te.innerAttrs = 5;
442 break;
443 case 2:
444 te.innerAttrs = 6;
445 break;
446 case 3:
447 te.innerAttrs = 7;
448 break;
449 }
450
451 switch(curr_or) {
452 case 0:
453 te.nonCacheable = true;
454 te.outerAttrs = 0;
455 break;
456 case 1:
457 te.outerAttrs = 1;
458 break;
459 case 2:
460 te.outerAttrs = 2;
461 break;
462 case 3:
463 te.outerAttrs = 3;
464 break;
465 }
466 }
467 }
468 DPRINTF(TLBVerbose, "memAttrs: shareable: %d, innerAttrs: %d, \
469 outerAttrs: %d\n",
470 te.shareable, te.innerAttrs, te.outerAttrs);
471
472 /** Formatting for Physical Address Register (PAR)
473 * Only including lower bits (TLB info here)
474 * PAR:
475 * PA [31:12]
476 * Reserved [11]
477 * TLB info [10:1]
478 * NOS [10] (Not Outer Sharable)
479 * NS [9] (Non-Secure)
480 * -- [8] (Implementation Defined)
481 * SH [7] (Sharable)
482 * Inner[6:4](Inner memory attributes)
483 * Outer[3:2](Outer memory attributes)
484 * SS [1] (SuperSection)
485 * F [0] (Fault, Fault Status in [6:1] if faulted)
486 */
487 te.attributes = (
488 ((outer_shareable ? 0:1) << 10) |
489 // TODO: NS Bit
490 ((te.shareable ? 1:0) << 7) |
491 (te.innerAttrs << 4) |
492 (te.outerAttrs << 2)
493 // TODO: Supersection bit
494 // TODO: Fault bit
495 );
496
497
498}
499
500void
501TableWalker::doL1Descriptor()
502{
503 DPRINTF(TLB, "L1 descriptor for %#x is %#x\n",
504 currState->vaddr, currState->l1Desc.data);
505 TlbEntry te;
506
507 switch (currState->l1Desc.type()) {
508 case L1Descriptor::Ignore:
509 case L1Descriptor::Reserved:
510 if (!currState->timing) {
511 currState->tc = NULL;
512 currState->req = NULL;
513 }
514 DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n");
515 if (currState->isFetch)
516 currState->fault =
517 new PrefetchAbort(currState->vaddr, ArmFault::Translation0);
518 else
519 currState->fault =
520 new DataAbort(currState->vaddr, 0, currState->isWrite,
521 ArmFault::Translation0);
522 return;
523 case L1Descriptor::Section:
524 if (currState->sctlr.afe && bits(currState->l1Desc.ap(), 0) == 0) {
525 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is
526 * enabled if set, do l1.Desc.setAp0() instead of generating
527 * AccessFlag0
528 */
529
530 currState->fault = new DataAbort(currState->vaddr,
531 currState->l1Desc.domain(), currState->isWrite,
532 ArmFault::AccessFlag0);
533 }
534 if (currState->l1Desc.supersection()) {
535 panic("Haven't implemented supersections\n");
536 }
537 te.N = 20;
538 te.pfn = currState->l1Desc.pfn();
539 te.size = (1<<te.N) - 1;
540 te.global = !currState->l1Desc.global();
541 te.valid = true;
542 te.vpn = currState->vaddr >> te.N;
543 te.sNp = true;
544 te.xn = currState->l1Desc.xn();
545 te.ap = currState->l1Desc.ap();
546 te.domain = currState->l1Desc.domain();
547 te.asid = currState->contextId;
548 memAttrs(currState->tc, te, currState->sctlr,
549 currState->l1Desc.texcb(), currState->l1Desc.shareable());
550
551 DPRINTF(TLB, "Inserting Section Descriptor into TLB\n");
552 DPRINTF(TLB, " - N:%d pfn:%#x size: %#x global:%d valid: %d\n",
553 te.N, te.pfn, te.size, te.global, te.valid);
554 DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d nc:%d\n",
555 te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid,
556 te.nonCacheable);
557 DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n",
558 currState->l1Desc.domain(), currState->l1Desc.data,
559 (currState->l1Desc.data >> 5) & 0xF );
560
561 if (!currState->timing) {
562 currState->tc = NULL;
563 currState->req = NULL;
564 }
565 tlb->insert(currState->vaddr, te);
566
567 return;
568 case L1Descriptor::PageTable:
569 Addr l2desc_addr;
570 l2desc_addr = currState->l1Desc.l2Addr() |
571 (bits(currState->vaddr, 19,12) << 2);
572 DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n",
573 l2desc_addr);
574
575 // Trickbox address check
576 currState->fault = tlb->walkTrickBoxCheck(l2desc_addr, currState->vaddr,
577 sizeof(uint32_t), currState->isFetch, currState->isWrite,
578 currState->l1Desc.domain(), false);
579
580 if (currState->fault) {
581 if (!currState->timing) {
582 currState->tc = NULL;
583 currState->req = NULL;
584 }
585 return;
586 }
587
588
589 if (currState->timing) {
590 currState->delayed = true;
591 port.dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
592 &doL2DescEvent, (uint8_t*)&currState->l2Desc.data,
593 currState->tc->getCpuPtr()->ticks(1));
594 } else if (!currState->functional) {
595 port.dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
596 NULL, (uint8_t*)&currState->l2Desc.data,
597 currState->tc->getCpuPtr()->ticks(1));
598 doL2Descriptor();
599 } else {
600 RequestPtr req = new Request(l2desc_addr, sizeof(uint32_t), 0,
601 masterId);
602 PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
603 pkt->dataStatic((uint8_t*)&currState->l2Desc.data);
604 port.sendFunctional(pkt);
605 doL2Descriptor();
606 delete req;
607 delete pkt;
608 }
609 return;
610 default:
611 panic("A new type in a 2 bit field?\n");
612 }
613}
614
615void
616TableWalker::doL2Descriptor()
617{
618 DPRINTF(TLB, "L2 descriptor for %#x is %#x\n",
619 currState->vaddr, currState->l2Desc.data);
620 TlbEntry te;
621
622 if (currState->l2Desc.invalid()) {
623 DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
624 if (!currState->timing) {
625 currState->tc = NULL;
626 currState->req = NULL;
627 }
628 if (currState->isFetch)
629 currState->fault =
630 new PrefetchAbort(currState->vaddr, ArmFault::Translation1);
631 else
632 currState->fault =
633 new DataAbort(currState->vaddr, currState->l1Desc.domain(),
634 currState->isWrite, ArmFault::Translation1);
635 return;
636 }
637
638 if (currState->sctlr.afe && bits(currState->l2Desc.ap(), 0) == 0) {
639 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled
640 * if set, do l2.Desc.setAp0() instead of generating AccessFlag0
641 */
642
643 currState->fault =
644 new DataAbort(currState->vaddr, 0, currState->isWrite,
645 ArmFault::AccessFlag1);
646
647 }
648
649 if (currState->l2Desc.large()) {
650 te.N = 16;
651 te.pfn = currState->l2Desc.pfn();
652 } else {
653 te.N = 12;
654 te.pfn = currState->l2Desc.pfn();
655 }
656
657 te.valid = true;
658 te.size = (1 << te.N) - 1;
659 te.asid = currState->contextId;
660 te.sNp = false;
661 te.vpn = currState->vaddr >> te.N;
662 te.global = currState->l2Desc.global();
663 te.xn = currState->l2Desc.xn();
664 te.ap = currState->l2Desc.ap();
665 te.domain = currState->l1Desc.domain();
666 memAttrs(currState->tc, te, currState->sctlr, currState->l2Desc.texcb(),
667 currState->l2Desc.shareable());
668
669 if (!currState->timing) {
670 currState->tc = NULL;
671 currState->req = NULL;
672 }
673 tlb->insert(currState->vaddr, te);
674}
675
676void
677TableWalker::doL1DescriptorWrapper()
678{
679 currState = stateQueueL1.front();
680 currState->delayed = false;
681
682 DPRINTF(TLBVerbose, "L1 Desc object host addr: %p\n",&currState->l1Desc.data);
683 DPRINTF(TLBVerbose, "L1 Desc object data: %08x\n",currState->l1Desc.data);
684
685 DPRINTF(TLBVerbose, "calling doL1Descriptor for vaddr:%#x\n", currState->vaddr);
686 doL1Descriptor();
687
688 stateQueueL1.pop_front();
689 completeDrain();
690 // Check if fault was generated
691 if (currState->fault != NoFault) {
692 currState->transState->finish(currState->fault, currState->req,
693 currState->tc, currState->mode);
694
695 pending = false;
696 nextWalk(currState->tc);
697
698 currState->req = NULL;
699 currState->tc = NULL;
700 currState->delayed = false;
701 delete currState;
702 }
703 else if (!currState->delayed) {
704 // delay is not set so there is no L2 to do
705 DPRINTF(TLBVerbose, "calling translateTiming again\n");
706 currState->fault = tlb->translateTiming(currState->req, currState->tc,
707 currState->transState, currState->mode);
708
709 pending = false;
710 nextWalk(currState->tc);
711
712 currState->req = NULL;
713 currState->tc = NULL;
714 currState->delayed = false;
715 delete currState;
716 } else {
717 // need to do L2 descriptor
718 stateQueueL2.push_back(currState);
719 }
720 currState = NULL;
721}
722
723void
724TableWalker::doL2DescriptorWrapper()
725{
726 currState = stateQueueL2.front();
727 assert(currState->delayed);
728
729 DPRINTF(TLBVerbose, "calling doL2Descriptor for vaddr:%#x\n",
730 currState->vaddr);
731 doL2Descriptor();
732
733 // Check if fault was generated
734 if (currState->fault != NoFault) {
735 currState->transState->finish(currState->fault, currState->req,
736 currState->tc, currState->mode);
737 }
738 else {
739 DPRINTF(TLBVerbose, "calling translateTiming again\n");
740 currState->fault = tlb->translateTiming(currState->req, currState->tc,
741 currState->transState, currState->mode);
742 }
743
744
745 stateQueueL2.pop_front();
746 completeDrain();
747 pending = false;
748 nextWalk(currState->tc);
749
750 currState->req = NULL;
751 currState->tc = NULL;
752 currState->delayed = false;
753
754 delete currState;
755 currState = NULL;
756}
757
758void
759TableWalker::nextWalk(ThreadContext *tc)
760{
761 if (pendingQueue.size())
762 schedule(doProcessEvent, tc->getCpuPtr()->nextCycle(curTick()+1));
763}
764
765
766
767ArmISA::TableWalker *
768ArmTableWalkerParams::create()
769{
770 return new ArmISA::TableWalker(this);
771}
772
55 tlb(NULL), currState(NULL), pending(false),
56 masterId(p->sys->getMasterId(name())),
57 doL1DescEvent(this), doL2DescEvent(this), doProcessEvent(this)
58{
59 sctlr = 0;
60}
61
62TableWalker::~TableWalker()
63{
64 ;
65}
66
67void
68TableWalker::completeDrain()
69{
70 if (drainEvent && stateQueueL1.empty() && stateQueueL2.empty() &&
71 pendingQueue.empty()) {
72 changeState(Drained);
73 DPRINTF(Drain, "TableWalker done draining, processing drain event\n");
74 drainEvent->process();
75 drainEvent = NULL;
76 }
77}
78
79unsigned int
80TableWalker::drain(Event *de)
81{
82 unsigned int count = port.drain(de);
83
84 if (stateQueueL1.empty() && stateQueueL2.empty() &&
85 pendingQueue.empty()) {
86 changeState(Drained);
87 DPRINTF(Drain, "TableWalker free, no need to drain\n");
88
89 // table walker is drained, but its ports may still need to be drained
90 return count;
91 } else {
92 drainEvent = de;
93 changeState(Draining);
94 DPRINTF(Drain, "TableWalker not drained\n");
95
96 // return port drain count plus the table walker itself needs to drain
97 return count + 1;
98
99 }
100}
101
102void
103TableWalker::resume()
104{
105 MemObject::resume();
106 if ((params()->sys->getMemoryMode() == Enums::timing) && currState) {
107 delete currState;
108 currState = NULL;
109 }
110}
111
112MasterPort&
113TableWalker::getMasterPort(const std::string &if_name, int idx)
114{
115 if (if_name == "port") {
116 return port;
117 }
118 return MemObject::getMasterPort(if_name, idx);
119}
120
121Fault
122TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _mode,
123 TLB::Translation *_trans, bool _timing, bool _functional)
124{
125 assert(!(_functional && _timing));
126 if (!currState) {
127 // For atomic mode, a new WalkerState instance should be only created
128 // once per TLB. For timing mode, a new instance is generated for every
129 // TLB miss.
130 DPRINTF(TLBVerbose, "creating new instance of WalkerState\n");
131
132 currState = new WalkerState();
133 currState->tableWalker = this;
134 } else if (_timing) {
135 // This is a translation that was completed and then faulted again
136 // because some underlying parameters that affect the translation
137 // changed out from under us (e.g. asid). It will either be a
138 // misprediction, in which case nothing will happen or we'll use
139 // this fault to re-execute the faulting instruction which should clean
140 // up everything.
141 if (currState->vaddr == _req->getVaddr()) {
142 return new ReExec;
143 }
144 panic("currState should always be empty in timing mode!\n");
145 }
146
147 currState->tc = _tc;
148 currState->transState = _trans;
149 currState->req = _req;
150 currState->fault = NoFault;
151 currState->contextId = _cid;
152 currState->timing = _timing;
153 currState->functional = _functional;
154 currState->mode = _mode;
155
156 /** @todo These should be cached or grabbed from cached copies in
157 the TLB, all these miscreg reads are expensive */
158 currState->vaddr = currState->req->getVaddr();
159 currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR);
160 sctlr = currState->sctlr;
161 currState->N = currState->tc->readMiscReg(MISCREG_TTBCR);
162
163 currState->isFetch = (currState->mode == TLB::Execute);
164 currState->isWrite = (currState->mode == TLB::Write);
165
166
167 if (!currState->timing)
168 return processWalk();
169
170 if (pending || pendingQueue.size()) {
171 pendingQueue.push_back(currState);
172 currState = NULL;
173 } else {
174 pending = true;
175 return processWalk();
176 }
177
178 return NoFault;
179}
180
181void
182TableWalker::processWalkWrapper()
183{
184 assert(!currState);
185 assert(pendingQueue.size());
186 currState = pendingQueue.front();
187 pendingQueue.pop_front();
188 pending = true;
189 processWalk();
190}
191
192Fault
193TableWalker::processWalk()
194{
195 Addr ttbr = 0;
196
197 // If translation isn't enabled, we shouldn't be here
198 assert(currState->sctlr.m);
199
200 DPRINTF(TLB, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n",
201 currState->vaddr, currState->N, mbits(currState->vaddr, 31,
202 32-currState->N));
203
204 if (currState->N == 0 || !mbits(currState->vaddr, 31, 32-currState->N)) {
205 DPRINTF(TLB, " - Selecting TTBR0\n");
206 ttbr = currState->tc->readMiscReg(MISCREG_TTBR0);
207 } else {
208 DPRINTF(TLB, " - Selecting TTBR1\n");
209 ttbr = currState->tc->readMiscReg(MISCREG_TTBR1);
210 currState->N = 0;
211 }
212
213 Addr l1desc_addr = mbits(ttbr, 31, 14-currState->N) |
214 (bits(currState->vaddr,31-currState->N,20) << 2);
215 DPRINTF(TLB, " - Descriptor at address %#x\n", l1desc_addr);
216
217
218 // Trickbox address check
219 Fault f;
220 f = tlb->walkTrickBoxCheck(l1desc_addr, currState->vaddr, sizeof(uint32_t),
221 currState->isFetch, currState->isWrite, 0, true);
222 if (f) {
223 DPRINTF(TLB, "Trickbox check caused fault on %#x\n", currState->vaddr);
224 if (currState->timing) {
225 pending = false;
226 nextWalk(currState->tc);
227 currState = NULL;
228 } else {
229 currState->tc = NULL;
230 currState->req = NULL;
231 }
232 return f;
233 }
234
235 Request::Flags flag = 0;
236 if (currState->sctlr.c == 0) {
237 flag = Request::UNCACHEABLE;
238 }
239
240 if (currState->timing) {
241 port.dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
242 &doL1DescEvent, (uint8_t*)&currState->l1Desc.data,
243 currState->tc->getCpuPtr()->ticks(1), flag);
244 DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n",
245 stateQueueL1.size());
246 stateQueueL1.push_back(currState);
247 currState = NULL;
248 } else if (!currState->functional) {
249 port.dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
250 NULL, (uint8_t*)&currState->l1Desc.data,
251 currState->tc->getCpuPtr()->ticks(1), flag);
252 doL1Descriptor();
253 f = currState->fault;
254 } else {
255 RequestPtr req = new Request(l1desc_addr, sizeof(uint32_t), flag, masterId);
256 PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
257 pkt->dataStatic((uint8_t*)&currState->l1Desc.data);
258 port.sendFunctional(pkt);
259 doL1Descriptor();
260 delete req;
261 delete pkt;
262 f = currState->fault;
263 }
264
265 return f;
266}
267
268void
269TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr,
270 uint8_t texcb, bool s)
271{
272 // Note: tc and sctlr local variables are hiding tc and sctrl class
273 // variables
274 DPRINTF(TLBVerbose, "memAttrs texcb:%d s:%d\n", texcb, s);
275 te.shareable = false; // default value
276 te.nonCacheable = false;
277 bool outer_shareable = false;
278 if (sctlr.tre == 0 || ((sctlr.tre == 1) && (sctlr.m == 0))) {
279 switch(texcb) {
280 case 0: // Stongly-ordered
281 te.nonCacheable = true;
282 te.mtype = TlbEntry::StronglyOrdered;
283 te.shareable = true;
284 te.innerAttrs = 1;
285 te.outerAttrs = 0;
286 break;
287 case 1: // Shareable Device
288 te.nonCacheable = true;
289 te.mtype = TlbEntry::Device;
290 te.shareable = true;
291 te.innerAttrs = 3;
292 te.outerAttrs = 0;
293 break;
294 case 2: // Outer and Inner Write-Through, no Write-Allocate
295 te.mtype = TlbEntry::Normal;
296 te.shareable = s;
297 te.innerAttrs = 6;
298 te.outerAttrs = bits(texcb, 1, 0);
299 break;
300 case 3: // Outer and Inner Write-Back, no Write-Allocate
301 te.mtype = TlbEntry::Normal;
302 te.shareable = s;
303 te.innerAttrs = 7;
304 te.outerAttrs = bits(texcb, 1, 0);
305 break;
306 case 4: // Outer and Inner Non-cacheable
307 te.nonCacheable = true;
308 te.mtype = TlbEntry::Normal;
309 te.shareable = s;
310 te.innerAttrs = 0;
311 te.outerAttrs = bits(texcb, 1, 0);
312 break;
313 case 5: // Reserved
314 panic("Reserved texcb value!\n");
315 break;
316 case 6: // Implementation Defined
317 panic("Implementation-defined texcb value!\n");
318 break;
319 case 7: // Outer and Inner Write-Back, Write-Allocate
320 te.mtype = TlbEntry::Normal;
321 te.shareable = s;
322 te.innerAttrs = 5;
323 te.outerAttrs = 1;
324 break;
325 case 8: // Non-shareable Device
326 te.nonCacheable = true;
327 te.mtype = TlbEntry::Device;
328 te.shareable = false;
329 te.innerAttrs = 3;
330 te.outerAttrs = 0;
331 break;
332 case 9 ... 15: // Reserved
333 panic("Reserved texcb value!\n");
334 break;
335 case 16 ... 31: // Cacheable Memory
336 te.mtype = TlbEntry::Normal;
337 te.shareable = s;
338 if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0)
339 te.nonCacheable = true;
340 te.innerAttrs = bits(texcb, 1, 0);
341 te.outerAttrs = bits(texcb, 3, 2);
342 break;
343 default:
344 panic("More than 32 states for 5 bits?\n");
345 }
346 } else {
347 assert(tc);
348 PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
349 NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
350 DPRINTF(TLBVerbose, "memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr);
351 uint8_t curr_tr = 0, curr_ir = 0, curr_or = 0;
352 switch(bits(texcb, 2,0)) {
353 case 0:
354 curr_tr = prrr.tr0;
355 curr_ir = nmrr.ir0;
356 curr_or = nmrr.or0;
357 outer_shareable = (prrr.nos0 == 0);
358 break;
359 case 1:
360 curr_tr = prrr.tr1;
361 curr_ir = nmrr.ir1;
362 curr_or = nmrr.or1;
363 outer_shareable = (prrr.nos1 == 0);
364 break;
365 case 2:
366 curr_tr = prrr.tr2;
367 curr_ir = nmrr.ir2;
368 curr_or = nmrr.or2;
369 outer_shareable = (prrr.nos2 == 0);
370 break;
371 case 3:
372 curr_tr = prrr.tr3;
373 curr_ir = nmrr.ir3;
374 curr_or = nmrr.or3;
375 outer_shareable = (prrr.nos3 == 0);
376 break;
377 case 4:
378 curr_tr = prrr.tr4;
379 curr_ir = nmrr.ir4;
380 curr_or = nmrr.or4;
381 outer_shareable = (prrr.nos4 == 0);
382 break;
383 case 5:
384 curr_tr = prrr.tr5;
385 curr_ir = nmrr.ir5;
386 curr_or = nmrr.or5;
387 outer_shareable = (prrr.nos5 == 0);
388 break;
389 case 6:
390 panic("Imp defined type\n");
391 case 7:
392 curr_tr = prrr.tr7;
393 curr_ir = nmrr.ir7;
394 curr_or = nmrr.or7;
395 outer_shareable = (prrr.nos7 == 0);
396 break;
397 }
398
399 switch(curr_tr) {
400 case 0:
401 DPRINTF(TLBVerbose, "StronglyOrdered\n");
402 te.mtype = TlbEntry::StronglyOrdered;
403 te.nonCacheable = true;
404 te.innerAttrs = 1;
405 te.outerAttrs = 0;
406 te.shareable = true;
407 break;
408 case 1:
409 DPRINTF(TLBVerbose, "Device ds1:%d ds0:%d s:%d\n",
410 prrr.ds1, prrr.ds0, s);
411 te.mtype = TlbEntry::Device;
412 te.nonCacheable = true;
413 te.innerAttrs = 3;
414 te.outerAttrs = 0;
415 if (prrr.ds1 && s)
416 te.shareable = true;
417 if (prrr.ds0 && !s)
418 te.shareable = true;
419 break;
420 case 2:
421 DPRINTF(TLBVerbose, "Normal ns1:%d ns0:%d s:%d\n",
422 prrr.ns1, prrr.ns0, s);
423 te.mtype = TlbEntry::Normal;
424 if (prrr.ns1 && s)
425 te.shareable = true;
426 if (prrr.ns0 && !s)
427 te.shareable = true;
428 break;
429 case 3:
430 panic("Reserved type");
431 }
432
433 if (te.mtype == TlbEntry::Normal){
434 switch(curr_ir) {
435 case 0:
436 te.nonCacheable = true;
437 te.innerAttrs = 0;
438 break;
439 case 1:
440 te.innerAttrs = 5;
441 break;
442 case 2:
443 te.innerAttrs = 6;
444 break;
445 case 3:
446 te.innerAttrs = 7;
447 break;
448 }
449
450 switch(curr_or) {
451 case 0:
452 te.nonCacheable = true;
453 te.outerAttrs = 0;
454 break;
455 case 1:
456 te.outerAttrs = 1;
457 break;
458 case 2:
459 te.outerAttrs = 2;
460 break;
461 case 3:
462 te.outerAttrs = 3;
463 break;
464 }
465 }
466 }
467 DPRINTF(TLBVerbose, "memAttrs: shareable: %d, innerAttrs: %d, \
468 outerAttrs: %d\n",
469 te.shareable, te.innerAttrs, te.outerAttrs);
470
471 /** Formatting for Physical Address Register (PAR)
472 * Only including lower bits (TLB info here)
473 * PAR:
474 * PA [31:12]
475 * Reserved [11]
476 * TLB info [10:1]
477 * NOS [10] (Not Outer Sharable)
478 * NS [9] (Non-Secure)
479 * -- [8] (Implementation Defined)
480 * SH [7] (Sharable)
481 * Inner[6:4](Inner memory attributes)
482 * Outer[3:2](Outer memory attributes)
483 * SS [1] (SuperSection)
484 * F [0] (Fault, Fault Status in [6:1] if faulted)
485 */
486 te.attributes = (
487 ((outer_shareable ? 0:1) << 10) |
488 // TODO: NS Bit
489 ((te.shareable ? 1:0) << 7) |
490 (te.innerAttrs << 4) |
491 (te.outerAttrs << 2)
492 // TODO: Supersection bit
493 // TODO: Fault bit
494 );
495
496
497}
498
499void
500TableWalker::doL1Descriptor()
501{
502 DPRINTF(TLB, "L1 descriptor for %#x is %#x\n",
503 currState->vaddr, currState->l1Desc.data);
504 TlbEntry te;
505
506 switch (currState->l1Desc.type()) {
507 case L1Descriptor::Ignore:
508 case L1Descriptor::Reserved:
509 if (!currState->timing) {
510 currState->tc = NULL;
511 currState->req = NULL;
512 }
513 DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n");
514 if (currState->isFetch)
515 currState->fault =
516 new PrefetchAbort(currState->vaddr, ArmFault::Translation0);
517 else
518 currState->fault =
519 new DataAbort(currState->vaddr, 0, currState->isWrite,
520 ArmFault::Translation0);
521 return;
522 case L1Descriptor::Section:
523 if (currState->sctlr.afe && bits(currState->l1Desc.ap(), 0) == 0) {
524 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is
525 * enabled if set, do l1.Desc.setAp0() instead of generating
526 * AccessFlag0
527 */
528
529 currState->fault = new DataAbort(currState->vaddr,
530 currState->l1Desc.domain(), currState->isWrite,
531 ArmFault::AccessFlag0);
532 }
533 if (currState->l1Desc.supersection()) {
534 panic("Haven't implemented supersections\n");
535 }
536 te.N = 20;
537 te.pfn = currState->l1Desc.pfn();
538 te.size = (1<<te.N) - 1;
539 te.global = !currState->l1Desc.global();
540 te.valid = true;
541 te.vpn = currState->vaddr >> te.N;
542 te.sNp = true;
543 te.xn = currState->l1Desc.xn();
544 te.ap = currState->l1Desc.ap();
545 te.domain = currState->l1Desc.domain();
546 te.asid = currState->contextId;
547 memAttrs(currState->tc, te, currState->sctlr,
548 currState->l1Desc.texcb(), currState->l1Desc.shareable());
549
550 DPRINTF(TLB, "Inserting Section Descriptor into TLB\n");
551 DPRINTF(TLB, " - N:%d pfn:%#x size: %#x global:%d valid: %d\n",
552 te.N, te.pfn, te.size, te.global, te.valid);
553 DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d nc:%d\n",
554 te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid,
555 te.nonCacheable);
556 DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n",
557 currState->l1Desc.domain(), currState->l1Desc.data,
558 (currState->l1Desc.data >> 5) & 0xF );
559
560 if (!currState->timing) {
561 currState->tc = NULL;
562 currState->req = NULL;
563 }
564 tlb->insert(currState->vaddr, te);
565
566 return;
567 case L1Descriptor::PageTable:
568 Addr l2desc_addr;
569 l2desc_addr = currState->l1Desc.l2Addr() |
570 (bits(currState->vaddr, 19,12) << 2);
571 DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n",
572 l2desc_addr);
573
574 // Trickbox address check
575 currState->fault = tlb->walkTrickBoxCheck(l2desc_addr, currState->vaddr,
576 sizeof(uint32_t), currState->isFetch, currState->isWrite,
577 currState->l1Desc.domain(), false);
578
579 if (currState->fault) {
580 if (!currState->timing) {
581 currState->tc = NULL;
582 currState->req = NULL;
583 }
584 return;
585 }
586
587
588 if (currState->timing) {
589 currState->delayed = true;
590 port.dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
591 &doL2DescEvent, (uint8_t*)&currState->l2Desc.data,
592 currState->tc->getCpuPtr()->ticks(1));
593 } else if (!currState->functional) {
594 port.dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
595 NULL, (uint8_t*)&currState->l2Desc.data,
596 currState->tc->getCpuPtr()->ticks(1));
597 doL2Descriptor();
598 } else {
599 RequestPtr req = new Request(l2desc_addr, sizeof(uint32_t), 0,
600 masterId);
601 PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
602 pkt->dataStatic((uint8_t*)&currState->l2Desc.data);
603 port.sendFunctional(pkt);
604 doL2Descriptor();
605 delete req;
606 delete pkt;
607 }
608 return;
609 default:
610 panic("A new type in a 2 bit field?\n");
611 }
612}
613
614void
615TableWalker::doL2Descriptor()
616{
617 DPRINTF(TLB, "L2 descriptor for %#x is %#x\n",
618 currState->vaddr, currState->l2Desc.data);
619 TlbEntry te;
620
621 if (currState->l2Desc.invalid()) {
622 DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
623 if (!currState->timing) {
624 currState->tc = NULL;
625 currState->req = NULL;
626 }
627 if (currState->isFetch)
628 currState->fault =
629 new PrefetchAbort(currState->vaddr, ArmFault::Translation1);
630 else
631 currState->fault =
632 new DataAbort(currState->vaddr, currState->l1Desc.domain(),
633 currState->isWrite, ArmFault::Translation1);
634 return;
635 }
636
637 if (currState->sctlr.afe && bits(currState->l2Desc.ap(), 0) == 0) {
638 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled
639 * if set, do l2.Desc.setAp0() instead of generating AccessFlag0
640 */
641
642 currState->fault =
643 new DataAbort(currState->vaddr, 0, currState->isWrite,
644 ArmFault::AccessFlag1);
645
646 }
647
648 if (currState->l2Desc.large()) {
649 te.N = 16;
650 te.pfn = currState->l2Desc.pfn();
651 } else {
652 te.N = 12;
653 te.pfn = currState->l2Desc.pfn();
654 }
655
656 te.valid = true;
657 te.size = (1 << te.N) - 1;
658 te.asid = currState->contextId;
659 te.sNp = false;
660 te.vpn = currState->vaddr >> te.N;
661 te.global = currState->l2Desc.global();
662 te.xn = currState->l2Desc.xn();
663 te.ap = currState->l2Desc.ap();
664 te.domain = currState->l1Desc.domain();
665 memAttrs(currState->tc, te, currState->sctlr, currState->l2Desc.texcb(),
666 currState->l2Desc.shareable());
667
668 if (!currState->timing) {
669 currState->tc = NULL;
670 currState->req = NULL;
671 }
672 tlb->insert(currState->vaddr, te);
673}
674
675void
676TableWalker::doL1DescriptorWrapper()
677{
678 currState = stateQueueL1.front();
679 currState->delayed = false;
680
681 DPRINTF(TLBVerbose, "L1 Desc object host addr: %p\n",&currState->l1Desc.data);
682 DPRINTF(TLBVerbose, "L1 Desc object data: %08x\n",currState->l1Desc.data);
683
684 DPRINTF(TLBVerbose, "calling doL1Descriptor for vaddr:%#x\n", currState->vaddr);
685 doL1Descriptor();
686
687 stateQueueL1.pop_front();
688 completeDrain();
689 // Check if fault was generated
690 if (currState->fault != NoFault) {
691 currState->transState->finish(currState->fault, currState->req,
692 currState->tc, currState->mode);
693
694 pending = false;
695 nextWalk(currState->tc);
696
697 currState->req = NULL;
698 currState->tc = NULL;
699 currState->delayed = false;
700 delete currState;
701 }
702 else if (!currState->delayed) {
703 // delay is not set so there is no L2 to do
704 DPRINTF(TLBVerbose, "calling translateTiming again\n");
705 currState->fault = tlb->translateTiming(currState->req, currState->tc,
706 currState->transState, currState->mode);
707
708 pending = false;
709 nextWalk(currState->tc);
710
711 currState->req = NULL;
712 currState->tc = NULL;
713 currState->delayed = false;
714 delete currState;
715 } else {
716 // need to do L2 descriptor
717 stateQueueL2.push_back(currState);
718 }
719 currState = NULL;
720}
721
722void
723TableWalker::doL2DescriptorWrapper()
724{
725 currState = stateQueueL2.front();
726 assert(currState->delayed);
727
728 DPRINTF(TLBVerbose, "calling doL2Descriptor for vaddr:%#x\n",
729 currState->vaddr);
730 doL2Descriptor();
731
732 // Check if fault was generated
733 if (currState->fault != NoFault) {
734 currState->transState->finish(currState->fault, currState->req,
735 currState->tc, currState->mode);
736 }
737 else {
738 DPRINTF(TLBVerbose, "calling translateTiming again\n");
739 currState->fault = tlb->translateTiming(currState->req, currState->tc,
740 currState->transState, currState->mode);
741 }
742
743
744 stateQueueL2.pop_front();
745 completeDrain();
746 pending = false;
747 nextWalk(currState->tc);
748
749 currState->req = NULL;
750 currState->tc = NULL;
751 currState->delayed = false;
752
753 delete currState;
754 currState = NULL;
755}
756
757void
758TableWalker::nextWalk(ThreadContext *tc)
759{
760 if (pendingQueue.size())
761 schedule(doProcessEvent, tc->getCpuPtr()->nextCycle(curTick()+1));
762}
763
764
765
766ArmISA::TableWalker *
767ArmTableWalkerParams::create()
768{
769 return new ArmISA::TableWalker(this);
770}
771