table_walker.cc revision 7404
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 if (N == 0 || mbits(vaddr, 31, 32-N)) { 115 ttbr = tc->readMiscReg(MISCREG_TTBR0); 116 } else { 117 ttbr = tc->readMiscReg(MISCREG_TTBR0); 118 N = 0; 119 } 120 121 Addr l1desc_addr = mbits(ttbr, 31, 14-N) | (bits(vaddr,31-N,20) << 2); 122 DPRINTF(TLB, "Begining table walk for address %#x at descriptor %#x\n", 123 vaddr, l1desc_addr); 124 125 126 // Trickbox address check 127 fault = tlb->walkTrickBoxCheck(l1desc_addr, vaddr, sizeof(uint32_t), 128 isFetch, 0, true); 129 if (fault) { 130 tc = NULL; 131 req = NULL; 132 return fault; 133 } 134 135 if (timing) { 136 port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 137 &doL1DescEvent, (uint8_t*)&l1Desc.data, (Tick)0); 138 } else { 139 port->dmaAction(MemCmd::ReadReq, l1desc_addr, sizeof(uint32_t), 140 NULL, (uint8_t*)&l1Desc.data, (Tick)0); 141 doL1Descriptor(); 142 } 143 144 return fault; 145} 146 147void 148TableWalker::memAttrs(TlbEntry &te, uint8_t texcb) 149{ 150 151 if (sctlr.tre == 0) { 152 switch(texcb) { 153 case 0: 154 case 1: 155 case 4: 156 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