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 46 47using namespace ArmISA; 48 49TableWalker::TableWalker(const Params *p) 50 : MemObject(p), port(NULL), tlb(NULL), tc(NULL), req(NULL), 51 doL1DescEvent(this), doL2DescEvent(this) 52{} 53 54TableWalker::~TableWalker() 55{ 56 ; 57} 58 59 60unsigned int 61drain(Event *de) 62{ 63 panic("Not implemented\n"); 64} 65 66Port* 67TableWalker::getPort(const std::string &if_name, int idx) 68{ 69 if (if_name == "port") { 70 if (port != NULL) 71 fatal("%s: port already connected to %s", 72 name(), port->getPeer()->name()); 73 System *sys = params()->sys; 74 Tick minb = params()->min_backoff; 75 Tick maxb = params()->max_backoff; 76 port = new DmaPort(this, sys, minb, maxb); 77 return port; 78 } 79 return NULL; 80} 81 82Fault 83TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode mode, 84 TLB::Translation *_trans, bool _timing) 85{ 86 // Right now 1 CPU == 1 TLB == 1 TLB walker 87 // In the future we might want to change this as multiple 88 // threads/contexts could share a walker and/or a TLB 89 if (tc || req) 90 panic("Overlapping TLB walks attempted\n"); 91 92 tc = _tc; 93 transState = _trans; 94 req = _req; 95 fault = NoFault; 96 contextId = _cid; 97 timing = _timing; 98
|
99 // XXX These should be cached or grabbed from cached copies in
100 // the TLB, all these miscreg reads are expensive
|
99 /** @todo These should be cached or grabbed from cached copies in 100 the TLB, all these miscreg reads are expensive */ |
101 vaddr = req->getVaddr() & ~PcModeMask; 102 sctlr = tc->readMiscReg(MISCREG_SCTLR); 103 cpsr = tc->readMiscReg(MISCREG_CPSR); 104 N = tc->readMiscReg(MISCREG_TTBCR); 105 Addr ttbr = 0; 106 107 isFetch = (mode == TLB::Execute); 108 isWrite = (mode == TLB::Write); 109 isPriv = (cpsr.mode != MODE_USER); 110 111 // If translation isn't enabled, we shouldn't be here 112 assert(sctlr.m); 113 114 DPRINTF(TLB, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n", 115 vaddr, N, mbits(vaddr, 31, 32-N)); 116 117 if (N == 0 || !mbits(vaddr, 31, 32-N)) { 118 DPRINTF(TLB, " - Selecting TTBR0\n"); 119 ttbr = tc->readMiscReg(MISCREG_TTBR0); 120 } else { 121 DPRINTF(TLB, " - Selecting TTBR1\n"); 122 ttbr = tc->readMiscReg(MISCREG_TTBR1); 123 N = 0; 124 } 125 126 Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(vaddr,31-N,20) << 2); 127 DPRINTF(TLB, " - Descriptor at address %#x\n", l1desc_addr); 128 129 130 // Trickbox address check 131 fault = tlb->walkTrickBoxCheck(l1desc_addr, vaddr, sizeof(uint32_t), 132 isFetch, isWrite, 0, true); 133 if (fault) { 134 tc = NULL; 135 req = NULL; 136 return fault; 137 } 138 139 if (timing) { 140 port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 141 &doL1DescEvent, (uint8_t*)&l1Desc.data, (Tick)0); 142 } else { 143 port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 144 NULL, (uint8_t*)&l1Desc.data, (Tick)0); 145 doL1Descriptor(); 146 } 147 148 return fault; 149} 150 151void
|
152TableWalker::memAttrs(TlbEntry &te, uint8_t texcb)
|
152TableWalker::memAttrs(TlbEntry &te, uint8_t texcb, bool s) |
153{
|
154
|
154 DPRINTF(TLBVerbose, "memAttrs texcb:%d s:%d\n", texcb, s); 155 te.shareable = false; // default value 156 bool outer_shareable = false; |
157 if (sctlr.tre == 0) { 158 switch(texcb) {
|
157 case 0:
158 case 1:
159 case 4:
160 case 8:
|
159 case 0: // Stongly-ordered |
160 te.nonCacheable = true;
|
161 te.mtype = TlbEntry::StronglyOrdered; 162 te.shareable = true; 163 te.innerAttrs = 1; 164 te.outerAttrs = 0; |
165 break;
|
163 case 16:
|
166 case 1: // Shareable Device 167 te.nonCacheable = true; 168 te.mtype = TlbEntry::Device; 169 te.shareable = true; 170 te.innerAttrs = 3; 171 te.outerAttrs = 0; 172 break; 173 case 2: // Outer and Inner Write-Through, no Write-Allocate 174 te.mtype = TlbEntry::Normal; 175 te.shareable = s; 176 te.innerAttrs = 6; 177 te.outerAttrs = bits(texcb, 1, 0); 178 break; 179 case 3: // Outer and Inner Write-Back, no Write-Allocate 180 te.mtype = TlbEntry::Normal; 181 te.shareable = s; 182 te.innerAttrs = 7; 183 te.outerAttrs = bits(texcb, 1, 0); 184 break; 185 case 4: // Outer and Inner Non-cacheable 186 te.nonCacheable = true; 187 te.mtype = TlbEntry::Normal; 188 te.shareable = s; 189 te.innerAttrs = 0; 190 te.outerAttrs = bits(texcb, 1, 0); 191 break; 192 case 5: // Reserved 193 break; 194 case 6: // Implementation Defined 195 break; 196 case 7: // Outer and Inner Write-Back, Write-Allocate 197 te.mtype = TlbEntry::Normal; 198 te.shareable = s; 199 te.innerAttrs = 5; 200 te.outerAttrs = 1; 201 break; 202 case 8: // Non-shareable Device 203 te.nonCacheable = true; 204 te.mtype = TlbEntry::Device; 205 te.shareable = false; 206 te.innerAttrs = 3; 207 te.outerAttrs = 0; 208 break; 209 case 9 ... 15: // Reserved 210 break; 211 case 16 ... 31: // Cacheable Memory 212 te.mtype = TlbEntry::Normal; 213 te.shareable = s; |
214 if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0) 215 te.nonCacheable = true;
|
216 te.innerAttrs = bits(texcb, 1, 0); 217 te.outerAttrs = bits(texcb, 3, 2); |
218 break;
|
219 default: 220 panic("More than 32 states for 5 bits?\n"); |
221 } 222 } else { 223 PRRR prrr = tc->readMiscReg(MISCREG_PRRR); 224 NMRR nmrr = tc->readMiscReg(MISCREG_NMRR);
|
225 DPRINTF(TLBVerbose, "memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr); 226 uint8_t curr_tr, curr_ir, curr_or; |
227 switch(bits(texcb, 2,0)) { 228 case 0:
|
173 if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2)
174 te.nonCacheable = true;
|
229 curr_tr = prrr.tr0; 230 curr_ir = nmrr.ir0; 231 curr_or = nmrr.or0; 232 outer_shareable = (prrr.nos0 == 0); |
233 break; 234 case 1:
|
177 if (nmrr.ir1 == 0 || nmrr.or1 == 0 || prrr.tr1 != 0x2)
178 te.nonCacheable = true;
|
235 curr_tr = prrr.tr1; 236 curr_ir = nmrr.ir1; 237 curr_or = nmrr.or1; 238 outer_shareable = (prrr.nos1 == 0); |
239 break; 240 case 2:
|
181 if (nmrr.ir2 == 0 || nmrr.or2 == 0 || prrr.tr2 != 0x2)
182 te.nonCacheable = true;
|
241 curr_tr = prrr.tr2; 242 curr_ir = nmrr.ir2; 243 curr_or = nmrr.or2; 244 outer_shareable = (prrr.nos2 == 0); |
245 break; 246 case 3:
|
185 if (nmrr.ir3 == 0 || nmrr.or3 == 0 || prrr.tr3 != 0x2)
186 te.nonCacheable = true;
|
247 curr_tr = prrr.tr3; 248 curr_ir = nmrr.ir3; 249 curr_or = nmrr.or3; 250 outer_shareable = (prrr.nos3 == 0); |
251 break; 252 case 4:
|
189 if (nmrr.ir4 == 0 || nmrr.or4 == 0 || prrr.tr4 != 0x2)
190 te.nonCacheable = true;
|
253 curr_tr = prrr.tr4; 254 curr_ir = nmrr.ir4; 255 curr_or = nmrr.or4; 256 outer_shareable = (prrr.nos4 == 0); |
257 break; 258 case 5:
|
193 if (nmrr.ir5 == 0 || nmrr.or5 == 0 || prrr.tr5 != 0x2)
194 te.nonCacheable = true;
|
259 curr_tr = prrr.tr5; 260 curr_ir = nmrr.ir5; 261 curr_or = nmrr.or5; 262 outer_shareable = (prrr.nos5 == 0); |
263 break; 264 case 6: 265 panic("Imp defined type\n"); 266 case 7:
|
199 if (nmrr.ir7 == 0 || nmrr.or7 == 0 || prrr.tr7 != 0x2)
200 te.nonCacheable = true;
|
267 curr_tr = prrr.tr7; 268 curr_ir = nmrr.ir7; 269 curr_or = nmrr.or7; 270 outer_shareable = (prrr.nos7 == 0); |
271 break; 272 }
|
273 274 switch(curr_tr) { 275 case 0: 276 DPRINTF(TLBVerbose, "StronglyOrdered\n"); 277 te.mtype = TlbEntry::StronglyOrdered; 278 te.nonCacheable = true; 279 te.innerAttrs = 1; 280 te.outerAttrs = 0; 281 te.shareable = true; 282 break; 283 case 1: 284 DPRINTF(TLBVerbose, "Device ds1:%d ds0:%d s:%d\n", 285 prrr.ds1, prrr.ds0, s); 286 te.mtype = TlbEntry::Device; 287 te.nonCacheable = true; 288 te.innerAttrs = 3; 289 te.outerAttrs = 0; 290 if (prrr.ds1 && s) 291 te.shareable = true; 292 if (prrr.ds0 && !s) 293 te.shareable = true; 294 break; 295 case 2: 296 DPRINTF(TLBVerbose, "Normal ns1:%d ns0:%d s:%d\n", 297 prrr.ns1, prrr.ns0, s); 298 te.mtype = TlbEntry::Normal; 299 if (prrr.ns1 && s) 300 te.shareable = true; 301 if (prrr.ns0 && !s) 302 te.shareable = true; 303 //te.shareable = outer_shareable; 304 break; 305 case 3: 306 panic("Reserved type"); 307 } 308 309 if (te.mtype == TlbEntry::Normal){ 310 switch(curr_ir) { 311 case 0: 312 te.nonCacheable = true; 313 te.innerAttrs = 0; 314 break; 315 case 1: 316 te.innerAttrs = 5; 317 break; 318 case 2: 319 te.innerAttrs = 6; 320 break; 321 case 3: 322 te.innerAttrs = 7; 323 break; 324 } 325 326 switch(curr_or) { 327 case 0: 328 te.nonCacheable = true; 329 te.outerAttrs = 0; 330 break; 331 case 1: 332 te.outerAttrs = 1; 333 break; 334 case 2: 335 te.outerAttrs = 2; 336 break; 337 case 3: 338 te.outerAttrs = 3; 339 break; 340 } 341 } |
342 }
|
343 344 /** Formatting for Physical Address Register (PAR) 345 * Only including lower bits (TLB info here) 346 * PAR: 347 * PA [31:12] 348 * Reserved [11] 349 * TLB info [10:1] 350 * NOS [10] (Not Outer Sharable) 351 * NS [9] (Non-Secure) 352 * -- [8] (Implementation Defined) 353 * SH [7] (Sharable) 354 * Inner[6:4](Inner memory attributes) 355 * Outer[3:2](Outer memory attributes) 356 * SS [1] (SuperSection) 357 * F [0] (Fault, Fault Status in [6:1] if faulted) 358 */ 359 te.attributes = ( 360 ((outer_shareable ? 0:1) << 10) | 361 // TODO: NS Bit 362 ((te.shareable ? 1:0) << 7) | 363 (te.innerAttrs << 4) | 364 (te.outerAttrs << 2) 365 // TODO: Supersection bit 366 // TODO: Fault bit 367 ); 368 369 |
370} 371 372void 373TableWalker::doL1Descriptor() 374{ 375 DPRINTF(TLB, "L1 descriptor for %#x is %#x\n", vaddr, l1Desc.data); 376 TlbEntry te; 377 378 switch (l1Desc.type()) { 379 case L1Descriptor::Ignore: 380 case L1Descriptor::Reserved: 381 tc = NULL; 382 req = NULL; 383 DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n"); 384 if (isFetch) 385 fault = new PrefetchAbort(vaddr, ArmFault::Translation0); 386 else
|
221 fault = new DataAbort(vaddr, NULL, isWrite, ArmFault::Translation0);
|
387 fault = new DataAbort(vaddr, NULL, isWrite, 388 ArmFault::Translation0); |
389 return; 390 case L1Descriptor::Section:
|
224 if (sctlr.afe && bits(l1Desc.ap(), 0) == 0)
225 panic("Haven't implemented AFE\n");
|
391 if (sctlr.afe && bits(l1Desc.ap(), 0) == 0) { 392 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is 393 * enabled if set, do l1.Desc.setAp0() instead of generating 394 * AccessFlag0 395 */ |
396
|
397 fault = new DataAbort(vaddr, NULL, isWrite, 398 ArmFault::AccessFlag0); 399 } 400 |
401 if (l1Desc.supersection()) { 402 panic("Haven't implemented supersections\n"); 403 } 404 te.N = 20; 405 te.pfn = l1Desc.pfn(); 406 te.size = (1<<te.N) - 1; 407 te.global = !l1Desc.global(); 408 te.valid = true; 409 te.vpn = vaddr >> te.N; 410 te.sNp = true; 411 te.xn = l1Desc.xn(); 412 te.ap = l1Desc.ap(); 413 te.domain = l1Desc.domain(); 414 te.asid = contextId;
|
241 memAttrs(te, l1Desc.texcb());
|
415 memAttrs(te, l1Desc.texcb(), l1Desc.shareable()); |
416 417 DPRINTF(TLB, "Inserting Section Descriptor into TLB\n"); 418 DPRINTF(TLB, " - N%d pfn:%#x size: %#x global:%d valid: %d\n", 419 te.N, te.pfn, te.size, te.global, te.valid); 420 DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d\n", 421 te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid); 422 DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n", 423 l1Desc.domain(), l1Desc.data, (l1Desc.data >> 5) & 0xF ); 424 425 tc = NULL; 426 req = NULL; 427 tlb->insert(vaddr, te); 428 429 return; 430 case L1Descriptor::PageTable: 431 Addr l2desc_addr; 432 l2desc_addr = l1Desc.l2Addr() | (bits(vaddr, 19,12) << 2);
|
259 DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n", l2desc_addr);
|
433 DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n", 434 l2desc_addr); |
435 436 // Trickbox address check 437 fault = tlb->walkTrickBoxCheck(l2desc_addr, vaddr, sizeof(uint32_t), 438 isFetch, isWrite, l1Desc.domain(), false); 439 if (fault) { 440 tc = NULL; 441 req = NULL; 442 return; 443 } 444 445 446 if (timing) { 447 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 448 &doL2DescEvent, (uint8_t*)&l2Desc.data, 0); 449 } else { 450 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 451 NULL, (uint8_t*)&l2Desc.data, 0); 452 doL2Descriptor(); 453 } 454 return; 455 default: 456 panic("A new type in a 2 bit field?\n"); 457 } 458} 459 460void 461TableWalker::doL2Descriptor() 462{ 463 DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", vaddr, l2Desc.data); 464 TlbEntry te; 465
|
291 if (sctlr.afe && bits(l1Desc.ap(), 0) == 0)
292 panic("Haven't implemented AFE\n");
293
|
466 if (l2Desc.invalid()) { 467 DPRINTF(TLB, "L2 descriptor invalid, causing fault\n"); 468 tc = NULL; 469 req = NULL; 470 if (isFetch) 471 fault = new PrefetchAbort(vaddr, ArmFault::Translation1); 472 else
|
301 fault = new DataAbort(vaddr, l1Desc.domain(), isWrite, ArmFault::Translation1);
|
473 fault = new DataAbort(vaddr, l1Desc.domain(), isWrite, 474 ArmFault::Translation1); |
475 return; 476 } 477
|
478 if (sctlr.afe && bits(l2Desc.ap(), 0) == 0) { 479 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled 480 * if set, do l2.Desc.setAp0() instead of generating AccessFlag0 481 */ 482 483 fault = new DataAbort(vaddr, NULL, isWrite, ArmFault::AccessFlag1); 484 } 485 |
486 if (l2Desc.large()) { 487 te.N = 16; 488 te.pfn = l2Desc.pfn(); 489 } else { 490 te.N = 12; 491 te.pfn = l2Desc.pfn(); 492 } 493 494 te.valid = true; 495 te.size = (1 << te.N) - 1; 496 te.asid = contextId; 497 te.sNp = false; 498 te.vpn = vaddr >> te.N; 499 te.global = l2Desc.global(); 500 te.xn = l2Desc.xn(); 501 te.ap = l2Desc.ap(); 502 te.domain = l1Desc.domain();
|
322 memAttrs(te, l2Desc.texcb());
|
503 memAttrs(te, l2Desc.texcb(), l2Desc.shareable()); |
504 505 tc = NULL; 506 req = NULL; 507 tlb->insert(vaddr, te); 508} 509 510ArmISA::TableWalker * 511ArmTableWalkerParams::create() 512{ 513 return new ArmISA::TableWalker(this); 514} 515
|