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