table_walker.cc revision 7404:bfc74724914e
13115SN/A/* 24125SN/A * Copyright (c) 2010 ARM Limited 33115SN/A * All rights reserved 43115SN/A * 53115SN/A * The license below extends only to copyright in the software and shall 63115SN/A * not be construed as granting a license to any other intellectual 73115SN/A * property including but not limited to intellectual property relating 83115SN/A * to a hardware implementation of the functionality of the software 93115SN/A * licensed hereunder. You may use the software subject to the license 103115SN/A * terms below provided that you ensure that this notice is replicated 113115SN/A * unmodified and in its entirety in all distributions of the software, 123115SN/A * modified or unmodified, in source code or in binary form. 133115SN/A * 143115SN/A * Redistribution and use in source and binary forms, with or without 153115SN/A * modification, are permitted provided that the following conditions are 163115SN/A * met: redistributions of source code must retain the above copyright 173115SN/A * notice, this list of conditions and the following disclaimer; 183115SN/A * redistributions in binary form must reproduce the above copyright 193115SN/A * notice, this list of conditions and the following disclaimer in the 203115SN/A * documentation and/or other materials provided with the distribution; 213115SN/A * neither the name of the copyright holders nor the names of its 223115SN/A * contributors may be used to endorse or promote products derived from 233115SN/A * this software without specific prior written permission. 243115SN/A * 253115SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 263115SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 273115SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 283115SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 293115SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 303115SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 316406SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 326406SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 336406SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 343115SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 353115SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 368229Snate@binkert.org * 373115SN/A * Authors: Ali Saidi 383115SN/A */ 398229Snate@binkert.org 408229Snate@binkert.org#include "arch/arm/faults.hh" 418229Snate@binkert.org#include "arch/arm/table_walker.hh" 428229Snate@binkert.org#include "arch/arm/tlb.hh" 438229Snate@binkert.org#include "dev/io_device.hh" 448229Snate@binkert.org#include "cpu/thread_context.hh" 458229Snate@binkert.org 468229Snate@binkert.org 473115SN/Ausing namespace ArmISA; 483115SN/A 493115SN/ATableWalker::TableWalker(const Params *p) 503115SN/A : MemObject(p), port(NULL), tlb(NULL), tc(NULL), req(NULL), 518108SN/A doL1DescEvent(this), doL2DescEvent(this) 528108SN/A{} 533115SN/A 547414SN/ATableWalker::~TableWalker() 557414SN/A{ 567414SN/A ; 577414SN/A} 587414SN/A 598114Sgblack@eecs.umich.edu 603115SN/Aunsigned int 613115SN/Adrain(Event *de) 628108SN/A{ 638108SN/A panic("Not implemented\n"); 643115SN/A} 654779SN/A 664779SN/APort* 674779SN/ATableWalker::getPort(const std::string &if_name, int idx) 683115SN/A{ 694779SN/A if (if_name == "port") { 704779SN/A if (port != NULL) 714779SN/A fatal("%s: port already connected to %s", 726408SN/A name(), port->getPeer()->name()); 737414SN/A System *sys = params()->sys; 747414SN/A Tick minb = params()->min_backoff; 757414SN/A Tick maxb = params()->max_backoff; 767414SN/A port = new DmaPort(this, sys, minb, maxb); 777414SN/A return port; 788108SN/A } 798108SN/A return NULL; 804779SN/A} 814779SN/A 823115SN/AFault 838108SN/ATableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode mode, 846408SN/A TLB::Translation *_trans, bool _timing) 858108SN/A{ 866408SN/A // Right now 1 CPU == 1 TLB == 1 TLB walker 876408SN/A // In the future we might want to change this as multiple 886408SN/A // threads/contexts could share a walker and/or a TLB 896408SN/A if (tc || req) 906408SN/A panic("Overlapping TLB walks attempted\n"); 918108SN/A 924779SN/A tc = _tc; 938108SN/A transState = _trans; 944779SN/A req = _req; 958108SN/A fault = NoFault; 964779SN/A contextId = _cid; 978108SN/A timing = _timing; 984779SN/A 994779SN/A // XXX These should be cached or grabbed from cached copies in 1004245SN/A // the TLB, all these miscreg reads are expensive 1013115SN/A vaddr = req->getVaddr() & ~PcModeMask; 1024779SN/A sctlr = tc->readMiscReg(MISCREG_SCTLR); 1034779SN/A cpsr = tc->readMiscReg(MISCREG_CPSR); 1048108SN/A N = tc->readMiscReg(MISCREG_TTBCR); 1054779SN/A Addr ttbr = 0; 1064779SN/A 1074779SN/A isFetch = (mode == TLB::Execute); 1083115SN/A isWrite = (mode == TLB::Write); 1094779SN/A isPriv = (cpsr.mode != MODE_USER); 1108108SN/A 1118108SN/A // If translation isn't enabled, we shouldn't be here 1124779SN/A assert(sctlr.m); 1134779SN/A 1144779SN/A if (N == 0 || mbits(vaddr, 31, 32-N)) { 1156422SN/A ttbr = tc->readMiscReg(MISCREG_TTBR0); 1168108SN/A } else { 1174779SN/A ttbr = tc->readMiscReg(MISCREG_TTBR0); 1188108SN/A N = 0; 1194779SN/A } 1204779SN/A 1214779SN/A Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(vaddr,31-N,20) << 2); 1224779SN/A DPRINTF(TLB, "Begining table walk for address %#x at descriptor %#x\n", 1238108SN/A vaddr, l1desc_addr); 1244779SN/A 1254779SN/A 1264779SN/A // Trickbox address check 1274779SN/A fault = tlb->walkTrickBoxCheck(l1desc_addr, vaddr, sizeof(uint32_t), 1286408SN/A isFetch, 0, true); 1298108SN/A if (fault) { 1304779SN/A tc = NULL; 1314779SN/A req = NULL; 1324779SN/A return fault; 1334779SN/A } 1344779SN/A 1354779SN/A if (timing) { 1364779SN/A port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 1374779SN/A &doL1DescEvent, (uint8_t*)&l1Desc.data, (Tick)0); 1384779SN/A } else { 1394779SN/A port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 1408108SN/A NULL, (uint8_t*)&l1Desc.data, (Tick)0); 1414779SN/A doL1Descriptor(); 1424779SN/A } 1434779SN/A 1448108SN/A return fault; 1458108SN/A} 1468108SN/A 1478108SN/Avoid 1484779SN/ATableWalker::memAttrs(TlbEntry &te, uint8_t texcb) 1494779SN/A{ 1508108SN/A 1518108SN/A if (sctlr.tre == 0) { 1528108SN/A switch(texcb) { 1534779SN/A case 0: 1544779SN/A case 1: 1553115SN/A case 4: 1563115SN/A case 8: 157 te.nonCacheable = true; 158 break; 159 case 16: 160 if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0) 161 te.nonCacheable = true; 162 break; 163 } 164 } else { 165 PRRR prrr = tc->readMiscReg(MISCREG_PRRR); 166 NMRR nmrr = tc->readMiscReg(MISCREG_NMRR); 167 switch(bits(texcb, 2,0)) { 168 case 0: 169 if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2) 170 te.nonCacheable = true; 171 break; 172 case 1: 173 if (nmrr.ir1 == 0 || nmrr.or1 == 0 || prrr.tr1 != 0x2) 174 te.nonCacheable = true; 175 break; 176 case 2: 177 if (nmrr.ir2 == 0 || nmrr.or2 == 0 || prrr.tr2 != 0x2) 178 te.nonCacheable = true; 179 break; 180 case 3: 181 if (nmrr.ir3 == 0 || nmrr.or3 == 0 || prrr.tr3 != 0x2) 182 te.nonCacheable = true; 183 break; 184 case 4: 185 if (nmrr.ir4 == 0 || nmrr.or4 == 0 || prrr.tr4 != 0x2) 186 te.nonCacheable = true; 187 break; 188 case 5: 189 if (nmrr.ir5 == 0 || nmrr.or5 == 0 || prrr.tr5 != 0x2) 190 te.nonCacheable = true; 191 break; 192 case 6: 193 panic("Imp defined type\n"); 194 case 7: 195 if (nmrr.ir7 == 0 || nmrr.or7 == 0 || prrr.tr7 != 0x2) 196 te.nonCacheable = true; 197 break; 198 } 199 } 200} 201 202void 203TableWalker::doL1Descriptor() 204{ 205 DPRINTF(TLB, "L1 descriptor for %#x is %#x\n", vaddr, l1Desc.data); 206 TlbEntry te; 207 208 switch (l1Desc.type()) { 209 case L1Descriptor::Ignore: 210 case L1Descriptor::Reserved: 211 tc = NULL; 212 req = NULL; 213 fault = new DataAbort(vaddr, NULL, isWrite, ArmFault::Translation0); 214 return; 215 case L1Descriptor::Section: 216 if (sctlr.afe && bits(l1Desc.ap(), 0) == 0) 217 panic("Haven't implemented AFE\n"); 218 219 if (l1Desc.supersection()) { 220 panic("Haven't implemented supersections\n"); 221 } 222 te.N = 20; 223 te.pfn = l1Desc.pfn(); 224 te.size = (1<<te.N) - 1; 225 te.global = !l1Desc.global(); 226 te.valid = true; 227 te.vpn = vaddr >> te.N; 228 te.sNp = true; 229 te.xn = l1Desc.xn(); 230 te.ap = l1Desc.ap(); 231 te.domain = l1Desc.domain(); 232 te.asid = contextId; 233 memAttrs(te, l1Desc.texcb()); 234 235 DPRINTF(TLB, "Inserting Section Descriptor into TLB\n"); 236 DPRINTF(TLB, " - N%d pfn:%#x size: %#x global:%d valid: %d\n", 237 te.N, te.pfn, te.size, te.global, te.valid); 238 DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d\n", 239 te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid); 240 DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n", 241 l1Desc.domain(), l1Desc.data, (l1Desc.data >> 5) & 0xF ); 242 243 tc = NULL; 244 req = NULL; 245 tlb->insert(vaddr, te); 246 247 return; 248 case L1Descriptor::PageTable: 249 Addr l2desc_addr; 250 l2desc_addr = l1Desc.l2Addr() | (bits(vaddr, 19,12) << 2); 251 DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n", l2desc_addr); 252 253 // Trickbox address check 254 fault = tlb->walkTrickBoxCheck(l2desc_addr, vaddr, sizeof(uint32_t), 255 isFetch, l1Desc.domain(), false); 256 if (fault) { 257 tc = NULL; 258 req = NULL; 259 return; 260 } 261 262 263 if (timing) { 264 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 265 &doL2DescEvent, (uint8_t*)&l2Desc.data, 0); 266 } else { 267 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 268 NULL, (uint8_t*)&l2Desc.data, 0); 269 doL2Descriptor(); 270 } 271 return; 272 default: 273 panic("A new type in a 2 bit field?\n"); 274 } 275} 276 277void 278TableWalker::doL2Descriptor() 279{ 280 DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", vaddr, l2Desc.data); 281 TlbEntry te; 282 283 if (sctlr.afe && bits(l1Desc.ap(), 0) == 0) 284 panic("Haven't implemented AFE\n"); 285 286 if (l2Desc.invalid()) { 287 DPRINTF(TLB, "L2 descriptor invalid, causing fault\n"); 288 tc = NULL; 289 req = NULL; 290 fault = new DataAbort(vaddr, l1Desc.domain(), isWrite, ArmFault::Translation1); 291 return; 292 } 293 294 if (l2Desc.large()) { 295 te.N = 16; 296 te.pfn = l2Desc.pfn(); 297 } else { 298 te.N = 12; 299 te.pfn = l2Desc.pfn(); 300 } 301 302 te.valid = true; 303 te.size = (1 << te.N) - 1; 304 te.asid = contextId; 305 te.sNp = false; 306 te.vpn = vaddr >> te.N; 307 te.global = l2Desc.global(); 308 te.xn = l2Desc.xn(); 309 te.ap = l2Desc.ap(); 310 te.domain = l1Desc.domain(); 311 memAttrs(te, l2Desc.texcb()); 312 313 tc = NULL; 314 req = NULL; 315 tlb->insert(vaddr, te); 316} 317 318ArmISA::TableWalker * 319ArmTableWalkerParams::create() 320{ 321 return new ArmISA::TableWalker(this); 322} 323 324