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_ptops.hh" 41 42#include "base/bitfield.hh" 43#include "base/logging.hh" 44 45bool 46V7LPageTableOps::isValid(pte_t pte, unsigned level) const 47{ 48 switch (level) { 49 case 1: return pte & 0x1; 50 case 2: return pte & 0x1; 51 case 3: return (pte & 0x1) && (pte & 0x2); 52 default: panic("bad level %d", level); 53 } 54} 55 56bool 57V7LPageTableOps::isLeaf(pte_t pte, unsigned level) const 58{ 59 switch (level) { 60 case 1: return !(pte & 0x2); 61 case 2: return !(pte & 0x2); 62 case 3: return true; 63 default: panic("bad level %d", level); 64 } 65} 66 67bool 68V7LPageTableOps::isWritable(pte_t pte, unsigned level, bool stage2) const 69{ 70 return stage2 ? bits(pte, 7, 6)==3 : bits(pte, 7)==0; 71} 72 73Addr 74V7LPageTableOps::nextLevelPointer(pte_t pte, unsigned level) const 75{ 76 if (isLeaf(pte, level)) { 77 switch (level) { 78 case 1: return mbits(pte, 39, 30); 79 case 2: return mbits(pte, 39, 21); 80 case 3: return mbits(pte, 39, 12); 81 default: panic("bad level %d", level); 82 } 83 } else { 84 return mbits(pte, 39, 12); 85 } 86} 87 88Addr 89V7LPageTableOps::index(Addr va, unsigned level) const 90{ 91 // In theory this should be configurable... 92 const int n = 12; 93 94 switch (level) { 95 case 1: return bits(va, 26+n, 30) << 3; break; 96 case 2: return bits(va, 29, 21) << 3; break; 97 case 3: return bits(va, 20, 12) << 3; break; 98 default: panic("bad level %d", level); 99 } 100} 101 102Addr 103V7LPageTableOps::pageMask(pte_t pte, unsigned level) const 104{ 105 switch (level) { 106 case 1: return ~mask(30); 107 case 2: return ~mask(21); 108 case 3: return bits(pte, 52) ? ~mask(16) : ~mask(12); 109 default: panic("bad level %d", level); 110 } 111} 112 113Addr 114V7LPageTableOps::walkMask(unsigned level) const 115{ 116 switch (level) { 117 case 1: return mask(39, 30); 118 case 2: return mask(39, 21); 119 case 3: return mask(39, 12); 120 default: panic("bad level %d", level); 121 } 122} 123 124unsigned 125V7LPageTableOps::firstLevel(uint8_t tsz) const 126{ 127 return 1; 128} 129 130unsigned 131V7LPageTableOps::lastLevel() const 132{ 133 return 3; 134} 135 136bool 137V8PageTableOps4k::isValid(pte_t pte, unsigned level) const 138{ 139 switch (level) { 140 case 0: return pte & 0x1; 141 case 1: return pte & 0x1; 142 case 2: return pte & 0x1; 143 case 3: return (pte & 0x1) && (pte & 0x2); 144 default: panic("bad level %d", level); 145 } 146} 147 148bool 149V8PageTableOps4k::isLeaf(pte_t pte, unsigned level) const 150{ 151 switch (level) { 152 case 0: return false; 153 case 1: return !(pte & 0x2); 154 case 2: return !(pte & 0x2); 155 case 3: return true; 156 default: panic("bad level %d", level); 157 } 158} 159 160bool 161V8PageTableOps4k::isWritable(pte_t pte, unsigned level, bool stage2) const 162{ 163 return stage2 ? bits(pte, 7, 6)==3 : bits(pte, 7)==0; 164} 165 166Addr 167V8PageTableOps4k::nextLevelPointer(pte_t pte, unsigned level) const 168{ 169 if (isLeaf(pte, level)) { 170 switch (level) { 171 // no level 0 here 172 case 1: return mbits(pte, 47, 30); 173 case 2: return mbits(pte, 47, 21); 174 case 3: return mbits(pte, 47, 12); 175 default: panic("bad level %d", level); 176 } 177 } else { 178 return mbits(pte, 47, 12); 179 } 180} 181 182Addr 183V8PageTableOps4k::index(Addr va, unsigned level) const 184{ 185 switch (level) { 186 case 0: return bits(va, 47, 39) << 3; break; 187 case 1: return bits(va, 38, 30) << 3; break; 188 case 2: return bits(va, 29, 21) << 3; break; 189 case 3: return bits(va, 20, 12) << 3; break; 190 default: panic("bad level %d", level); 191 } 192} 193 194Addr 195V8PageTableOps4k::pageMask(pte_t pte, unsigned level) const 196{ 197 switch (level) { 198 // no level 0 here 199 case 1: return ~mask(30); 200 case 2: return ~mask(21); 201 case 3: return bits(pte, 52) ? ~mask(16) : ~mask(12); 202 default: panic("bad level %d", level); 203 } 204} 205 206Addr 207V8PageTableOps4k::walkMask(unsigned level) const 208{ 209 switch (level) { 210 case 0: return mask(47, 39); 211 case 1: return mask(47, 30); 212 case 2: return mask(47, 21); 213 case 3: return mask(47, 12); 214 default: panic("bad level %d", level); 215 } 216} 217 218unsigned 219V8PageTableOps4k::firstLevel(uint8_t tsz) const 220{ 221 if (tsz >= 16 && tsz <= 24) return 0; 222 if (tsz >= 25 && tsz <= 33) return 1; 223 if (tsz >= 34 && tsz <= 39) return 2; 224 225 panic("Unsupported TnSZ: %d\n", tsz); 226} 227 228unsigned 229V8PageTableOps4k::lastLevel() const 230{ 231 return 3; 232} 233 234bool 235V8PageTableOps16k::isValid(pte_t pte, unsigned level) const 236{ 237 switch (level) { 238 case 0: return pte & 0x1; 239 case 1: return pte & 0x1; 240 case 2: return pte & 0x1; 241 case 3: return (pte & 0x1) && (pte & 0x2); 242 default: panic("bad level %d", level); 243 } 244} 245 246bool 247V8PageTableOps16k::isLeaf(pte_t pte, unsigned level) const 248{ 249 switch (level) { 250 case 0: return false; 251 case 1: return false; 252 case 2: return !(pte & 0x2); 253 case 3: return true; 254 default: panic("bad level %d", level); 255 } 256} 257 258bool 259V8PageTableOps16k::isWritable(pte_t pte, unsigned level, bool stage2) const 260{ 261 return stage2 ? bits(pte, 7, 6) == 3 : bits(pte, 7) == 0; 262} 263 264Addr 265V8PageTableOps16k::nextLevelPointer(pte_t pte, unsigned level) const 266{ 267 if (isLeaf(pte, level)) { 268 switch (level) { 269 // no level 0 here 270 case 1: return mbits(pte, 47, 36); 271 case 2: return mbits(pte, 47, 25); 272 case 3: return mbits(pte, 47, 14); 273 default: panic("bad level %d", level); 274 } 275 } else { 276 return mbits(pte, 47, 12); 277 } 278} 279 280Addr 281V8PageTableOps16k::index(Addr va, unsigned level) const 282{ 283 switch (level) { 284 case 0: return bits(va, 47, 47) << 3; break; 285 case 1: return bits(va, 46, 36) << 3; break; 286 case 2: return bits(va, 35, 25) << 3; break; 287 case 3: return bits(va, 24, 14) << 3; break; 288 default: panic("bad level %d", level); 289 } 290} 291 292Addr 293V8PageTableOps16k::pageMask(pte_t pte, unsigned level) const 294{ 295 switch (level) { 296 // no level 0 here 297 case 1: return ~mask(36); 298 // 16K granule supports contiguous entries also at L2; - 1G 299 case 2: return bits(pte, 52) ? ~mask(30) : ~mask(25); 300 // as well as at L3; - 2M 301 case 3: return bits(pte, 52) ? ~mask(21) : ~mask(14); 302 default: panic("bad level %d", level); 303 } 304} 305 306Addr 307V8PageTableOps16k::walkMask(unsigned level) const 308{ 309 switch (level) { 310 case 0: return ~mask(47); 311 case 1: return ~mask(36); 312 case 2: return ~mask(25); 313 case 3: return ~mask(14); 314 default: panic("bad level %d", level); 315 } 316} 317 318unsigned 319V8PageTableOps16k::firstLevel(uint8_t tsz) const 320{ 321 if (tsz == 16) return 0; 322 if (tsz >= 17 && tsz <= 27) return 1; 323 if (tsz >= 28 && tsz <= 38) return 2; 324 if (tsz == 39) return 3; 325 326 panic("Unsupported TnSZ: %d\n", tsz); 327} 328 329unsigned 330V8PageTableOps16k::lastLevel() const 331{ 332 return 3; 333} 334 335bool 336V8PageTableOps64k::isValid(pte_t pte, unsigned level) const 337{ 338 switch (level) { 339 case 1: return pte & 0x1; 340 case 2: return pte & 0x1; 341 case 3: return (pte & 0x1) && (pte & 0x2); 342 default: panic("bad level %d", level); 343 } 344} 345 346bool 347V8PageTableOps64k::isLeaf(pte_t pte, unsigned level) const 348{ 349 switch (level) { 350 case 1: return false; 351 case 2: return !(pte & 0x2); 352 case 3: return true; 353 default: panic("bad level %d", level); 354 } 355} 356 357bool 358V8PageTableOps64k::isWritable(pte_t pte, unsigned level, bool stage2) const 359{ 360 return stage2 ? bits(pte, 7, 6)==3 : bits(pte, 7)==0; 361} 362 363Addr 364V8PageTableOps64k::nextLevelPointer(pte_t pte, unsigned level) const 365{ 366 if (isLeaf(pte, level)) { 367 switch (level) { 368 // no level 1 here 369 case 2: return mbits(pte, 47, 29); 370 case 3: return mbits(pte, 47, 16); 371 default: panic("bad level %d", level); 372 } 373 } else { 374 return mbits(pte, 47, 16); 375 } 376} 377 378Addr 379V8PageTableOps64k::index(Addr va, unsigned level) const 380{ 381 switch (level) { 382 case 1: return bits(va, 47, 42) << 3; break; 383 case 2: return bits(va, 41, 29) << 3; break; 384 case 3: return bits(va, 28, 16) << 3; break; 385 default: panic("bad level %d", level); 386 } 387} 388 389Addr 390V8PageTableOps64k::pageMask(pte_t pte, unsigned level) const 391{ 392 switch (level) { 393 // no level 1 here 394 case 2: return ~mask(29); 395 case 3: return bits(pte, 52) ? ~mask(21) : ~mask(16); 396 default: panic("bad level %d", level); 397 } 398} 399 400Addr 401V8PageTableOps64k::walkMask(unsigned level) const 402{ 403 switch (level) { 404 case 1: return mask(47, 42); 405 case 2: return mask(47, 29); 406 case 3: return mask(47, 16); 407 default: panic("bad level %d", level); 408 } 409} 410 411unsigned 412V8PageTableOps64k::firstLevel(uint8_t tsz) const 413{ 414 if (tsz >= 12 && tsz <= 21) return 1; 415 if (tsz >= 22 && tsz <= 34) return 2; 416 if (tsz >= 35 && tsz <= 39) return 3; 417 418 panic("Unsupported TnSZ: %d\n", tsz); 419} 420 421unsigned 422V8PageTableOps64k::lastLevel() const 423{ 424 return 3; 425} 426