smmu_v3_transl.cc revision 14063:fc05dc40f6d1
16019Shines@cs.fsu.edu/* 214028Sgiacomo.gabrielli@arm.com * Copyright (c) 2013, 2018-2019 ARM Limited 37091Sgblack@eecs.umich.edu * All rights reserved 47091Sgblack@eecs.umich.edu * 57091Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 67091Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 77091Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 87091Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 97091Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 107091Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 117091Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 127091Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 137091Sgblack@eecs.umich.edu * 146019Shines@cs.fsu.edu * Redistribution and use in source and binary forms, with or without 156019Shines@cs.fsu.edu * modification, are permitted provided that the following conditions are 166019Shines@cs.fsu.edu * met: redistributions of source code must retain the above copyright 176019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer; 186019Shines@cs.fsu.edu * redistributions in binary form must reproduce the above copyright 196019Shines@cs.fsu.edu * notice, this list of conditions and the following disclaimer in the 206019Shines@cs.fsu.edu * documentation and/or other materials provided with the distribution; 216019Shines@cs.fsu.edu * neither the name of the copyright holders nor the names of its 226019Shines@cs.fsu.edu * contributors may be used to endorse or promote products derived from 236019Shines@cs.fsu.edu * this software without specific prior written permission. 246019Shines@cs.fsu.edu * 256019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 266019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 276019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 286019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 296019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 306019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 316019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 326019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 336019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 346019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 356019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 366019Shines@cs.fsu.edu * 376019Shines@cs.fsu.edu * Authors: Stan Czerniawski 386019Shines@cs.fsu.edu */ 396019Shines@cs.fsu.edu 406019Shines@cs.fsu.edu#include "dev/arm/smmu_v3_transl.hh" 416019Shines@cs.fsu.edu 426019Shines@cs.fsu.edu#include "debug/SMMUv3.hh" 438449Sgblack@eecs.umich.edu#include "debug/SMMUv3Hazard.hh" 448449Sgblack@eecs.umich.edu#include "dev/arm/amba.hh" 458449Sgblack@eecs.umich.edu#include "dev/arm/smmu_v3.hh" 468449Sgblack@eecs.umich.edu#include "sim/system.hh" 478449Sgblack@eecs.umich.edu 488449Sgblack@eecs.umich.eduSMMUTranslRequest 4913759Sgiacomo.gabrielli@arm.comSMMUTranslRequest::fromPacket(PacketPtr pkt, bool ats) 508449Sgblack@eecs.umich.edu{ 5112386Sgabeblack@google.com SMMUTranslRequest req; 528449Sgblack@eecs.umich.edu req.addr = pkt->getAddr(); 5312110SRekai.GonzalezAlberquilla@arm.com req.size = pkt->getSize(); 5413915Sgabeblack@google.com req.sid = pkt->req->streamId(); 5512110SRekai.GonzalezAlberquilla@arm.com req.ssid = pkt->req->hasSubstreamId() ? 5612110SRekai.GonzalezAlberquilla@arm.com pkt->req->substreamId() : 0; 5713759Sgiacomo.gabrielli@arm.com req.isWrite = pkt->isWrite(); 5813759Sgiacomo.gabrielli@arm.com req.isPrefetch = false; 5913915Sgabeblack@google.com req.isAtsRequest = ats; 6013759Sgiacomo.gabrielli@arm.com req.pkt = pkt; 616019Shines@cs.fsu.edu 626019Shines@cs.fsu.edu return req; 636312Sgblack@eecs.umich.edu} 646312Sgblack@eecs.umich.edu 657720Sgblack@eecs.umich.eduSMMUTranslRequest 666312Sgblack@eecs.umich.eduSMMUTranslRequest::prefetch(Addr addr, uint32_t sid, uint32_t ssid) 677186Sgblack@eecs.umich.edu{ 687720Sgblack@eecs.umich.edu SMMUTranslRequest req; 697186Sgblack@eecs.umich.edu req.addr = addr; 707186Sgblack@eecs.umich.edu req.size = 0; 716312Sgblack@eecs.umich.edu req.sid = sid; 727093Sgblack@eecs.umich.edu req.ssid = ssid; 736312Sgblack@eecs.umich.edu req.isWrite = false; 746312Sgblack@eecs.umich.edu req.isPrefetch = true; 757148Sgblack@eecs.umich.edu req.isAtsRequest = false; 767148Sgblack@eecs.umich.edu req.pkt = NULL; 777148Sgblack@eecs.umich.edu 787148Sgblack@eecs.umich.edu return req; 797184Sgblack@eecs.umich.edu} 807184Sgblack@eecs.umich.edu 817289Sgblack@eecs.umich.eduSMMUTranslationProcess::SMMUTranslationProcess(const std::string &name, 827289Sgblack@eecs.umich.edu SMMUv3 &_smmu, SMMUv3SlaveInterface &_ifc) 837289Sgblack@eecs.umich.edu : 847289Sgblack@eecs.umich.edu SMMUProcess(name, _smmu), 857184Sgblack@eecs.umich.edu ifc(_ifc) 867184Sgblack@eecs.umich.edu{ 877184Sgblack@eecs.umich.edu // Decrease number of pending translation slots on the slave interface 887184Sgblack@eecs.umich.edu assert(ifc.xlateSlotsRemaining > 0); 897184Sgblack@eecs.umich.edu ifc.xlateSlotsRemaining--; 907184Sgblack@eecs.umich.edu reinit(); 9110037SARM gem5 Developers} 9210037SARM gem5 Developers 9310037SARM gem5 DevelopersSMMUTranslationProcess::~SMMUTranslationProcess() 9410037SARM gem5 Developers{ 9510037SARM gem5 Developers // Increase number of pending translation slots on the slave interface 9610037SARM gem5 Developers ifc.xlateSlotsRemaining++; 9710037SARM gem5 Developers} 9810037SARM gem5 Developers 9910037SARM gem5 Developersvoid 10010037SARM gem5 DevelopersSMMUTranslationProcess::beginTransaction(const SMMUTranslRequest &req) 10110037SARM gem5 Developers{ 10210037SARM gem5 Developers request = req; 10310037SARM gem5 Developers 10410037SARM gem5 Developers reinit(); 10510037SARM gem5 Developers} 10610037SARM gem5 Developers 10710037SARM gem5 Developersvoid 10810037SARM gem5 DevelopersSMMUTranslationProcess::resumeTransaction() 10910037SARM gem5 Developers{ 11012499Sgiacomo.travaglini@arm.com assert(smmu.system.isTimingMode()); 11110037SARM gem5 Developers 11210037SARM gem5 Developers assert(!"Stalls are broken"); 11310037SARM gem5 Developers 11412499Sgiacomo.travaglini@arm.com Tick resumeTick = curTick(); 11510037SARM gem5 Developers 1167797Sgblack@eecs.umich.edu (void) resumeTick; 1177797Sgblack@eecs.umich.edu DPRINTF(SMMUv3, "Resume at tick = %d. Fault duration = %d (%.3fus)\n", 1187797Sgblack@eecs.umich.edu resumeTick, resumeTick-faultTick, (resumeTick-faultTick) / 1e6); 1197797Sgblack@eecs.umich.edu 1207797Sgblack@eecs.umich.edu beginTransaction(request); 1217797Sgblack@eecs.umich.edu 1227797Sgblack@eecs.umich.edu smmu.runProcessTiming(this, request.pkt); 1237797Sgblack@eecs.umich.edu} 1247797Sgblack@eecs.umich.edu 1257797Sgblack@eecs.umich.eduvoid 1267797Sgblack@eecs.umich.eduSMMUTranslationProcess::main(Yield &yield) 1277797Sgblack@eecs.umich.edu{ 12812110SRekai.GonzalezAlberquilla@arm.com // Hack: 12912110SRekai.GonzalezAlberquilla@arm.com // The coroutine starts running as soon as it's created. 13012110SRekai.GonzalezAlberquilla@arm.com // But we need to wait for request data esp. in atomic mode. 13112110SRekai.GonzalezAlberquilla@arm.com SMMUAction a; 13212110SRekai.GonzalezAlberquilla@arm.com a.type = ACTION_INITIAL_NOP; 13312110SRekai.GonzalezAlberquilla@arm.com a.pkt = NULL; 13412110SRekai.GonzalezAlberquilla@arm.com yield(a); 13512110SRekai.GonzalezAlberquilla@arm.com 13612110SRekai.GonzalezAlberquilla@arm.com const Addr next4k = (request.addr + 0x1000ULL) & ~0xfffULL; 13713759Sgiacomo.gabrielli@arm.com 13813759Sgiacomo.gabrielli@arm.com if ((request.addr + request.size) > next4k) 13913759Sgiacomo.gabrielli@arm.com panic("Transaction crosses 4k boundary (addr=%#x size=%#x)!\n", 1407797Sgblack@eecs.umich.edu request.addr, request.size); 1417797Sgblack@eecs.umich.edu 1427797Sgblack@eecs.umich.edu 1437797Sgblack@eecs.umich.edu unsigned numSlaveBeats = request.isWrite ? 14410037SARM gem5 Developers (request.size + (ifc.portWidth - 1)) / ifc.portWidth : 1; 14510037SARM gem5 Developers 14610037SARM gem5 Developers doSemaphoreDown(yield, ifc.slavePortSem); 14710037SARM gem5 Developers doDelay(yield, Cycles(numSlaveBeats)); 14810037SARM gem5 Developers doSemaphoreUp(ifc.slavePortSem); 14910037SARM gem5 Developers 15010037SARM gem5 Developers 15110037SARM gem5 Developers recvTick = curTick(); 15210037SARM gem5 Developers 15310037SARM gem5 Developers 15410037SARM gem5 Developers if (!(smmu.regs.cr0 & 0x1)) { 15510037SARM gem5 Developers // SMMU disabled 1567797Sgblack@eecs.umich.edu doDelay(yield, Cycles(1)); 1577797Sgblack@eecs.umich.edu completeTransaction(yield, bypass(request.addr)); 1587797Sgblack@eecs.umich.edu return; 1597797Sgblack@eecs.umich.edu } 1607797Sgblack@eecs.umich.edu 1617797Sgblack@eecs.umich.edu TranslResult tr; 1627797Sgblack@eecs.umich.edu bool wasPrefetched = false; 1637797Sgblack@eecs.umich.edu 1647797Sgblack@eecs.umich.edu if (request.isPrefetch) { 1657797Sgblack@eecs.umich.edu // Abort prefetch if: 1667797Sgblack@eecs.umich.edu // - there's already a transaction looking up the same 4k page, OR 1677797Sgblack@eecs.umich.edu // - requested address is already in the TLB. 1687797Sgblack@eecs.umich.edu if (hazard4kCheck() || ifcTLBLookup(yield, tr, wasPrefetched)) 1697797Sgblack@eecs.umich.edu completePrefetch(yield); // this never returns 1707797Sgblack@eecs.umich.edu 17110338SCurtis.Dunham@arm.com hazard4kRegister(); 17210338SCurtis.Dunham@arm.com 1737797Sgblack@eecs.umich.edu tr = smmuTranslation(yield); 1747797Sgblack@eecs.umich.edu 1759251Snathanael.premillieu@irisa.fr if (tr.fault == FAULT_NONE) 1767797Sgblack@eecs.umich.edu ifcTLBUpdate(yield, tr); 17710037SARM gem5 Developers 17810037SARM gem5 Developers hazard4kRelease(); 17910037SARM gem5 Developers 18010037SARM gem5 Developers completePrefetch(yield); 18110037SARM gem5 Developers } else { 18210037SARM gem5 Developers hazardIdRegister(); 1837797Sgblack@eecs.umich.edu 1847797Sgblack@eecs.umich.edu if (!microTLBLookup(yield, tr)) { 1857797Sgblack@eecs.umich.edu bool hit = ifcTLBLookup(yield, tr, wasPrefetched); 1867797Sgblack@eecs.umich.edu if (!hit) { 18710037SARM gem5 Developers while (!hit && hazard4kCheck()) { 1886312Sgblack@eecs.umich.edu hazard4kHold(yield); 1896312Sgblack@eecs.umich.edu hit = ifcTLBLookup(yield, tr, wasPrefetched); 1906019Shines@cs.fsu.edu } 1917119Sgblack@eecs.umich.edu } 1927797Sgblack@eecs.umich.edu 19310037SARM gem5 Developers // Issue prefetch if: 19410037SARM gem5 Developers // - there was a TLB hit and the entry was prefetched, OR 19510037SARM gem5 Developers // - TLB miss was successfully serviced 1967797Sgblack@eecs.umich.edu if (hit) { 1977797Sgblack@eecs.umich.edu if (wasPrefetched) 1987797Sgblack@eecs.umich.edu issuePrefetch(next4k); 19910037SARM gem5 Developers } else { 20012134Sgedare@rtems.org hazard4kRegister(); 2017797Sgblack@eecs.umich.edu 20210037SARM gem5 Developers tr = smmuTranslation(yield); 20310037SARM gem5 Developers 2047797Sgblack@eecs.umich.edu if (tr.fault == FAULT_NONE) { 20510037SARM gem5 Developers ifcTLBUpdate(yield, tr); 2067797Sgblack@eecs.umich.edu 2077797Sgblack@eecs.umich.edu issuePrefetch(next4k); 2087797Sgblack@eecs.umich.edu } 2097797Sgblack@eecs.umich.edu 2107797Sgblack@eecs.umich.edu hazard4kRelease(); 21110037SARM gem5 Developers } 21210037SARM gem5 Developers 21310037SARM gem5 Developers if (tr.fault == FAULT_NONE) 21410037SARM gem5 Developers microTLBUpdate(yield, tr); 21510037SARM gem5 Developers } 21610037SARM gem5 Developers 21710037SARM gem5 Developers hazardIdHold(yield); 21810037SARM gem5 Developers hazardIdRelease(); 21910037SARM gem5 Developers 2207797Sgblack@eecs.umich.edu if (tr.fault != FAULT_NONE) 2217797Sgblack@eecs.umich.edu panic("fault\n"); 2227797Sgblack@eecs.umich.edu 2237797Sgblack@eecs.umich.edu completeTransaction(yield, tr); 2246019Shines@cs.fsu.edu } 2257797Sgblack@eecs.umich.edu} 2267797Sgblack@eecs.umich.edu 22710037SARM gem5 DevelopersSMMUTranslationProcess::TranslResult 2287797Sgblack@eecs.umich.eduSMMUTranslationProcess::bypass(Addr addr) const 22910037SARM gem5 Developers{ 2307797Sgblack@eecs.umich.edu TranslResult tr; 2318204SAli.Saidi@ARM.com tr.fault = FAULT_NONE; 2327797Sgblack@eecs.umich.edu tr.addr = addr; 2338204SAli.Saidi@ARM.com tr.addrMask = 0; 2348204SAli.Saidi@ARM.com tr.writable = 1; 2358204SAli.Saidi@ARM.com 23610037SARM gem5 Developers return tr; 23710037SARM gem5 Developers} 23810037SARM gem5 Developers 23910037SARM gem5 DevelopersSMMUTranslationProcess::TranslResult 2407797Sgblack@eecs.umich.eduSMMUTranslationProcess::smmuTranslation(Yield &yield) 24110338SCurtis.Dunham@arm.com{ 24210338SCurtis.Dunham@arm.com TranslResult tr; 24310338SCurtis.Dunham@arm.com 24410338SCurtis.Dunham@arm.com // Need SMMU credit to proceed 24510338SCurtis.Dunham@arm.com doSemaphoreDown(yield, smmu.transSem); 24610338SCurtis.Dunham@arm.com 24710338SCurtis.Dunham@arm.com // Simulate pipelined IFC->SMMU link 24810338SCurtis.Dunham@arm.com doSemaphoreDown(yield, smmu.ifcSmmuSem); 24910338SCurtis.Dunham@arm.com doDelay(yield, Cycles(1)); // serialize transactions 25010338SCurtis.Dunham@arm.com doSemaphoreUp(smmu.ifcSmmuSem); 25110338SCurtis.Dunham@arm.com doDelay(yield, smmu.ifcSmmuLat - Cycles(1)); // remaining pipeline delay 25210338SCurtis.Dunham@arm.com 2538303SAli.Saidi@ARM.com bool haveConfig = true; 25410338SCurtis.Dunham@arm.com if (!configCacheLookup(yield, context)) { 25510338SCurtis.Dunham@arm.com if(findConfig(yield, context, tr)) { 25610338SCurtis.Dunham@arm.com configCacheUpdate(yield, context); 25710338SCurtis.Dunham@arm.com } else { 25810338SCurtis.Dunham@arm.com haveConfig = false; 25910338SCurtis.Dunham@arm.com } 26010338SCurtis.Dunham@arm.com } 26110338SCurtis.Dunham@arm.com 26210338SCurtis.Dunham@arm.com if (haveConfig && !smmuTLBLookup(yield, tr)) { 26310338SCurtis.Dunham@arm.com // SMMU main TLB miss 26410338SCurtis.Dunham@arm.com 26510338SCurtis.Dunham@arm.com // Need PTW slot to proceed 2667797Sgblack@eecs.umich.edu doSemaphoreDown(yield, smmu.ptwSem); 2677797Sgblack@eecs.umich.edu 26813603Sgiacomo.travaglini@arm.com // Page table walk 26913815Sgiacomo.travaglini@arm.com Tick ptwStartTick = curTick(); 27013815Sgiacomo.travaglini@arm.com 27113815Sgiacomo.travaglini@arm.com if (context.stage1Enable) { 27213815Sgiacomo.travaglini@arm.com tr = translateStage1And2(yield, request.addr); 27313815Sgiacomo.travaglini@arm.com } else if (context.stage2Enable) { 27413815Sgiacomo.travaglini@arm.com tr = translateStage2(yield, request.addr, true); 27513815Sgiacomo.travaglini@arm.com } else { 27613815Sgiacomo.travaglini@arm.com tr = bypass(request.addr); 2777797Sgblack@eecs.umich.edu } 27813603Sgiacomo.travaglini@arm.com 27913603Sgiacomo.travaglini@arm.com if (context.stage1Enable || context.stage2Enable) 28013603Sgiacomo.travaglini@arm.com smmu.ptwTimeDist.sample(curTick() - ptwStartTick); 28113603Sgiacomo.travaglini@arm.com 28213603Sgiacomo.travaglini@arm.com // Free PTW slot 28313603Sgiacomo.travaglini@arm.com doSemaphoreUp(smmu.ptwSem); 28413603Sgiacomo.travaglini@arm.com 28513603Sgiacomo.travaglini@arm.com if (tr.fault == FAULT_NONE) 28613603Sgiacomo.travaglini@arm.com smmuTLBUpdate(yield, tr); 28713603Sgiacomo.travaglini@arm.com } 28813603Sgiacomo.travaglini@arm.com 28913603Sgiacomo.travaglini@arm.com // Simulate pipelined SMMU->SLAVE INTERFACE link 29013603Sgiacomo.travaglini@arm.com doSemaphoreDown(yield, smmu.smmuIfcSem); 29113603Sgiacomo.travaglini@arm.com doDelay(yield, Cycles(1)); // serialize transactions 29213603Sgiacomo.travaglini@arm.com doSemaphoreUp(smmu.smmuIfcSem); 29313603Sgiacomo.travaglini@arm.com doDelay(yield, smmu.smmuIfcLat - Cycles(1)); // remaining pipeline delay 2947797Sgblack@eecs.umich.edu 29513603Sgiacomo.travaglini@arm.com // return SMMU credit 29613815Sgiacomo.travaglini@arm.com doSemaphoreUp(smmu.transSem); 29713815Sgiacomo.travaglini@arm.com 29813815Sgiacomo.travaglini@arm.com return tr; 29913815Sgiacomo.travaglini@arm.com} 3007797Sgblack@eecs.umich.edu 30113603Sgiacomo.travaglini@arm.combool 30213815Sgiacomo.travaglini@arm.comSMMUTranslationProcess::microTLBLookup(Yield &yield, TranslResult &tr) 30313815Sgiacomo.travaglini@arm.com{ 30413815Sgiacomo.travaglini@arm.com if (!ifc.microTLBEnable) 30513815Sgiacomo.travaglini@arm.com return false; 30613815Sgiacomo.travaglini@arm.com 30713815Sgiacomo.travaglini@arm.com doSemaphoreDown(yield, ifc.microTLBSem); 30813815Sgiacomo.travaglini@arm.com doDelay(yield, ifc.microTLBLat); 30913815Sgiacomo.travaglini@arm.com const SMMUTLB::Entry *e = 31013603Sgiacomo.travaglini@arm.com ifc.microTLB->lookup(request.sid, request.ssid, request.addr); 31113603Sgiacomo.travaglini@arm.com doSemaphoreUp(ifc.microTLBSem); 31213603Sgiacomo.travaglini@arm.com 31313603Sgiacomo.travaglini@arm.com if (!e) { 31413603Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, "micro TLB miss vaddr=%#x sid=%#x ssid=%#x\n", 31513603Sgiacomo.travaglini@arm.com request.addr, request.sid, request.ssid); 31613603Sgiacomo.travaglini@arm.com 31713603Sgiacomo.travaglini@arm.com return false; 31813603Sgiacomo.travaglini@arm.com } 31913603Sgiacomo.travaglini@arm.com 32013603Sgiacomo.travaglini@arm.com DPRINTF(SMMUv3, 32113603Sgiacomo.travaglini@arm.com "micro TLB hit vaddr=%#x amask=%#x sid=%#x ssid=%#x paddr=%#x\n", 32213603Sgiacomo.travaglini@arm.com request.addr, e->vaMask, request.sid, request.ssid, e->pa); 32313603Sgiacomo.travaglini@arm.com 32413603Sgiacomo.travaglini@arm.com tr.fault = FAULT_NONE; 32513603Sgiacomo.travaglini@arm.com tr.addr = e->pa + (request.addr & ~e->vaMask);; 32613603Sgiacomo.travaglini@arm.com tr.addrMask = e->vaMask; 32713603Sgiacomo.travaglini@arm.com tr.writable = e->permissions; 32813603Sgiacomo.travaglini@arm.com 32913815Sgiacomo.travaglini@arm.com return true; 33013815Sgiacomo.travaglini@arm.com} 33113815Sgiacomo.travaglini@arm.com 33213815Sgiacomo.travaglini@arm.combool 3337797Sgblack@eecs.umich.eduSMMUTranslationProcess::ifcTLBLookup(Yield &yield, TranslResult &tr, 33410037SARM gem5 Developers bool &wasPrefetched) 33512110SRekai.GonzalezAlberquilla@arm.com{ 33612110SRekai.GonzalezAlberquilla@arm.com if (!ifc.mainTLBEnable) 33712110SRekai.GonzalezAlberquilla@arm.com return false; 33812110SRekai.GonzalezAlberquilla@arm.com 33912110SRekai.GonzalezAlberquilla@arm.com doSemaphoreDown(yield, ifc.mainTLBSem); 34012110SRekai.GonzalezAlberquilla@arm.com doDelay(yield, ifc.mainTLBLat); 34112110SRekai.GonzalezAlberquilla@arm.com const SMMUTLB::Entry *e = 34212110SRekai.GonzalezAlberquilla@arm.com ifc.mainTLB->lookup(request.sid, request.ssid, request.addr); 34312110SRekai.GonzalezAlberquilla@arm.com doSemaphoreUp(ifc.mainTLBSem); 34412110SRekai.GonzalezAlberquilla@arm.com 34510037SARM gem5 Developers if (!e) { 34612110SRekai.GonzalezAlberquilla@arm.com DPRINTF(SMMUv3, 34712110SRekai.GonzalezAlberquilla@arm.com "SLAVE Interface TLB miss vaddr=%#x sid=%#x ssid=%#x\n", 34812110SRekai.GonzalezAlberquilla@arm.com request.addr, request.sid, request.ssid); 34912110SRekai.GonzalezAlberquilla@arm.com 35012110SRekai.GonzalezAlberquilla@arm.com return false; 35112110SRekai.GonzalezAlberquilla@arm.com } 35212110SRekai.GonzalezAlberquilla@arm.com 35312110SRekai.GonzalezAlberquilla@arm.com DPRINTF(SMMUv3, 35412110SRekai.GonzalezAlberquilla@arm.com "SLAVE Interface TLB hit vaddr=%#x amask=%#x sid=%#x ssid=%#x " 35512110SRekai.GonzalezAlberquilla@arm.com "paddr=%#x\n", request.addr, e->vaMask, request.sid, 35610037SARM gem5 Developers request.ssid, e->pa); 35712110SRekai.GonzalezAlberquilla@arm.com 35812110SRekai.GonzalezAlberquilla@arm.com tr.fault = FAULT_NONE; 35912110SRekai.GonzalezAlberquilla@arm.com tr.addr = e->pa + (request.addr & ~e->vaMask);; 36012110SRekai.GonzalezAlberquilla@arm.com tr.addrMask = e->vaMask; 36112110SRekai.GonzalezAlberquilla@arm.com tr.writable = e->permissions; 36212110SRekai.GonzalezAlberquilla@arm.com wasPrefetched = e->prefetched; 36312110SRekai.GonzalezAlberquilla@arm.com 36412110SRekai.GonzalezAlberquilla@arm.com return true; 36512110SRekai.GonzalezAlberquilla@arm.com} 36612110SRekai.GonzalezAlberquilla@arm.com 36710037SARM gem5 Developersbool 36812110SRekai.GonzalezAlberquilla@arm.comSMMUTranslationProcess::smmuTLBLookup(Yield &yield, TranslResult &tr) 36912110SRekai.GonzalezAlberquilla@arm.com{ 37012110SRekai.GonzalezAlberquilla@arm.com if (!smmu.tlbEnable) 37112110SRekai.GonzalezAlberquilla@arm.com return false; 37212110SRekai.GonzalezAlberquilla@arm.com 37312110SRekai.GonzalezAlberquilla@arm.com doSemaphoreDown(yield, smmu.tlbSem); 37412110SRekai.GonzalezAlberquilla@arm.com doDelay(yield, smmu.tlbLat); 37512110SRekai.GonzalezAlberquilla@arm.com const ARMArchTLB::Entry *e = 37612110SRekai.GonzalezAlberquilla@arm.com smmu.tlb.lookup(request.addr, context.asid, context.vmid); 37712110SRekai.GonzalezAlberquilla@arm.com doSemaphoreUp(smmu.tlbSem); 37810037SARM gem5 Developers 37912110SRekai.GonzalezAlberquilla@arm.com if (!e) { 38012110SRekai.GonzalezAlberquilla@arm.com DPRINTF(SMMUv3, "SMMU TLB miss vaddr=%#x asid=%#x vmid=%#x\n", 38112110SRekai.GonzalezAlberquilla@arm.com request.addr, context.asid, context.vmid); 38212110SRekai.GonzalezAlberquilla@arm.com 38312110SRekai.GonzalezAlberquilla@arm.com return false; 38412110SRekai.GonzalezAlberquilla@arm.com } 38512110SRekai.GonzalezAlberquilla@arm.com 38612110SRekai.GonzalezAlberquilla@arm.com DPRINTF(SMMUv3, 38712110SRekai.GonzalezAlberquilla@arm.com "SMMU TLB hit vaddr=%#x amask=%#x asid=%#x vmid=%#x paddr=%#x\n", 38812110SRekai.GonzalezAlberquilla@arm.com request.addr, e->vaMask, context.asid, context.vmid, e->pa); 38910037SARM gem5 Developers 39012110SRekai.GonzalezAlberquilla@arm.com tr.fault = FAULT_NONE; 39112110SRekai.GonzalezAlberquilla@arm.com tr.addr = e->pa + (request.addr & ~e->vaMask);; 39212110SRekai.GonzalezAlberquilla@arm.com tr.addrMask = e->vaMask; 39312110SRekai.GonzalezAlberquilla@arm.com tr.writable = e->permissions; 39412110SRekai.GonzalezAlberquilla@arm.com 39512110SRekai.GonzalezAlberquilla@arm.com return true; 39612110SRekai.GonzalezAlberquilla@arm.com} 39712110SRekai.GonzalezAlberquilla@arm.com 39812110SRekai.GonzalezAlberquilla@arm.comvoid 39912110SRekai.GonzalezAlberquilla@arm.comSMMUTranslationProcess::microTLBUpdate(Yield &yield, 40010037SARM gem5 Developers const TranslResult &tr) 40112110SRekai.GonzalezAlberquilla@arm.com{ 40212110SRekai.GonzalezAlberquilla@arm.com assert(tr.fault == FAULT_NONE); 40312110SRekai.GonzalezAlberquilla@arm.com 40412110SRekai.GonzalezAlberquilla@arm.com if (!ifc.microTLBEnable) 40512110SRekai.GonzalezAlberquilla@arm.com return; 40612110SRekai.GonzalezAlberquilla@arm.com 40712110SRekai.GonzalezAlberquilla@arm.com SMMUTLB::Entry e; 40812110SRekai.GonzalezAlberquilla@arm.com e.valid = true; 40912110SRekai.GonzalezAlberquilla@arm.com e.prefetched = false; 41012110SRekai.GonzalezAlberquilla@arm.com e.sid = request.sid; 41110037SARM gem5 Developers e.ssid = request.ssid; 41212110SRekai.GonzalezAlberquilla@arm.com e.vaMask = tr.addrMask; 41312110SRekai.GonzalezAlberquilla@arm.com e.va = request.addr & e.vaMask; 41412110SRekai.GonzalezAlberquilla@arm.com e.pa = tr.addr & e.vaMask; 41512110SRekai.GonzalezAlberquilla@arm.com e.permissions = tr.writable; 41612110SRekai.GonzalezAlberquilla@arm.com e.asid = context.asid; 41712110SRekai.GonzalezAlberquilla@arm.com e.vmid = context.vmid; 41812110SRekai.GonzalezAlberquilla@arm.com 41912110SRekai.GonzalezAlberquilla@arm.com doSemaphoreDown(yield, ifc.microTLBSem); 42012110SRekai.GonzalezAlberquilla@arm.com 42112110SRekai.GonzalezAlberquilla@arm.com DPRINTF(SMMUv3, 42210037SARM gem5 Developers "micro TLB upd vaddr=%#x amask=%#x paddr=%#x sid=%#x ssid=%#x\n", 42312110SRekai.GonzalezAlberquilla@arm.com e.va, e.vaMask, e.pa, e.sid, e.ssid); 42412110SRekai.GonzalezAlberquilla@arm.com 42512110SRekai.GonzalezAlberquilla@arm.com ifc.microTLB->store(e, SMMUTLB::ALLOC_ANY_WAY); 42612110SRekai.GonzalezAlberquilla@arm.com 42712110SRekai.GonzalezAlberquilla@arm.com doSemaphoreUp(ifc.microTLBSem); 42812110SRekai.GonzalezAlberquilla@arm.com} 42912110SRekai.GonzalezAlberquilla@arm.com 43012110SRekai.GonzalezAlberquilla@arm.comvoid 43112110SRekai.GonzalezAlberquilla@arm.comSMMUTranslationProcess::ifcTLBUpdate(Yield &yield, 43212110SRekai.GonzalezAlberquilla@arm.com const TranslResult &tr) 43310037SARM gem5 Developers{ 43412110SRekai.GonzalezAlberquilla@arm.com assert(tr.fault == FAULT_NONE); 43512110SRekai.GonzalezAlberquilla@arm.com 43612110SRekai.GonzalezAlberquilla@arm.com if (!ifc.mainTLBEnable) 43712110SRekai.GonzalezAlberquilla@arm.com return; 43812110SRekai.GonzalezAlberquilla@arm.com 43912110SRekai.GonzalezAlberquilla@arm.com SMMUTLB::Entry e; 44012110SRekai.GonzalezAlberquilla@arm.com e.valid = true; 44112110SRekai.GonzalezAlberquilla@arm.com e.prefetched = request.isPrefetch; 44212110SRekai.GonzalezAlberquilla@arm.com e.sid = request.sid; 44312110SRekai.GonzalezAlberquilla@arm.com e.ssid = request.ssid; 44410037SARM gem5 Developers e.vaMask = tr.addrMask; 44512110SRekai.GonzalezAlberquilla@arm.com e.va = request.addr & e.vaMask; 44612110SRekai.GonzalezAlberquilla@arm.com e.pa = tr.addr & e.vaMask; 44712110SRekai.GonzalezAlberquilla@arm.com e.permissions = tr.writable; 44812110SRekai.GonzalezAlberquilla@arm.com e.asid = context.asid; 44912110SRekai.GonzalezAlberquilla@arm.com e.vmid = context.vmid; 45012110SRekai.GonzalezAlberquilla@arm.com 45112110SRekai.GonzalezAlberquilla@arm.com SMMUTLB::AllocPolicy alloc = SMMUTLB::ALLOC_ANY_WAY; 45212110SRekai.GonzalezAlberquilla@arm.com if (ifc.prefetchEnable && ifc.prefetchReserveLastWay) 45312110SRekai.GonzalezAlberquilla@arm.com alloc = request.isPrefetch ? 45412110SRekai.GonzalezAlberquilla@arm.com SMMUTLB::ALLOC_LAST_WAY : SMMUTLB::ALLOC_ANY_BUT_LAST_WAY; 45510037SARM gem5 Developers 45612110SRekai.GonzalezAlberquilla@arm.com doSemaphoreDown(yield, ifc.mainTLBSem); 45712110SRekai.GonzalezAlberquilla@arm.com 45812110SRekai.GonzalezAlberquilla@arm.com DPRINTF(SMMUv3, 45912110SRekai.GonzalezAlberquilla@arm.com "SLAVE Interface upd vaddr=%#x amask=%#x paddr=%#x sid=%#x " 46012110SRekai.GonzalezAlberquilla@arm.com "ssid=%#x\n", e.va, e.vaMask, e.pa, e.sid, e.ssid); 46112110SRekai.GonzalezAlberquilla@arm.com 46212110SRekai.GonzalezAlberquilla@arm.com ifc.mainTLB->store(e, alloc); 46312110SRekai.GonzalezAlberquilla@arm.com 46412110SRekai.GonzalezAlberquilla@arm.com doSemaphoreUp(ifc.mainTLBSem); 46512110SRekai.GonzalezAlberquilla@arm.com} 46610037SARM gem5 Developers 46712110SRekai.GonzalezAlberquilla@arm.comvoid 46812110SRekai.GonzalezAlberquilla@arm.comSMMUTranslationProcess::smmuTLBUpdate(Yield &yield, 46912110SRekai.GonzalezAlberquilla@arm.com const TranslResult &tr) 47012110SRekai.GonzalezAlberquilla@arm.com{ 47112110SRekai.GonzalezAlberquilla@arm.com assert(tr.fault == FAULT_NONE); 47212110SRekai.GonzalezAlberquilla@arm.com 47312110SRekai.GonzalezAlberquilla@arm.com if (!smmu.tlbEnable) 47412110SRekai.GonzalezAlberquilla@arm.com return; 47512110SRekai.GonzalezAlberquilla@arm.com 47612110SRekai.GonzalezAlberquilla@arm.com ARMArchTLB::Entry e; 47712110SRekai.GonzalezAlberquilla@arm.com e.valid = true; 47812110SRekai.GonzalezAlberquilla@arm.com e.vaMask = tr.addrMask; 47912110SRekai.GonzalezAlberquilla@arm.com e.va = request.addr & e.vaMask; 48012110SRekai.GonzalezAlberquilla@arm.com e.asid = context.asid; 48112110SRekai.GonzalezAlberquilla@arm.com e.vmid = context.vmid; 48212110SRekai.GonzalezAlberquilla@arm.com e.pa = tr.addr & e.vaMask; 48312110SRekai.GonzalezAlberquilla@arm.com e.permissions = tr.writable; 48412110SRekai.GonzalezAlberquilla@arm.com 48512110SRekai.GonzalezAlberquilla@arm.com doSemaphoreDown(yield, smmu.tlbSem); 48612110SRekai.GonzalezAlberquilla@arm.com 48712110SRekai.GonzalezAlberquilla@arm.com DPRINTF(SMMUv3, 48812110SRekai.GonzalezAlberquilla@arm.com "SMMU TLB upd vaddr=%#x amask=%#x paddr=%#x asid=%#x vmid=%#x\n", 48912110SRekai.GonzalezAlberquilla@arm.com e.va, e.vaMask, e.pa, e.asid, e.vmid); 49012110SRekai.GonzalezAlberquilla@arm.com 49112110SRekai.GonzalezAlberquilla@arm.com smmu.tlb.store(e); 49212110SRekai.GonzalezAlberquilla@arm.com 49312110SRekai.GonzalezAlberquilla@arm.com doSemaphoreUp(smmu.tlbSem); 49412110SRekai.GonzalezAlberquilla@arm.com} 49512110SRekai.GonzalezAlberquilla@arm.com 49612110SRekai.GonzalezAlberquilla@arm.combool 49712110SRekai.GonzalezAlberquilla@arm.comSMMUTranslationProcess::configCacheLookup(Yield &yield, TranslContext &tc) 49812110SRekai.GonzalezAlberquilla@arm.com{ 49912110SRekai.GonzalezAlberquilla@arm.com if (!smmu.configCacheEnable) 50012110SRekai.GonzalezAlberquilla@arm.com return false; 50112110SRekai.GonzalezAlberquilla@arm.com 50212110SRekai.GonzalezAlberquilla@arm.com doSemaphoreDown(yield, smmu.configSem); 50312110SRekai.GonzalezAlberquilla@arm.com doDelay(yield, smmu.configLat); 50412110SRekai.GonzalezAlberquilla@arm.com const ConfigCache::Entry *e = 50512110SRekai.GonzalezAlberquilla@arm.com smmu.configCache.lookup(request.sid, request.ssid); 50612110SRekai.GonzalezAlberquilla@arm.com doSemaphoreUp(smmu.configSem); 50712110SRekai.GonzalezAlberquilla@arm.com 50812110SRekai.GonzalezAlberquilla@arm.com if (!e) { 50912110SRekai.GonzalezAlberquilla@arm.com DPRINTF(SMMUv3, "Config miss sid=%#x ssid=%#x\n", 51012110SRekai.GonzalezAlberquilla@arm.com request.sid, request.ssid); 51112110SRekai.GonzalezAlberquilla@arm.com 51212110SRekai.GonzalezAlberquilla@arm.com return false; 51312110SRekai.GonzalezAlberquilla@arm.com } 51412110SRekai.GonzalezAlberquilla@arm.com 51512110SRekai.GonzalezAlberquilla@arm.com DPRINTF(SMMUv3, "Config hit sid=%#x ssid=%#x ttb=%#08x asid=%#x\n", 51612110SRekai.GonzalezAlberquilla@arm.com request.sid, request.ssid, e->ttb0, e->asid); 51712110SRekai.GonzalezAlberquilla@arm.com 51812110SRekai.GonzalezAlberquilla@arm.com tc.stage1Enable = e->stage1_en; 51912110SRekai.GonzalezAlberquilla@arm.com tc.stage2Enable = e->stage2_en; 52012110SRekai.GonzalezAlberquilla@arm.com 52112110SRekai.GonzalezAlberquilla@arm.com tc.ttb0 = e->ttb0; 52212110SRekai.GonzalezAlberquilla@arm.com tc.ttb1 = e->ttb1; 52312110SRekai.GonzalezAlberquilla@arm.com tc.asid = e->asid; 52412110SRekai.GonzalezAlberquilla@arm.com tc.httb = e->httb; 52512110SRekai.GonzalezAlberquilla@arm.com tc.vmid = e->vmid; 52612110SRekai.GonzalezAlberquilla@arm.com 52712110SRekai.GonzalezAlberquilla@arm.com tc.stage1TranslGranule = e->stage1_tg; 52812110SRekai.GonzalezAlberquilla@arm.com tc.stage2TranslGranule = e->stage2_tg; 52912110SRekai.GonzalezAlberquilla@arm.com 53012110SRekai.GonzalezAlberquilla@arm.com return true; 53112110SRekai.GonzalezAlberquilla@arm.com} 53210037SARM gem5 Developers 53314106Sjavier.setoain@arm.comvoid 53414106Sjavier.setoain@arm.comSMMUTranslationProcess::configCacheUpdate(Yield &yield, 53514106Sjavier.setoain@arm.com const TranslContext &tc) 53614106Sjavier.setoain@arm.com{ 53714106Sjavier.setoain@arm.com if (!smmu.configCacheEnable) 53814106Sjavier.setoain@arm.com return; 53914106Sjavier.setoain@arm.com 54014106Sjavier.setoain@arm.com ConfigCache::Entry e; 54114106Sjavier.setoain@arm.com e.valid = true; 54214106Sjavier.setoain@arm.com e.sid = request.sid; 54314106Sjavier.setoain@arm.com e.ssid = request.ssid; 54414106Sjavier.setoain@arm.com e.stage1_en = tc.stage1Enable; 54514106Sjavier.setoain@arm.com e.stage2_en = tc.stage2Enable; 54614106Sjavier.setoain@arm.com e.ttb0 = tc.ttb0; 54714106Sjavier.setoain@arm.com e.ttb1 = tc.ttb1; 54814106Sjavier.setoain@arm.com e.asid = tc.asid; 54914106Sjavier.setoain@arm.com e.httb = tc.httb; 55014106Sjavier.setoain@arm.com e.vmid = tc.vmid; 55114106Sjavier.setoain@arm.com e.stage1_tg = tc.stage1TranslGranule; 55214106Sjavier.setoain@arm.com e.stage2_tg = tc.stage2TranslGranule; 55314106Sjavier.setoain@arm.com 55414106Sjavier.setoain@arm.com doSemaphoreDown(yield, smmu.configSem); 55514106Sjavier.setoain@arm.com 55614106Sjavier.setoain@arm.com DPRINTF(SMMUv3, "Config upd sid=%#x ssid=%#x\n", e.sid, e.ssid); 55714106Sjavier.setoain@arm.com 55814106Sjavier.setoain@arm.com smmu.configCache.store(e); 55914106Sjavier.setoain@arm.com 56014106Sjavier.setoain@arm.com doSemaphoreUp(smmu.configSem); 56114106Sjavier.setoain@arm.com} 56214106Sjavier.setoain@arm.com 56314106Sjavier.setoain@arm.combool 56414106Sjavier.setoain@arm.comSMMUTranslationProcess::findConfig(Yield &yield, 56514106Sjavier.setoain@arm.com TranslContext &tc, 56614106Sjavier.setoain@arm.com TranslResult &tr) 56714106Sjavier.setoain@arm.com{ 56814106Sjavier.setoain@arm.com tc.stage1Enable = false; 56914106Sjavier.setoain@arm.com tc.stage2Enable = false; 57014106Sjavier.setoain@arm.com 57114106Sjavier.setoain@arm.com StreamTableEntry ste; 57214106Sjavier.setoain@arm.com doReadSTE(yield, ste, request.sid); 57314106Sjavier.setoain@arm.com 57414106Sjavier.setoain@arm.com switch (ste.dw0.config) { 57514106Sjavier.setoain@arm.com case STE_CONFIG_BYPASS: 57614106Sjavier.setoain@arm.com break; 57714106Sjavier.setoain@arm.com 57813759Sgiacomo.gabrielli@arm.com case STE_CONFIG_STAGE1_ONLY: 57913759Sgiacomo.gabrielli@arm.com tc.stage1Enable = true; 58013759Sgiacomo.gabrielli@arm.com break; 58113759Sgiacomo.gabrielli@arm.com 58213759Sgiacomo.gabrielli@arm.com case STE_CONFIG_STAGE2_ONLY: 58313759Sgiacomo.gabrielli@arm.com tc.stage2Enable = true; 58413759Sgiacomo.gabrielli@arm.com break; 58513759Sgiacomo.gabrielli@arm.com 58613759Sgiacomo.gabrielli@arm.com case STE_CONFIG_STAGE1_AND_2: 58713759Sgiacomo.gabrielli@arm.com tc.stage1Enable = true; 58813759Sgiacomo.gabrielli@arm.com tc.stage2Enable = true; 58914028Sgiacomo.gabrielli@arm.com break; 59014028Sgiacomo.gabrielli@arm.com 59114028Sgiacomo.gabrielli@arm.com default: 59214028Sgiacomo.gabrielli@arm.com panic("Bad or unimplemented STE config %d\n", 59314028Sgiacomo.gabrielli@arm.com ste.dw0.config); 59414028Sgiacomo.gabrielli@arm.com } 59514028Sgiacomo.gabrielli@arm.com 59614028Sgiacomo.gabrielli@arm.com 59714028Sgiacomo.gabrielli@arm.com // Establish stage 2 context first since 59814028Sgiacomo.gabrielli@arm.com // Context Descriptors can be in IPA space. 59914028Sgiacomo.gabrielli@arm.com if (tc.stage2Enable) { 60014028Sgiacomo.gabrielli@arm.com tc.httb = ste.dw3.s2ttb << STE_S2TTB_SHIFT; 60114028Sgiacomo.gabrielli@arm.com tc.vmid = ste.dw2.s2vmid; 60214028Sgiacomo.gabrielli@arm.com tc.stage2TranslGranule = ste.dw2.s2tg; 60314028Sgiacomo.gabrielli@arm.com } else { 60414028Sgiacomo.gabrielli@arm.com tc.httb = 0xdeadbeef; 60514028Sgiacomo.gabrielli@arm.com tc.vmid = 0; 60614028Sgiacomo.gabrielli@arm.com tc.stage2TranslGranule = TRANS_GRANULE_INVALID; 60714028Sgiacomo.gabrielli@arm.com } 60814028Sgiacomo.gabrielli@arm.com 60914028Sgiacomo.gabrielli@arm.com 61014028Sgiacomo.gabrielli@arm.com // Now fetch stage 1 config. 61114028Sgiacomo.gabrielli@arm.com if (context.stage1Enable) { 61214028Sgiacomo.gabrielli@arm.com ContextDescriptor cd; 61314028Sgiacomo.gabrielli@arm.com doReadCD(yield, cd, ste, request.sid, request.ssid); 61414028Sgiacomo.gabrielli@arm.com 61514028Sgiacomo.gabrielli@arm.com tc.ttb0 = cd.dw1.ttb0 << CD_TTB_SHIFT; 61614028Sgiacomo.gabrielli@arm.com tc.ttb1 = cd.dw2.ttb1 << CD_TTB_SHIFT; 61714028Sgiacomo.gabrielli@arm.com tc.asid = cd.dw0.asid; 61814028Sgiacomo.gabrielli@arm.com tc.stage1TranslGranule = cd.dw0.tg0; 61914028Sgiacomo.gabrielli@arm.com } else { 62014028Sgiacomo.gabrielli@arm.com tc.ttb0 = 0xcafebabe; 62114028Sgiacomo.gabrielli@arm.com tc.ttb1 = 0xcafed00d; 62213759Sgiacomo.gabrielli@arm.com tc.asid = 0; 62313759Sgiacomo.gabrielli@arm.com tc.stage1TranslGranule = TRANS_GRANULE_INVALID; 62413759Sgiacomo.gabrielli@arm.com } 62513759Sgiacomo.gabrielli@arm.com 62613759Sgiacomo.gabrielli@arm.com return true; 62713759Sgiacomo.gabrielli@arm.com} 62813759Sgiacomo.gabrielli@arm.com 62914091Sgabor.dozsa@arm.comvoid 63014091Sgabor.dozsa@arm.comSMMUTranslationProcess::walkCacheLookup( 63113759Sgiacomo.gabrielli@arm.com Yield &yield, 6327797Sgblack@eecs.umich.edu const WalkCache::Entry *&walkEntry, 6337797Sgblack@eecs.umich.edu Addr addr, uint16_t asid, uint16_t vmid, 6347797Sgblack@eecs.umich.edu unsigned stage, unsigned level) 63510037SARM gem5 Developers{ 63610037SARM gem5 Developers const char *indent = stage==2 ? " " : ""; 63710037SARM gem5 Developers (void) indent; // this is only used in DPRINTFs 63810037SARM gem5 Developers 6397797Sgblack@eecs.umich.edu const PageTableOps *pt_ops = 6407797Sgblack@eecs.umich.edu stage == 1 ? 6417797Sgblack@eecs.umich.edu smmu.getPageTableOps(context.stage1TranslGranule) : 6428302SAli.Saidi@ARM.com smmu.getPageTableOps(context.stage2TranslGranule); 6437797Sgblack@eecs.umich.edu 6447797Sgblack@eecs.umich.edu unsigned walkCacheLevels = 6457797Sgblack@eecs.umich.edu smmu.walkCacheEnable ? 6467797Sgblack@eecs.umich.edu (stage == 1 ? smmu.walkCacheS1Levels : smmu.walkCacheS2Levels) : 6477797Sgblack@eecs.umich.edu 0; 6487797Sgblack@eecs.umich.edu 6497797Sgblack@eecs.umich.edu if ((1 << level) & walkCacheLevels) { 65010037SARM gem5 Developers doSemaphoreDown(yield, smmu.walkSem); 6517797Sgblack@eecs.umich.edu doDelay(yield, smmu.walkLat); 65210037SARM gem5 Developers 65310037SARM gem5 Developers walkEntry = smmu.walkCache.lookup(addr, pt_ops->walkMask(level), 65410037SARM gem5 Developers asid, vmid, stage, level); 65510037SARM gem5 Developers 65610037SARM gem5 Developers if (walkEntry) { 65710037SARM gem5 Developers DPRINTF(SMMUv3, "%sWalkCache hit va=%#x asid=%#x vmid=%#x " 65810037SARM gem5 Developers "base=%#x (S%d, L%d)\n", 65910037SARM gem5 Developers indent, addr, asid, vmid, walkEntry->pa, stage, level); 66010037SARM gem5 Developers } else { 66110037SARM gem5 Developers DPRINTF(SMMUv3, "%sWalkCache miss va=%#x asid=%#x vmid=%#x " 66210037SARM gem5 Developers "(S%d, L%d)\n", 6637797Sgblack@eecs.umich.edu indent, addr, asid, vmid, stage, level); 6647797Sgblack@eecs.umich.edu } 6658209SAli.Saidi@ARM.com 66610037SARM gem5 Developers doSemaphoreUp(smmu.walkSem); 6676019Shines@cs.fsu.edu } 6686308Sgblack@eecs.umich.edu} 6698139SMatt.Horsnell@arm.com 67010037SARM gem5 Developersvoid 67110037SARM gem5 DevelopersSMMUTranslationProcess::walkCacheUpdate(Yield &yield, Addr va, 6727797Sgblack@eecs.umich.edu Addr vaMask, Addr pa, 67313603Sgiacomo.travaglini@arm.com unsigned stage, unsigned level, 6748139SMatt.Horsnell@arm.com bool leaf, uint8_t permissions) 67510037SARM gem5 Developers{ 6768139SMatt.Horsnell@arm.com unsigned walkCacheLevels = 67710037SARM gem5 Developers stage == 1 ? smmu.walkCacheS1Levels : smmu.walkCacheS2Levels; 6786308Sgblack@eecs.umich.edu 6796019Shines@cs.fsu.edu if (smmu.walkCacheEnable && ((1<<level) & walkCacheLevels)) { 6807797Sgblack@eecs.umich.edu WalkCache::Entry e; 6816019Shines@cs.fsu.edu e.valid = true; 6827797Sgblack@eecs.umich.edu e.va = va; 68310037SARM gem5 Developers e.vaMask = vaMask; 6847797Sgblack@eecs.umich.edu e.asid = stage==1 ? context.asid : 0; 6857797Sgblack@eecs.umich.edu e.vmid = context.vmid; 6867797Sgblack@eecs.umich.edu e.stage = stage; 6877797Sgblack@eecs.umich.edu e.level = level; 6887797Sgblack@eecs.umich.edu e.leaf = leaf; 6897797Sgblack@eecs.umich.edu e.pa = pa; 6907797Sgblack@eecs.umich.edu e.permissions = permissions; 6918205SAli.Saidi@ARM.com 6928205SAli.Saidi@ARM.com doSemaphoreDown(yield, smmu.walkSem); 69311514Sandreas.sandberg@arm.com 6947797Sgblack@eecs.umich.edu DPRINTF(SMMUv3, "%sWalkCache upd va=%#x mask=%#x asid=%#x vmid=%#x " 6957797Sgblack@eecs.umich.edu "tpa=%#x leaf=%s (S%d, L%d)\n", 6967797Sgblack@eecs.umich.edu e.stage==2 ? " " : "", 6977797Sgblack@eecs.umich.edu e.va, e.vaMask, e.asid, e.vmid, 6987797Sgblack@eecs.umich.edu e.pa, e.leaf, e.stage, e.level); 6997797Sgblack@eecs.umich.edu 7007797Sgblack@eecs.umich.edu smmu.walkCache.store(e); 7017797Sgblack@eecs.umich.edu 7027797Sgblack@eecs.umich.edu doSemaphoreUp(smmu.walkSem); 7036019Shines@cs.fsu.edu } 704} 705 706/* 707 * Please note: 708 * This does not deal with the case where stage 1 page size 709 * is larger than stage 2 page size. 710 */ 711SMMUTranslationProcess::TranslResult 712SMMUTranslationProcess::walkStage1And2(Yield &yield, Addr addr, 713 const PageTableOps *pt_ops, 714 unsigned level, Addr walkPtr) 715{ 716 PageTableOps::pte_t pte = 0; 717 718 doSemaphoreDown(yield, smmu.cycleSem); 719 doDelay(yield, Cycles(1)); 720 doSemaphoreUp(smmu.cycleSem); 721 722 for (; level <= pt_ops->lastLevel(); level++) { 723 Addr pte_addr = walkPtr + pt_ops->index(addr, level); 724 725 DPRINTF(SMMUv3, "Fetching S1 L%d PTE from pa=%#08x\n", 726 level, pte_addr); 727 728 doReadPTE(yield, addr, pte_addr, &pte, 1, level); 729 730 DPRINTF(SMMUv3, "Got S1 L%d PTE=%#x from pa=%#08x\n", 731 level, pte, pte_addr); 732 733 doSemaphoreDown(yield, smmu.cycleSem); 734 doDelay(yield, Cycles(1)); 735 doSemaphoreUp(smmu.cycleSem); 736 737 bool valid = pt_ops->isValid(pte, level); 738 bool leaf = pt_ops->isLeaf(pte, level); 739 740 if (!valid) { 741 DPRINTF(SMMUv3, "S1 PTE not valid - fault\n"); 742 743 TranslResult tr; 744 tr.fault = FAULT_TRANSLATION; 745 return tr; 746 } 747 748 if (valid && leaf && request.isWrite && 749 !pt_ops->isWritable(pte, level, false)) 750 { 751 DPRINTF(SMMUv3, "S1 page not writable - fault\n"); 752 753 TranslResult tr; 754 tr.fault = FAULT_PERMISSION; 755 return tr; 756 } 757 758 walkPtr = pt_ops->nextLevelPointer(pte, level); 759 760 if (leaf) 761 break; 762 763 if (context.stage2Enable) { 764 TranslResult s2tr = translateStage2(yield, walkPtr, false); 765 if (s2tr.fault != FAULT_NONE) 766 return s2tr; 767 768 walkPtr = s2tr.addr; 769 } 770 771 walkCacheUpdate(yield, addr, pt_ops->walkMask(level), walkPtr, 772 1, level, leaf, 0); 773 } 774 775 TranslResult tr; 776 tr.fault = FAULT_NONE; 777 tr.addrMask = pt_ops->pageMask(pte, level); 778 tr.addr = walkPtr + (addr & ~tr.addrMask); 779 tr.writable = pt_ops->isWritable(pte, level, false); 780 781 if (context.stage2Enable) { 782 TranslResult s2tr = translateStage2(yield, tr.addr, true); 783 if (s2tr.fault != FAULT_NONE) 784 return s2tr; 785 786 tr = combineTranslations(tr, s2tr); 787 } 788 789 walkCacheUpdate(yield, addr, tr.addrMask, tr.addr, 790 1, level, true, tr.writable); 791 792 return tr; 793} 794 795SMMUTranslationProcess::TranslResult 796SMMUTranslationProcess::walkStage2(Yield &yield, Addr addr, bool final_tr, 797 const PageTableOps *pt_ops, 798 unsigned level, Addr walkPtr) 799{ 800 PageTableOps::pte_t pte; 801 802 doSemaphoreDown(yield, smmu.cycleSem); 803 doDelay(yield, Cycles(1)); 804 doSemaphoreUp(smmu.cycleSem); 805 806 for (; level <= pt_ops->lastLevel(); level++) { 807 Addr pte_addr = walkPtr + pt_ops->index(addr, level); 808 809 DPRINTF(SMMUv3, " Fetching S2 L%d PTE from pa=%#08x\n", 810 level, pte_addr); 811 812 doReadPTE(yield, addr, pte_addr, &pte, 2, level); 813 814 DPRINTF(SMMUv3, " Got S2 L%d PTE=%#x from pa=%#08x\n", 815 level, pte, pte_addr); 816 817 doSemaphoreDown(yield, smmu.cycleSem); 818 doDelay(yield, Cycles(1)); 819 doSemaphoreUp(smmu.cycleSem); 820 821 bool valid = pt_ops->isValid(pte, level); 822 bool leaf = pt_ops->isLeaf(pte, level); 823 824 if (!valid) { 825 DPRINTF(SMMUv3, " S2 PTE not valid - fault\n"); 826 827 TranslResult tr; 828 tr.fault = FAULT_TRANSLATION; 829 return tr; 830 } 831 832 if (valid && leaf && request.isWrite && 833 !pt_ops->isWritable(pte, level, true)) 834 { 835 DPRINTF(SMMUv3, " S2 PTE not writable = fault\n"); 836 837 TranslResult tr; 838 tr.fault = FAULT_PERMISSION; 839 return tr; 840 } 841 842 walkPtr = pt_ops->nextLevelPointer(pte, level); 843 844 if (final_tr || smmu.walkCacheNonfinalEnable) 845 walkCacheUpdate(yield, addr, pt_ops->walkMask(level), walkPtr, 846 2, level, leaf, 847 leaf ? pt_ops->isWritable(pte, level, true) : 0); 848 if (leaf) 849 break; 850 } 851 852 TranslResult tr; 853 tr.fault = FAULT_NONE; 854 tr.addrMask = pt_ops->pageMask(pte, level); 855 tr.addr = walkPtr + (addr & ~tr.addrMask); 856 tr.writable = pt_ops->isWritable(pte, level, true); 857 858 return tr; 859} 860 861SMMUTranslationProcess::TranslResult 862SMMUTranslationProcess::translateStage1And2(Yield &yield, Addr addr) 863{ 864 const PageTableOps *pt_ops = 865 smmu.getPageTableOps(context.stage1TranslGranule); 866 867 const WalkCache::Entry *walk_ep = NULL; 868 unsigned level; 869 870 // Level here is actually (level+1) so we can count down 871 // to 0 using unsigned int. 872 for (level = pt_ops->lastLevel() + 1; 873 level > pt_ops->firstLevel(); 874 level--) 875 { 876 walkCacheLookup(yield, walk_ep, addr, 877 context.asid, context.vmid, 1, level-1); 878 879 if (walk_ep) 880 break; 881 } 882 883 // Correct level (see above). 884 level -= 1; 885 886 TranslResult tr; 887 if (walk_ep) { 888 if (walk_ep->leaf) { 889 tr.fault = FAULT_NONE; 890 tr.addr = walk_ep->pa + (addr & ~walk_ep->vaMask); 891 tr.addrMask = walk_ep->vaMask; 892 tr.writable = walk_ep->permissions; 893 } else { 894 tr = walkStage1And2(yield, addr, pt_ops, level+1, walk_ep->pa); 895 } 896 } else { 897 Addr table_addr = context.ttb0; 898 if (context.stage2Enable) { 899 TranslResult s2tr = translateStage2(yield, table_addr, false); 900 if (s2tr.fault != FAULT_NONE) 901 return s2tr; 902 903 table_addr = s2tr.addr; 904 } 905 906 tr = walkStage1And2(yield, addr, pt_ops, pt_ops->firstLevel(), 907 table_addr); 908 } 909 910 if (tr.fault == FAULT_NONE) 911 DPRINTF(SMMUv3, "Translated vaddr %#x to paddr %#x\n", addr, tr.addr); 912 913 return tr; 914} 915 916SMMUTranslationProcess::TranslResult 917SMMUTranslationProcess::translateStage2(Yield &yield, Addr addr, bool final_tr) 918{ 919 const PageTableOps *pt_ops = 920 smmu.getPageTableOps(context.stage2TranslGranule); 921 922 const IPACache::Entry *ipa_ep = NULL; 923 if (smmu.ipaCacheEnable) { 924 doSemaphoreDown(yield, smmu.ipaSem); 925 doDelay(yield, smmu.ipaLat); 926 ipa_ep = smmu.ipaCache.lookup(addr, context.vmid); 927 doSemaphoreUp(smmu.ipaSem); 928 } 929 930 if (ipa_ep) { 931 TranslResult tr; 932 tr.fault = FAULT_NONE; 933 tr.addr = ipa_ep->pa + (addr & ~ipa_ep->ipaMask); 934 tr.addrMask = ipa_ep->ipaMask; 935 tr.writable = ipa_ep->permissions; 936 937 DPRINTF(SMMUv3, " IPACache hit ipa=%#x vmid=%#x pa=%#x\n", 938 addr, context.vmid, tr.addr); 939 940 return tr; 941 } else if (smmu.ipaCacheEnable) { 942 DPRINTF(SMMUv3, " IPACache miss ipa=%#x vmid=%#x\n", 943 addr, context.vmid); 944 } 945 946 const WalkCache::Entry *walk_ep = NULL; 947 unsigned level = pt_ops->firstLevel(); 948 949 if (final_tr || smmu.walkCacheNonfinalEnable) { 950 // Level here is actually (level+1) so we can count down 951 // to 0 using unsigned int. 952 for (level = pt_ops->lastLevel() + 1; 953 level > pt_ops->firstLevel(); 954 level--) 955 { 956 walkCacheLookup(yield, walk_ep, addr, 957 0, context.vmid, 2, level-1); 958 959 if (walk_ep) 960 break; 961 } 962 963 // Correct level (see above). 964 level -= 1; 965 } 966 967 TranslResult tr; 968 if (walk_ep) { 969 if (walk_ep->leaf) { 970 tr.fault = FAULT_NONE; 971 tr.addr = walk_ep->pa + (addr & ~walk_ep->vaMask); 972 tr.addrMask = walk_ep->vaMask; 973 tr.writable = walk_ep->permissions; 974 } else { 975 tr = walkStage2(yield, addr, final_tr, pt_ops, 976 level + 1, walk_ep->pa); 977 } 978 } else { 979 tr = walkStage2(yield, addr, final_tr, pt_ops, pt_ops->firstLevel(), 980 context.httb); 981 } 982 983 if (tr.fault == FAULT_NONE) 984 DPRINTF(SMMUv3, " Translated %saddr %#x to paddr %#x\n", 985 context.stage1Enable ? "ip" : "v", addr, tr.addr); 986 987 if (smmu.ipaCacheEnable) { 988 IPACache::Entry e; 989 e.valid = true; 990 e.ipaMask = tr.addrMask; 991 e.ipa = addr & e.ipaMask; 992 e.pa = tr.addr & tr.addrMask; 993 e.permissions = tr.writable; 994 e.vmid = context.vmid; 995 996 doSemaphoreDown(yield, smmu.ipaSem); 997 smmu.ipaCache.store(e); 998 doSemaphoreUp(smmu.ipaSem); 999 } 1000 1001 return tr; 1002} 1003 1004SMMUTranslationProcess::TranslResult 1005SMMUTranslationProcess::combineTranslations(const TranslResult &s1tr, 1006 const TranslResult &s2tr) const 1007{ 1008 if (s2tr.fault != FAULT_NONE) 1009 return s2tr; 1010 1011 assert(s1tr.fault == FAULT_NONE); 1012 1013 TranslResult tr; 1014 tr.fault = FAULT_NONE; 1015 tr.addr = s2tr.addr; 1016 tr.addrMask = s1tr.addrMask | s2tr.addrMask; 1017 tr.writable = s1tr.writable & s2tr.writable; 1018 1019 return tr; 1020} 1021 1022bool 1023SMMUTranslationProcess::hazard4kCheck() 1024{ 1025 Addr addr4k = request.addr & ~0xfffULL; 1026 1027 for (auto it = ifc.duplicateReqs.begin(); 1028 it != ifc.duplicateReqs.end(); 1029 ++it) 1030 { 1031 Addr other4k = (*it)->request.addr & ~0xfffULL; 1032 if (addr4k == other4k) 1033 return true; 1034 } 1035 1036 return false; 1037} 1038 1039void 1040SMMUTranslationProcess::hazard4kRegister() 1041{ 1042 DPRINTF(SMMUv3Hazard, "4kReg: p=%p a4k=%#x\n", 1043 this, request.addr & ~0xfffULL); 1044 1045 ifc.duplicateReqs.push_back(this); 1046} 1047 1048void 1049SMMUTranslationProcess::hazard4kHold(Yield &yield) 1050{ 1051 Addr addr4k = request.addr & ~0xfffULL; 1052 1053 bool found_hazard; 1054 1055 do { 1056 found_hazard = false; 1057 1058 for (auto it = ifc.duplicateReqs.begin(); 1059 it!=ifc.duplicateReqs.end() && *it!=this; 1060 ++it) 1061 { 1062 Addr other4k = (*it)->request.addr & ~0xfffULL; 1063 1064 DPRINTF(SMMUv3Hazard, "4kHold: p=%p a4k=%#x Q: p=%p a4k=%#x\n", 1065 this, addr4k, *it, other4k); 1066 1067 if (addr4k == other4k) { 1068 DPRINTF(SMMUv3Hazard, 1069 "4kHold: p=%p a4k=%#x WAIT on p=%p a4k=%#x\n", 1070 this, addr4k, *it, other4k); 1071 1072 doWaitForSignal(yield, ifc.duplicateReqRemoved); 1073 1074 DPRINTF(SMMUv3Hazard, "4kHold: p=%p a4k=%#x RESUME\n", 1075 this, addr4k); 1076 1077 // This is to avoid checking *it!=this after doWaitForSignal() 1078 // since it could have been deleted. 1079 found_hazard = true; 1080 break; 1081 } 1082 } 1083 } while (found_hazard); 1084} 1085 1086void 1087SMMUTranslationProcess::hazard4kRelease() 1088{ 1089 DPRINTF(SMMUv3Hazard, "4kRel: p=%p a4k=%#x\n", 1090 this, request.addr & ~0xfffULL); 1091 1092 std::list<SMMUTranslationProcess *>::iterator it; 1093 1094 for (it = ifc.duplicateReqs.begin(); it != ifc.duplicateReqs.end(); ++it) 1095 if (*it == this) 1096 break; 1097 1098 if (it == ifc.duplicateReqs.end()) 1099 panic("hazard4kRelease: request not found"); 1100 1101 ifc.duplicateReqs.erase(it); 1102 1103 doBroadcastSignal(ifc.duplicateReqRemoved); 1104} 1105 1106void 1107SMMUTranslationProcess::hazardIdRegister() 1108{ 1109 auto orderId = AMBA::orderId(request.pkt); 1110 1111 DPRINTF(SMMUv3Hazard, "IdReg: p=%p oid=%d\n", this, orderId); 1112 1113 assert(orderId < SMMU_MAX_TRANS_ID); 1114 1115 std::list<SMMUTranslationProcess *> &depReqs = 1116 request.isWrite ? 1117 ifc.dependentWrites[orderId] : ifc.dependentReads[orderId]; 1118 depReqs.push_back(this); 1119} 1120 1121void 1122SMMUTranslationProcess::hazardIdHold(Yield &yield) 1123{ 1124 auto orderId = AMBA::orderId(request.pkt); 1125 1126 DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d\n", this, orderId); 1127 1128 std::list<SMMUTranslationProcess *> &depReqs = 1129 request.isWrite ? 1130 ifc.dependentWrites[orderId] : ifc.dependentReads[orderId]; 1131 std::list<SMMUTranslationProcess *>::iterator it; 1132 1133 bool found_hazard; 1134 1135 do { 1136 found_hazard = false; 1137 1138 for (auto it = depReqs.begin(); it!=depReqs.end() && *it!=this; ++it) { 1139 DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d Q: %p\n", 1140 this, orderId, *it); 1141 1142 if (AMBA::orderId((*it)->request.pkt) == orderId) { 1143 DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d WAIT on=%p\n", 1144 this, orderId, *it); 1145 1146 doWaitForSignal(yield, ifc.dependentReqRemoved); 1147 1148 DPRINTF(SMMUv3Hazard, "IdHold: p=%p oid=%d RESUME\n", 1149 this, orderId); 1150 1151 // This is to avoid checking *it!=this after doWaitForSignal() 1152 // since it could have been deleted. 1153 found_hazard = true; 1154 break; 1155 } 1156 } 1157 } while (found_hazard); 1158} 1159 1160void 1161SMMUTranslationProcess::hazardIdRelease() 1162{ 1163 auto orderId = AMBA::orderId(request.pkt); 1164 1165 DPRINTF(SMMUv3Hazard, "IdRel: p=%p oid=%d\n", this, orderId); 1166 1167 std::list<SMMUTranslationProcess *> &depReqs = 1168 request.isWrite ? 1169 ifc.dependentWrites[orderId] : ifc.dependentReads[orderId]; 1170 std::list<SMMUTranslationProcess *>::iterator it; 1171 1172 for (it = depReqs.begin(); it != depReqs.end(); ++it) { 1173 if (*it == this) 1174 break; 1175 } 1176 1177 if (it == depReqs.end()) 1178 panic("hazardIdRelease: request not found"); 1179 1180 depReqs.erase(it); 1181 1182 doBroadcastSignal(ifc.dependentReqRemoved); 1183} 1184 1185void 1186SMMUTranslationProcess::issuePrefetch(Addr addr) 1187{ 1188 if (!smmu.system.isTimingMode()) 1189 return; 1190 1191 if (!ifc.prefetchEnable || ifc.xlateSlotsRemaining == 0) 1192 return; 1193 1194 std::string proc_name = csprintf("%sprf", name()); 1195 SMMUTranslationProcess *proc = 1196 new SMMUTranslationProcess(proc_name, smmu, ifc); 1197 1198 proc->beginTransaction( 1199 SMMUTranslRequest::prefetch(addr, request.sid, request.ssid)); 1200 proc->scheduleWakeup(smmu.clockEdge(Cycles(1))); 1201} 1202 1203void 1204SMMUTranslationProcess::completeTransaction(Yield &yield, 1205 const TranslResult &tr) 1206{ 1207 assert(tr.fault == FAULT_NONE); 1208 1209 unsigned numMasterBeats = request.isWrite ? 1210 (request.size + (smmu.masterPortWidth-1)) 1211 / smmu.masterPortWidth : 1212 1; 1213 1214 doSemaphoreDown(yield, smmu.masterPortSem); 1215 doDelay(yield, Cycles(numMasterBeats)); 1216 doSemaphoreUp(smmu.masterPortSem); 1217 1218 1219 smmu.translationTimeDist.sample(curTick() - recvTick); 1220 if (!request.isAtsRequest && request.isWrite) 1221 ifc.wrBufSlotsRemaining += 1222 (request.size + (ifc.portWidth-1)) / ifc.portWidth; 1223 1224 smmu.scheduleSlaveRetries(); 1225 1226 1227 SMMUAction a; 1228 1229 if (request.isAtsRequest) { 1230 a.type = ACTION_SEND_RESP_ATS; 1231 1232 if (smmu.system.isAtomicMode()) { 1233 request.pkt->makeAtomicResponse(); 1234 } else if (smmu.system.isTimingMode()) { 1235 request.pkt->makeTimingResponse(); 1236 } else { 1237 panic("Not in atomic or timing mode"); 1238 } 1239 } else { 1240 a.type = ACTION_SEND_REQ_FINAL; 1241 a.ifc = &ifc; 1242 } 1243 1244 a.pkt = request.pkt; 1245 a.delay = 0; 1246 1247 a.pkt->setAddr(tr.addr); 1248 a.pkt->req->setPaddr(tr.addr); 1249 1250 yield(a); 1251 1252 if (!request.isAtsRequest) { 1253 PacketPtr pkt = yield.get(); 1254 pkt->setAddr(request.addr); 1255 1256 a.type = ACTION_SEND_RESP; 1257 a.pkt = pkt; 1258 a.ifc = &ifc; 1259 a.delay = 0; 1260 yield(a); 1261 } 1262} 1263 1264void 1265SMMUTranslationProcess::completePrefetch(Yield &yield) 1266{ 1267 SMMUAction a; 1268 a.type = ACTION_TERMINATE; 1269 a.pkt = NULL; 1270 a.ifc = &ifc; 1271 a.delay = 0; 1272 yield(a); 1273} 1274 1275void 1276SMMUTranslationProcess::sendEvent(Yield &yield, const SMMUEvent &ev) 1277{ 1278 int sizeMask = mask(smmu.regs.eventq_base & Q_BASE_SIZE_MASK) & 1279 Q_CONS_PROD_MASK; 1280 1281 if (((smmu.regs.eventq_prod+1) & sizeMask) == 1282 (smmu.regs.eventq_cons & sizeMask)) 1283 panic("Event queue full - aborting\n"); 1284 1285 Addr event_addr = 1286 (smmu.regs.eventq_base & Q_BASE_ADDR_MASK) + 1287 (smmu.regs.eventq_prod & sizeMask) * sizeof(ev); 1288 1289 DPRINTF(SMMUv3, "Sending event to addr=%#08x (pos=%d): type=%#x stag=%#x " 1290 "flags=%#x sid=%#x ssid=%#x va=%#08x ipa=%#x\n", 1291 event_addr, smmu.regs.eventq_prod, ev.type, ev.stag, 1292 ev.flags, ev.streamId, ev.substreamId, ev.va, ev.ipa); 1293 1294 // This deliberately resets the overflow field in eventq_prod! 1295 smmu.regs.eventq_prod = (smmu.regs.eventq_prod + 1) & sizeMask; 1296 1297 doWrite(yield, event_addr, &ev, sizeof(ev)); 1298 1299 if (!(smmu.regs.eventq_irq_cfg0 & E_BASE_ENABLE_MASK)) 1300 panic("eventq msi not enabled\n"); 1301 1302 doWrite(yield, smmu.regs.eventq_irq_cfg0 & E_BASE_ADDR_MASK, 1303 &smmu.regs.eventq_irq_cfg1, sizeof(smmu.regs.eventq_irq_cfg1)); 1304} 1305 1306void 1307SMMUTranslationProcess::doReadSTE(Yield &yield, 1308 StreamTableEntry &ste, 1309 uint32_t sid) 1310{ 1311 unsigned max_sid = 1 << (smmu.regs.strtab_base_cfg & ST_CFG_SIZE_MASK); 1312 if (sid >= max_sid) 1313 panic("SID %#x out of range, max=%#x", sid, max_sid); 1314 1315 Addr ste_addr; 1316 1317 if ((smmu.regs.strtab_base_cfg & ST_CFG_FMT_MASK) == ST_CFG_FMT_2LEVEL) { 1318 unsigned split = 1319 (smmu.regs.strtab_base_cfg & ST_CFG_SPLIT_MASK) >> ST_CFG_SPLIT_SHIFT; 1320 1321 if (split!= 7 && split!=8 && split!=16) 1322 panic("Invalid stream table split %d", split); 1323 1324 uint64_t l2_ptr; 1325 uint64_t l2_addr = 1326 (smmu.regs.strtab_base & VMT_BASE_ADDR_MASK) + 1327 bits(sid, 32, split) * sizeof(l2_ptr); 1328 1329 DPRINTF(SMMUv3, "Read L1STE at %#x\n", l2_addr); 1330 1331 doReadConfig(yield, l2_addr, &l2_ptr, sizeof(l2_ptr), sid, 0); 1332 1333 DPRINTF(SMMUv3, "Got L1STE L1 at %#x: 0x%016x\n", l2_addr, l2_ptr); 1334 1335 unsigned span = l2_ptr & ST_L2_SPAN_MASK; 1336 if (span == 0) 1337 panic("Invalid level 1 stream table descriptor"); 1338 1339 unsigned index = bits(sid, split-1, 0); 1340 if (index >= (1 << span)) 1341 panic("StreamID %d out of level 1 descriptor range %d", 1342 sid, 1<<span); 1343 1344 ste_addr = (l2_ptr & ST_L2_ADDR_MASK) + index * sizeof(ste); 1345 1346 smmu.steL1Fetches++; 1347 } else if ((smmu.regs.strtab_base_cfg & ST_CFG_FMT_MASK) == ST_CFG_FMT_LINEAR) { 1348 ste_addr = 1349 (smmu.regs.strtab_base & VMT_BASE_ADDR_MASK) + sid * sizeof(ste); 1350 } else { 1351 panic("Invalid stream table format"); 1352 } 1353 1354 DPRINTF(SMMUv3, "Read STE at %#x\n", ste_addr); 1355 1356 doReadConfig(yield, ste_addr, &ste, sizeof(ste), sid, 0); 1357 1358 DPRINTF(SMMUv3, "Got STE at %#x [0]: 0x%016x\n", ste_addr, ste.dw0); 1359 DPRINTF(SMMUv3, " STE at %#x [1]: 0x%016x\n", ste_addr, ste.dw1); 1360 DPRINTF(SMMUv3, " STE at %#x [2]: 0x%016x\n", ste_addr, ste.dw2); 1361 DPRINTF(SMMUv3, " STE at %#x [3]: 0x%016x\n", ste_addr, ste.dw3); 1362 DPRINTF(SMMUv3, " STE at %#x [4]: 0x%016x\n", ste_addr, ste._pad[0]); 1363 DPRINTF(SMMUv3, " STE at %#x [5]: 0x%016x\n", ste_addr, ste._pad[1]); 1364 DPRINTF(SMMUv3, " STE at %#x [6]: 0x%016x\n", ste_addr, ste._pad[2]); 1365 DPRINTF(SMMUv3, " STE at %#x [7]: 0x%016x\n", ste_addr, ste._pad[3]); 1366 1367 if (!ste.dw0.valid) 1368 panic("STE @ %#x not valid\n", ste_addr); 1369 1370 smmu.steFetches++; 1371} 1372 1373void 1374SMMUTranslationProcess::doReadCD(Yield &yield, 1375 ContextDescriptor &cd, 1376 const StreamTableEntry &ste, 1377 uint32_t sid, uint32_t ssid) 1378{ 1379 Addr cd_addr; 1380 1381 if (ste.dw0.s1cdmax == 0) { 1382 cd_addr = ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT; 1383 } else { 1384 unsigned max_ssid = 1 << ste.dw0.s1cdmax; 1385 if (ssid >= max_ssid) 1386 panic("SSID %#x out of range, max=%#x", ssid, max_ssid); 1387 1388 if (ste.dw0.s1fmt==STAGE1_CFG_2L_4K || 1389 ste.dw0.s1fmt==STAGE1_CFG_2L_64K) 1390 { 1391 unsigned split = ste.dw0.s1fmt==STAGE1_CFG_2L_4K ? 7 : 11; 1392 1393 uint64_t l2_ptr; 1394 uint64_t l2_addr = (ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT) + 1395 bits(ssid, 24, split) * sizeof(l2_ptr); 1396 1397 if (context.stage2Enable) 1398 l2_addr = translateStage2(yield, l2_addr, false).addr; 1399 1400 DPRINTF(SMMUv3, "Read L1CD at %#x\n", l2_addr); 1401 1402 doReadConfig(yield, l2_addr, &l2_ptr, sizeof(l2_ptr), sid, ssid); 1403 1404 DPRINTF(SMMUv3, "Got L1CD at %#x: 0x%016x\n", l2_addr, l2_ptr); 1405 1406 cd_addr = l2_ptr + bits(ssid, split-1, 0) * sizeof(cd); 1407 1408 smmu.cdL1Fetches++; 1409 } else if (ste.dw0.s1fmt == STAGE1_CFG_1L) { 1410 cd_addr = (ste.dw0.s1ctxptr << ST_CD_ADDR_SHIFT) + ssid*sizeof(cd); 1411 } 1412 } 1413 1414 if (context.stage2Enable) 1415 cd_addr = translateStage2(yield, cd_addr, false).addr; 1416 1417 DPRINTF(SMMUv3, "Read CD at %#x\n", cd_addr); 1418 1419 doReadConfig(yield, cd_addr, &cd, sizeof(cd), sid, ssid); 1420 1421 DPRINTF(SMMUv3, "Got CD at %#x [0]: 0x%016x\n", cd_addr, cd.dw0); 1422 DPRINTF(SMMUv3, " CD at %#x [1]: 0x%016x\n", cd_addr, cd.dw1); 1423 DPRINTF(SMMUv3, " CD at %#x [2]: 0x%016x\n", cd_addr, cd.dw2); 1424 DPRINTF(SMMUv3, " CD at %#x [3]: 0x%016x\n", cd_addr, cd.mair); 1425 DPRINTF(SMMUv3, " CD at %#x [4]: 0x%016x\n", cd_addr, cd.amair); 1426 DPRINTF(SMMUv3, " CD at %#x [5]: 0x%016x\n", cd_addr, cd._pad[0]); 1427 DPRINTF(SMMUv3, " CD at %#x [6]: 0x%016x\n", cd_addr, cd._pad[1]); 1428 DPRINTF(SMMUv3, " CD at %#x [7]: 0x%016x\n", cd_addr, cd._pad[2]); 1429 1430 1431 if (!cd.dw0.valid) 1432 panic("CD @ %#x not valid\n", cd_addr); 1433 1434 smmu.cdFetches++; 1435} 1436 1437void 1438SMMUTranslationProcess::doReadConfig(Yield &yield, Addr addr, 1439 void *ptr, size_t size, 1440 uint32_t sid, uint32_t ssid) 1441{ 1442 doRead(yield, addr, ptr, size); 1443} 1444 1445void 1446SMMUTranslationProcess::doReadPTE(Yield &yield, Addr va, Addr addr, 1447 void *ptr, unsigned stage, 1448 unsigned level) 1449{ 1450 size_t pte_size = sizeof(PageTableOps::pte_t); 1451 1452 Addr mask = pte_size - 1; 1453 Addr base = addr & ~mask; 1454 1455 doRead(yield, base, ptr, pte_size); 1456} 1457