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