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