table_walker.hh revision 11395
12929Sktlim@umich.edu/* 22929Sktlim@umich.edu * Copyright (c) 2010-2015 ARM Limited 32929Sktlim@umich.edu * All rights reserved 42929Sktlim@umich.edu * 52929Sktlim@umich.edu * The license below extends only to copyright in the software and shall 62929Sktlim@umich.edu * not be construed as granting a license to any other intellectual 72929Sktlim@umich.edu * property including but not limited to intellectual property relating 82929Sktlim@umich.edu * to a hardware implementation of the functionality of the software 92929Sktlim@umich.edu * licensed hereunder. You may use the software subject to the license 102929Sktlim@umich.edu * terms below provided that you ensure that this notice is replicated 112929Sktlim@umich.edu * unmodified and in its entirety in all distributions of the software, 122929Sktlim@umich.edu * modified or unmodified, in source code or in binary form. 132929Sktlim@umich.edu * 142929Sktlim@umich.edu * Redistribution and use in source and binary forms, with or without 152929Sktlim@umich.edu * modification, are permitted provided that the following conditions are 162929Sktlim@umich.edu * met: redistributions of source code must retain the above copyright 172929Sktlim@umich.edu * notice, this list of conditions and the following disclaimer; 182929Sktlim@umich.edu * redistributions in binary form must reproduce the above copyright 192929Sktlim@umich.edu * notice, this list of conditions and the following disclaimer in the 202929Sktlim@umich.edu * documentation and/or other materials provided with the distribution; 212929Sktlim@umich.edu * neither the name of the copyright holders nor the names of its 222929Sktlim@umich.edu * contributors may be used to endorse or promote products derived from 232929Sktlim@umich.edu * this software without specific prior written permission. 242929Sktlim@umich.edu * 252929Sktlim@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262929Sktlim@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272929Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282929Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292929Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302929Sktlim@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312929Sktlim@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322929Sktlim@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332929Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342929Sktlim@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352929Sktlim@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 367686Ssteve.reinhardt@amd.com * 372929Sktlim@umich.edu * Authors: Ali Saidi 382929Sktlim@umich.edu * Giacomo Gabrielli 392929Sktlim@umich.edu */ 402929Sktlim@umich.edu 417686Ssteve.reinhardt@amd.com#ifndef __ARCH_ARM_TABLE_WALKER_HH__ 427686Ssteve.reinhardt@amd.com#define __ARCH_ARM_TABLE_WALKER_HH__ 437686Ssteve.reinhardt@amd.com 447686Ssteve.reinhardt@amd.com#include <list> 457686Ssteve.reinhardt@amd.com 467686Ssteve.reinhardt@amd.com#include "arch/arm/miscregs.hh" 472929Sktlim@umich.edu#include "arch/arm/system.hh" 482929Sktlim@umich.edu#include "arch/arm/tlb.hh" 492929Sktlim@umich.edu#include "mem/request.hh" 502929Sktlim@umich.edu#include "params/ArmTableWalker.hh" 512929Sktlim@umich.edu#include "sim/eventq.hh" 522929Sktlim@umich.edu 532929Sktlim@umich.educlass ThreadContext; 542929Sktlim@umich.edu 552929Sktlim@umich.educlass DmaPort; 562929Sktlim@umich.edu 572929Sktlim@umich.edunamespace ArmISA { 587686Ssteve.reinhardt@amd.comclass Translation; 592929Sktlim@umich.educlass TLB; 602929Sktlim@umich.educlass Stage2MMU; 617686Ssteve.reinhardt@amd.com 622929Sktlim@umich.educlass TableWalker : public MemObject 632929Sktlim@umich.edu{ 642929Sktlim@umich.edu public: 652929Sktlim@umich.edu class WalkerState; 662929Sktlim@umich.edu 672929Sktlim@umich.edu class DescriptorBase { 682929Sktlim@umich.edu public: 692929Sktlim@umich.edu /** Current lookup level for this descriptor */ 702929Sktlim@umich.edu LookupLevel lookupLevel; 712929Sktlim@umich.edu 722929Sktlim@umich.edu virtual Addr pfn() const = 0; 732929Sktlim@umich.edu virtual TlbEntry::DomainType domain() const = 0; 742929Sktlim@umich.edu virtual bool xn() const = 0; 752929Sktlim@umich.edu virtual uint8_t ap() const = 0; 762929Sktlim@umich.edu virtual bool global(WalkerState *currState) const = 0; 772929Sktlim@umich.edu virtual uint8_t offsetBits() const = 0; 782929Sktlim@umich.edu virtual bool secure(bool have_security, WalkerState *currState) const = 0; 792929Sktlim@umich.edu virtual std::string dbgHeader() const = 0; 802929Sktlim@umich.edu virtual uint64_t getRawData() const = 0; 812929Sktlim@umich.edu virtual uint8_t texcb() const 822929Sktlim@umich.edu { 832929Sktlim@umich.edu panic("texcb() not implemented for this class\n"); 842929Sktlim@umich.edu } 852929Sktlim@umich.edu virtual bool shareable() const 862929Sktlim@umich.edu { 872929Sktlim@umich.edu panic("shareable() not implemented for this class\n"); 882929Sktlim@umich.edu } 892929Sktlim@umich.edu }; 902929Sktlim@umich.edu 912929Sktlim@umich.edu class L1Descriptor : public DescriptorBase { 922929Sktlim@umich.edu public: 932929Sktlim@umich.edu /** Type of page table entry ARM DDI 0406B: B3-8*/ 942929Sktlim@umich.edu enum EntryType { 952929Sktlim@umich.edu Ignore, 962929Sktlim@umich.edu PageTable, 972929Sktlim@umich.edu Section, 982929Sktlim@umich.edu Reserved 992929Sktlim@umich.edu }; 1002929Sktlim@umich.edu 1012929Sktlim@umich.edu /** The raw bits of the entry */ 1022929Sktlim@umich.edu uint32_t data; 1032929Sktlim@umich.edu 1042929Sktlim@umich.edu /** This entry has been modified (access flag set) and needs to be 1052929Sktlim@umich.edu * written back to memory */ 1062929Sktlim@umich.edu bool _dirty; 1072929Sktlim@umich.edu 1082929Sktlim@umich.edu /** Default ctor */ 1092929Sktlim@umich.edu L1Descriptor() : data(0), _dirty(false) 1102929Sktlim@umich.edu { 1112929Sktlim@umich.edu lookupLevel = L1; 1122929Sktlim@umich.edu } 1132929Sktlim@umich.edu 1142929Sktlim@umich.edu virtual uint64_t getRawData() const 1152929Sktlim@umich.edu { 1162929Sktlim@umich.edu return (data); 1172929Sktlim@umich.edu } 1182929Sktlim@umich.edu 1192929Sktlim@umich.edu virtual std::string dbgHeader() const 1202929Sktlim@umich.edu { 1212929Sktlim@umich.edu return "Inserting Section Descriptor into TLB\n"; 1222929Sktlim@umich.edu } 1232929Sktlim@umich.edu 1242929Sktlim@umich.edu virtual uint8_t offsetBits() const 1252929Sktlim@umich.edu { 1262929Sktlim@umich.edu return 20; 1272929Sktlim@umich.edu } 1282929Sktlim@umich.edu 1292929Sktlim@umich.edu EntryType type() const 1302929Sktlim@umich.edu { 1312929Sktlim@umich.edu return (EntryType)(data & 0x3); 1322929Sktlim@umich.edu } 1332929Sktlim@umich.edu 1347448Sstever@gmail.com /** Is the page a Supersection (16MB)?*/ 1357448Sstever@gmail.com bool supersection() const 1367448Sstever@gmail.com { 1377448Sstever@gmail.com return bits(data, 18); 1382929Sktlim@umich.edu } 1397448Sstever@gmail.com 1407448Sstever@gmail.com /** Return the physcal address of the entry, bits in position*/ 1417448Sstever@gmail.com Addr paddr() const 1427448Sstever@gmail.com { 1437448Sstever@gmail.com if (supersection()) 1447448Sstever@gmail.com panic("Super sections not implemented\n"); 1457448Sstever@gmail.com return mbits(data, 31, 20); 1467448Sstever@gmail.com } 1477448Sstever@gmail.com /** Return the physcal address of the entry, bits in position*/ 1482929Sktlim@umich.edu Addr paddr(Addr va) const 1492929Sktlim@umich.edu { 1502929Sktlim@umich.edu if (supersection()) 1512929Sktlim@umich.edu panic("Super sections not implemented\n"); 1522929Sktlim@umich.edu return mbits(data, 31, 20) | mbits(va, 19, 0); 1532929Sktlim@umich.edu } 1542929Sktlim@umich.edu 1552929Sktlim@umich.edu 1562929Sktlim@umich.edu /** Return the physical frame, bits shifted right */ 1572929Sktlim@umich.edu Addr pfn() const 1582929Sktlim@umich.edu { 1592929Sktlim@umich.edu if (supersection()) 1602929Sktlim@umich.edu panic("Super sections not implemented\n"); 1612929Sktlim@umich.edu return bits(data, 31, 20); 1622929Sktlim@umich.edu } 1632929Sktlim@umich.edu 1642929Sktlim@umich.edu /** Is the translation global (no asid used)? */ 1652929Sktlim@umich.edu bool global(WalkerState *currState) const 1662929Sktlim@umich.edu { 1672929Sktlim@umich.edu return !bits(data, 17); 1682929Sktlim@umich.edu } 1692929Sktlim@umich.edu 1702929Sktlim@umich.edu /** Is the translation not allow execution? */ 1712929Sktlim@umich.edu bool xn() const 1722929Sktlim@umich.edu { 1732929Sktlim@umich.edu return bits(data, 4); 1742929Sktlim@umich.edu } 1752929Sktlim@umich.edu 1762929Sktlim@umich.edu /** Three bit access protection flags */ 1772929Sktlim@umich.edu uint8_t ap() const 1782929Sktlim@umich.edu { 1792929Sktlim@umich.edu return (bits(data, 15) << 2) | bits(data, 11, 10); 1802929Sktlim@umich.edu } 1812929Sktlim@umich.edu 1822929Sktlim@umich.edu /** Domain Client/Manager: ARM DDI 0406B: B3-31 */ 1832929Sktlim@umich.edu TlbEntry::DomainType domain() const 1842929Sktlim@umich.edu { 1852929Sktlim@umich.edu return static_cast<TlbEntry::DomainType>(bits(data, 8, 5)); 1862929Sktlim@umich.edu } 1872929Sktlim@umich.edu 1882929Sktlim@umich.edu /** Address of L2 descriptor if it exists */ 1898838Ssaidi@eecs.umich.edu Addr l2Addr() const 1902929Sktlim@umich.edu { 1912929Sktlim@umich.edu return mbits(data, 31, 10); 1922929Sktlim@umich.edu } 1932929Sktlim@umich.edu 1942929Sktlim@umich.edu /** Memory region attributes: ARM DDI 0406B: B3-32. 1952929Sktlim@umich.edu * These bits are largly ignored by M5 and only used to 1962929Sktlim@umich.edu * provide the illusion that the memory system cares about 1972929Sktlim@umich.edu * anything but cachable vs. uncachable. 1988838Ssaidi@eecs.umich.edu */ 1998838Ssaidi@eecs.umich.edu uint8_t texcb() const 2008838Ssaidi@eecs.umich.edu { 2018838Ssaidi@eecs.umich.edu return bits(data, 2) | bits(data, 3) << 1 | bits(data, 14, 12) << 2; 2028838Ssaidi@eecs.umich.edu } 2038838Ssaidi@eecs.umich.edu 2042929Sktlim@umich.edu /** If the section is shareable. See texcb() comment. */ 2052929Sktlim@umich.edu bool shareable() const 2062929Sktlim@umich.edu { 2072929Sktlim@umich.edu return bits(data, 16); 2082929Sktlim@umich.edu } 2092929Sktlim@umich.edu 2102929Sktlim@umich.edu /** Set access flag that this entry has been touched. Mark 2112929Sktlim@umich.edu * the entry as requiring a writeback, in the future. 2122929Sktlim@umich.edu */ 2132929Sktlim@umich.edu void setAp0() 2142929Sktlim@umich.edu { 2152929Sktlim@umich.edu data |= 1 << 10; 2162929Sktlim@umich.edu _dirty = true; 2172929Sktlim@umich.edu } 2182929Sktlim@umich.edu 2192929Sktlim@umich.edu /** This entry needs to be written back to memory */ 2202929Sktlim@umich.edu bool dirty() const 2212929Sktlim@umich.edu { 2222929Sktlim@umich.edu return _dirty; 2232929Sktlim@umich.edu } 2242929Sktlim@umich.edu 2252929Sktlim@umich.edu /** 2262929Sktlim@umich.edu * Returns true if this entry targets the secure physical address 2272929Sktlim@umich.edu * map. 2282929Sktlim@umich.edu */ 2292929Sktlim@umich.edu bool secure(bool have_security, WalkerState *currState) const 2302929Sktlim@umich.edu { 2312929Sktlim@umich.edu if (have_security) { 2322929Sktlim@umich.edu if (type() == PageTable) 2332929Sktlim@umich.edu return !bits(data, 3); 2342929Sktlim@umich.edu else 2352929Sktlim@umich.edu return !bits(data, 19); 2362929Sktlim@umich.edu } 2372929Sktlim@umich.edu return false; 2382929Sktlim@umich.edu } 2392929Sktlim@umich.edu }; 2402929Sktlim@umich.edu 2412929Sktlim@umich.edu /** Level 2 page table descriptor */ 2422929Sktlim@umich.edu class L2Descriptor : public DescriptorBase { 2432929Sktlim@umich.edu public: 2442929Sktlim@umich.edu /** The raw bits of the entry. */ 2452929Sktlim@umich.edu uint32_t data; 2462929Sktlim@umich.edu L1Descriptor *l1Parent; 2472929Sktlim@umich.edu 2482929Sktlim@umich.edu /** This entry has been modified (access flag set) and needs to be 2492929Sktlim@umich.edu * written back to memory */ 2502929Sktlim@umich.edu bool _dirty; 2512929Sktlim@umich.edu 2522929Sktlim@umich.edu /** Default ctor */ 2532929Sktlim@umich.edu L2Descriptor() : data(0), l1Parent(nullptr), _dirty(false) 2542929Sktlim@umich.edu { 2552929Sktlim@umich.edu lookupLevel = L2; 2562929Sktlim@umich.edu } 2572929Sktlim@umich.edu 2582929Sktlim@umich.edu L2Descriptor(L1Descriptor &parent) : data(0), l1Parent(&parent), 2592929Sktlim@umich.edu _dirty(false) 2602929Sktlim@umich.edu { 2612929Sktlim@umich.edu lookupLevel = L2; 2622929Sktlim@umich.edu } 2632929Sktlim@umich.edu 2642929Sktlim@umich.edu virtual uint64_t getRawData() const 2652929Sktlim@umich.edu { 2662929Sktlim@umich.edu return (data); 2672929Sktlim@umich.edu } 2682929Sktlim@umich.edu 2692929Sktlim@umich.edu virtual std::string dbgHeader() const 2702929Sktlim@umich.edu { 2712929Sktlim@umich.edu return "Inserting L2 Descriptor into TLB\n"; 2722929Sktlim@umich.edu } 2732929Sktlim@umich.edu 2742929Sktlim@umich.edu virtual TlbEntry::DomainType domain() const 2752929Sktlim@umich.edu { 2762929Sktlim@umich.edu return l1Parent->domain(); 2772929Sktlim@umich.edu } 2782929Sktlim@umich.edu 2792929Sktlim@umich.edu bool secure(bool have_security, WalkerState *currState) const 2802929Sktlim@umich.edu { 2812929Sktlim@umich.edu return l1Parent->secure(have_security, currState); 2822929Sktlim@umich.edu } 2832929Sktlim@umich.edu 2842929Sktlim@umich.edu virtual uint8_t offsetBits() const 2852929Sktlim@umich.edu { 2862929Sktlim@umich.edu return large() ? 16 : 12; 2872929Sktlim@umich.edu } 2882929Sktlim@umich.edu 2892929Sktlim@umich.edu /** Is the entry invalid */ 2907686Ssteve.reinhardt@amd.com bool invalid() const 2912929Sktlim@umich.edu { 2927686Ssteve.reinhardt@amd.com return bits(data, 1, 0) == 0; 2937686Ssteve.reinhardt@amd.com } 2947686Ssteve.reinhardt@amd.com 2957686Ssteve.reinhardt@amd.com /** What is the size of the mapping? */ 2962929Sktlim@umich.edu bool large() const 2972929Sktlim@umich.edu { 2982929Sktlim@umich.edu return bits(data, 1) == 0; 2992929Sktlim@umich.edu } 3007686Ssteve.reinhardt@amd.com 3017686Ssteve.reinhardt@amd.com /** Is execution allowed on this mapping? */ 3022929Sktlim@umich.edu bool xn() const 3032929Sktlim@umich.edu { 3042929Sktlim@umich.edu return large() ? bits(data, 15) : bits(data, 0); 3052929Sktlim@umich.edu } 3062929Sktlim@umich.edu 3072929Sktlim@umich.edu /** Is the translation global (no asid used)? */ 3082929Sktlim@umich.edu bool global(WalkerState *currState) const 3092929Sktlim@umich.edu { 3102929Sktlim@umich.edu return !bits(data, 11); 3112929Sktlim@umich.edu } 3122929Sktlim@umich.edu 3132929Sktlim@umich.edu /** Three bit access protection flags */ 3142929Sktlim@umich.edu uint8_t ap() const 3152929Sktlim@umich.edu { 3162929Sktlim@umich.edu return bits(data, 5, 4) | (bits(data, 9) << 2); 3172929Sktlim@umich.edu } 3182929Sktlim@umich.edu 3197686Ssteve.reinhardt@amd.com /** Memory region attributes: ARM DDI 0406B: B3-32 */ 3202929Sktlim@umich.edu uint8_t texcb() const 3217686Ssteve.reinhardt@amd.com { 3222929Sktlim@umich.edu return large() ? 3232929Sktlim@umich.edu (bits(data, 2) | (bits(data, 3) << 1) | (bits(data, 14, 12) << 2)) : 3242929Sktlim@umich.edu (bits(data, 2) | (bits(data, 3) << 1) | (bits(data, 8, 6) << 2)); 3252929Sktlim@umich.edu } 3262929Sktlim@umich.edu 3277448Sstever@gmail.com /** Return the physical frame, bits shifted right */ 3287448Sstever@gmail.com Addr pfn() const 3292929Sktlim@umich.edu { 3302929Sktlim@umich.edu return large() ? bits(data, 31, 16) : bits(data, 31, 12); 3312929Sktlim@umich.edu } 3322929Sktlim@umich.edu 3332929Sktlim@umich.edu /** Return complete physical address given a VA */ 3342929Sktlim@umich.edu Addr paddr(Addr va) const 3352929Sktlim@umich.edu { 3362929Sktlim@umich.edu if (large()) 3372929Sktlim@umich.edu return mbits(data, 31, 16) | mbits(va, 15, 0); 3382929Sktlim@umich.edu else 3392929Sktlim@umich.edu return mbits(data, 31, 12) | mbits(va, 11, 0); 3402929Sktlim@umich.edu } 3412929Sktlim@umich.edu 3422929Sktlim@umich.edu /** If the section is shareable. See texcb() comment. */ 3432929Sktlim@umich.edu bool shareable() const 3442929Sktlim@umich.edu { 3452929Sktlim@umich.edu return bits(data, 10); 3462929Sktlim@umich.edu } 3472929Sktlim@umich.edu 3482929Sktlim@umich.edu /** Set access flag that this entry has been touched. Mark 3492929Sktlim@umich.edu * the entry as requiring a writeback, in the future. 3502929Sktlim@umich.edu */ 3512929Sktlim@umich.edu void setAp0() 3522929Sktlim@umich.edu { 3532929Sktlim@umich.edu data |= 1 << 4; 3542929Sktlim@umich.edu _dirty = true; 3552929Sktlim@umich.edu } 3562929Sktlim@umich.edu 3572929Sktlim@umich.edu /** This entry needs to be written back to memory */ 3582929Sktlim@umich.edu bool dirty() const 3592929Sktlim@umich.edu { 3602929Sktlim@umich.edu return _dirty; 3612929Sktlim@umich.edu } 3622929Sktlim@umich.edu 3632929Sktlim@umich.edu }; 3647448Sstever@gmail.com 3657448Sstever@gmail.com // Granule sizes for AArch64 long descriptors 3662929Sktlim@umich.edu enum GrainSize { 3672929Sktlim@umich.edu Grain4KB = 12, 3682929Sktlim@umich.edu Grain16KB = 14, 3692929Sktlim@umich.edu Grain64KB = 16, 3702929Sktlim@umich.edu ReservedGrain = 0 3712929Sktlim@umich.edu }; 3722929Sktlim@umich.edu 373 /** Long-descriptor format (LPAE) */ 374 class LongDescriptor : public DescriptorBase { 375 public: 376 /** Descriptor type */ 377 enum EntryType { 378 Invalid, 379 Table, 380 Block, 381 Page 382 }; 383 384 /** The raw bits of the entry */ 385 uint64_t data; 386 387 /** This entry has been modified (access flag set) and needs to be 388 * written back to memory */ 389 bool _dirty; 390 391 virtual uint64_t getRawData() const 392 { 393 return (data); 394 } 395 396 virtual std::string dbgHeader() const 397 { 398 if (type() == LongDescriptor::Page) { 399 assert(lookupLevel == L3); 400 return "Inserting Page descriptor into TLB\n"; 401 } else { 402 assert(lookupLevel < L3); 403 return "Inserting Block descriptor into TLB\n"; 404 } 405 } 406 407 /** 408 * Returns true if this entry targets the secure physical address 409 * map. 410 */ 411 bool secure(bool have_security, WalkerState *currState) const 412 { 413 assert(type() == Block || type() == Page); 414 return have_security && (currState->secureLookup && !bits(data, 5)); 415 } 416 417 /** True if the current lookup is performed in AArch64 state */ 418 bool aarch64; 419 420 /** Width of the granule size in bits */ 421 GrainSize grainSize; 422 423 /** Return the descriptor type */ 424 EntryType type() const 425 { 426 switch (bits(data, 1, 0)) { 427 case 0x1: 428 // In AArch64 blocks are not allowed at L0 for the 4 KB granule 429 // and at L1 for 16/64 KB granules 430 if (grainSize > Grain4KB) 431 return lookupLevel == L2 ? Block : Invalid; 432 return lookupLevel == L0 || lookupLevel == L3 ? Invalid : Block; 433 case 0x3: 434 return lookupLevel == L3 ? Page : Table; 435 default: 436 return Invalid; 437 } 438 } 439 440 /** Return the bit width of the page/block offset */ 441 uint8_t offsetBits() const 442 { 443 if (type() == Block) { 444 switch (grainSize) { 445 case Grain4KB: 446 return lookupLevel == L1 ? 30 /* 1 GB */ 447 : 21 /* 2 MB */; 448 case Grain16KB: 449 return 25 /* 32 MB */; 450 case Grain64KB: 451 return 29 /* 512 MB */; 452 default: 453 panic("Invalid AArch64 VM granule size\n"); 454 } 455 } else if (type() == Page) { 456 switch (grainSize) { 457 case Grain4KB: 458 case Grain16KB: 459 case Grain64KB: 460 return grainSize; /* enum -> uint okay */ 461 default: 462 panic("Invalid AArch64 VM granule size\n"); 463 } 464 } else { 465 panic("AArch64 page table entry must be block or page\n"); 466 } 467 } 468 469 /** Return the physical frame, bits shifted right */ 470 Addr pfn() const 471 { 472 if (aarch64) 473 return bits(data, 47, offsetBits()); 474 return bits(data, 39, offsetBits()); 475 } 476 477 /** Return the complete physical address given a VA */ 478 Addr paddr(Addr va) const 479 { 480 int n = offsetBits(); 481 if (aarch64) 482 return mbits(data, 47, n) | mbits(va, n - 1, 0); 483 return mbits(data, 39, n) | mbits(va, n - 1, 0); 484 } 485 486 /** Return the physical address of the entry */ 487 Addr paddr() const 488 { 489 if (aarch64) 490 return mbits(data, 47, offsetBits()); 491 return mbits(data, 39, offsetBits()); 492 } 493 494 /** Return the address of the next page table */ 495 Addr nextTableAddr() const 496 { 497 assert(type() == Table); 498 if (aarch64) 499 return mbits(data, 47, grainSize); 500 else 501 return mbits(data, 39, 12); 502 } 503 504 /** Return the address of the next descriptor */ 505 Addr nextDescAddr(Addr va) const 506 { 507 assert(type() == Table); 508 Addr pa = 0; 509 if (aarch64) { 510 int stride = grainSize - 3; 511 int va_lo = stride * (3 - (lookupLevel + 1)) + grainSize; 512 int va_hi = va_lo + stride - 1; 513 pa = nextTableAddr() | (bits(va, va_hi, va_lo) << 3); 514 } else { 515 if (lookupLevel == L1) 516 pa = nextTableAddr() | (bits(va, 29, 21) << 3); 517 else // lookupLevel == L2 518 pa = nextTableAddr() | (bits(va, 20, 12) << 3); 519 } 520 return pa; 521 } 522 523 /** Is execution allowed on this mapping? */ 524 bool xn() const 525 { 526 assert(type() == Block || type() == Page); 527 return bits(data, 54); 528 } 529 530 /** Is privileged execution allowed on this mapping? (LPAE only) */ 531 bool pxn() const 532 { 533 assert(type() == Block || type() == Page); 534 return bits(data, 53); 535 } 536 537 /** Contiguous hint bit. */ 538 bool contiguousHint() const 539 { 540 assert(type() == Block || type() == Page); 541 return bits(data, 52); 542 } 543 544 /** Is the translation global (no asid used)? */ 545 bool global(WalkerState *currState) const 546 { 547 assert(currState && (type() == Block || type() == Page)); 548 if (!currState->aarch64 && (currState->isSecure && 549 !currState->secureLookup)) { 550 return false; // ARM ARM issue C B3.6.3 551 } else if (currState->aarch64) { 552 if (currState->el == EL2 || currState->el == EL3) { 553 return true; // By default translations are treated as global 554 // in AArch64 EL2 and EL3 555 } else if (currState->isSecure && !currState->secureLookup) { 556 return false; 557 } 558 } 559 return !bits(data, 11); 560 } 561 562 /** Returns true if the access flag (AF) is set. */ 563 bool af() const 564 { 565 assert(type() == Block || type() == Page); 566 return bits(data, 10); 567 } 568 569 /** 2-bit shareability field */ 570 uint8_t sh() const 571 { 572 assert(type() == Block || type() == Page); 573 return bits(data, 9, 8); 574 } 575 576 /** 2-bit access protection flags */ 577 uint8_t ap() const 578 { 579 assert(type() == Block || type() == Page); 580 // Long descriptors only support the AP[2:1] scheme 581 return bits(data, 7, 6); 582 } 583 584 /** Read/write access protection flag */ 585 bool rw() const 586 { 587 assert(type() == Block || type() == Page); 588 return !bits(data, 7); 589 } 590 591 /** User/privileged level access protection flag */ 592 bool user() const 593 { 594 assert(type() == Block || type() == Page); 595 return bits(data, 6); 596 } 597 598 /** Return the AP bits as compatible with the AP[2:0] format. Utility 599 * function used to simplify the code in the TLB for performing 600 * permission checks. */ 601 static uint8_t ap(bool rw, bool user) 602 { 603 return ((!rw) << 2) | (user << 1); 604 } 605 606 TlbEntry::DomainType domain() const 607 { 608 // Long-desc. format only supports Client domain 609 assert(type() == Block || type() == Page); 610 return TlbEntry::DomainType::Client; 611 } 612 613 /** Attribute index */ 614 uint8_t attrIndx() const 615 { 616 assert(type() == Block || type() == Page); 617 return bits(data, 4, 2); 618 } 619 620 /** Memory attributes, only used by stage 2 translations */ 621 uint8_t memAttr() const 622 { 623 assert(type() == Block || type() == Page); 624 return bits(data, 5, 2); 625 } 626 627 /** Set access flag that this entry has been touched. Mark the entry as 628 * requiring a writeback, in the future. */ 629 void setAf() 630 { 631 data |= 1 << 10; 632 _dirty = true; 633 } 634 635 /** This entry needs to be written back to memory */ 636 bool dirty() const 637 { 638 return _dirty; 639 } 640 641 /** Whether the subsequent levels of lookup are secure */ 642 bool secureTable() const 643 { 644 assert(type() == Table); 645 return !bits(data, 63); 646 } 647 648 /** Two bit access protection flags for subsequent levels of lookup */ 649 uint8_t apTable() const 650 { 651 assert(type() == Table); 652 return bits(data, 62, 61); 653 } 654 655 /** R/W protection flag for subsequent levels of lookup */ 656 uint8_t rwTable() const 657 { 658 assert(type() == Table); 659 return !bits(data, 62); 660 } 661 662 /** User/privileged mode protection flag for subsequent levels of 663 * lookup */ 664 uint8_t userTable() const 665 { 666 assert(type() == Table); 667 return !bits(data, 61); 668 } 669 670 /** Is execution allowed on subsequent lookup levels? */ 671 bool xnTable() const 672 { 673 assert(type() == Table); 674 return bits(data, 60); 675 } 676 677 /** Is privileged execution allowed on subsequent lookup levels? */ 678 bool pxnTable() const 679 { 680 assert(type() == Table); 681 return bits(data, 59); 682 } 683 }; 684 685 class WalkerState 686 { 687 public: 688 /** Thread context that we're doing the walk for */ 689 ThreadContext *tc; 690 691 /** If the access is performed in AArch64 state */ 692 bool aarch64; 693 694 /** Current exception level */ 695 ExceptionLevel el; 696 697 /** Current physical address range in bits */ 698 int physAddrRange; 699 700 /** Request that is currently being serviced */ 701 RequestPtr req; 702 703 /** ASID that we're servicing the request under */ 704 uint16_t asid; 705 uint8_t vmid; 706 bool isHyp; 707 708 /** Translation state for delayed requests */ 709 TLB::Translation *transState; 710 711 /** The fault that we are going to return */ 712 Fault fault; 713 714 /** The virtual address that is being translated with tagging removed.*/ 715 Addr vaddr; 716 717 /** The virtual address that is being translated */ 718 Addr vaddr_tainted; 719 720 /** Cached copy of the sctlr as it existed when translation began */ 721 SCTLR sctlr; 722 723 /** Cached copy of the scr as it existed when translation began */ 724 SCR scr; 725 726 /** Cached copy of the cpsr as it existed when translation began */ 727 CPSR cpsr; 728 729 /** Cached copy of ttbcr/tcr as it existed when translation began */ 730 union { 731 TTBCR ttbcr; // AArch32 translations 732 TCR tcr; // AArch64 translations 733 }; 734 735 /** Cached copy of the htcr as it existed when translation began. */ 736 HTCR htcr; 737 738 /** Cached copy of the htcr as it existed when translation began. */ 739 HCR hcr; 740 741 /** Cached copy of the vtcr as it existed when translation began. */ 742 VTCR_t vtcr; 743 744 /** If the access is a write */ 745 bool isWrite; 746 747 /** If the access is a fetch (for execution, and no-exec) must be checked?*/ 748 bool isFetch; 749 750 /** If the access comes from the secure state. */ 751 bool isSecure; 752 753 /** Helper variables used to implement hierarchical access permissions 754 * when the long-desc. format is used (LPAE only) */ 755 bool secureLookup; 756 bool rwTable; 757 bool userTable; 758 bool xnTable; 759 bool pxnTable; 760 761 /** Flag indicating if a second stage of lookup is required */ 762 bool stage2Req; 763 764 /** Indicates whether the translation has been passed onto the second 765 * stage mmu, and no more work is required from the first stage. 766 */ 767 bool doingStage2; 768 769 /** A pointer to the stage 2 translation that's in progress */ 770 TLB::Translation *stage2Tran; 771 772 /** If the mode is timing or atomic */ 773 bool timing; 774 775 /** If the atomic mode should be functional */ 776 bool functional; 777 778 /** Save mode for use in delayed response */ 779 BaseTLB::Mode mode; 780 781 /** The translation type that has been requested */ 782 TLB::ArmTranslationType tranType; 783 784 /** Short-format descriptors */ 785 L1Descriptor l1Desc; 786 L2Descriptor l2Desc; 787 788 /** Long-format descriptor (LPAE and AArch64) */ 789 LongDescriptor longDesc; 790 791 /** Whether the response is delayed in timing mode due to additional 792 * lookups */ 793 bool delayed; 794 795 TableWalker *tableWalker; 796 797 /** Timestamp for calculating elapsed time in service (for stats) */ 798 Tick startTime; 799 800 /** Page entries walked during service (for stats) */ 801 unsigned levels; 802 803 void doL1Descriptor(); 804 void doL2Descriptor(); 805 806 void doLongDescriptor(); 807 808 WalkerState(); 809 810 std::string name() const { return tableWalker->name(); } 811 }; 812 813 protected: 814 815 /** Queues of requests for all the different lookup levels */ 816 std::list<WalkerState *> stateQueues[MAX_LOOKUP_LEVELS]; 817 818 /** Queue of requests that have passed are waiting because the walker is 819 * currently busy. */ 820 std::list<WalkerState *> pendingQueue; 821 822 /** The MMU to forward second stage look upts to */ 823 Stage2MMU *stage2Mmu; 824 825 /** Port shared by the two table walkers. */ 826 DmaPort* port; 827 828 /** Master id assigned by the MMU. */ 829 MasterID masterId; 830 831 /** Indicates whether this table walker is part of the stage 2 mmu */ 832 const bool isStage2; 833 834 /** TLB that is initiating these table walks */ 835 TLB *tlb; 836 837 /** Cached copy of the sctlr as it existed when translation began */ 838 SCTLR sctlr; 839 840 WalkerState *currState; 841 842 /** If a timing translation is currently in progress */ 843 bool pending; 844 845 /** The number of walks belonging to squashed instructions that can be 846 * removed from the pendingQueue per cycle. */ 847 unsigned numSquashable; 848 849 /** Cached copies of system-level properties */ 850 bool haveSecurity; 851 bool _haveLPAE; 852 bool _haveVirtualization; 853 uint8_t physAddrRange; 854 bool _haveLargeAsid64; 855 856 /** Statistics */ 857 Stats::Scalar statWalks; 858 Stats::Scalar statWalksShortDescriptor; 859 Stats::Scalar statWalksLongDescriptor; 860 Stats::Vector statWalksShortTerminatedAtLevel; 861 Stats::Vector statWalksLongTerminatedAtLevel; 862 Stats::Scalar statSquashedBefore; 863 Stats::Scalar statSquashedAfter; 864 Stats::Histogram statWalkWaitTime; 865 Stats::Histogram statWalkServiceTime; 866 Stats::Histogram statPendingWalks; // essentially "L" of queueing theory 867 Stats::Vector statPageSizes; 868 Stats::Vector2d statRequestOrigin; 869 870 mutable unsigned pendingReqs; 871 mutable Tick pendingChangeTick; 872 873 static const unsigned REQUESTED = 0; 874 static const unsigned COMPLETED = 1; 875 876 public: 877 typedef ArmTableWalkerParams Params; 878 TableWalker(const Params *p); 879 virtual ~TableWalker(); 880 881 const Params * 882 params() const 883 { 884 return dynamic_cast<const Params *>(_params); 885 } 886 887 void init() override; 888 889 bool haveLPAE() const { return _haveLPAE; } 890 bool haveVirtualization() const { return _haveVirtualization; } 891 bool haveLargeAsid64() const { return _haveLargeAsid64; } 892 /** Checks if all state is cleared and if so, completes drain */ 893 void completeDrain(); 894 DrainState drain() override; 895 void drainResume() override; 896 897 BaseMasterPort& getMasterPort(const std::string &if_name, 898 PortID idx = InvalidPortID) override; 899 900 void regStats() override; 901 902 Fault walk(RequestPtr req, ThreadContext *tc, uint16_t asid, uint8_t _vmid, 903 bool _isHyp, TLB::Mode mode, TLB::Translation *_trans, 904 bool timing, bool functional, bool secure, 905 TLB::ArmTranslationType tranType); 906 907 void setTlb(TLB *_tlb) { tlb = _tlb; } 908 TLB* getTlb() { return tlb; } 909 void setMMU(Stage2MMU *m, MasterID master_id); 910 void memAttrs(ThreadContext *tc, TlbEntry &te, SCTLR sctlr, 911 uint8_t texcb, bool s); 912 void memAttrsLPAE(ThreadContext *tc, TlbEntry &te, 913 LongDescriptor &lDescriptor); 914 void memAttrsAArch64(ThreadContext *tc, TlbEntry &te, uint8_t attrIndx, 915 uint8_t sh); 916 917 static LookupLevel toLookupLevel(uint8_t lookup_level_as_int); 918 919 private: 920 921 void doL1Descriptor(); 922 void doL1DescriptorWrapper(); 923 EventWrapper<TableWalker, 924 &TableWalker::doL1DescriptorWrapper> doL1DescEvent; 925 926 void doL2Descriptor(); 927 void doL2DescriptorWrapper(); 928 EventWrapper<TableWalker, 929 &TableWalker::doL2DescriptorWrapper> doL2DescEvent; 930 931 void doLongDescriptor(); 932 933 void doL0LongDescriptorWrapper(); 934 EventWrapper<TableWalker, 935 &TableWalker::doL0LongDescriptorWrapper> doL0LongDescEvent; 936 void doL1LongDescriptorWrapper(); 937 EventWrapper<TableWalker, 938 &TableWalker::doL1LongDescriptorWrapper> doL1LongDescEvent; 939 void doL2LongDescriptorWrapper(); 940 EventWrapper<TableWalker, 941 &TableWalker::doL2LongDescriptorWrapper> doL2LongDescEvent; 942 void doL3LongDescriptorWrapper(); 943 EventWrapper<TableWalker, 944 &TableWalker::doL3LongDescriptorWrapper> doL3LongDescEvent; 945 946 void doLongDescriptorWrapper(LookupLevel curr_lookup_level); 947 948 bool fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes, 949 Request::Flags flags, int queueIndex, Event *event, 950 void (TableWalker::*doDescriptor)()); 951 952 void insertTableEntry(DescriptorBase &descriptor, bool longDescriptor); 953 954 Fault processWalk(); 955 Fault processWalkLPAE(); 956 static unsigned adjustTableSizeAArch64(unsigned tsz); 957 /// Returns true if the address exceeds the range permitted by the 958 /// system-wide setting or by the TCR_ELx IPS/PS setting 959 static bool checkAddrSizeFaultAArch64(Addr addr, int currPhysAddrRange); 960 Fault processWalkAArch64(); 961 void processWalkWrapper(); 962 EventWrapper<TableWalker, &TableWalker::processWalkWrapper> doProcessEvent; 963 964 void nextWalk(ThreadContext *tc); 965 966 void pendingChange(); 967 968 static uint8_t pageSizeNtoStatBin(uint8_t N); 969 970 Fault testWalk(Addr pa, Addr size, TlbEntry::DomainType domain, 971 LookupLevel lookup_level); 972}; 973 974} // namespace ArmISA 975 976#endif //__ARCH_ARM_TABLE_WALKER_HH__ 977 978