table_walker.cc (9180:ee8d7a51651d) table_walker.cc (9258:baa17ba80e06)
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), drainEvent(NULL),
55 tlb(NULL), currState(NULL), pending(false),
56 masterId(p->sys->getMasterId(name())),
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), drainEvent(NULL),
55 tlb(NULL), currState(NULL), pending(false),
56 masterId(p->sys->getMasterId(name())),
57 numSquashable(p->num_squash_per_cycle),
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();
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();
187 pendingQueue.pop_front();
188 pending = true;
189 processWalk();
188
189
190 if (!currState->transState->squashed()) {
191 // We've got a valid request, lets process it
192 pending = true;
193 pendingQueue.pop_front();
194 processWalk();
195 return;
196 }
197
198
199 // If the instruction that we were translating for has been
200 // squashed we shouldn't bother.
201 unsigned num_squashed = 0;
202 ThreadContext *tc = currState->tc;
203 assert(currState->transState->squashed());
204 while ((num_squashed < numSquashable) && currState &&
205 currState->transState->squashed()) {
206 pendingQueue.pop_front();
207 num_squashed++;
208
209 DPRINTF(TLB, "Squashing table walk for address %#x\n", currState->vaddr);
210
211 // finish the translation which will delete the translation object
212 currState->transState->finish(new UnimpFault("Squashed Inst"),
213 currState->req, currState->tc, currState->mode);
214
215 // delete the current request
216 delete currState;
217
218 // peak at the next one
219 if (pendingQueue.size())
220 currState = pendingQueue.front();
221 else
222 currState = NULL;
223 }
224
225 // if we've still got pending translations schedule more work
226 nextWalk(tc);
227 currState = NULL;
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()->clockPeriod(), flag);
244 DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before "
245 "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()->clockPeriod(), 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()->clockPeriod());
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()->clockPeriod());
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()->clockEdge(Cycles(1)));
763}
764
765
766
767ArmISA::TableWalker *
768ArmTableWalkerParams::create()
769{
770 return new ArmISA::TableWalker(this);
771}
772
228}
229
230Fault
231TableWalker::processWalk()
232{
233 Addr ttbr = 0;
234
235 // If translation isn't enabled, we shouldn't be here
236 assert(currState->sctlr.m);
237
238 DPRINTF(TLB, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n",
239 currState->vaddr, currState->N, mbits(currState->vaddr, 31,
240 32-currState->N));
241
242 if (currState->N == 0 || !mbits(currState->vaddr, 31, 32-currState->N)) {
243 DPRINTF(TLB, " - Selecting TTBR0\n");
244 ttbr = currState->tc->readMiscReg(MISCREG_TTBR0);
245 } else {
246 DPRINTF(TLB, " - Selecting TTBR1\n");
247 ttbr = currState->tc->readMiscReg(MISCREG_TTBR1);
248 currState->N = 0;
249 }
250
251 Addr l1desc_addr = mbits(ttbr, 31, 14-currState->N) |
252 (bits(currState->vaddr,31-currState->N,20) << 2);
253 DPRINTF(TLB, " - Descriptor at address %#x\n", l1desc_addr);
254
255
256 // Trickbox address check
257 Fault f;
258 f = tlb->walkTrickBoxCheck(l1desc_addr, currState->vaddr, sizeof(uint32_t),
259 currState->isFetch, currState->isWrite, 0, true);
260 if (f) {
261 DPRINTF(TLB, "Trickbox check caused fault on %#x\n", currState->vaddr);
262 if (currState->timing) {
263 pending = false;
264 nextWalk(currState->tc);
265 currState = NULL;
266 } else {
267 currState->tc = NULL;
268 currState->req = NULL;
269 }
270 return f;
271 }
272
273 Request::Flags flag = 0;
274 if (currState->sctlr.c == 0) {
275 flag = Request::UNCACHEABLE;
276 }
277
278 if (currState->timing) {
279 port.dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
280 &doL1DescEvent, (uint8_t*)&currState->l1Desc.data,
281 currState->tc->getCpuPtr()->clockPeriod(), flag);
282 DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before "
283 "adding: %d\n",
284 stateQueueL1.size());
285 stateQueueL1.push_back(currState);
286 currState = NULL;
287 } else if (!currState->functional) {
288 port.dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t),
289 NULL, (uint8_t*)&currState->l1Desc.data,
290 currState->tc->getCpuPtr()->clockPeriod(), flag);
291 doL1Descriptor();
292 f = currState->fault;
293 } else {
294 RequestPtr req = new Request(l1desc_addr, sizeof(uint32_t), flag, masterId);
295 PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
296 pkt->dataStatic((uint8_t*)&currState->l1Desc.data);
297 port.sendFunctional(pkt);
298 doL1Descriptor();
299 delete req;
300 delete pkt;
301 f = currState->fault;
302 }
303
304 return f;
305}
306
307void
308TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr,
309 uint8_t texcb, bool s)
310{
311 // Note: tc and sctlr local variables are hiding tc and sctrl class
312 // variables
313 DPRINTF(TLBVerbose, "memAttrs texcb:%d s:%d\n", texcb, s);
314 te.shareable = false; // default value
315 te.nonCacheable = false;
316 bool outer_shareable = false;
317 if (sctlr.tre == 0 || ((sctlr.tre == 1) && (sctlr.m == 0))) {
318 switch(texcb) {
319 case 0: // Stongly-ordered
320 te.nonCacheable = true;
321 te.mtype = TlbEntry::StronglyOrdered;
322 te.shareable = true;
323 te.innerAttrs = 1;
324 te.outerAttrs = 0;
325 break;
326 case 1: // Shareable Device
327 te.nonCacheable = true;
328 te.mtype = TlbEntry::Device;
329 te.shareable = true;
330 te.innerAttrs = 3;
331 te.outerAttrs = 0;
332 break;
333 case 2: // Outer and Inner Write-Through, no Write-Allocate
334 te.mtype = TlbEntry::Normal;
335 te.shareable = s;
336 te.innerAttrs = 6;
337 te.outerAttrs = bits(texcb, 1, 0);
338 break;
339 case 3: // Outer and Inner Write-Back, no Write-Allocate
340 te.mtype = TlbEntry::Normal;
341 te.shareable = s;
342 te.innerAttrs = 7;
343 te.outerAttrs = bits(texcb, 1, 0);
344 break;
345 case 4: // Outer and Inner Non-cacheable
346 te.nonCacheable = true;
347 te.mtype = TlbEntry::Normal;
348 te.shareable = s;
349 te.innerAttrs = 0;
350 te.outerAttrs = bits(texcb, 1, 0);
351 break;
352 case 5: // Reserved
353 panic("Reserved texcb value!\n");
354 break;
355 case 6: // Implementation Defined
356 panic("Implementation-defined texcb value!\n");
357 break;
358 case 7: // Outer and Inner Write-Back, Write-Allocate
359 te.mtype = TlbEntry::Normal;
360 te.shareable = s;
361 te.innerAttrs = 5;
362 te.outerAttrs = 1;
363 break;
364 case 8: // Non-shareable Device
365 te.nonCacheable = true;
366 te.mtype = TlbEntry::Device;
367 te.shareable = false;
368 te.innerAttrs = 3;
369 te.outerAttrs = 0;
370 break;
371 case 9 ... 15: // Reserved
372 panic("Reserved texcb value!\n");
373 break;
374 case 16 ... 31: // Cacheable Memory
375 te.mtype = TlbEntry::Normal;
376 te.shareable = s;
377 if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0)
378 te.nonCacheable = true;
379 te.innerAttrs = bits(texcb, 1, 0);
380 te.outerAttrs = bits(texcb, 3, 2);
381 break;
382 default:
383 panic("More than 32 states for 5 bits?\n");
384 }
385 } else {
386 assert(tc);
387 PRRR prrr = tc->readMiscReg(MISCREG_PRRR);
388 NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
389 DPRINTF(TLBVerbose, "memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr);
390 uint8_t curr_tr = 0, curr_ir = 0, curr_or = 0;
391 switch(bits(texcb, 2,0)) {
392 case 0:
393 curr_tr = prrr.tr0;
394 curr_ir = nmrr.ir0;
395 curr_or = nmrr.or0;
396 outer_shareable = (prrr.nos0 == 0);
397 break;
398 case 1:
399 curr_tr = prrr.tr1;
400 curr_ir = nmrr.ir1;
401 curr_or = nmrr.or1;
402 outer_shareable = (prrr.nos1 == 0);
403 break;
404 case 2:
405 curr_tr = prrr.tr2;
406 curr_ir = nmrr.ir2;
407 curr_or = nmrr.or2;
408 outer_shareable = (prrr.nos2 == 0);
409 break;
410 case 3:
411 curr_tr = prrr.tr3;
412 curr_ir = nmrr.ir3;
413 curr_or = nmrr.or3;
414 outer_shareable = (prrr.nos3 == 0);
415 break;
416 case 4:
417 curr_tr = prrr.tr4;
418 curr_ir = nmrr.ir4;
419 curr_or = nmrr.or4;
420 outer_shareable = (prrr.nos4 == 0);
421 break;
422 case 5:
423 curr_tr = prrr.tr5;
424 curr_ir = nmrr.ir5;
425 curr_or = nmrr.or5;
426 outer_shareable = (prrr.nos5 == 0);
427 break;
428 case 6:
429 panic("Imp defined type\n");
430 case 7:
431 curr_tr = prrr.tr7;
432 curr_ir = nmrr.ir7;
433 curr_or = nmrr.or7;
434 outer_shareable = (prrr.nos7 == 0);
435 break;
436 }
437
438 switch(curr_tr) {
439 case 0:
440 DPRINTF(TLBVerbose, "StronglyOrdered\n");
441 te.mtype = TlbEntry::StronglyOrdered;
442 te.nonCacheable = true;
443 te.innerAttrs = 1;
444 te.outerAttrs = 0;
445 te.shareable = true;
446 break;
447 case 1:
448 DPRINTF(TLBVerbose, "Device ds1:%d ds0:%d s:%d\n",
449 prrr.ds1, prrr.ds0, s);
450 te.mtype = TlbEntry::Device;
451 te.nonCacheable = true;
452 te.innerAttrs = 3;
453 te.outerAttrs = 0;
454 if (prrr.ds1 && s)
455 te.shareable = true;
456 if (prrr.ds0 && !s)
457 te.shareable = true;
458 break;
459 case 2:
460 DPRINTF(TLBVerbose, "Normal ns1:%d ns0:%d s:%d\n",
461 prrr.ns1, prrr.ns0, s);
462 te.mtype = TlbEntry::Normal;
463 if (prrr.ns1 && s)
464 te.shareable = true;
465 if (prrr.ns0 && !s)
466 te.shareable = true;
467 break;
468 case 3:
469 panic("Reserved type");
470 }
471
472 if (te.mtype == TlbEntry::Normal){
473 switch(curr_ir) {
474 case 0:
475 te.nonCacheable = true;
476 te.innerAttrs = 0;
477 break;
478 case 1:
479 te.innerAttrs = 5;
480 break;
481 case 2:
482 te.innerAttrs = 6;
483 break;
484 case 3:
485 te.innerAttrs = 7;
486 break;
487 }
488
489 switch(curr_or) {
490 case 0:
491 te.nonCacheable = true;
492 te.outerAttrs = 0;
493 break;
494 case 1:
495 te.outerAttrs = 1;
496 break;
497 case 2:
498 te.outerAttrs = 2;
499 break;
500 case 3:
501 te.outerAttrs = 3;
502 break;
503 }
504 }
505 }
506 DPRINTF(TLBVerbose, "memAttrs: shareable: %d, innerAttrs: %d, \
507 outerAttrs: %d\n",
508 te.shareable, te.innerAttrs, te.outerAttrs);
509
510 /** Formatting for Physical Address Register (PAR)
511 * Only including lower bits (TLB info here)
512 * PAR:
513 * PA [31:12]
514 * Reserved [11]
515 * TLB info [10:1]
516 * NOS [10] (Not Outer Sharable)
517 * NS [9] (Non-Secure)
518 * -- [8] (Implementation Defined)
519 * SH [7] (Sharable)
520 * Inner[6:4](Inner memory attributes)
521 * Outer[3:2](Outer memory attributes)
522 * SS [1] (SuperSection)
523 * F [0] (Fault, Fault Status in [6:1] if faulted)
524 */
525 te.attributes = (
526 ((outer_shareable ? 0:1) << 10) |
527 // TODO: NS Bit
528 ((te.shareable ? 1:0) << 7) |
529 (te.innerAttrs << 4) |
530 (te.outerAttrs << 2)
531 // TODO: Supersection bit
532 // TODO: Fault bit
533 );
534
535
536}
537
538void
539TableWalker::doL1Descriptor()
540{
541 DPRINTF(TLB, "L1 descriptor for %#x is %#x\n",
542 currState->vaddr, currState->l1Desc.data);
543 TlbEntry te;
544
545 switch (currState->l1Desc.type()) {
546 case L1Descriptor::Ignore:
547 case L1Descriptor::Reserved:
548 if (!currState->timing) {
549 currState->tc = NULL;
550 currState->req = NULL;
551 }
552 DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n");
553 if (currState->isFetch)
554 currState->fault =
555 new PrefetchAbort(currState->vaddr, ArmFault::Translation0);
556 else
557 currState->fault =
558 new DataAbort(currState->vaddr, 0, currState->isWrite,
559 ArmFault::Translation0);
560 return;
561 case L1Descriptor::Section:
562 if (currState->sctlr.afe && bits(currState->l1Desc.ap(), 0) == 0) {
563 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is
564 * enabled if set, do l1.Desc.setAp0() instead of generating
565 * AccessFlag0
566 */
567
568 currState->fault = new DataAbort(currState->vaddr,
569 currState->l1Desc.domain(), currState->isWrite,
570 ArmFault::AccessFlag0);
571 }
572 if (currState->l1Desc.supersection()) {
573 panic("Haven't implemented supersections\n");
574 }
575 te.N = 20;
576 te.pfn = currState->l1Desc.pfn();
577 te.size = (1<<te.N) - 1;
578 te.global = !currState->l1Desc.global();
579 te.valid = true;
580 te.vpn = currState->vaddr >> te.N;
581 te.sNp = true;
582 te.xn = currState->l1Desc.xn();
583 te.ap = currState->l1Desc.ap();
584 te.domain = currState->l1Desc.domain();
585 te.asid = currState->contextId;
586 memAttrs(currState->tc, te, currState->sctlr,
587 currState->l1Desc.texcb(), currState->l1Desc.shareable());
588
589 DPRINTF(TLB, "Inserting Section Descriptor into TLB\n");
590 DPRINTF(TLB, " - N:%d pfn:%#x size: %#x global:%d valid: %d\n",
591 te.N, te.pfn, te.size, te.global, te.valid);
592 DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d nc:%d\n",
593 te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid,
594 te.nonCacheable);
595 DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n",
596 currState->l1Desc.domain(), currState->l1Desc.data,
597 (currState->l1Desc.data >> 5) & 0xF );
598
599 if (!currState->timing) {
600 currState->tc = NULL;
601 currState->req = NULL;
602 }
603 tlb->insert(currState->vaddr, te);
604
605 return;
606 case L1Descriptor::PageTable:
607 Addr l2desc_addr;
608 l2desc_addr = currState->l1Desc.l2Addr() |
609 (bits(currState->vaddr, 19,12) << 2);
610 DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n",
611 l2desc_addr);
612
613 // Trickbox address check
614 currState->fault = tlb->walkTrickBoxCheck(l2desc_addr, currState->vaddr,
615 sizeof(uint32_t), currState->isFetch, currState->isWrite,
616 currState->l1Desc.domain(), false);
617
618 if (currState->fault) {
619 if (!currState->timing) {
620 currState->tc = NULL;
621 currState->req = NULL;
622 }
623 return;
624 }
625
626
627 if (currState->timing) {
628 currState->delayed = true;
629 port.dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
630 &doL2DescEvent, (uint8_t*)&currState->l2Desc.data,
631 currState->tc->getCpuPtr()->clockPeriod());
632 } else if (!currState->functional) {
633 port.dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
634 NULL, (uint8_t*)&currState->l2Desc.data,
635 currState->tc->getCpuPtr()->clockPeriod());
636 doL2Descriptor();
637 } else {
638 RequestPtr req = new Request(l2desc_addr, sizeof(uint32_t), 0,
639 masterId);
640 PacketPtr pkt = new Packet(req, MemCmd::ReadReq);
641 pkt->dataStatic((uint8_t*)&currState->l2Desc.data);
642 port.sendFunctional(pkt);
643 doL2Descriptor();
644 delete req;
645 delete pkt;
646 }
647 return;
648 default:
649 panic("A new type in a 2 bit field?\n");
650 }
651}
652
653void
654TableWalker::doL2Descriptor()
655{
656 DPRINTF(TLB, "L2 descriptor for %#x is %#x\n",
657 currState->vaddr, currState->l2Desc.data);
658 TlbEntry te;
659
660 if (currState->l2Desc.invalid()) {
661 DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
662 if (!currState->timing) {
663 currState->tc = NULL;
664 currState->req = NULL;
665 }
666 if (currState->isFetch)
667 currState->fault =
668 new PrefetchAbort(currState->vaddr, ArmFault::Translation1);
669 else
670 currState->fault =
671 new DataAbort(currState->vaddr, currState->l1Desc.domain(),
672 currState->isWrite, ArmFault::Translation1);
673 return;
674 }
675
676 if (currState->sctlr.afe && bits(currState->l2Desc.ap(), 0) == 0) {
677 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled
678 * if set, do l2.Desc.setAp0() instead of generating AccessFlag0
679 */
680
681 currState->fault =
682 new DataAbort(currState->vaddr, 0, currState->isWrite,
683 ArmFault::AccessFlag1);
684
685 }
686
687 if (currState->l2Desc.large()) {
688 te.N = 16;
689 te.pfn = currState->l2Desc.pfn();
690 } else {
691 te.N = 12;
692 te.pfn = currState->l2Desc.pfn();
693 }
694
695 te.valid = true;
696 te.size = (1 << te.N) - 1;
697 te.asid = currState->contextId;
698 te.sNp = false;
699 te.vpn = currState->vaddr >> te.N;
700 te.global = currState->l2Desc.global();
701 te.xn = currState->l2Desc.xn();
702 te.ap = currState->l2Desc.ap();
703 te.domain = currState->l1Desc.domain();
704 memAttrs(currState->tc, te, currState->sctlr, currState->l2Desc.texcb(),
705 currState->l2Desc.shareable());
706
707 if (!currState->timing) {
708 currState->tc = NULL;
709 currState->req = NULL;
710 }
711 tlb->insert(currState->vaddr, te);
712}
713
714void
715TableWalker::doL1DescriptorWrapper()
716{
717 currState = stateQueueL1.front();
718 currState->delayed = false;
719
720 DPRINTF(TLBVerbose, "L1 Desc object host addr: %p\n",&currState->l1Desc.data);
721 DPRINTF(TLBVerbose, "L1 Desc object data: %08x\n",currState->l1Desc.data);
722
723 DPRINTF(TLBVerbose, "calling doL1Descriptor for vaddr:%#x\n", currState->vaddr);
724 doL1Descriptor();
725
726 stateQueueL1.pop_front();
727 completeDrain();
728 // Check if fault was generated
729 if (currState->fault != NoFault) {
730 currState->transState->finish(currState->fault, currState->req,
731 currState->tc, currState->mode);
732
733 pending = false;
734 nextWalk(currState->tc);
735
736 currState->req = NULL;
737 currState->tc = NULL;
738 currState->delayed = false;
739 delete currState;
740 }
741 else if (!currState->delayed) {
742 // delay is not set so there is no L2 to do
743 DPRINTF(TLBVerbose, "calling translateTiming again\n");
744 currState->fault = tlb->translateTiming(currState->req, currState->tc,
745 currState->transState, currState->mode);
746
747 pending = false;
748 nextWalk(currState->tc);
749
750 currState->req = NULL;
751 currState->tc = NULL;
752 currState->delayed = false;
753 delete currState;
754 } else {
755 // need to do L2 descriptor
756 stateQueueL2.push_back(currState);
757 }
758 currState = NULL;
759}
760
761void
762TableWalker::doL2DescriptorWrapper()
763{
764 currState = stateQueueL2.front();
765 assert(currState->delayed);
766
767 DPRINTF(TLBVerbose, "calling doL2Descriptor for vaddr:%#x\n",
768 currState->vaddr);
769 doL2Descriptor();
770
771 // Check if fault was generated
772 if (currState->fault != NoFault) {
773 currState->transState->finish(currState->fault, currState->req,
774 currState->tc, currState->mode);
775 }
776 else {
777 DPRINTF(TLBVerbose, "calling translateTiming again\n");
778 currState->fault = tlb->translateTiming(currState->req, currState->tc,
779 currState->transState, currState->mode);
780 }
781
782
783 stateQueueL2.pop_front();
784 completeDrain();
785 pending = false;
786 nextWalk(currState->tc);
787
788 currState->req = NULL;
789 currState->tc = NULL;
790 currState->delayed = false;
791
792 delete currState;
793 currState = NULL;
794}
795
796void
797TableWalker::nextWalk(ThreadContext *tc)
798{
799 if (pendingQueue.size())
800 schedule(doProcessEvent, tc->getCpuPtr()->clockEdge(Cycles(1)));
801}
802
803
804
805ArmISA::TableWalker *
806ArmTableWalkerParams::create()
807{
808 return new ArmISA::TableWalker(this);
809}
810