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