table_walker.cc (7608:17aabeaa1a8f) table_walker.cc (7611:c119da5a80c8)
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);
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
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);
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 =
443 new DataAbort(currState->vaddr, NULL, currState->isWrite,
442 currState->fault = new DataAbort(currState->vaddr,
443 currState->l1Desc.domain(), currState->isWrite,
444 ArmFault::AccessFlag0);
445 }
444 ArmFault::AccessFlag0);
445 }
446
447 if (currState->l1Desc.supersection()) {
448 panic("Haven't implemented supersections\n");
449 }
450 te.N = 20;
451 te.pfn = currState->l1Desc.pfn();
452 te.size = (1<<te.N) - 1;
453 te.global = !currState->l1Desc.global();
454 te.valid = true;
455 te.vpn = currState->vaddr >> te.N;
456 te.sNp = true;
457 te.xn = currState->l1Desc.xn();
458 te.ap = currState->l1Desc.ap();
459 te.domain = currState->l1Desc.domain();
460 te.asid = currState->contextId;
461 memAttrs(currState->tc, te, currState->sctlr,
462 currState->l1Desc.texcb(), currState->l1Desc.shareable());
463
464 DPRINTF(TLB, "Inserting Section Descriptor into TLB\n");
465 DPRINTF(TLB, " - N:%d pfn:%#x size: %#x global:%d valid: %d\n",
466 te.N, te.pfn, te.size, te.global, te.valid);
467 DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d nc:%d\n",
468 te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid,
469 te.nonCacheable);
470 DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n",
471 currState->l1Desc.domain(), currState->l1Desc.data,
472 (currState->l1Desc.data >> 5) & 0xF );
473
474 if (!currState->timing) {
475 currState->tc = NULL;
476 currState->req = NULL;
477 }
478 tlb->insert(currState->vaddr, te);
479
480 return;
481 case L1Descriptor::PageTable:
482 Addr l2desc_addr;
483 l2desc_addr = currState->l1Desc.l2Addr() |
484 (bits(currState->vaddr, 19,12) << 2);
485 DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n",
486 l2desc_addr);
487
488 // Trickbox address check
489 currState->fault = tlb->walkTrickBoxCheck(l2desc_addr, currState->vaddr,
490 sizeof(uint32_t), currState->isFetch, currState->isWrite,
491 currState->l1Desc.domain(), false);
492
493 if (currState->fault) {
494 if (!currState->timing) {
495 currState->tc = NULL;
496 currState->req = NULL;
497 }
498 return;
499 }
500
501
502 if (currState->timing) {
503 currState->delayed = true;
504 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
505 &doL2DescEvent, (uint8_t*)&currState->l2Desc.data, 0);
506 } else {
507 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t),
508 NULL, (uint8_t*)&currState->l2Desc.data, 0);
509 doL2Descriptor();
510 }
511 return;
512 default:
513 panic("A new type in a 2 bit field?\n");
514 }
515}
516
517void
518TableWalker::doL2Descriptor()
519{
520 DPRINTF(TLB, "L2 descriptor for %#x is %#x\n",
521 currState->vaddr, currState->l2Desc.data);
522 TlbEntry te;
523
524 if (currState->l2Desc.invalid()) {
525 DPRINTF(TLB, "L2 descriptor invalid, causing fault\n");
526 if (!currState->delayed) {
527 currState->tc = NULL;
528 currState->req = NULL;
529 }
530 if (currState->isFetch)
531 currState->fault =
532 new PrefetchAbort(currState->vaddr, ArmFault::Translation1);
533 else
534 currState->fault =
535 new DataAbort(currState->vaddr, currState->l1Desc.domain(),
536 currState->isWrite, ArmFault::Translation1);
537 return;
538 }
539
540 if (currState->sctlr.afe && bits(currState->l2Desc.ap(), 0) == 0) {
541 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled
542 * if set, do l2.Desc.setAp0() instead of generating AccessFlag0
543 */
544
545 currState->fault =
546 new DataAbort(currState->vaddr, 0, currState->isWrite,
547 ArmFault::AccessFlag1);
548
549 }
550
551 if (currState->l2Desc.large()) {
552 te.N = 16;
553 te.pfn = currState->l2Desc.pfn();
554 } else {
555 te.N = 12;
556 te.pfn = currState->l2Desc.pfn();
557 }
558
559 te.valid = true;
560 te.size = (1 << te.N) - 1;
561 te.asid = currState->contextId;
562 te.sNp = false;
563 te.vpn = currState->vaddr >> te.N;
564 te.global = currState->l2Desc.global();
565 te.xn = currState->l2Desc.xn();
566 te.ap = currState->l2Desc.ap();
567 te.domain = currState->l1Desc.domain();
568 memAttrs(currState->tc, te, currState->sctlr, currState->l2Desc.texcb(),
569 currState->l2Desc.shareable());
570
571 if (!currState->delayed) {
572 currState->tc = NULL;
573 currState->req = NULL;
574 }
575 tlb->insert(currState->vaddr, te);
576}
577
578void
579TableWalker::doL1DescriptorWrapper()
580{
581 currState = stateQueue.front();
582 currState->delayed = false;
583
584 DPRINTF(TLBVerbose, "L1 Desc object host addr: %p\n",&currState->l1Desc.data);
585 DPRINTF(TLBVerbose, "L1 Desc object data: %08x\n",currState->l1Desc.data);
586
587 DPRINTF(TLBVerbose, "calling doL1Descriptor for vaddr:%#x\n", currState->vaddr);
588 doL1Descriptor();
589
590 // Check if fault was generated
591 if (currState->fault != NoFault) {
592 currState->transState->finish(currState->fault, currState->req,
593 currState->tc, currState->mode);
594
595 currState->req = NULL;
596 currState->tc = NULL;
597 currState->delayed = false;
598
599 stateQueue.pop_front();
600 }
601 else if (!currState->delayed) {
602 DPRINTF(TLBVerbose, "calling translateTiming again\n");
603 currState->fault = tlb->translateTiming(currState->req, currState->tc,
604 currState->transState, currState->mode);
605
606 currState->req = NULL;
607 currState->tc = NULL;
608 currState->delayed = false;
609
610 stateQueue.pop_front();
611 }
612 currState = NULL;
613}
614
615void
616TableWalker::doL2DescriptorWrapper()
617{
618 currState = stateQueue.front();
619 assert(currState->delayed);
620
621 DPRINTF(TLBVerbose, "calling doL2Descriptor for vaddr:%#x\n",
622 currState->vaddr);
623 doL2Descriptor();
624
625 // Check if fault was generated
626 if (currState->fault != NoFault) {
627 currState->transState->finish(currState->fault, currState->req,
628 currState->tc, currState->mode);
629 }
630 else {
631 DPRINTF(TLBVerbose, "calling translateTiming again\n");
632 currState->fault = tlb->translateTiming(currState->req, currState->tc,
633 currState->transState, currState->mode);
634 }
635
636 currState->req = NULL;
637 currState->tc = NULL;
638 currState->delayed = false;
639
640 stateQueue.pop_front();
641 currState = NULL;
642}
643
644ArmISA::TableWalker *
645ArmTableWalkerParams::create()
646{
647 return new ArmISA::TableWalker(this);
648}
649
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{
580 currState = stateQueue.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
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) {
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();
610 }
611 currState = NULL;
612}
613
614void
615TableWalker::doL2DescriptorWrapper()
616{
617 currState = stateQueue.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
639 stateQueue.pop_front();
640 currState = NULL;
641}
642
643ArmISA::TableWalker *
644ArmTableWalkerParams::create()
645{
646 return new ArmISA::TableWalker(this);
647}
648