table_walker.cc revision 7733
14159Sgblack@eecs.umich.edu/* 24159Sgblack@eecs.umich.edu * Copyright (c) 2010 ARM Limited 34159Sgblack@eecs.umich.edu * All rights reserved 44159Sgblack@eecs.umich.edu * 54159Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 64159Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 74159Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 84159Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 94159Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 104159Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 114159Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 124159Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 134159Sgblack@eecs.umich.edu * 144159Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 154159Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 164159Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 174159Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 184159Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 194159Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 204159Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 214159Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 224159Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 234159Sgblack@eecs.umich.edu * this software without specific prior written permission. 244159Sgblack@eecs.umich.edu * 254159Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 264159Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 274159Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 284159Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 294159Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 304159Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 314159Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 324159Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 334159Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 344159Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 354159Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 364159Sgblack@eecs.umich.edu * 374159Sgblack@eecs.umich.edu * Authors: Ali Saidi 384159Sgblack@eecs.umich.edu */ 394159Sgblack@eecs.umich.edu 404159Sgblack@eecs.umich.edu#include "arch/arm/faults.hh" 414159Sgblack@eecs.umich.edu#include "arch/arm/table_walker.hh" 424159Sgblack@eecs.umich.edu#include "arch/arm/tlb.hh" 434159Sgblack@eecs.umich.edu#include "dev/io_device.hh" 444159Sgblack@eecs.umich.edu#include "cpu/base.hh" 454159Sgblack@eecs.umich.edu#include "cpu/thread_context.hh" 464159Sgblack@eecs.umich.edu 474159Sgblack@eecs.umich.eduusing namespace ArmISA; 484159Sgblack@eecs.umich.edu 494159Sgblack@eecs.umich.eduTableWalker::TableWalker(const Params *p) 504159Sgblack@eecs.umich.edu : MemObject(p), port(NULL), tlb(NULL), currState(NULL), pending(false), 514159Sgblack@eecs.umich.edu doL1DescEvent(this), doL2DescEvent(this), doProcessEvent(this) 524159Sgblack@eecs.umich.edu{ 534159Sgblack@eecs.umich.edu sctlr = 0; 544159Sgblack@eecs.umich.edu} 554159Sgblack@eecs.umich.edu 564159Sgblack@eecs.umich.eduTableWalker::~TableWalker() 574159Sgblack@eecs.umich.edu{ 584159Sgblack@eecs.umich.edu ; 594159Sgblack@eecs.umich.edu} 604159Sgblack@eecs.umich.edu 615124Sgblack@eecs.umich.edu 625124Sgblack@eecs.umich.eduunsigned int TableWalker::drain(Event *de) 635124Sgblack@eecs.umich.edu{ 644159Sgblack@eecs.umich.edu if (stateQueueL1.size() != 0 || stateQueueL2.size() != 0) 655237Sgblack@eecs.umich.edu { 664159Sgblack@eecs.umich.edu changeState(Draining); 674159Sgblack@eecs.umich.edu DPRINTF(Checkpoint, "TableWalker busy, wait to drain\n"); 685124Sgblack@eecs.umich.edu return 1; 695124Sgblack@eecs.umich.edu } 704159Sgblack@eecs.umich.edu else 714159Sgblack@eecs.umich.edu { 725237Sgblack@eecs.umich.edu changeState(Drained); 735237Sgblack@eecs.umich.edu DPRINTF(Checkpoint, "TableWalker free, no need to drain\n"); 745237Sgblack@eecs.umich.edu return 0; 755237Sgblack@eecs.umich.edu } 765237Sgblack@eecs.umich.edu} 775237Sgblack@eecs.umich.edu 785237Sgblack@eecs.umich.eduPort* 795237Sgblack@eecs.umich.eduTableWalker::getPort(const std::string &if_name, int idx) 805237Sgblack@eecs.umich.edu{ 815237Sgblack@eecs.umich.edu if (if_name == "port") { 825237Sgblack@eecs.umich.edu if (port != NULL) 835237Sgblack@eecs.umich.edu fatal("%s: port already connected to %s", 845237Sgblack@eecs.umich.edu name(), port->getPeer()->name()); 854159Sgblack@eecs.umich.edu System *sys = params()->sys; 865124Sgblack@eecs.umich.edu Tick minb = params()->min_backoff; 874159Sgblack@eecs.umich.edu Tick maxb = params()->max_backoff; 885124Sgblack@eecs.umich.edu port = new DmaPort(this, sys, minb, maxb); 895184Sgblack@eecs.umich.edu return port; 905184Sgblack@eecs.umich.edu } 915184Sgblack@eecs.umich.edu return NULL; 925184Sgblack@eecs.umich.edu} 935184Sgblack@eecs.umich.edu 945184Sgblack@eecs.umich.eduFault 955184Sgblack@eecs.umich.eduTableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode _mode, 965124Sgblack@eecs.umich.edu TLB::Translation *_trans, bool _timing) 975124Sgblack@eecs.umich.edu{ 985184Sgblack@eecs.umich.edu if (!currState) { 995124Sgblack@eecs.umich.edu // For atomic mode, a new WalkerState instance should be only created 1005124Sgblack@eecs.umich.edu // once per TLB. For timing mode, a new instance is generated for every 1015124Sgblack@eecs.umich.edu // TLB miss. 1025124Sgblack@eecs.umich.edu DPRINTF(TLBVerbose, "creating new instance of WalkerState\n"); 1035124Sgblack@eecs.umich.edu 1045124Sgblack@eecs.umich.edu currState = new WalkerState(); 1055124Sgblack@eecs.umich.edu currState->tableWalker = this; 1065124Sgblack@eecs.umich.edu } 1075124Sgblack@eecs.umich.edu else if (_timing) { 1085124Sgblack@eecs.umich.edu panic("currState should always be empty in timing mode!\n"); 1095124Sgblack@eecs.umich.edu } 1105124Sgblack@eecs.umich.edu 1115124Sgblack@eecs.umich.edu currState->tc = _tc; 1125124Sgblack@eecs.umich.edu currState->transState = _trans; 1135184Sgblack@eecs.umich.edu currState->req = _req; 1145184Sgblack@eecs.umich.edu currState->fault = NoFault; 1155124Sgblack@eecs.umich.edu currState->contextId = _cid; 1165184Sgblack@eecs.umich.edu currState->timing = _timing; 1175184Sgblack@eecs.umich.edu currState->mode = _mode; 1185184Sgblack@eecs.umich.edu 1195184Sgblack@eecs.umich.edu /** @todo These should be cached or grabbed from cached copies in 1205124Sgblack@eecs.umich.edu the TLB, all these miscreg reads are expensive */ 1215124Sgblack@eecs.umich.edu currState->vaddr = currState->req->getVaddr(); 1225124Sgblack@eecs.umich.edu currState->sctlr = currState->tc->readMiscReg(MISCREG_SCTLR); 1234159Sgblack@eecs.umich.edu sctlr = currState->sctlr; 1244159Sgblack@eecs.umich.edu currState->N = currState->tc->readMiscReg(MISCREG_TTBCR); 1254159Sgblack@eecs.umich.edu 1264159Sgblack@eecs.umich.edu currState->isFetch = (currState->mode == TLB::Execute); 127 currState->isWrite = (currState->mode == TLB::Write); 128 129 130 if (!currState->timing) 131 return processWalk(); 132 133 if (pending) { 134 pendingQueue.push_back(currState); 135 currState = NULL; 136 } else { 137 pending = true; 138 processWalk(); 139 } 140 141 return NoFault; 142} 143 144void 145TableWalker::processWalkWrapper() 146{ 147 assert(!currState); 148 assert(pendingQueue.size()); 149 currState = pendingQueue.front(); 150 pendingQueue.pop_front(); 151 pending = true; 152 processWalk(); 153} 154 155Fault 156TableWalker::processWalk() 157{ 158 Addr ttbr = 0; 159 160 // If translation isn't enabled, we shouldn't be here 161 assert(currState->sctlr.m); 162 163 DPRINTF(TLB, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n", 164 currState->vaddr, currState->N, mbits(currState->vaddr, 31, 165 32-currState->N)); 166 167 if (currState->N == 0 || !mbits(currState->vaddr, 31, 32-currState->N)) { 168 DPRINTF(TLB, " - Selecting TTBR0\n"); 169 ttbr = currState->tc->readMiscReg(MISCREG_TTBR0); 170 } else { 171 DPRINTF(TLB, " - Selecting TTBR1\n"); 172 ttbr = currState->tc->readMiscReg(MISCREG_TTBR1); 173 currState->N = 0; 174 } 175 176 Addr l1desc_addr = mbits(ttbr, 31, 14-currState->N) | 177 (bits(currState->vaddr,31-currState->N,20) << 2); 178 DPRINTF(TLB, " - Descriptor at address %#x\n", l1desc_addr); 179 180 181 // Trickbox address check 182 Fault f; 183 f = tlb->walkTrickBoxCheck(l1desc_addr, currState->vaddr, sizeof(uint32_t), 184 currState->isFetch, currState->isWrite, 0, true); 185 if (f) { 186 if (currState->timing) { 187 currState->transState->finish(f, currState->req, 188 currState->tc, currState->mode); 189 190 pending = false; 191 nextWalk(currState->tc); 192 currState = NULL; 193 } else { 194 currState->tc = NULL; 195 currState->req = NULL; 196 } 197 return f; 198 } 199 200 if (currState->timing) { 201 port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 202 &doL1DescEvent, (uint8_t*)&currState->l1Desc.data, 203 currState->tc->getCpuPtr()->ticks(1)); 204 DPRINTF(TLBVerbose, "Adding to walker fifo: queue size before adding: %d\n", 205 stateQueueL1.size()); 206 stateQueueL1.push_back(currState); 207 currState = NULL; 208 } else { 209 Request::Flags flag = 0; 210 if (currState->sctlr.c == 0){ 211 flag = Request::UNCACHEABLE; 212 } 213 port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 214 NULL, (uint8_t*)&currState->l1Desc.data, 215 currState->tc->getCpuPtr()->ticks(1), flag); 216 doL1Descriptor(); 217 f = currState->fault; 218 } 219 220 return f; 221} 222 223void 224TableWalker::memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, 225 uint8_t texcb, bool s) 226{ 227 // Note: tc and sctlr local variables are hiding tc and sctrl class 228 // variables 229 DPRINTF(TLBVerbose, "memAttrs texcb:%d s:%d\n", texcb, s); 230 te.shareable = false; // default value 231 te.nonCacheable = false; 232 bool outer_shareable = false; 233 if (sctlr.tre == 0 || ((sctlr.tre == 1) && (sctlr.m == 0))) { 234 switch(texcb) { 235 case 0: // Stongly-ordered 236 te.nonCacheable = true; 237 te.mtype = TlbEntry::StronglyOrdered; 238 te.shareable = true; 239 te.innerAttrs = 1; 240 te.outerAttrs = 0; 241 break; 242 case 1: // Shareable Device 243 te.nonCacheable = true; 244 te.mtype = TlbEntry::Device; 245 te.shareable = true; 246 te.innerAttrs = 3; 247 te.outerAttrs = 0; 248 break; 249 case 2: // Outer and Inner Write-Through, no Write-Allocate 250 te.mtype = TlbEntry::Normal; 251 te.shareable = s; 252 te.innerAttrs = 6; 253 te.outerAttrs = bits(texcb, 1, 0); 254 break; 255 case 3: // Outer and Inner Write-Back, no Write-Allocate 256 te.mtype = TlbEntry::Normal; 257 te.shareable = s; 258 te.innerAttrs = 7; 259 te.outerAttrs = bits(texcb, 1, 0); 260 break; 261 case 4: // Outer and Inner Non-cacheable 262 te.nonCacheable = true; 263 te.mtype = TlbEntry::Normal; 264 te.shareable = s; 265 te.innerAttrs = 0; 266 te.outerAttrs = bits(texcb, 1, 0); 267 break; 268 case 5: // Reserved 269 panic("Reserved texcb value!\n"); 270 break; 271 case 6: // Implementation Defined 272 panic("Implementation-defined texcb value!\n"); 273 break; 274 case 7: // Outer and Inner Write-Back, Write-Allocate 275 te.mtype = TlbEntry::Normal; 276 te.shareable = s; 277 te.innerAttrs = 5; 278 te.outerAttrs = 1; 279 break; 280 case 8: // Non-shareable Device 281 te.nonCacheable = true; 282 te.mtype = TlbEntry::Device; 283 te.shareable = false; 284 te.innerAttrs = 3; 285 te.outerAttrs = 0; 286 break; 287 case 9 ... 15: // Reserved 288 panic("Reserved texcb value!\n"); 289 break; 290 case 16 ... 31: // Cacheable Memory 291 te.mtype = TlbEntry::Normal; 292 te.shareable = s; 293 if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0) 294 te.nonCacheable = true; 295 te.innerAttrs = bits(texcb, 1, 0); 296 te.outerAttrs = bits(texcb, 3, 2); 297 break; 298 default: 299 panic("More than 32 states for 5 bits?\n"); 300 } 301 } else { 302 assert(tc); 303 PRRR prrr = tc->readMiscReg(MISCREG_PRRR); 304 NMRR nmrr = tc->readMiscReg(MISCREG_NMRR); 305 DPRINTF(TLBVerbose, "memAttrs PRRR:%08x NMRR:%08x\n", prrr, nmrr); 306 uint8_t curr_tr = 0, curr_ir = 0, curr_or = 0; 307 switch(bits(texcb, 2,0)) { 308 case 0: 309 curr_tr = prrr.tr0; 310 curr_ir = nmrr.ir0; 311 curr_or = nmrr.or0; 312 outer_shareable = (prrr.nos0 == 0); 313 break; 314 case 1: 315 curr_tr = prrr.tr1; 316 curr_ir = nmrr.ir1; 317 curr_or = nmrr.or1; 318 outer_shareable = (prrr.nos1 == 0); 319 break; 320 case 2: 321 curr_tr = prrr.tr2; 322 curr_ir = nmrr.ir2; 323 curr_or = nmrr.or2; 324 outer_shareable = (prrr.nos2 == 0); 325 break; 326 case 3: 327 curr_tr = prrr.tr3; 328 curr_ir = nmrr.ir3; 329 curr_or = nmrr.or3; 330 outer_shareable = (prrr.nos3 == 0); 331 break; 332 case 4: 333 curr_tr = prrr.tr4; 334 curr_ir = nmrr.ir4; 335 curr_or = nmrr.or4; 336 outer_shareable = (prrr.nos4 == 0); 337 break; 338 case 5: 339 curr_tr = prrr.tr5; 340 curr_ir = nmrr.ir5; 341 curr_or = nmrr.or5; 342 outer_shareable = (prrr.nos5 == 0); 343 break; 344 case 6: 345 panic("Imp defined type\n"); 346 case 7: 347 curr_tr = prrr.tr7; 348 curr_ir = nmrr.ir7; 349 curr_or = nmrr.or7; 350 outer_shareable = (prrr.nos7 == 0); 351 break; 352 } 353 354 switch(curr_tr) { 355 case 0: 356 DPRINTF(TLBVerbose, "StronglyOrdered\n"); 357 te.mtype = TlbEntry::StronglyOrdered; 358 te.nonCacheable = true; 359 te.innerAttrs = 1; 360 te.outerAttrs = 0; 361 te.shareable = true; 362 break; 363 case 1: 364 DPRINTF(TLBVerbose, "Device ds1:%d ds0:%d s:%d\n", 365 prrr.ds1, prrr.ds0, s); 366 te.mtype = TlbEntry::Device; 367 te.nonCacheable = true; 368 te.innerAttrs = 3; 369 te.outerAttrs = 0; 370 if (prrr.ds1 && s) 371 te.shareable = true; 372 if (prrr.ds0 && !s) 373 te.shareable = true; 374 break; 375 case 2: 376 DPRINTF(TLBVerbose, "Normal ns1:%d ns0:%d s:%d\n", 377 prrr.ns1, prrr.ns0, s); 378 te.mtype = TlbEntry::Normal; 379 if (prrr.ns1 && s) 380 te.shareable = true; 381 if (prrr.ns0 && !s) 382 te.shareable = true; 383 break; 384 case 3: 385 panic("Reserved type"); 386 } 387 388 if (te.mtype == TlbEntry::Normal){ 389 switch(curr_ir) { 390 case 0: 391 te.nonCacheable = true; 392 te.innerAttrs = 0; 393 break; 394 case 1: 395 te.innerAttrs = 5; 396 break; 397 case 2: 398 te.innerAttrs = 6; 399 break; 400 case 3: 401 te.innerAttrs = 7; 402 break; 403 } 404 405 switch(curr_or) { 406 case 0: 407 te.nonCacheable = true; 408 te.outerAttrs = 0; 409 break; 410 case 1: 411 te.outerAttrs = 1; 412 break; 413 case 2: 414 te.outerAttrs = 2; 415 break; 416 case 3: 417 te.outerAttrs = 3; 418 break; 419 } 420 } 421 } 422 DPRINTF(TLBVerbose, "memAttrs: shareable: %d, innerAttrs: %d, \ 423 outerAttrs: %d\n", 424 te.shareable, te.innerAttrs, te.outerAttrs); 425 426 /** Formatting for Physical Address Register (PAR) 427 * Only including lower bits (TLB info here) 428 * PAR: 429 * PA [31:12] 430 * Reserved [11] 431 * TLB info [10:1] 432 * NOS [10] (Not Outer Sharable) 433 * NS [9] (Non-Secure) 434 * -- [8] (Implementation Defined) 435 * SH [7] (Sharable) 436 * Inner[6:4](Inner memory attributes) 437 * Outer[3:2](Outer memory attributes) 438 * SS [1] (SuperSection) 439 * F [0] (Fault, Fault Status in [6:1] if faulted) 440 */ 441 te.attributes = ( 442 ((outer_shareable ? 0:1) << 10) | 443 // TODO: NS Bit 444 ((te.shareable ? 1:0) << 7) | 445 (te.innerAttrs << 4) | 446 (te.outerAttrs << 2) 447 // TODO: Supersection bit 448 // TODO: Fault bit 449 ); 450 451 452} 453 454void 455TableWalker::doL1Descriptor() 456{ 457 DPRINTF(TLB, "L1 descriptor for %#x is %#x\n", 458 currState->vaddr, currState->l1Desc.data); 459 TlbEntry te; 460 461 switch (currState->l1Desc.type()) { 462 case L1Descriptor::Ignore: 463 case L1Descriptor::Reserved: 464 if (!currState->delayed) { 465 currState->tc = NULL; 466 currState->req = NULL; 467 } 468 DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n"); 469 if (currState->isFetch) 470 currState->fault = 471 new PrefetchAbort(currState->vaddr, ArmFault::Translation0); 472 else 473 currState->fault = 474 new DataAbort(currState->vaddr, 0, currState->isWrite, 475 ArmFault::Translation0); 476 return; 477 case L1Descriptor::Section: 478 if (currState->sctlr.afe && bits(currState->l1Desc.ap(), 0) == 0) { 479 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is 480 * enabled if set, do l1.Desc.setAp0() instead of generating 481 * AccessFlag0 482 */ 483 484 currState->fault = new DataAbort(currState->vaddr, 485 currState->l1Desc.domain(), currState->isWrite, 486 ArmFault::AccessFlag0); 487 } 488 if (currState->l1Desc.supersection()) { 489 panic("Haven't implemented supersections\n"); 490 } 491 te.N = 20; 492 te.pfn = currState->l1Desc.pfn(); 493 te.size = (1<<te.N) - 1; 494 te.global = !currState->l1Desc.global(); 495 te.valid = true; 496 te.vpn = currState->vaddr >> te.N; 497 te.sNp = true; 498 te.xn = currState->l1Desc.xn(); 499 te.ap = currState->l1Desc.ap(); 500 te.domain = currState->l1Desc.domain(); 501 te.asid = currState->contextId; 502 memAttrs(currState->tc, te, currState->sctlr, 503 currState->l1Desc.texcb(), currState->l1Desc.shareable()); 504 505 DPRINTF(TLB, "Inserting Section Descriptor into TLB\n"); 506 DPRINTF(TLB, " - N:%d pfn:%#x size: %#x global:%d valid: %d\n", 507 te.N, te.pfn, te.size, te.global, te.valid); 508 DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d nc:%d\n", 509 te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid, 510 te.nonCacheable); 511 DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n", 512 currState->l1Desc.domain(), currState->l1Desc.data, 513 (currState->l1Desc.data >> 5) & 0xF ); 514 515 if (!currState->timing) { 516 currState->tc = NULL; 517 currState->req = NULL; 518 } 519 tlb->insert(currState->vaddr, te); 520 521 return; 522 case L1Descriptor::PageTable: 523 Addr l2desc_addr; 524 l2desc_addr = currState->l1Desc.l2Addr() | 525 (bits(currState->vaddr, 19,12) << 2); 526 DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n", 527 l2desc_addr); 528 529 // Trickbox address check 530 currState->fault = tlb->walkTrickBoxCheck(l2desc_addr, currState->vaddr, 531 sizeof(uint32_t), currState->isFetch, currState->isWrite, 532 currState->l1Desc.domain(), false); 533 534 if (currState->fault) { 535 if (!currState->timing) { 536 currState->tc = NULL; 537 currState->req = NULL; 538 } 539 return; 540 } 541 542 543 if (currState->timing) { 544 currState->delayed = true; 545 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 546 &doL2DescEvent, (uint8_t*)&currState->l2Desc.data, 547 currState->tc->getCpuPtr()->ticks(1)); 548 } else { 549 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 550 NULL, (uint8_t*)&currState->l2Desc.data, 551 currState->tc->getCpuPtr()->ticks(1)); 552 doL2Descriptor(); 553 } 554 return; 555 default: 556 panic("A new type in a 2 bit field?\n"); 557 } 558} 559 560void 561TableWalker::doL2Descriptor() 562{ 563 DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", 564 currState->vaddr, currState->l2Desc.data); 565 TlbEntry te; 566 567 if (currState->l2Desc.invalid()) { 568 DPRINTF(TLB, "L2 descriptor invalid, causing fault\n"); 569 if (!currState->delayed) { 570 currState->tc = NULL; 571 currState->req = NULL; 572 } 573 if (currState->isFetch) 574 currState->fault = 575 new PrefetchAbort(currState->vaddr, ArmFault::Translation1); 576 else 577 currState->fault = 578 new DataAbort(currState->vaddr, currState->l1Desc.domain(), 579 currState->isWrite, ArmFault::Translation1); 580 return; 581 } 582 583 if (currState->sctlr.afe && bits(currState->l2Desc.ap(), 0) == 0) { 584 /** @todo: check sctlr.ha (bit[17]) if Hardware Access Flag is enabled 585 * if set, do l2.Desc.setAp0() instead of generating AccessFlag0 586 */ 587 588 currState->fault = 589 new DataAbort(currState->vaddr, 0, currState->isWrite, 590 ArmFault::AccessFlag1); 591 592 } 593 594 if (currState->l2Desc.large()) { 595 te.N = 16; 596 te.pfn = currState->l2Desc.pfn(); 597 } else { 598 te.N = 12; 599 te.pfn = currState->l2Desc.pfn(); 600 } 601 602 te.valid = true; 603 te.size = (1 << te.N) - 1; 604 te.asid = currState->contextId; 605 te.sNp = false; 606 te.vpn = currState->vaddr >> te.N; 607 te.global = currState->l2Desc.global(); 608 te.xn = currState->l2Desc.xn(); 609 te.ap = currState->l2Desc.ap(); 610 te.domain = currState->l1Desc.domain(); 611 memAttrs(currState->tc, te, currState->sctlr, currState->l2Desc.texcb(), 612 currState->l2Desc.shareable()); 613 614 if (!currState->delayed) { 615 currState->tc = NULL; 616 currState->req = NULL; 617 } 618 tlb->insert(currState->vaddr, te); 619} 620 621void 622TableWalker::doL1DescriptorWrapper() 623{ 624 currState = stateQueueL1.front(); 625 currState->delayed = false; 626 627 DPRINTF(TLBVerbose, "L1 Desc object host addr: %p\n",&currState->l1Desc.data); 628 DPRINTF(TLBVerbose, "L1 Desc object data: %08x\n",currState->l1Desc.data); 629 630 DPRINTF(TLBVerbose, "calling doL1Descriptor for vaddr:%#x\n", currState->vaddr); 631 doL1Descriptor(); 632 633 stateQueueL1.pop_front(); 634 // Check if fault was generated 635 if (currState->fault != NoFault) { 636 currState->transState->finish(currState->fault, currState->req, 637 currState->tc, currState->mode); 638 639 pending = false; 640 nextWalk(currState->tc); 641 642 currState->req = NULL; 643 currState->tc = NULL; 644 currState->delayed = false; 645 646 } 647 else if (!currState->delayed) { 648 // delay is not set so there is no L2 to do 649 DPRINTF(TLBVerbose, "calling translateTiming again\n"); 650 currState->fault = tlb->translateTiming(currState->req, currState->tc, 651 currState->transState, currState->mode); 652 653 pending = false; 654 nextWalk(currState->tc); 655 656 currState->req = NULL; 657 currState->tc = NULL; 658 currState->delayed = false; 659 delete currState; 660 } else { 661 // need to do L2 descriptor 662 stateQueueL2.push_back(currState); 663 } 664 currState = NULL; 665} 666 667void 668TableWalker::doL2DescriptorWrapper() 669{ 670 currState = stateQueueL2.front(); 671 assert(currState->delayed); 672 673 DPRINTF(TLBVerbose, "calling doL2Descriptor for vaddr:%#x\n", 674 currState->vaddr); 675 doL2Descriptor(); 676 677 // Check if fault was generated 678 if (currState->fault != NoFault) { 679 currState->transState->finish(currState->fault, currState->req, 680 currState->tc, currState->mode); 681 } 682 else { 683 DPRINTF(TLBVerbose, "calling translateTiming again\n"); 684 currState->fault = tlb->translateTiming(currState->req, currState->tc, 685 currState->transState, currState->mode); 686 } 687 688 689 stateQueueL2.pop_front(); 690 pending = false; 691 nextWalk(currState->tc); 692 693 currState->req = NULL; 694 currState->tc = NULL; 695 currState->delayed = false; 696 697 delete currState; 698 currState = NULL; 699} 700 701void 702TableWalker::nextWalk(ThreadContext *tc) 703{ 704 if (pendingQueue.size()) 705 schedule(doProcessEvent, tc->getCpuPtr()->nextCycle(curTick+1)); 706} 707 708 709 710ArmISA::TableWalker * 711ArmTableWalkerParams::create() 712{ 713 return new ArmISA::TableWalker(this); 714} 715 716