smmu_v3_transl.cc revision 14100:6ef1220dc6da
1/* 2 * Copyright (c) 2013, 2018-2019 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: Stan Czerniawski 38 */ 39 40#include "dev/arm/smmu_v3_transl.hh" 41 42#include "debug/SMMUv3.hh" 43#include "debug/SMMUv3Hazard.hh" 44#include "dev/arm/amba.hh" 45#include "dev/arm/smmu_v3.hh" 46#include "sim/system.hh" 47 48SMMUTranslRequest 49SMMUTranslRequest::fromPacket(PacketPtr pkt, bool ats) 50{ 51 SMMUTranslRequest req; 52 req.addr = pkt->getAddr(); 53 req.size = pkt->getSize(); 54 req.sid = pkt->req->streamId(); 55 req.ssid = pkt->req->hasSubstreamId() ? 56 pkt->req->substreamId() : 0; 57 req.isWrite = pkt->isWrite(); 58 req.isPrefetch = false; 59 req.isAtsRequest = ats; 60 req.pkt = pkt; 61 62 return req; 63} 64 65SMMUTranslRequest 66SMMUTranslRequest::prefetch(Addr addr, uint32_t sid, uint32_t ssid) 67{ 68 SMMUTranslRequest req; 69 req.addr = addr; 70 req.size = 0; 71 req.sid = sid; 72 req.ssid = ssid; 73 req.isWrite = false; 74 req.isPrefetch = true; 75 req.isAtsRequest = false; 76 req.pkt = NULL; 77 78 return req; 79} 80 81SMMUTranslationProcess::SMMUTranslationProcess(const std::string &name, 82 SMMUv3 &_smmu, SMMUv3SlaveInterface &_ifc) 83 : 84 SMMUProcess(name, _smmu), 85 ifc(_ifc) 86{ 87 // Decrease number of pending translation slots on the slave interface 88 assert(ifc.xlateSlotsRemaining > 0); 89 ifc.xlateSlotsRemaining--; 90 reinit(); 91} 92 93SMMUTranslationProcess::~SMMUTranslationProcess() 94{ 95 // Increase number of pending translation slots on the slave interface 96 ifc.xlateSlotsRemaining++; 97 // If no more SMMU translations are pending (all slots available), 98 // signal SMMU Slave Interface as drained 99 if (ifc.xlateSlotsRemaining == ifc.params()->xlate_slots) { 100 ifc.signalDrainDone(); 101 } 102} 103 104void 105SMMUTranslationProcess::beginTransaction(const SMMUTranslRequest &req) 106{ 107 request = req; 108 109 reinit(); 110} 111 112void 113SMMUTranslationProcess::resumeTransaction() 114{ 115 assert(smmu.system.isTimingMode()); 116 117 assert(!"Stalls are broken"); 118 119 Tick resumeTick = curTick(); 120 121 (void) resumeTick; 122 DPRINTF(SMMUv3, "Resume at tick = %d. Fault duration = %d (%.3fus)\n", 123 resumeTick, resumeTick-faultTick, (resumeTick-faultTick) / 1e6); 124 125 beginTransaction(request); 126 127 smmu.runProcessTiming(this, request.pkt); 128} 129 130void 131SMMUTranslationProcess::main(Yield &yield) 132{ 133 // Hack: 134 // The coroutine starts running as soon as it's created. 135 // But we need to wait for request data esp. in atomic mode. 136 SMMUAction a; 137 a.type = ACTION_INITIAL_NOP; 138 a.pkt = NULL; 139 yield(a); 140 141 const Addr next4k = (request.addr + 0x1000ULL) & ~0xfffULL; 142 143 if ((request.addr + request.size) > next4k) 144 panic("Transaction crosses 4k boundary (addr=%#x size=%#x)!\n", 145 request.addr, request.size); 146 147 148 unsigned numSlaveBeats = request.isWrite ? 149 (request.size + (ifc.portWidth - 1)) / ifc.portWidth : 1; 150 151 doSemaphoreDown(yield, ifc.slavePortSem); 152 doDelay(yield, Cycles(numSlaveBeats)); 153 doSemaphoreUp(ifc.slavePortSem); 154 155 156 recvTick = curTick(); 157 158 159 if (!(smmu.regs.cr0 & 0x1)) { 160 // SMMU disabled 161 doDelay(yield, Cycles(1)); 162 completeTransaction(yield, bypass(request.addr)); 163 return; 164 } 165 166 TranslResult tr; 167 bool wasPrefetched = false; 168 169 if (request.isPrefetch) { 170 // Abort prefetch if: 171 // - there's already a transaction looking up the same 4k page, OR 172 // - requested address is already in the TLB. 173 if (hazard4kCheck() || ifcTLBLookup(yield, tr, wasPrefetched)) 174 completePrefetch(yield); // this never returns 175 176 hazard4kRegister(); 177 178 tr = smmuTranslation(yield); 179 180 if (tr.fault == FAULT_NONE) 181 ifcTLBUpdate(yield, tr); 182 183 hazard4kRelease(); 184 185 completePrefetch(yield); 186 } else { 187 hazardIdRegister(); 188 189 if (!microTLBLookup(yield, tr)) { 190 bool hit = ifcTLBLookup(yield, tr, wasPrefetched); 191 if (!hit) { 192 while (!hit && hazard4kCheck()) { 193 hazard4kHold(yield); 194 hit = ifcTLBLookup(yield, tr, wasPrefetched); 195 } 196 } 197 198 // Issue prefetch if: 199 // - there was a TLB hit and the entry was prefetched, OR 200 // - TLB miss was successfully serviced 201 if (hit) { 202 if (wasPrefetched) 203 issuePrefetch(next4k); 204 } else { 205 hazard4kRegister(); 206 207 tr = smmuTranslation(yield); 208 209 if (tr.fault == FAULT_NONE) { 210 ifcTLBUpdate(yield, tr); 211 212 issuePrefetch(next4k); 213 } 214 215 hazard4kRelease(); 216 } 217 218 if (tr.fault == FAULT_NONE) 219 microTLBUpdate(yield, tr); 220 } 221 222 hazardIdHold(yield); 223 hazardIdRelease(); 224 225 if (tr.fault != FAULT_NONE) 226 panic("fault\n"); 227 228 completeTransaction(yield, tr); 229 } 230} 231 232SMMUTranslationProcess::TranslResult 233SMMUTranslationProcess::bypass(Addr addr) const 234{ 235 TranslResult tr; 236 tr.fault = FAULT_NONE; 237 tr.addr = addr; 238 tr.addrMask = 0; 239 tr.writable = 1; 240 241 return tr; 242} 243 244SMMUTranslationProcess::TranslResult 245SMMUTranslationProcess::smmuTranslation(Yield &yield) 246{ 247 TranslResult tr; 248 249 // Need SMMU credit to proceed 250 doSemaphoreDown(yield, smmu.transSem); 251 252 // Simulate pipelined IFC->SMMU link 253 doSemaphoreDown(yield, smmu.ifcSmmuSem); 254 doDelay(yield, Cycles(1)); // serialize transactions 255 doSemaphoreUp(smmu.ifcSmmuSem); 256 doDelay(yield, smmu.ifcSmmuLat - Cycles(1)); // remaining pipeline delay 257 258 bool haveConfig = true; 259 if (!configCacheLookup(yield, context)) { 260 if(findConfig(yield, context, tr)) { 261 configCacheUpdate(yield, context); 262 } else { 263 haveConfig = false; 264 } 265 } 266 267 if (haveConfig && !smmuTLBLookup(yield, tr)) { 268 // SMMU main TLB miss 269 270 // Need PTW slot to proceed 271 doSemaphoreDown(yield, smmu.ptwSem); 272 273 // Page table walk 274 Tick ptwStartTick = curTick(); 275 276 if (context.stage1Enable) { 277 tr = translateStage1And2(yield, request.addr); 278 } else if (context.stage2Enable) { 279 tr = translateStage2(yield, request.addr, true); 280 } else { 281 tr = bypass(request.addr); 282 } 283 284 if (context.stage1Enable || context.stage2Enable) 285 smmu.ptwTimeDist.sample(curTick() - ptwStartTick); 286 287 // Free PTW slot 288 doSemaphoreUp(smmu.ptwSem); 289 290 if (tr.fault == FAULT_NONE) 291 smmuTLBUpdate(yield, tr); 292 } 293 294 // Simulate pipelined SMMU->SLAVE INTERFACE link 295 doSemaphoreDown(yield, smmu.smmuIfcSem); 296 doDelay(yield, Cycles(1)); // serialize transactions 297 doSemaphoreUp(smmu.smmuIfcSem); 298 doDelay(yield, smmu.smmuIfcLat - Cycles(1)); // remaining pipeline delay 299 300 // return SMMU credit 301 doSemaphoreUp(smmu.transSem); 302 303 return tr; 304} 305 306bool 307SMMUTranslationProcess::microTLBLookup(Yield &yield, TranslResult &tr) 308{ 309 if (!ifc.microTLBEnable) 310 return false; 311 312 doSemaphoreDown(yield, ifc.microTLBSem); 313 doDelay(yield, ifc.microTLBLat); 314 const SMMUTLB::Entry *e = 315 ifc.microTLB->lookup(request.sid, request.ssid, request.addr); 316 doSemaphoreUp(ifc.microTLBSem); 317 318 if (!e) { 319 DPRINTF(SMMUv3, "micro TLB miss vaddr=%#x sid=%#x ssid=%#x\n", 320 request.addr, request.sid, request.ssid); 321 322 return false; 323 } 324 325 DPRINTF(SMMUv3, 326 "micro TLB hit vaddr=%#x amask=%#x sid=%#x ssid=%#x paddr=%#x\n", 327 request.addr, e->vaMask, request.sid, request.ssid, e->pa); 328 329 tr.fault = FAULT_NONE; 330 tr.addr = e->pa + (request.addr & ~e->vaMask);; 331 tr.addrMask = e->vaMask; 332 tr.writable = e->permissions; 333 334 return true; 335} 336 337bool 338SMMUTranslationProcess::ifcTLBLookup(Yield &yield, TranslResult &tr, 339 bool &wasPrefetched) 340{ 341 if (!ifc.mainTLBEnable) 342 return false; 343 344 doSemaphoreDown(yield, ifc.mainTLBSem); 345 doDelay(yield, ifc.mainTLBLat); 346 const SMMUTLB::Entry *e = 347 ifc.mainTLB->lookup(request.sid, request.ssid, request.addr); 348 doSemaphoreUp(ifc.mainTLBSem); 349 350 if (!e) { 351 DPRINTF(SMMUv3, 352 "SLAVE Interface TLB miss vaddr=%#x sid=%#x ssid=%#x\n", 353 request.addr, request.sid, request.ssid); 354 355 return false; 356 } 357 358 DPRINTF(SMMUv3, 359 "SLAVE Interface TLB hit vaddr=%#x amask=%#x sid=%#x ssid=%#x " 360 "paddr=%#x\n", request.addr, e->vaMask, request.sid, 361 request.ssid, e->pa); 362 363 tr.fault = FAULT_NONE; 364 tr.addr = e->pa + (request.addr & ~e->vaMask);; 365 tr.addrMask = e->vaMask; 366 tr.writable = e->permissions; 367 wasPrefetched = e->prefetched; 368 369 return true; 370} 371 372bool 373SMMUTranslationProcess::smmuTLBLookup(Yield &yield, TranslResult &tr) 374{ 375 if (!smmu.tlbEnable) 376 return false; 377 378 doSemaphoreDown(yield, smmu.tlbSem); 379 doDelay(yield, smmu.tlbLat); 380 const ARMArchTLB::Entry *e = 381 smmu.tlb.lookup(request.addr, context.asid, context.vmid); 382 doSemaphoreUp(smmu.tlbSem); 383 384 if (!e) { 385 DPRINTF(SMMUv3, "SMMU TLB miss vaddr=%#x asid=%#x vmid=%#x\n", 386 request.addr, context.asid, context.vmid); 387 388 return false; 389 } 390 391 DPRINTF(SMMUv3, 392 "SMMU TLB hit vaddr=%#x amask=%#x asid=%#x vmid=%#x paddr=%#x\n", 393 request.addr, e->vaMask, context.asid, context.vmid, e->pa); 394 395 tr.fault = FAULT_NONE; 396 tr.addr = e->pa + (request.addr & ~e->vaMask);; 397 tr.addrMask = e->vaMask; 398 tr.writable = e->permissions; 399 400 return true; 401} 402 403void 404SMMUTranslationProcess::microTLBUpdate(Yield &yield, 405 const TranslResult &tr) 406{ 407 assert(tr.fault == FAULT_NONE); 408 409 if (!ifc.microTLBEnable) 410 return; 411 412 SMMUTLB::Entry e; 413 e.valid = true; 414 e.prefetched = false; 415 e.sid = request.sid; 416 e.ssid = request.ssid; 417 e.vaMask = tr.addrMask; 418 e.va = request.addr & e.vaMask; 419 e.pa = tr.addr & e.vaMask; 420 e.permissions = tr.writable; 421 e.asid = context.asid; 422 e.vmid = context.vmid; 423 424 doSemaphoreDown(yield, ifc.microTLBSem); 425 426 DPRINTF(SMMUv3, 427 "micro TLB upd vaddr=%#x amask=%#x paddr=%#x sid=%#x ssid=%#x\n", 428 e.va, e.vaMask, e.pa, e.sid, e.ssid); 429 430 ifc.microTLB->store(e, SMMUTLB::ALLOC_ANY_WAY); 431 432 doSemaphoreUp(ifc.microTLBSem); 433} 434 435void 436SMMUTranslationProcess::ifcTLBUpdate(Yield &yield, 437 const TranslResult &tr) 438{ 439 assert(tr.fault == FAULT_NONE); 440 441 if (!ifc.mainTLBEnable) 442 return; 443 444 SMMUTLB::Entry e; 445 e.valid = true; 446 e.prefetched = request.isPrefetch; 447 e.sid = request.sid; 448 e.ssid = request.ssid; 449 e.vaMask = tr.addrMask; 450 e.va = request.addr & e.vaMask; 451 e.pa = tr.addr & e.vaMask; 452 e.permissions = tr.writable; 453 e.asid = context.asid; 454 e.vmid = context.vmid; 455 456 SMMUTLB::AllocPolicy alloc = SMMUTLB::ALLOC_ANY_WAY; 457 if (ifc.prefetchEnable && ifc.prefetchReserveLastWay) 458 alloc = request.isPrefetch ? 459 SMMUTLB::ALLOC_LAST_WAY : SMMUTLB::ALLOC_ANY_BUT_LAST_WAY; 460 461 doSemaphoreDown(yield, ifc.mainTLBSem); 462 463 DPRINTF(SMMUv3, 464 "SLAVE Interface upd vaddr=%#x amask=%#x paddr=%#x sid=%#x " 465 "ssid=%#x\n", e.va, e.vaMask, e.pa, e.sid, e.ssid); 466 467 ifc.mainTLB->store(e, alloc); 468 469 doSemaphoreUp(ifc.mainTLBSem); 470} 471 472void 473SMMUTranslationProcess::smmuTLBUpdate(Yield &yield, 474 const TranslResult &tr) 475{ 476 assert(tr.fault == FAULT_NONE); 477 478 if (!smmu.tlbEnable) 479 return; 480 481 ARMArchTLB::Entry e; 482 e.valid = true; 483 e.vaMask = tr.addrMask; 484 e.va = request.addr & e.vaMask; 485 e.asid = context.asid; 486 e.vmid = context.vmid; 487 e.pa = tr.addr & e.vaMask; 488 e.permissions = tr.writable; 489 490 doSemaphoreDown(yield, smmu.tlbSem); 491 492 DPRINTF(SMMUv3, 493 "SMMU TLB upd vaddr=%#x amask=%#x paddr=%#x asid=%#x vmid=%#x\n", 494 e.va, e.vaMask, e.pa, e.asid, e.vmid); 495 496 smmu.tlb.store(e); 497 498 doSemaphoreUp(smmu.tlbSem); 499} 500 501bool 502SMMUTranslationProcess::configCacheLookup(Yield &yield, TranslContext &tc) 503{ 504 if (!smmu.configCacheEnable) 505 return false; 506 507 doSemaphoreDown(yield, smmu.configSem); 508 doDelay(yield, smmu.configLat); 509 const ConfigCache::Entry *e = 510 smmu.configCache.lookup(request.sid, request.ssid); 511 doSemaphoreUp(smmu.configSem); 512 513 if (!e) { 514 DPRINTF(SMMUv3, "Config miss sid=%#x ssid=%#x\n", 515 request.sid, request.ssid); 516 517 return false; 518 } 519 520 DPRINTF(SMMUv3, "Config hit sid=%#x ssid=%#x ttb=%#08x asid=%#x\n", 521 request.sid, request.ssid, e->ttb0, e->asid); 522 523 tc.stage1Enable = e->stage1_en; 524 tc.stage2Enable = e->stage2_en; 525 526 tc.ttb0 = e->ttb0; 527 tc.ttb1 = e->ttb1; 528 tc.asid = e->asid; 529 tc.httb = e->httb; 530 tc.vmid = e->vmid; 531 532 tc.stage1TranslGranule = e->stage1_tg; 533 tc.stage2TranslGranule = e->stage2_tg; 534 535 return true; 536} 537 538void 539SMMUTranslationProcess::configCacheUpdate(Yield &yield, 540 const TranslContext &tc) 541{ 542 if (!smmu.configCacheEnable) 543 return; 544 545 ConfigCache::Entry e; 546 e.valid = true; 547 e.sid = request.sid; 548 e.ssid = request.ssid; 549 e.stage1_en = tc.stage1Enable; 550 e.stage2_en = tc.stage2Enable; 551 e.ttb0 = tc.ttb0; 552 e.ttb1 = tc.ttb1; 553 e.asid = tc.asid; 554 e.httb = tc.httb; 555 e.vmid = tc.vmid; 556 e.stage1_tg = tc.stage1TranslGranule; 557 e.stage2_tg = tc.stage2TranslGranule; 558 559 doSemaphoreDown(yield, smmu.configSem); 560 561 DPRINTF(SMMUv3, "Config upd sid=%#x ssid=%#x\n", e.sid, e.ssid); 562 563 smmu.configCache.store(e); 564 565 doSemaphoreUp(smmu.configSem); 566} 567 568bool 569SMMUTranslationProcess::findConfig(Yield &yield, 570 TranslContext &tc, 571 TranslResult &tr) 572{ 573 tc.stage1Enable = false; 574 tc.stage2Enable = false; 575 576 StreamTableEntry ste; 577 doReadSTE(yield, ste, request.sid); 578 579 switch (ste.dw0.config) { 580 case STE_CONFIG_BYPASS: 581 break; 582 583 case STE_CONFIG_STAGE1_ONLY: 584 tc.stage1Enable = true; 585 break; 586 587 case STE_CONFIG_STAGE2_ONLY: 588 tc.stage2Enable = true; 589 break; 590 591 case STE_CONFIG_STAGE1_AND_2: 592 tc.stage1Enable = true; 593 tc.stage2Enable = true; 594 break; 595 596 default: 597 panic("Bad or unimplemented STE config %d\n", 598 ste.dw0.config); 599 } 600 601 602 // Establish stage 2 context first since 603 // Context Descriptors can be in IPA space. 604 if (tc.stage2Enable) { 605 tc.httb = ste.dw3.s2ttb << STE_S2TTB_SHIFT; 606 tc.vmid = ste.dw2.s2vmid; 607 tc.stage2TranslGranule = ste.dw2.s2tg; 608 tc.s2t0sz = ste.dw2.s2t0sz; 609 } else { 610 tc.httb = 0xdeadbeef; 611 tc.vmid = 0; 612 tc.stage2TranslGranule = TRANS_GRANULE_INVALID; 613 tc.s2t0sz = 0; 614 } 615 616 617 // Now fetch stage 1 config. 618 if (context.stage1Enable) { 619 ContextDescriptor cd; 620 doReadCD(yield, cd, ste, request.sid, request.ssid); 621 622 tc.ttb0 = cd.dw1.ttb0 << CD_TTB_SHIFT; 623 tc.ttb1 = cd.dw2.ttb1 << CD_TTB_SHIFT; 624 tc.asid = cd.dw0.asid; 625 tc.stage1TranslGranule = cd.dw0.tg0; 626 tc.t0sz = cd.dw0.t0sz; 627 } else { 628 tc.ttb0 = 0xcafebabe; 629 tc.ttb1 = 0xcafed00d; 630 tc.asid = 0; 631 tc.stage1TranslGranule = TRANS_GRANULE_INVALID; 632 tc.t0sz = 0; 633 } 634 635 return true; 636} 637 638void 639SMMUTranslationProcess::walkCacheLookup( 640 Yield &yield, 641 const WalkCache::Entry *&walkEntry, 642 Addr addr, uint16_t asid, uint16_t vmid, 643 unsigned stage, unsigned level) 644{ 645 const char *indent = stage==2 ? " " : ""; 646 (void) indent; // this is only used in DPRINTFs 647 648 const PageTableOps *pt_ops = 649 stage == 1 ? 650 smmu.getPageTableOps(context.stage1TranslGranule) : 651 smmu.getPageTableOps(context.stage2TranslGranule); 652 653 unsigned walkCacheLevels = 654 smmu.walkCacheEnable ? 655 (stage == 1 ? smmu.walkCacheS1Levels : smmu.walkCacheS2Levels) : 656 0; 657 658 if ((1 << level) & walkCacheLevels) { 659 doSemaphoreDown(yield, smmu.walkSem); 660 doDelay(yield, smmu.walkLat); 661 662 walkEntry = smmu.walkCache.lookup(addr, pt_ops->walkMask(level), 663 asid, vmid, stage, level); 664 665 if (walkEntry) { 666 DPRINTF(SMMUv3, "%sWalkCache hit va=%#x asid=%#x vmid=%#x " 667 "base=%#x (S%d, L%d)\n", 668 indent, addr, asid, vmid, walkEntry->pa, stage, level); 669 } else { 670 DPRINTF(SMMUv3, "%sWalkCache miss va=%#x asid=%#x vmid=%#x " 671 "(S%d, L%d)\n", 672 indent, addr, asid, vmid, stage, level); 673 } 674 675 doSemaphoreUp(smmu.walkSem); 676 } 677} 678 679void 680SMMUTranslationProcess::walkCacheUpdate(Yield &yield, Addr va, 681 Addr vaMask, Addr pa, 682 unsigned stage, unsigned level, 683 bool leaf, uint8_t permissions) 684{ 685 unsigned walkCacheLevels = 686 stage == 1 ? smmu.walkCacheS1Levels : smmu.walkCacheS2Levels; 687 688 if (smmu.walkCacheEnable && ((1<<level) & walkCacheLevels)) { 689 WalkCache::Entry e; 690 e.valid = true; 691 e.va = va; 692 e.vaMask = vaMask; 693 e.asid = stage==1 ? context.asid : 0; 694 e.vmid = context.vmid; 695 e.stage = stage; 696 e.level = level; 697 e.leaf = leaf; 698 e.pa = pa; 699 e.permissions = permissions; 700 701 doSemaphoreDown(yield, smmu.walkSem); 702 703 DPRINTF(SMMUv3, "%sWalkCache upd va=%#x mask=%#x asid=%#x vmid=%#x " 704 "tpa=%#x leaf=%s (S%d, L%d)\n", 705 e.stage==2 ? " " : "", 706 e.va, e.vaMask, e.asid, e.vmid, 707 e.pa, e.leaf, e.stage, e.level); 708 709 smmu.walkCache.store(e); 710 711 doSemaphoreUp(smmu.walkSem); 712 } 713} 714 715/* 716 * Please note: 717 * This does not deal with the case where stage 1 page size 718 * is larger than stage 2 page size. 719 */ 720SMMUTranslationProcess::TranslResult 721SMMUTranslationProcess::walkStage1And2(Yield &yield, Addr addr, 722 const PageTableOps *pt_ops, 723 unsigned level, Addr walkPtr) 724{ 725 PageTableOps::pte_t pte = 0; 726 727 doSemaphoreDown(yield, smmu.cycleSem); 728 doDelay(yield, Cycles(1)); 729 doSemaphoreUp(smmu.cycleSem); 730 731 for (; level <= pt_ops->lastLevel(); level++) { 732 Addr pte_addr = walkPtr + pt_ops->index(addr, level); 733 734 DPRINTF(SMMUv3, "Fetching S1 L%d PTE from pa=%#08x\n", 735 level, pte_addr); 736 737 doReadPTE(yield, addr, pte_addr, &pte, 1, level); 738 739 DPRINTF(SMMUv3, "Got S1 L%d PTE=%#x from pa=%#08x\n", 740 level, pte, pte_addr); 741 742 doSemaphoreDown(yield, smmu.cycleSem); 743 doDelay(yield, Cycles(1)); 744 doSemaphoreUp(smmu.cycleSem); 745 746 bool valid = pt_ops->isValid(pte, level); 747 bool leaf = pt_ops->isLeaf(pte, level); 748 749 if (!valid) { 750 DPRINTF(SMMUv3, "S1 PTE not valid - fault\n"); 751 752 TranslResult tr; 753 tr.fault = FAULT_TRANSLATION; 754 return tr; 755 } 756 757 if (valid && leaf && request.isWrite && 758 !pt_ops->isWritable(pte, level, false)) 759 { 760 DPRINTF(SMMUv3, "S1 page not writable - fault\n"); 761 762 TranslResult tr; 763 tr.fault = FAULT_PERMISSION; 764 return tr; 765 } 766 767 walkPtr = pt_ops->nextLevelPointer(pte, level); 768 769 if (leaf) 770 break; 771 772 if (context.stage2Enable) { 773 TranslResult s2tr = translateStage2(yield, walkPtr, false); 774 if (s2tr.fault != FAULT_NONE) 775 return s2tr; 776 777 walkPtr = s2tr.addr; 778 } 779 780 walkCacheUpdate(yield, addr, pt_ops->walkMask(level), walkPtr, 781 1, level, leaf, 0); 782 } 783 784 TranslResult tr; 785 tr.fault = FAULT_NONE; 786 tr.addrMask = pt_ops->pageMask(pte, level); 787 tr.addr = walkPtr + (addr & ~tr.addrMask); 788 tr.writable = pt_ops->isWritable(pte, level, false); 789 790 if (context.stage2Enable) { 791 TranslResult s2tr = translateStage2(yield, tr.addr, true); 792 if (s2tr.fault != FAULT_NONE) 793 return s2tr; 794 795 tr = combineTranslations(tr, s2tr); 796 } 797 798 walkCacheUpdate(yield, addr, tr.addrMask, tr.addr, 799 1, level, true, tr.writable); 800 801 return tr; 802} 803 804SMMUTranslationProcess::TranslResult 805SMMUTranslationProcess::walkStage2(Yield &yield, Addr addr, bool final_tr, 806 const PageTableOps *pt_ops, 807 unsigned level, Addr walkPtr) 808{ 809 PageTableOps::pte_t pte; 810 811 doSemaphoreDown(yield, smmu.cycleSem); 812 doDelay(yield, Cycles(1)); 813 doSemaphoreUp(smmu.cycleSem); 814 815 for (; level <= pt_ops->lastLevel(); level++) { 816 Addr pte_addr = walkPtr + pt_ops->index(addr, level); 817 818 DPRINTF(SMMUv3, " Fetching S2 L%d PTE from pa=%#08x\n", 819 level, pte_addr); 820 821 doReadPTE(yield, addr, pte_addr, &pte, 2, level); 822 823 DPRINTF(SMMUv3, " Got S2 L%d PTE=%#x from pa=%#08x\n", 824 level, pte, pte_addr); 825 826 doSemaphoreDown(yield, smmu.cycleSem); 827 doDelay(yield, Cycles(1)); 828 doSemaphoreUp(smmu.cycleSem); 829 830 bool valid = pt_ops->isValid(pte, level); 831 bool leaf = pt_ops->isLeaf(pte, level); 832 833 if (!valid) { 834 DPRINTF(SMMUv3, " S2 PTE not valid - fault\n"); 835 836 TranslResult tr; 837 tr.fault = FAULT_TRANSLATION; 838 return tr; 839 } 840 841 if (valid && leaf && request.isWrite && 842 !pt_ops->isWritable(pte, level, true)) 843 { 844 DPRINTF(SMMUv3, " S2 PTE not writable = fault\n"); 845 846 TranslResult tr; 847 tr.fault = FAULT_PERMISSION; 848 return tr; 849 } 850 851 walkPtr = pt_ops->nextLevelPointer(pte, level); 852 853 if (final_tr || smmu.walkCacheNonfinalEnable) 854 walkCacheUpdate(yield, addr, pt_ops->walkMask(level), walkPtr, 855 2, level, leaf, 856 leaf ? pt_ops->isWritable(pte, level, true) : 0); 857 if (leaf) 858 break; 859 } 860 861 TranslResult tr; 862 tr.fault = FAULT_NONE; 863 tr.addrMask = pt_ops->pageMask(pte, level); 864 tr.addr = walkPtr + (addr & ~tr.addrMask); 865 tr.writable = pt_ops->isWritable(pte, level, true); 866 867 return tr; 868} 869 870SMMUTranslationProcess::TranslResult 871SMMUTranslationProcess::translateStage1And2(Yield &yield, Addr addr) 872{ 873 const PageTableOps *pt_ops = 874 smmu.getPageTableOps(context.stage1TranslGranule); 875 876 const WalkCache::Entry *walk_ep = NULL; 877 unsigned level; 878 879 // Level here is actually (level+1) so we can count down 880 // to 0 using unsigned int. 881 for (level = pt_ops->lastLevel() + 1; 882 level > pt_ops->firstLevel(context.t0sz); 883 level--) 884 { 885 walkCacheLookup(yield, walk_ep, addr, 886 context.asid, context.vmid, 1, level-1); 887 888 if (walk_ep) 889 break; 890 } 891 892 // Correct level (see above). 893 level -= 1; 894 895 TranslResult tr; 896 if (walk_ep) { 897 if (walk_ep->leaf) { 898 tr.fault = FAULT_NONE; 899 tr.addr = walk_ep->pa + (addr & ~walk_ep->vaMask); 900 tr.addrMask = walk_ep->vaMask; 901 tr.writable = walk_ep->permissions; 902 } else { 903 tr = walkStage1And2(yield, addr, pt_ops, level+1, walk_ep->pa); 904 } 905 } else { 906 Addr table_addr = context.ttb0; 907 if (context.stage2Enable) { 908 TranslResult s2tr = translateStage2(yield, table_addr, false); 909 if (s2tr.fault != FAULT_NONE) 910 return s2tr; 911 912 table_addr = s2tr.addr; 913 } 914 915 tr = walkStage1And2(yield, addr, pt_ops, 916 pt_ops->firstLevel(context.t0sz), 917 table_addr); 918 } 919 920 if (tr.fault == FAULT_NONE) 921 DPRINTF(SMMUv3, "Translated vaddr %#x to paddr %#x\n", addr, tr.addr); 922 923 return tr; 924} 925 926SMMUTranslationProcess::TranslResult 927SMMUTranslationProcess::translateStage2(Yield &yield, Addr addr, bool final_tr) 928{ 929 const PageTableOps *pt_ops = 930 smmu.getPageTableOps(context.stage2TranslGranule); 931 932 const IPACache::Entry *ipa_ep = NULL; 933 if (smmu.ipaCacheEnable) { 934 doSemaphoreDown(yield, smmu.ipaSem); 935 doDelay(yield, smmu.ipaLat); 936 ipa_ep = smmu.ipaCache.lookup(addr, context.vmid); 937 doSemaphoreUp(smmu.ipaSem); 938 } 939 940 if (ipa_ep) { 941 TranslResult tr; 942 tr.fault = FAULT_NONE; 943 tr.addr = ipa_ep->pa + (addr & ~ipa_ep->ipaMask); 944 tr.addrMask = ipa_ep->ipaMask; 945 tr.writable = ipa_ep->permissions; 946 947 DPRINTF(SMMUv3, " IPACache hit ipa=%#x vmid=%#x pa=%#x\n", 948 addr, context.vmid, tr.addr); 949 950 return tr; 951 } else if (smmu.ipaCacheEnable) { 952 DPRINTF(SMMUv3, " IPACache miss ipa=%#x vmid=%#x\n", 953 addr, context.vmid); 954 } 955 956 const WalkCache::Entry *walk_ep = NULL; 957 unsigned level = pt_ops->firstLevel(context.s2t0sz); 958 959 if (final_tr || smmu.walkCacheNonfinalEnable) { 960 // Level here is actually (level+1) so we can count down 961 // to 0 using unsigned int. 962 for (level = pt_ops->lastLevel() + 1; 963 level > pt_ops->firstLevel(context.s2t0sz); 964 level--) 965 { 966 walkCacheLookup(yield, walk_ep, addr, 967 0, context.vmid, 2, level-1); 968 969 if (walk_ep) 970 break; 971 } 972 973 // Correct level (see above). 974 level -= 1; 975 } 976 977 TranslResult tr; 978 if (walk_ep) { 979 if (walk_ep->leaf) { 980 tr.fault = FAULT_NONE; 981 tr.addr = walk_ep->pa + (addr & ~walk_ep->vaMask); 982 tr.addrMask = walk_ep->vaMask; 983 tr.writable = walk_ep->permissions; 984 } else { 985 tr = walkStage2(yield, addr, final_tr, pt_ops, 986 level + 1, walk_ep->pa); 987 } 988 } else { 989 tr = walkStage2(yield, addr, final_tr, pt_ops, 990 pt_ops->firstLevel(context.s2t0sz), 991 context.httb); 992 } 993 994 if (tr.fault == FAULT_NONE) 995 DPRINTF(SMMUv3, " Translated %saddr %#x to paddr %#x\n", 996 context.stage1Enable ? "ip" : "v", addr, tr.addr); 997 998 if (smmu.ipaCacheEnable) { 999 IPACache::Entry e; 1000 e.valid = true; 1001 e.ipaMask = tr.addrMask; 1002 e.ipa = addr & e.ipaMask; 1003 e.pa = tr.addr & tr.addrMask; 1004 e.permissions = tr.writable; 1005 e.vmid = context.vmid; 1006 1007 doSemaphoreDown(yield, smmu.ipaSem); 1008 smmu.ipaCache.store(e); 1009 doSemaphoreUp(smmu.ipaSem); 1010 } 1011 1012 return tr; 1013} 1014 1015SMMUTranslationProcess::TranslResult 1016SMMUTranslationProcess::combineTranslations(const TranslResult &s1tr, 1017 const TranslResult &s2tr) const 1018{ 1019 if (s2tr.fault != FAULT_NONE) 1020 return s2tr; 1021 1022 assert(s1tr.fault == FAULT_NONE); 1023 1024 TranslResult tr; 1025 tr.fault = FAULT_NONE; 1026 tr.addr = s2tr.addr; 1027 tr.addrMask = s1tr.addrMask | s2tr.addrMask; 1028 tr.writable = s1tr.writable & s2tr.writable; 1029 1030 return tr; 1031} 1032 1033bool 1034SMMUTranslationProcess::hazard4kCheck() 1035{ 1036 Addr addr4k = request.addr & ~0xfffULL; 1037 1038 for (auto it = ifc.duplicateReqs.begin(); 1039 it != ifc.duplicateReqs.end(); 1040 ++it) 1041 { 1042 Addr other4k = (*it)->request.addr & ~0xfffULL; 1043 if (addr4k == other4k) 1044 return true; 1045 } 1046 1047 return false; 1048} 1049 1050void 1051SMMUTranslationProcess::hazard4kRegister() 1052{ 1053 DPRINTF(SMMUv3Hazard, "4kReg: p=%p a4k=%#x\n", 1054 this, request.addr & ~0xfffULL); 1055 1056 ifc.duplicateReqs.push_back(this); 1057} 1058 1059void 1060SMMUTranslationProcess::hazard4kHold(Yield &yield) 1061{ 1062 Addr addr4k = request.addr & ~0xfffULL; 1063 1064 bool found_hazard; 1065 1066 do { 1067 found_hazard = false; 1068 1069 for (auto it = ifc.duplicateReqs.begin(); 1070 it!=ifc.duplicateReqs.end() && *it!=this; 1071 ++it) 1072 { 1073 Addr other4k = (*it)->request.addr & ~0xfffULL; 1074 1075 DPRINTF(SMMUv3Hazard, "4kHold: p=%p a4k=%#x Q: p=%p a4k=%#x\n", 1076 this, addr4k, *it, other4k); 1077 1078 if (addr4k == other4k) { 1079 DPRINTF(SMMUv3Hazard, 1080 "4kHold: p=%p a4k=%#x WAIT on p=%p a4k=%#x\n", 1081 this, addr4k, *it, other4k); 1082 1083 doWaitForSignal(yield, ifc.duplicateReqRemoved); 1084 1085 DPRINTF(SMMUv3Hazard, "4kHold: p=%p a4k=%#x RESUME\n", 1086 this, addr4k); 1087 1088 // This is to avoid checking *it!=this after doWaitForSignal() 1089 // since it could have been deleted. 1090 found_hazard = true; 1091 break; 1092 } 1093 } 1094 } while (found_hazard); 1095} 1096 1097void 1098SMMUTranslationProcess::hazard4kRelease() 1099{ 1100 DPRINTF(SMMUv3Hazard, "4kRel: p=%p a4k=%#x\n", 1101 this, request.addr & ~0xfffULL); 1102 1103 std::list<SMMUTranslationProcess *>::iterator it; 1104 1105 for (it = ifc.duplicateReqs.begin(); it != ifc.duplicateReqs.end(); ++it) 1106 if (*it == this) 1107 break; 1108 1109 if (it == ifc.duplicateReqs.end()) 1110 panic("hazard4kRelease: request not found"); 1111 1112 ifc.duplicateReqs.erase(it); 1113 1114 doBroadcastSignal(ifc.duplicateReqRemoved); 1115} 1116 1117void 1118SMMUTranslationProcess::hazardIdRegister() 1119{ 1120 auto orderId = AMBA::orderId(request.pkt); 1121 1122 DPRINTF(SMMUv3Hazard, "IdReg: p=%p oid=%d\n", this, orderId); 1123 1124 assert(orderId < SMMU_MAX_TRANS_ID); 1125 1126 std::list<SMMUTranslationProcess *> &depReqs = 1127 request.isWrite ? 1128 ifc.dependentWrites[orderId] : ifc.dependentReads[orderId]; 1129 depReqs.push_back(this); 1130} 1131 1132void 1133SMMUTranslationProcess::hazardIdHold(Yield &yield) 1134{ 1135 auto orderId = AMBA::orderId(request.pkt); 1136 1137 DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d\n", this, orderId); 1138 1139 std::list<SMMUTranslationProcess *> &depReqs = 1140 request.isWrite ? 1141 ifc.dependentWrites[orderId] : ifc.dependentReads[orderId]; 1142 std::list<SMMUTranslationProcess *>::iterator it; 1143 1144 bool found_hazard; 1145 1146 do { 1147 found_hazard = false; 1148 1149 for (auto it = depReqs.begin(); it!=depReqs.end() && *it!=this; ++it) { 1150 DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d Q: %p\n", 1151 this, orderId, *it); 1152 1153 if (AMBA::orderId((*it)->request.pkt) == orderId) { 1154 DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d WAIT on=%p\n", 1155 this, orderId, *it); 1156 1157 doWaitForSignal(yield, ifc.dependentReqRemoved); 1158 1159 DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d RESUME\n", 1160 this, orderId); 1161 1162 // This is to avoid checking *it!=this after doWaitForSignal() 1163 // since it could have been deleted. 1164 found_hazard = true; 1165 break; 1166 } 1167 } 1168 } while (found_hazard); 1169} 1170 1171void 1172SMMUTranslationProcess::hazardIdRelease() 1173{ 1174 auto orderId = AMBA::orderId(request.pkt); 1175 1176 DPRINTF(SMMUv3Hazard, "IdRel: p=%p oid=%d\n", this, orderId); 1177 1178 std::list<SMMUTranslationProcess *> &depReqs = 1179 request.isWrite ? 1180 ifc.dependentWrites[orderId] : ifc.dependentReads[orderId]; 1181 std::list<SMMUTranslationProcess *>::iterator it; 1182 1183 for (it = depReqs.begin(); it != depReqs.end(); ++it) { 1184 if (*it == this) 1185 break; 1186 } 1187 1188 if (it == depReqs.end()) 1189 panic("hazardIdRelease: request not found"); 1190 1191 depReqs.erase(it); 1192 1193 doBroadcastSignal(ifc.dependentReqRemoved); 1194} 1195 1196void 1197SMMUTranslationProcess::issuePrefetch(Addr addr) 1198{ 1199 if (!smmu.system.isTimingMode()) 1200 return; 1201 1202 if (!ifc.prefetchEnable || ifc.xlateSlotsRemaining == 0) 1203 return; 1204 1205 std::string proc_name = csprintf("%sprf", name()); 1206 SMMUTranslationProcess *proc = 1207 new SMMUTranslationProcess(proc_name, smmu, ifc); 1208 1209 proc->beginTransaction( 1210 SMMUTranslRequest::prefetch(addr, request.sid, request.ssid)); 1211 proc->scheduleWakeup(smmu.clockEdge(Cycles(1))); 1212} 1213 1214void 1215SMMUTranslationProcess::completeTransaction(Yield &yield, 1216 const TranslResult &tr) 1217{ 1218 assert(tr.fault == FAULT_NONE); 1219 1220 unsigned numMasterBeats = request.isWrite ? 1221 (request.size + (smmu.masterPortWidth-1)) 1222 / smmu.masterPortWidth : 1223 1; 1224 1225 doSemaphoreDown(yield, smmu.masterPortSem); 1226 doDelay(yield, Cycles(numMasterBeats)); 1227 doSemaphoreUp(smmu.masterPortSem); 1228 1229 1230 smmu.translationTimeDist.sample(curTick() - recvTick); 1231 if (!request.isAtsRequest && request.isWrite) 1232 ifc.wrBufSlotsRemaining += 1233 (request.size + (ifc.portWidth-1)) / ifc.portWidth; 1234 1235 smmu.scheduleSlaveRetries(); 1236 1237 1238 SMMUAction a; 1239 1240 if (request.isAtsRequest) { 1241 a.type = ACTION_SEND_RESP_ATS; 1242 1243 if (smmu.system.isAtomicMode()) { 1244 request.pkt->makeAtomicResponse(); 1245 } else if (smmu.system.isTimingMode()) { 1246 request.pkt->makeTimingResponse(); 1247 } else { 1248 panic("Not in atomic or timing mode"); 1249 } 1250 } else { 1251 a.type = ACTION_SEND_REQ_FINAL; 1252 a.ifc = &ifc; 1253 } 1254 1255 a.pkt = request.pkt; 1256 a.delay = 0; 1257 1258 a.pkt->setAddr(tr.addr); 1259 a.pkt->req->setPaddr(tr.addr); 1260 1261 yield(a); 1262 1263 if (!request.isAtsRequest) { 1264 PacketPtr pkt = yield.get(); 1265 pkt->setAddr(request.addr); 1266 1267 a.type = ACTION_SEND_RESP; 1268 a.pkt = pkt; 1269 a.ifc = &ifc; 1270 a.delay = 0; 1271 yield(a); 1272 } 1273} 1274 1275void 1276SMMUTranslationProcess::completePrefetch(Yield &yield) 1277{ 1278 SMMUAction a; 1279 a.type = ACTION_TERMINATE; 1280 a.pkt = NULL; 1281 a.ifc = &ifc; 1282 a.delay = 0; 1283 yield(a); 1284} 1285 1286void 1287SMMUTranslationProcess::sendEvent(Yield &yield, const SMMUEvent &ev) 1288{ 1289 int sizeMask = mask(smmu.regs.eventq_base & Q_BASE_SIZE_MASK); 1290 1291 if (((smmu.regs.eventq_prod+1) & sizeMask) == 1292 (smmu.regs.eventq_cons & sizeMask)) 1293 panic("Event queue full - aborting\n"); 1294 1295 Addr event_addr = 1296 (smmu.regs.eventq_base & Q_BASE_ADDR_MASK) + 1297 (smmu.regs.eventq_prod & sizeMask) * sizeof(ev); 1298 1299 DPRINTF(SMMUv3, "Sending event to addr=%#08x (pos=%d): type=%#x stag=%#x " 1300 "flags=%#x sid=%#x ssid=%#x va=%#08x ipa=%#x\n", 1301 event_addr, smmu.regs.eventq_prod, ev.type, ev.stag, 1302 ev.flags, ev.streamId, ev.substreamId, ev.va, ev.ipa); 1303 1304 // This deliberately resets the overflow field in eventq_prod! 1305 smmu.regs.eventq_prod = (smmu.regs.eventq_prod + 1) & sizeMask; 1306 1307 doWrite(yield, event_addr, &ev, sizeof(ev)); 1308 1309 if (!(smmu.regs.eventq_irq_cfg0 & E_BASE_ENABLE_MASK)) 1310 panic("eventq msi not enabled\n"); 1311 1312 doWrite(yield, smmu.regs.eventq_irq_cfg0 & E_BASE_ADDR_MASK, 1313 &smmu.regs.eventq_irq_cfg1, sizeof(smmu.regs.eventq_irq_cfg1)); 1314} 1315 1316void 1317SMMUTranslationProcess::doReadSTE(Yield &yield, 1318 StreamTableEntry &ste, 1319 uint32_t sid) 1320{ 1321 unsigned max_sid = 1 << (smmu.regs.strtab_base_cfg & ST_CFG_SIZE_MASK); 1322 if (sid >= max_sid) 1323 panic("SID %#x out of range, max=%#x", sid, max_sid); 1324 1325 Addr ste_addr; 1326 1327 if ((smmu.regs.strtab_base_cfg & ST_CFG_FMT_MASK) == ST_CFG_FMT_2LEVEL) { 1328 unsigned split = 1329 (smmu.regs.strtab_base_cfg & ST_CFG_SPLIT_MASK) >> ST_CFG_SPLIT_SHIFT; 1330 1331 if (split!= 7 && split!=8 && split!=16) 1332 panic("Invalid stream table split %d", split); 1333 1334 uint64_t l2_ptr; 1335 uint64_t l2_addr = 1336 (smmu.regs.strtab_base & VMT_BASE_ADDR_MASK) + 1337 bits(sid, 32, split) * sizeof(l2_ptr); 1338 1339 DPRINTF(SMMUv3, "Read L1STE at %#x\n", l2_addr); 1340 1341 doReadConfig(yield, l2_addr, &l2_ptr, sizeof(l2_ptr), sid, 0); 1342 1343 DPRINTF(SMMUv3, "Got L1STE L1 at %#x: 0x%016x\n", l2_addr, l2_ptr); 1344 1345 unsigned span = l2_ptr & ST_L2_SPAN_MASK; 1346 if (span == 0) 1347 panic("Invalid level 1 stream table descriptor"); 1348 1349 unsigned index = bits(sid, split-1, 0); 1350 if (index >= (1 << span)) 1351 panic("StreamID %d out of level 1 descriptor range %d", 1352 sid, 1<<span); 1353 1354 ste_addr = (l2_ptr & ST_L2_ADDR_MASK) + index * sizeof(ste); 1355 1356 smmu.steL1Fetches++; 1357 } else if ((smmu.regs.strtab_base_cfg & ST_CFG_FMT_MASK) == ST_CFG_FMT_LINEAR) { 1358 ste_addr = 1359 (smmu.regs.strtab_base & VMT_BASE_ADDR_MASK) + sid * sizeof(ste); 1360 } else { 1361 panic("Invalid stream table format"); 1362 } 1363 1364 DPRINTF(SMMUv3, "Read STE at %#x\n", ste_addr); 1365 1366 doReadConfig(yield, ste_addr, &ste, sizeof(ste), sid, 0); 1367 1368 DPRINTF(SMMUv3, "Got STE at %#x [0]: 0x%016x\n", ste_addr, ste.dw0); 1369 DPRINTF(SMMUv3, " STE at %#x [1]: 0x%016x\n", ste_addr, ste.dw1); 1370 DPRINTF(SMMUv3, " STE at %#x [2]: 0x%016x\n", ste_addr, ste.dw2); 1371 DPRINTF(SMMUv3, " STE at %#x [3]: 0x%016x\n", ste_addr, ste.dw3); 1372 DPRINTF(SMMUv3, " STE at %#x [4]: 0x%016x\n", ste_addr, ste._pad[0]); 1373 DPRINTF(SMMUv3, " STE at %#x [5]: 0x%016x\n", ste_addr, ste._pad[1]); 1374 DPRINTF(SMMUv3, " STE at %#x [6]: 0x%016x\n", ste_addr, ste._pad[2]); 1375 DPRINTF(SMMUv3, " STE at %#x [7]: 0x%016x\n", ste_addr, ste._pad[3]); 1376 1377 if (!ste.dw0.valid) 1378 panic("STE @ %#x not valid\n", ste_addr); 1379 1380 smmu.steFetches++; 1381} 1382 1383void 1384SMMUTranslationProcess::doReadCD(Yield &yield, 1385 ContextDescriptor &cd, 1386 const StreamTableEntry &ste, 1387 uint32_t sid, uint32_t ssid) 1388{ 1389 Addr cd_addr; 1390 1391 if (ste.dw0.s1cdmax == 0) { 1392 cd_addr = ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT; 1393 } else { 1394 unsigned max_ssid = 1 << ste.dw0.s1cdmax; 1395 if (ssid >= max_ssid) 1396 panic("SSID %#x out of range, max=%#x", ssid, max_ssid); 1397 1398 if (ste.dw0.s1fmt==STAGE1_CFG_2L_4K || 1399 ste.dw0.s1fmt==STAGE1_CFG_2L_64K) 1400 { 1401 unsigned split = ste.dw0.s1fmt==STAGE1_CFG_2L_4K ? 7 : 11; 1402 1403 uint64_t l2_ptr; 1404 uint64_t l2_addr = (ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT) + 1405 bits(ssid, 24, split) * sizeof(l2_ptr); 1406 1407 if (context.stage2Enable) 1408 l2_addr = translateStage2(yield, l2_addr, false).addr; 1409 1410 DPRINTF(SMMUv3, "Read L1CD at %#x\n", l2_addr); 1411 1412 doReadConfig(yield, l2_addr, &l2_ptr, sizeof(l2_ptr), sid, ssid); 1413 1414 DPRINTF(SMMUv3, "Got L1CD at %#x: 0x%016x\n", l2_addr, l2_ptr); 1415 1416 cd_addr = l2_ptr + bits(ssid, split-1, 0) * sizeof(cd); 1417 1418 smmu.cdL1Fetches++; 1419 } else if (ste.dw0.s1fmt == STAGE1_CFG_1L) { 1420 cd_addr = (ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT) + ssid*sizeof(cd); 1421 } 1422 } 1423 1424 if (context.stage2Enable) 1425 cd_addr = translateStage2(yield, cd_addr, false).addr; 1426 1427 DPRINTF(SMMUv3, "Read CD at %#x\n", cd_addr); 1428 1429 doReadConfig(yield, cd_addr, &cd, sizeof(cd), sid, ssid); 1430 1431 DPRINTF(SMMUv3, "Got CD at %#x [0]: 0x%016x\n", cd_addr, cd.dw0); 1432 DPRINTF(SMMUv3, " CD at %#x [1]: 0x%016x\n", cd_addr, cd.dw1); 1433 DPRINTF(SMMUv3, " CD at %#x [2]: 0x%016x\n", cd_addr, cd.dw2); 1434 DPRINTF(SMMUv3, " CD at %#x [3]: 0x%016x\n", cd_addr, cd.mair); 1435 DPRINTF(SMMUv3, " CD at %#x [4]: 0x%016x\n", cd_addr, cd.amair); 1436 DPRINTF(SMMUv3, " CD at %#x [5]: 0x%016x\n", cd_addr, cd._pad[0]); 1437 DPRINTF(SMMUv3, " CD at %#x [6]: 0x%016x\n", cd_addr, cd._pad[1]); 1438 DPRINTF(SMMUv3, " CD at %#x [7]: 0x%016x\n", cd_addr, cd._pad[2]); 1439 1440 1441 if (!cd.dw0.valid) 1442 panic("CD @ %#x not valid\n", cd_addr); 1443 1444 smmu.cdFetches++; 1445} 1446 1447void 1448SMMUTranslationProcess::doReadConfig(Yield &yield, Addr addr, 1449 void *ptr, size_t size, 1450 uint32_t sid, uint32_t ssid) 1451{ 1452 doRead(yield, addr, ptr, size); 1453} 1454 1455void 1456SMMUTranslationProcess::doReadPTE(Yield &yield, Addr va, Addr addr, 1457 void *ptr, unsigned stage, 1458 unsigned level) 1459{ 1460 size_t pte_size = sizeof(PageTableOps::pte_t); 1461 1462 Addr mask = pte_size - 1; 1463 Addr base = addr & ~mask; 1464 1465 doRead(yield, base, ptr, pte_size); 1466} 1467