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#define NUM_WALKERS 2 // 2 should be enough to handle crossing page boundaries
47
|
46using namespace ArmISA; 47 48TableWalker::TableWalker(const Params *p)
|
51 : MemObject(p), stateQueue(NUM_WALKERS), port(NULL), tlb(NULL),
|
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 currState->tc = NULL; 149 currState->req = NULL; 150 return f; 151 } 152 153 if (currState->timing) { 154 port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 155 &doL1DescEvent, (uint8_t*)&currState->l1Desc.data, (Tick)0);
|
158 DPRINTF(TLBVerbose, "Adding to walker fifo: %d free before adding\n",
159 stateQueue.free_slots());
160 stateQueue.add(*currState);
|
156 DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n", 157 stateQueue.size()); 158 stateQueue.push_back(currState); 159 assert(stateQueue.size() < 5); |
160 currState = NULL; 161 } else { 162 port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 163 NULL, (uint8_t*)&currState->l1Desc.data, (Tick)0); 164 doL1Descriptor(); 165 f = currState->fault; 166 } 167 168 return f; 169} 170 171void 172TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, 173 uint8_t texcb, bool s) 174{ 175 // Note: tc and sctlr local variables are hiding tc and sctrl class 176 // variables 177 DPRINTF(TLBVerbose, "memAttrs texcb:%d s:%d\n", texcb, s); 178 te.shareable = false; // default value 179 bool outer_shareable = false; 180 if (sctlr.tre == 0 || ((sctlr.tre == 1) && (sctlr.m == 0))) { 181 switch(texcb) { 182 case 0: // Stongly-ordered 183 te.nonCacheable = true; 184 te.mtype = TlbEntry::StronglyOrdered; 185 te.shareable = true; 186 te.innerAttrs = 1; 187 te.outerAttrs = 0; 188 break; 189 case 1: // Shareable Device 190 te.nonCacheable = true; 191 te.mtype = TlbEntry::Device; 192 te.shareable = true; 193 te.innerAttrs = 3; 194 te.outerAttrs = 0; 195 break; 196 case 2: // Outer and Inner Write-Through, no Write-Allocate 197 te.mtype = TlbEntry::Normal; 198 te.shareable = s; 199 te.innerAttrs = 6; 200 te.outerAttrs = bits(texcb, 1, 0); 201 break; 202 case 3: // Outer and Inner Write-Back, no Write-Allocate 203 te.mtype = TlbEntry::Normal; 204 te.shareable = s; 205 te.innerAttrs = 7; 206 te.outerAttrs = bits(texcb, 1, 0); 207 break; 208 case 4: // Outer and Inner Non-cacheable 209 te.nonCacheable = true; 210 te.mtype = TlbEntry::Normal; 211 te.shareable = s; 212 te.innerAttrs = 0; 213 te.outerAttrs = bits(texcb, 1, 0); 214 break; 215 case 5: // Reserved 216 panic("Reserved texcb value!\n"); 217 break; 218 case 6: // Implementation Defined 219 panic("Implementation-defined texcb value!\n"); 220 break; 221 case 7: // Outer and Inner Write-Back, Write-Allocate 222 te.mtype = TlbEntry::Normal; 223 te.shareable = s; 224 te.innerAttrs = 5; 225 te.outerAttrs = 1; 226 break; 227 case 8: // Non-shareable Device 228 te.nonCacheable = true; 229 te.mtype = TlbEntry::Device; 230 te.shareable = false; 231 te.innerAttrs = 3; 232 te.outerAttrs = 0; 233 break; 234 case 9 ... 15: // Reserved 235 panic("Reserved texcb value!\n"); 236 break; 237 case 16 ... 31: // Cacheable Memory 238 te.mtype = TlbEntry::Normal; 239 te.shareable = s; 240 if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0) 241 te.nonCacheable = true; 242 te.innerAttrs = bits(texcb, 1, 0); 243 te.outerAttrs = bits(texcb, 3, 2); 244 break; 245 default: 246 panic("More than 32 states for 5 bits?\n"); 247 } 248 } else { 249 assert(tc); 250 PRRR prrr = tc->readMiscReg(MISCREG_PRRR); 251 NMRR nmrr = tc->readMiscReg(MISCREG_NMRR); 252 DPRINTF(TLBVerbose, "memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr); 253 uint8_t curr_tr, curr_ir, curr_or; 254 switch(bits(texcb, 2,0)) { 255 case 0: 256 curr_tr = prrr.tr0; 257 curr_ir = nmrr.ir0; 258 curr_or = nmrr.or0; 259 outer_shareable = (prrr.nos0 == 0); 260 break; 261 case 1: 262 curr_tr = prrr.tr1; 263 curr_ir = nmrr.ir1; 264 curr_or = nmrr.or1; 265 outer_shareable = (prrr.nos1 == 0); 266 break; 267 case 2: 268 curr_tr = prrr.tr2; 269 curr_ir = nmrr.ir2; 270 curr_or = nmrr.or2; 271 outer_shareable = (prrr.nos2 == 0); 272 break; 273 case 3: 274 curr_tr = prrr.tr3; 275 curr_ir = nmrr.ir3; 276 curr_or = nmrr.or3; 277 outer_shareable = (prrr.nos3 == 0); 278 break; 279 case 4: 280 curr_tr = prrr.tr4; 281 curr_ir = nmrr.ir4; 282 curr_or = nmrr.or4; 283 outer_shareable = (prrr.nos4 == 0); 284 break; 285 case 5: 286 curr_tr = prrr.tr5; 287 curr_ir = nmrr.ir5; 288 curr_or = nmrr.or5; 289 outer_shareable = (prrr.nos5 == 0); 290 break; 291 case 6: 292 panic("Imp defined type\n"); 293 case 7: 294 curr_tr = prrr.tr7; 295 curr_ir = nmrr.ir7; 296 curr_or = nmrr.or7; 297 outer_shareable = (prrr.nos7 == 0); 298 break; 299 } 300 301 switch(curr_tr) { 302 case 0: 303 DPRINTF(TLBVerbose, "StronglyOrdered\n"); 304 te.mtype = TlbEntry::StronglyOrdered; 305 te.nonCacheable = true; 306 te.innerAttrs = 1; 307 te.outerAttrs = 0; 308 te.shareable = true; 309 break; 310 case 1: 311 DPRINTF(TLBVerbose, "Device ds1:%d ds0:%d s:%d\n", 312 prrr.ds1, prrr.ds0, s); 313 te.mtype = TlbEntry::Device; 314 te.nonCacheable = true; 315 te.innerAttrs = 3; 316 te.outerAttrs = 0; 317 if (prrr.ds1 && s) 318 te.shareable = true; 319 if (prrr.ds0 && !s) 320 te.shareable = true; 321 break; 322 case 2: 323 DPRINTF(TLBVerbose, "Normal ns1:%d ns0:%d s:%d\n", 324 prrr.ns1, prrr.ns0, s); 325 te.mtype = TlbEntry::Normal; 326 if (prrr.ns1 && s) 327 te.shareable = true; 328 if (prrr.ns0 && !s) 329 te.shareable = true; 330 break; 331 case 3: 332 panic("Reserved type"); 333 } 334 335 if (te.mtype == TlbEntry::Normal){ 336 switch(curr_ir) { 337 case 0: 338 te.nonCacheable = true; 339 te.innerAttrs = 0; 340 break; 341 case 1: 342 te.innerAttrs = 5; 343 break; 344 case 2: 345 te.innerAttrs = 6; 346 break; 347 case 3: 348 te.innerAttrs = 7; 349 break; 350 } 351 352 switch(curr_or) { 353 case 0: 354 te.nonCacheable = true; 355 te.outerAttrs = 0; 356 break; 357 case 1: 358 te.outerAttrs = 1; 359 break; 360 case 2: 361 te.outerAttrs = 2; 362 break; 363 case 3: 364 te.outerAttrs = 3; 365 break; 366 } 367 } 368 } 369 DPRINTF(TLBVerbose, "memAttrs: shareable: %d, innerAttrs: %d, \ 370 outerAttrs: %d\n", 371 te.shareable, te.innerAttrs, te.outerAttrs); 372 373 /** Formatting for Physical Address Register (PAR) 374 * Only including lower bits (TLB info here) 375 * PAR: 376 * PA [31:12] 377 * Reserved [11] 378 * TLB info [10:1] 379 * NOS [10] (Not Outer Sharable) 380 * NS [9] (Non-Secure) 381 * -- [8] (Implementation Defined) 382 * SH [7] (Sharable) 383 * Inner[6:4](Inner memory attributes) 384 * Outer[3:2](Outer memory attributes) 385 * SS [1] (SuperSection) 386 * F [0] (Fault, Fault Status in [6:1] if faulted) 387 */ 388 te.attributes = ( 389 ((outer_shareable ? 0:1) << 10) | 390 // TODO: NS Bit 391 ((te.shareable ? 1:0) << 7) | 392 (te.innerAttrs << 4) | 393 (te.outerAttrs << 2) 394 // TODO: Supersection bit 395 // TODO: Fault bit 396 ); 397 398 399} 400 401void 402TableWalker::doL1Descriptor() 403{ 404 DPRINTF(TLB, "L1 descriptor for %#x is %#x\n", 405 currState->vaddr, currState->l1Desc.data); 406 TlbEntry te; 407 408 switch (currState->l1Desc.type()) { 409 case L1Descriptor::Ignore: 410 case L1Descriptor::Reserved: 411 if (!currState->delayed) { 412 currState->tc = NULL; 413 currState->req = NULL; 414 } 415 DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n"); 416 if (currState->isFetch) 417 currState->fault = 418 new PrefetchAbort(currState->vaddr, ArmFault::Translation0); 419 else 420 currState->fault = 421 new DataAbort(currState->vaddr, 0, currState->isWrite, 422 ArmFault::Translation0); 423 return; 424 case L1Descriptor::Section: 425 if (currState->sctlr.afe && bits(currState->l1Desc.ap(), 0) == 0) { 426 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is 427 * enabled if set, do l1.Desc.setAp0() instead of generating 428 * AccessFlag0 429 */ 430 431 currState->fault = 432 new DataAbort(currState->vaddr, NULL, currState->isWrite, 433 ArmFault::AccessFlag0); 434 } 435 436 if (currState->l1Desc.supersection()) { 437 panic("Haven't implemented supersections\n"); 438 } 439 te.N = 20; 440 te.pfn = currState->l1Desc.pfn(); 441 te.size = (1<<te.N) - 1; 442 te.global = !currState->l1Desc.global(); 443 te.valid = true; 444 te.vpn = currState->vaddr >> te.N; 445 te.sNp = true; 446 te.xn = currState->l1Desc.xn(); 447 te.ap = currState->l1Desc.ap(); 448 te.domain = currState->l1Desc.domain(); 449 te.asid = currState->contextId; 450 memAttrs(currState->tc, te, currState->sctlr, 451 currState->l1Desc.texcb(), currState->l1Desc.shareable()); 452 453 DPRINTF(TLB, "Inserting Section Descriptor into TLB\n"); 454 DPRINTF(TLB, " - N%d pfn:%#x size: %#x global:%d valid: %d\n", 455 te.N, te.pfn, te.size, te.global, te.valid); 456 DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d\n", 457 te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid); 458 DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n", 459 currState->l1Desc.domain(), currState->l1Desc.data, 460 (currState->l1Desc.data >> 5) & 0xF ); 461 462 if (!currState->timing) { 463 currState->tc = NULL; 464 currState->req = NULL; 465 } 466 tlb->insert(currState->vaddr, te); 467 468 return; 469 case L1Descriptor::PageTable: 470 Addr l2desc_addr; 471 l2desc_addr = currState->l1Desc.l2Addr() | 472 (bits(currState->vaddr, 19,12) << 2); 473 DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n", 474 l2desc_addr); 475 476 // Trickbox address check 477 currState->fault = tlb->walkTrickBoxCheck(l2desc_addr, currState->vaddr, 478 sizeof(uint32_t), currState->isFetch, currState->isWrite, 479 currState->l1Desc.domain(), false); 480 481 if (currState->fault) { 482 if (!currState->timing) { 483 currState->tc = NULL; 484 currState->req = NULL; 485 } 486 return; 487 } 488 489 490 if (currState->timing) { 491 currState->delayed = true; 492 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 493 &doL2DescEvent, (uint8_t*)&currState->l2Desc.data, 0); 494 } else { 495 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 496 NULL, (uint8_t*)&currState->l2Desc.data, 0); 497 doL2Descriptor(); 498 } 499 return; 500 default: 501 panic("A new type in a 2 bit field?\n"); 502 } 503} 504 505void 506TableWalker::doL2Descriptor() 507{ 508 DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", 509 currState->vaddr, currState->l2Desc.data); 510 TlbEntry te; 511 512 if (currState->l2Desc.invalid()) { 513 DPRINTF(TLB, "L2 descriptor invalid, causing fault\n"); 514 if (!currState->delayed) { 515 currState->tc = NULL; 516 currState->req = NULL; 517 } 518 if (currState->isFetch) 519 currState->fault = 520 new PrefetchAbort(currState->vaddr, ArmFault::Translation1); 521 else 522 currState->fault = 523 new DataAbort(currState->vaddr, currState->l1Desc.domain(), 524 currState->isWrite, ArmFault::Translation1); 525 return; 526 } 527 528 if (currState->sctlr.afe && bits(currState->l2Desc.ap(), 0) == 0) { 529 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled 530 * if set, do l2.Desc.setAp0() instead of generating AccessFlag0 531 */ 532 533 currState->fault = 534 new DataAbort(currState->vaddr, 0, currState->isWrite, 535 ArmFault::AccessFlag1); 536 537 } 538 539 if (currState->l2Desc.large()) { 540 te.N = 16; 541 te.pfn = currState->l2Desc.pfn(); 542 } else { 543 te.N = 12; 544 te.pfn = currState->l2Desc.pfn(); 545 } 546 547 te.valid = true; 548 te.size = (1 << te.N) - 1; 549 te.asid = currState->contextId; 550 te.sNp = false; 551 te.vpn = currState->vaddr >> te.N; 552 te.global = currState->l2Desc.global(); 553 te.xn = currState->l2Desc.xn(); 554 te.ap = currState->l2Desc.ap(); 555 te.domain = currState->l1Desc.domain(); 556 memAttrs(currState->tc, te, currState->sctlr, currState->l2Desc.texcb(), 557 currState->l2Desc.shareable()); 558 559 if (!currState->delayed) { 560 currState->tc = NULL; 561 currState->req = NULL; 562 } 563 tlb->insert(currState->vaddr, te); 564} 565 566void 567TableWalker::doL1DescriptorWrapper() 568{
|
570 currState = stateQueue.peek();
|
569 currState = stateQueue.front(); |
570 currState->delayed = false; 571
|
572 DPRINTF(TLBVerbose, "L1 Desc object host addr: %p\n",&currState->l1Desc.data); 573 DPRINTF(TLBVerbose, "L1 Desc object data: %08x\n",currState->l1Desc.data); 574 |
575 DPRINTF(TLBVerbose, "calling doL1Descriptor for vaddr:%#x\n", currState->vaddr); 576 doL1Descriptor(); 577 578 // Check if fault was generated 579 if (currState->fault != NoFault) { 580 currState->transState->finish(currState->fault, currState->req, 581 currState->tc, currState->mode); 582 583 currState->req = NULL; 584 currState->tc = NULL; 585 currState->delayed = false; 586
|
585 stateQueue.remove();
|
587 stateQueue.pop_front(); |
588 } 589 else if (!currState->delayed) { 590 DPRINTF(TLBVerbose, "calling translateTiming again\n"); 591 currState->fault = tlb->translateTiming(currState->req, currState->tc, 592 currState->transState, currState->mode); 593 594 currState->req = NULL; 595 currState->tc = NULL; 596 currState->delayed = false; 597
|
596 stateQueue.remove();
|
598 stateQueue.pop_front(); |
599 } 600 currState = NULL; 601} 602 603void 604TableWalker::doL2DescriptorWrapper() 605{
|
604 currState = stateQueue.peek();
|
606 currState = stateQueue.front(); |
607 assert(currState->delayed); 608 609 DPRINTF(TLBVerbose, "calling doL2Descriptor for vaddr:%#x\n", 610 currState->vaddr); 611 doL2Descriptor(); 612 613 // Check if fault was generated 614 if (currState->fault != NoFault) { 615 currState->transState->finish(currState->fault, currState->req, 616 currState->tc, currState->mode); 617 } 618 else { 619 DPRINTF(TLBVerbose, "calling translateTiming again\n"); 620 currState->fault = tlb->translateTiming(currState->req, currState->tc, 621 currState->transState, currState->mode); 622 } 623 624 currState->req = NULL; 625 currState->tc = NULL; 626 currState->delayed = false; 627
|
626 stateQueue.remove();
|
628 stateQueue.pop_front(); |
629 currState = NULL; 630} 631 632ArmISA::TableWalker * 633ArmTableWalkerParams::create() 634{ 635 return new ArmISA::TableWalker(this); 636} 637
|