table_walker.cc revision 7406
1/* 2 * Copyright (c) 2010 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Ali Saidi 38 */ 39 40#include "arch/arm/faults.hh" 41#include "arch/arm/table_walker.hh" 42#include "arch/arm/tlb.hh" 43#include "dev/io_device.hh" 44#include "cpu/thread_context.hh" 45 46 47using namespace ArmISA; 48 49TableWalker::TableWalker(const Params *p) 50 : MemObject(p), port(NULL), tlb(NULL), tc(NULL), req(NULL), 51 doL1DescEvent(this), doL2DescEvent(this) 52{} 53 54TableWalker::~TableWalker() 55{ 56 ; 57} 58 59 60unsigned int 61drain(Event *de) 62{ 63 panic("Not implemented\n"); 64} 65 66Port* 67TableWalker::getPort(const std::string &if_name, int idx) 68{ 69 if (if_name == "port") { 70 if (port != NULL) 71 fatal("%s: port already connected to %s", 72 name(), port->getPeer()->name()); 73 System *sys = params()->sys; 74 Tick minb = params()->min_backoff; 75 Tick maxb = params()->max_backoff; 76 port = new DmaPort(this, sys, minb, maxb); 77 return port; 78 } 79 return NULL; 80} 81 82Fault 83TableWalker::walk(RequestPtr _req, ThreadContext *_tc, uint8_t _cid, TLB::Mode mode, 84 TLB::Translation *_trans, bool _timing) 85{ 86 // Right now 1 CPU == 1 TLB == 1 TLB walker 87 // In the future we might want to change this as multiple 88 // threads/contexts could share a walker and/or a TLB 89 if (tc || req) 90 panic("Overlapping TLB walks attempted\n"); 91 92 tc = _tc; 93 transState = _trans; 94 req = _req; 95 fault = NoFault; 96 contextId = _cid; 97 timing = _timing; 98 99 // XXX These should be cached or grabbed from cached copies in 100 // the TLB, all these miscreg reads are expensive 101 vaddr = req->getVaddr() & ~PcModeMask; 102 sctlr = tc->readMiscReg(MISCREG_SCTLR); 103 cpsr = tc->readMiscReg(MISCREG_CPSR); 104 N = tc->readMiscReg(MISCREG_TTBCR); 105 Addr ttbr = 0; 106 107 isFetch = (mode == TLB::Execute); 108 isWrite = (mode == TLB::Write); 109 isPriv = (cpsr.mode != MODE_USER); 110 111 // If translation isn't enabled, we shouldn't be here 112 assert(sctlr.m); 113 114 DPRINTF(TLB, "Begining table walk for address %#x, TTBCR: %#x, bits:%#x\n", 115 vaddr, N, mbits(vaddr, 31, 32-N)); 116 117 if (N == 0 || !mbits(vaddr, 31, 32-N)) { 118 DPRINTF(TLB, " - Selecting TTBR0\n"); 119 ttbr = tc->readMiscReg(MISCREG_TTBR0); 120 } else { 121 DPRINTF(TLB, " - Selecting TTBR1\n"); 122 ttbr = tc->readMiscReg(MISCREG_TTBR1); 123 N = 0; 124 } 125 126 Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(vaddr,31-N,20) << 2); 127 DPRINTF(TLB, " - Descriptor at address %#x\n", l1desc_addr); 128 129 130 // Trickbox address check 131 fault = tlb->walkTrickBoxCheck(l1desc_addr, vaddr, sizeof(uint32_t), 132 isFetch, isWrite, 0, true); 133 if (fault) { 134 tc = NULL; 135 req = NULL; 136 return fault; 137 } 138 139 if (timing) { 140 port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 141 &doL1DescEvent, (uint8_t*)&l1Desc.data, (Tick)0); 142 } else { 143 port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 144 NULL, (uint8_t*)&l1Desc.data, (Tick)0); 145 doL1Descriptor(); 146 } 147 148 return fault; 149} 150 151void 152TableWalker::memAttrs(TlbEntry &te, uint8_t texcb) 153{ 154 155 if (sctlr.tre == 0) { 156 switch(texcb) { 157 case 0: 158 case 1: 159 case 4: 160 case 8: 161 te.nonCacheable = true; 162 break; 163 case 16: 164 if (bits(texcb, 1,0) == 0 || bits(texcb, 3,2) == 0) 165 te.nonCacheable = true; 166 break; 167 } 168 } else { 169 PRRR prrr = tc->readMiscReg(MISCREG_PRRR); 170 NMRR nmrr = tc->readMiscReg(MISCREG_NMRR); 171 switch(bits(texcb, 2,0)) { 172 case 0: 173 if (nmrr.ir0 == 0 || nmrr.or0 == 0 || prrr.tr0 != 0x2) 174 te.nonCacheable = true; 175 break; 176 case 1: 177 if (nmrr.ir1 == 0 || nmrr.or1 == 0 || prrr.tr1 != 0x2) 178 te.nonCacheable = true; 179 break; 180 case 2: 181 if (nmrr.ir2 == 0 || nmrr.or2 == 0 || prrr.tr2 != 0x2) 182 te.nonCacheable = true; 183 break; 184 case 3: 185 if (nmrr.ir3 == 0 || nmrr.or3 == 0 || prrr.tr3 != 0x2) 186 te.nonCacheable = true; 187 break; 188 case 4: 189 if (nmrr.ir4 == 0 || nmrr.or4 == 0 || prrr.tr4 != 0x2) 190 te.nonCacheable = true; 191 break; 192 case 5: 193 if (nmrr.ir5 == 0 || nmrr.or5 == 0 || prrr.tr5 != 0x2) 194 te.nonCacheable = true; 195 break; 196 case 6: 197 panic("Imp defined type\n"); 198 case 7: 199 if (nmrr.ir7 == 0 || nmrr.or7 == 0 || prrr.tr7 != 0x2) 200 te.nonCacheable = true; 201 break; 202 } 203 } 204} 205 206void 207TableWalker::doL1Descriptor() 208{ 209 DPRINTF(TLB, "L1 descriptor for %#x is %#x\n", vaddr, l1Desc.data); 210 TlbEntry te; 211 212 switch (l1Desc.type()) { 213 case L1Descriptor::Ignore: 214 case L1Descriptor::Reserved: 215 tc = NULL; 216 req = NULL; 217 DPRINTF(TLB, "L1 Descriptor Reserved/Ignore, causing fault\n"); 218 if (isFetch) 219 fault = new PrefetchAbort(vaddr, ArmFault::Translation0); 220 else 221 fault = new DataAbort(vaddr, NULL, isWrite, ArmFault::Translation0); 222 return; 223 case L1Descriptor::Section: 224 if (sctlr.afe && bits(l1Desc.ap(), 0) == 0) 225 panic("Haven't implemented AFE\n"); 226 227 if (l1Desc.supersection()) { 228 panic("Haven't implemented supersections\n"); 229 } 230 te.N = 20; 231 te.pfn = l1Desc.pfn(); 232 te.size = (1<<te.N) - 1; 233 te.global = !l1Desc.global(); 234 te.valid = true; 235 te.vpn = vaddr >> te.N; 236 te.sNp = true; 237 te.xn = l1Desc.xn(); 238 te.ap = l1Desc.ap(); 239 te.domain = l1Desc.domain(); 240 te.asid = contextId; 241 memAttrs(te, l1Desc.texcb()); 242 243 DPRINTF(TLB, "Inserting Section Descriptor into TLB\n"); 244 DPRINTF(TLB, " - N%d pfn:%#x size: %#x global:%d valid: %d\n", 245 te.N, te.pfn, te.size, te.global, te.valid); 246 DPRINTF(TLB, " - vpn:%#x sNp: %d xn:%d ap:%d domain: %d asid:%d\n", 247 te.vpn, te.sNp, te.xn, te.ap, te.domain, te.asid); 248 DPRINTF(TLB, " - domain from l1 desc: %d data: %#x bits:%d\n", 249 l1Desc.domain(), l1Desc.data, (l1Desc.data >> 5) & 0xF ); 250 251 tc = NULL; 252 req = NULL; 253 tlb->insert(vaddr, te); 254 255 return; 256 case L1Descriptor::PageTable: 257 Addr l2desc_addr; 258 l2desc_addr = l1Desc.l2Addr() | (bits(vaddr, 19,12) << 2); 259 DPRINTF(TLB, "L1 descriptor points to page table at: %#x\n", l2desc_addr); 260 261 // Trickbox address check 262 fault = tlb->walkTrickBoxCheck(l2desc_addr, vaddr, sizeof(uint32_t), 263 isFetch, isWrite, l1Desc.domain(), false); 264 if (fault) { 265 tc = NULL; 266 req = NULL; 267 return; 268 } 269 270 271 if (timing) { 272 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 273 &doL2DescEvent, (uint8_t*)&l2Desc.data, 0); 274 } else { 275 port->dmaAction(MemCmd::ReadReq, l2desc_addr, sizeof(uint32_t), 276 NULL, (uint8_t*)&l2Desc.data, 0); 277 doL2Descriptor(); 278 } 279 return; 280 default: 281 panic("A new type in a 2 bit field?\n"); 282 } 283} 284 285void 286TableWalker::doL2Descriptor() 287{ 288 DPRINTF(TLB, "L2 descriptor for %#x is %#x\n", vaddr, l2Desc.data); 289 TlbEntry te; 290 291 if (sctlr.afe && bits(l1Desc.ap(), 0) == 0) 292 panic("Haven't implemented AFE\n"); 293 294 if (l2Desc.invalid()) { 295 DPRINTF(TLB, "L2 descriptor invalid, causing fault\n"); 296 tc = NULL; 297 req = NULL; 298 if (isFetch) 299 fault = new PrefetchAbort(vaddr, ArmFault::Translation1); 300 else 301 fault = new DataAbort(vaddr, l1Desc.domain(), isWrite, ArmFault::Translation1); 302 return; 303 } 304 305 if (l2Desc.large()) { 306 te.N = 16; 307 te.pfn = l2Desc.pfn(); 308 } else { 309 te.N = 12; 310 te.pfn = l2Desc.pfn(); 311 } 312 313 te.valid = true; 314 te.size = (1 << te.N) - 1; 315 te.asid = contextId; 316 te.sNp = false; 317 te.vpn = vaddr >> te.N; 318 te.global = l2Desc.global(); 319 te.xn = l2Desc.xn(); 320 te.ap = l2Desc.ap(); 321 te.domain = l1Desc.domain(); 322 memAttrs(te, l2Desc.texcb()); 323 324 tc = NULL; 325 req = NULL; 326 tlb->insert(vaddr, te); 327} 328 329ArmISA::TableWalker * 330ArmTableWalkerParams::create() 331{ 332 return new ArmISA::TableWalker(this); 333} 334 335