2c2
< * Copyright (c) 2010-2012 ARM Limited
---
> * Copyright (c) 2010-2013 ARM Limited
37a38
> * Giacomo Gabrielli
45a47
> #include "arch/arm/system.hh"
58a61
> class Stage2MMU;
63c66,93
< struct L1Descriptor {
---
> class WalkerState;
>
> class DescriptorBase {
> public:
> /** Current lookup level for this descriptor */
> LookupLevel lookupLevel;
>
> virtual Addr pfn() const = 0;
> virtual TlbEntry::DomainType domain() const = 0;
> virtual bool xn() const = 0;
> virtual uint8_t ap() const = 0;
> virtual bool global(WalkerState *currState) const = 0;
> virtual uint8_t offsetBits() const = 0;
> virtual bool secure(bool have_security, WalkerState *currState) const = 0;
> virtual std::string dbgHeader() const = 0;
> virtual uint64_t getRawData() const = 0;
> virtual uint8_t texcb() const
> {
> panic("texcb() not implemented for this class\n");
> }
> virtual bool shareable() const
> {
> panic("shareable() not implemented for this class\n");
> }
> };
>
> class L1Descriptor : public DescriptorBase {
> public:
78a109,129
> /** Default ctor */
> L1Descriptor()
> {
> lookupLevel = L1;
> }
>
> virtual uint64_t getRawData() const
> {
> return (data);
> }
>
> virtual std::string dbgHeader() const
> {
> return "Inserting Section Descriptor into TLB\n";
> }
>
> virtual uint8_t offsetBits() const
> {
> return 20;
> }
>
115c166
< bool global() const
---
> bool global(WalkerState *currState) const
117c168
< return bits(data, 17);
---
> return !bits(data, 17);
133c184
< uint8_t domain() const
---
> TlbEntry::DomainType domain() const
135c186
< return bits(data, 8, 5);
---
> return static_cast<TlbEntry::DomainType>(bits(data, 8, 5));
173a225,239
>
> /**
> * Returns true if this entry targets the secure physical address
> * map.
> */
> bool secure(bool have_security, WalkerState *currState) const
> {
> if (have_security) {
> if (type() == PageTable)
> return !bits(data, 3);
> else
> return !bits(data, 19);
> }
> return false;
> }
177,178c243,244
< struct L2Descriptor {
<
---
> class L2Descriptor : public DescriptorBase {
> public:
180c246,247
< uint32_t data;
---
> uint32_t data;
> L1Descriptor *l1Parent;
185a253,288
> /** Default ctor */
> L2Descriptor()
> {
> lookupLevel = L2;
> }
>
> L2Descriptor(L1Descriptor &parent) : l1Parent(&parent)
> {
> lookupLevel = L2;
> }
>
> virtual uint64_t getRawData() const
> {
> return (data);
> }
>
> virtual std::string dbgHeader() const
> {
> return "Inserting L2 Descriptor into TLB\n";
> }
>
> virtual TlbEntry::DomainType domain() const
> {
> return l1Parent->domain();
> }
>
> bool secure(bool have_security, WalkerState *currState) const
> {
> return l1Parent->secure(have_security, currState);
> }
>
> virtual uint8_t offsetBits() const
> {
> return large() ? 16 : 12;
> }
>
205c308
< bool global() const
---
> bool global(WalkerState *currState) const
262c365,374
< protected:
---
> /** Long-descriptor format (LPAE) */
> class LongDescriptor : public DescriptorBase {
> public:
> /** Descriptor type */
> enum EntryType {
> Invalid,
> Table,
> Block,
> Page
> };
264,269c376,377
< /**
< * A snooping DMA port that currently does nothing besides
< * extending the DMA port to accept snoops without complaining.
< */
< class SnoopingDmaPort : public DmaPort
< {
---
> /** The raw bits of the entry */
> uint64_t data;
271c379,381
< protected:
---
> /** This entry has been modified (access flag set) and needs to be
> * written back to memory */
> bool _dirty;
273,274c383,386
< virtual void recvTimingSnoopReq(PacketPtr pkt)
< { }
---
> virtual uint64_t getRawData() const
> {
> return (data);
> }
276,277c388,397
< virtual Tick recvAtomicSnoop(PacketPtr pkt)
< { return 0; }
---
> virtual std::string dbgHeader() const
> {
> if (type() == LongDescriptor::Page) {
> assert(lookupLevel == L3);
> return "Inserting Page descriptor into TLB\n";
> } else {
> assert(lookupLevel < L3);
> return "Inserting Block descriptor into TLB\n";
> }
> }
279,280c399,407
< virtual void recvFunctionalSnoop(PacketPtr pkt)
< { }
---
> /**
> * Returns true if this entry targets the secure physical address
> * map.
> */
> bool secure(bool have_security, WalkerState *currState) const
> {
> assert(type() == Block || type() == Page);
> return have_security && (currState->secureLookup && !bits(data, 5));
> }
282c409,410
< virtual bool isSnooping() const { return true; }
---
> /** True if the current lookup is performed in AArch64 state */
> bool aarch64;
284c412,413
< public:
---
> /** True if the granule size is 64 KB (AArch64 only) */
> bool largeGrain;
286,292c415,663
< /**
< * A snooping DMA port merely calls the construtor of the DMA
< * port.
< */
< SnoopingDmaPort(MemObject *dev, System *s) :
< DmaPort(dev, s)
< { }
---
> /** Width of the granule size in bits */
> int grainSize;
>
> /** Return the descriptor type */
> EntryType type() const
> {
> switch (bits(data, 1, 0)) {
> case 0x1:
> // In AArch64 blocks are not allowed at L0 for the 4 KB granule
> // and at L1 for the 64 KB granule
> if (largeGrain)
> return lookupLevel == L2 ? Block : Invalid;
> return lookupLevel == L0 || lookupLevel == L3 ? Invalid : Block;
> case 0x3:
> return lookupLevel == L3 ? Page : Table;
> default:
> return Invalid;
> }
> }
>
> /** Return the bit width of the page/block offset */
> uint8_t offsetBits() const
> {
> assert(type() == Block || type() == Page);
> if (largeGrain) {
> if (type() == Block)
> return 29 /* 512 MB */;
> return 16 /* 64 KB */; // type() == Page
> } else {
> if (type() == Block)
> return lookupLevel == L1 ? 30 /* 1 GB */ : 21 /* 2 MB */;
> return 12 /* 4 KB */; // type() == Page
> }
> }
>
> /** Return the physical frame, bits shifted right */
> Addr pfn() const
> {
> if (aarch64)
> return bits(data, 47, offsetBits());
> return bits(data, 39, offsetBits());
> }
>
> /** Return the complete physical address given a VA */
> Addr paddr(Addr va) const
> {
> int n = offsetBits();
> if (aarch64)
> return mbits(data, 47, n) | mbits(va, n - 1, 0);
> return mbits(data, 39, n) | mbits(va, n - 1, 0);
> }
>
> /** Return the physical address of the entry */
> Addr paddr() const
> {
> if (aarch64)
> return mbits(data, 47, offsetBits());
> return mbits(data, 39, offsetBits());
> }
>
> /** Return the address of the next page table */
> Addr nextTableAddr() const
> {
> assert(type() == Table);
> if (aarch64)
> return mbits(data, 47, grainSize);
> else
> return mbits(data, 39, 12);
> }
>
> /** Return the address of the next descriptor */
> Addr nextDescAddr(Addr va) const
> {
> assert(type() == Table);
> Addr pa = 0;
> if (aarch64) {
> int stride = grainSize - 3;
> int va_lo = stride * (3 - (lookupLevel + 1)) + grainSize;
> int va_hi = va_lo + stride - 1;
> pa = nextTableAddr() | (bits(va, va_hi, va_lo) << 3);
> } else {
> if (lookupLevel == L1)
> pa = nextTableAddr() | (bits(va, 29, 21) << 3);
> else // lookupLevel == L2
> pa = nextTableAddr() | (bits(va, 20, 12) << 3);
> }
> return pa;
> }
>
> /** Is execution allowed on this mapping? */
> bool xn() const
> {
> assert(type() == Block || type() == Page);
> return bits(data, 54);
> }
>
> /** Is privileged execution allowed on this mapping? (LPAE only) */
> bool pxn() const
> {
> assert(type() == Block || type() == Page);
> return bits(data, 53);
> }
>
> /** Contiguous hint bit. */
> bool contiguousHint() const
> {
> assert(type() == Block || type() == Page);
> return bits(data, 52);
> }
>
> /** Is the translation global (no asid used)? */
> bool global(WalkerState *currState) const
> {
> assert(currState && (type() == Block || type() == Page));
> if (!currState->aarch64 && (currState->isSecure &&
> !currState->secureLookup)) {
> return false; // ARM ARM issue C B3.6.3
> } else if (currState->aarch64) {
> if (currState->el == EL2 || currState->el == EL3) {
> return true; // By default translations are treated as global
> // in AArch64 EL2 and EL3
> } else if (currState->isSecure && !currState->secureLookup) {
> return false;
> }
> }
> return !bits(data, 11);
> }
>
> /** Returns true if the access flag (AF) is set. */
> bool af() const
> {
> assert(type() == Block || type() == Page);
> return bits(data, 10);
> }
>
> /** 2-bit shareability field */
> uint8_t sh() const
> {
> assert(type() == Block || type() == Page);
> return bits(data, 9, 8);
> }
>
> /** 2-bit access protection flags */
> uint8_t ap() const
> {
> assert(type() == Block || type() == Page);
> // Long descriptors only support the AP[2:1] scheme
> return bits(data, 7, 6);
> }
>
> /** Read/write access protection flag */
> bool rw() const
> {
> assert(type() == Block || type() == Page);
> return !bits(data, 7);
> }
>
> /** User/privileged level access protection flag */
> bool user() const
> {
> assert(type() == Block || type() == Page);
> return bits(data, 6);
> }
>
> /** Return the AP bits as compatible with the AP[2:0] format. Utility
> * function used to simplify the code in the TLB for performing
> * permission checks. */
> static uint8_t ap(bool rw, bool user)
> {
> return ((!rw) << 2) | (user << 1);
> }
>
> TlbEntry::DomainType domain() const
> {
> // Long-desc. format only supports Client domain
> assert(type() == Block || type() == Page);
> return TlbEntry::DomainType::Client;
> }
>
> /** Attribute index */
> uint8_t attrIndx() const
> {
> assert(type() == Block || type() == Page);
> return bits(data, 4, 2);
> }
>
> /** Memory attributes, only used by stage 2 translations */
> uint8_t memAttr() const
> {
> assert(type() == Block || type() == Page);
> return bits(data, 5, 2);
> }
>
> /** Set access flag that this entry has been touched. Mark the entry as
> * requiring a writeback, in the future. */
> void setAf()
> {
> data |= 1 << 10;
> _dirty = true;
> }
>
> /** This entry needs to be written back to memory */
> bool dirty() const
> {
> return _dirty;
> }
>
> /** Whether the subsequent levels of lookup are secure */
> bool secureTable() const
> {
> assert(type() == Table);
> return !bits(data, 63);
> }
>
> /** Two bit access protection flags for subsequent levels of lookup */
> uint8_t apTable() const
> {
> assert(type() == Table);
> return bits(data, 62, 61);
> }
>
> /** R/W protection flag for subsequent levels of lookup */
> uint8_t rwTable() const
> {
> assert(type() == Table);
> return !bits(data, 62);
> }
>
> /** User/privileged mode protection flag for subsequent levels of
> * lookup */
> uint8_t userTable() const
> {
> assert(type() == Table);
> return !bits(data, 61);
> }
>
> /** Is execution allowed on subsequent lookup levels? */
> bool xnTable() const
> {
> assert(type() == Table);
> return bits(data, 60);
> }
>
> /** Is privileged execution allowed on subsequent lookup levels? */
> bool pxnTable() const
> {
> assert(type() == Table);
> return bits(data, 59);
> }
295c666
< struct WalkerState //: public SimObject
---
> class WalkerState
296a668
> public:
299a672,680
> /** If the access is performed in AArch64 state */
> bool aarch64;
>
> /** Current exception level */
> ExceptionLevel el;
>
> /** Current physical address range in bits */
> int physAddrRange;
>
303,304c684,687
< /** Context ID that we're servicing the request under */
< uint8_t contextId;
---
> /** ASID that we're servicing the request under */
> uint16_t asid;
> uint8_t vmid;
> bool isHyp;
312c695
< /** The virtual address that is being translated */
---
> /** The virtual address that is being translated with tagging removed.*/
314a698,700
> /** The virtual address that is being translated */
> Addr vaddr_tainted;
>
318,319c704,705
< /** Width of the base address held in TTRB0 */
< uint32_t N;
---
> /** Cached copy of the scr as it existed when translation began */
> SCR scr;
320a707,721
> /** Cached copy of the cpsr as it existed when translation began */
> CPSR cpsr;
>
> /** Cached copy of the ttbcr as it existed when translation began. */
> TTBCR ttbcr;
>
> /** Cached copy of the htcr as it existed when translation began. */
> HTCR htcr;
>
> /** Cached copy of the htcr as it existed when translation began. */
> HCR hcr;
>
> /** Cached copy of the vtcr as it existed when translation began. */
> VTCR_t vtcr;
>
326a728,749
> /** If the access comes from the secure state. */
> bool isSecure;
>
> /** Helper variables used to implement hierarchical access permissions
> * when the long-desc. format is used (LPAE only) */
> bool secureLookup;
> bool rwTable;
> bool userTable;
> bool xnTable;
> bool pxnTable;
>
> /** Flag indicating if a second stage of lookup is required */
> bool stage2Req;
>
> /** Indicates whether the translation has been passed onto the second
> * stage mmu, and no more work is required from the first stage.
> */
> bool doingStage2;
>
> /** A pointer to the stage 2 translation that's in progress */
> TLB::Translation *stage2Tran;
>
335a759,762
> /** The translation type that has been requested */
> TLB::ArmTranslationType tranType;
>
> /** Short-format descriptors */
339c766,770
< /** Whether L1/L2 descriptor response is delayed in timing mode */
---
> /** Long-format descriptor (LPAE and AArch64) */
> LongDescriptor longDesc;
>
> /** Whether the response is delayed in timing mode due to additional
> * lookups */
347c778,782
< std::string name() const {return tableWalker->name();}
---
> void doLongDescriptor();
>
> WalkerState();
>
> std::string name() const { return tableWalker->name(); }
349a785
> protected:
351,352c787,792
< /** Queue of requests that need processing first level translation */
< std::list<WalkerState *> stateQueueL1;
---
> /**
> * A snooping DMA port that currently does nothing besides
> * extending the DMA port to accept snoops without complaining.
> */
> class SnoopingDmaPort : public DmaPort
> {
354,356c794
< /** Queue of requests that have passed first level translation and
< * require an additional level. */
< std::list<WalkerState *> stateQueueL2;
---
> protected:
357a796,820
> virtual void recvTimingSnoopReq(PacketPtr pkt)
> { }
>
> virtual Tick recvAtomicSnoop(PacketPtr pkt)
> { return 0; }
>
> virtual void recvFunctionalSnoop(PacketPtr pkt)
> { }
>
> virtual bool isSnooping() const { return true; }
>
> public:
>
> /**
> * A snooping DMA port merely calls the construtor of the DMA
> * port.
> */
> SnoopingDmaPort(MemObject *dev, System *s) :
> DmaPort(dev, s)
> { }
> };
>
> /** Queues of requests for all the different lookup levels */
> std::list<WalkerState *> stateQueues[MAX_LOOKUP_LEVELS];
>
368a832,837
> /** The MMU to forward second stage look upts to */
> Stage2MMU *stage2Mmu;
>
> /** Indicates whether this table walker is part of the stage 2 mmu */
> const bool isStage2;
>
386a856,863
> /** Cached copies of system-level properties */
> bool haveSecurity;
> bool _haveLPAE;
> bool _haveVirtualization;
> uint8_t physAddrRange;
> bool _haveLargeAsid64;
> ArmSystem *armSys;
>
388c865
< typedef ArmTableWalkerParams Params;
---
> typedef ArmTableWalkerParams Params;
397a875,877
> bool haveLPAE() const { return _haveLPAE; }
> bool haveVirtualization() const { return _haveVirtualization; }
> bool haveLargeAsid64() const { return _haveLargeAsid64; }
401c881
< void drainResume();
---
> virtual void drainResume();
405,406c885,892
< Fault walk(RequestPtr req, ThreadContext *tc, uint8_t cid, TLB::Mode mode,
< TLB::Translation *_trans, bool timing, bool functional = false);
---
> /**
> * Allow the MMU (overseeing both stage 1 and stage 2 TLBs) to
> * access the table walker port through the TLB so that it can
> * orchestrate staged translations.
> *
> * @return Our DMA port
> */
> DmaPort& getWalkerPort() { return port; }
407a894,898
> Fault walk(RequestPtr req, ThreadContext *tc, uint16_t asid, uint8_t _vmid,
> bool _isHyp, TLB::Mode mode, TLB::Translation *_trans,
> bool timing, bool functional, bool secure,
> TLB::ArmTranslationType tranType);
>
408a900,901
> TLB* getTlb() { return tlb; }
> void setMMU(Stage2MMU *m) { stage2Mmu = m; }
410a904,907
> void memAttrsLPAE(ThreadContext *tc, TlbEntry &te,
> LongDescriptor &lDescriptor);
> void memAttrsAArch64(ThreadContext *tc, TlbEntry &te, uint8_t attrIndx,
> uint8_t sh);
411a909,910
> static LookupLevel toLookupLevel(uint8_t lookup_level_as_int);
>
416c915,916
< EventWrapper<TableWalker, &TableWalker::doL1DescriptorWrapper> doL1DescEvent;
---
> EventWrapper<TableWalker,
> &TableWalker::doL1DescriptorWrapper> doL1DescEvent;
420c920,921
< EventWrapper<TableWalker, &TableWalker::doL2DescriptorWrapper> doL2DescEvent;
---
> EventWrapper<TableWalker,
> &TableWalker::doL2DescriptorWrapper> doL2DescEvent;
421a923,945
> void doLongDescriptor();
>
> void doL0LongDescriptorWrapper();
> EventWrapper<TableWalker,
> &TableWalker::doL0LongDescriptorWrapper> doL0LongDescEvent;
> void doL1LongDescriptorWrapper();
> EventWrapper<TableWalker,
> &TableWalker::doL1LongDescriptorWrapper> doL1LongDescEvent;
> void doL2LongDescriptorWrapper();
> EventWrapper<TableWalker,
> &TableWalker::doL2LongDescriptorWrapper> doL2LongDescEvent;
> void doL3LongDescriptorWrapper();
> EventWrapper<TableWalker,
> &TableWalker::doL3LongDescriptorWrapper> doL3LongDescEvent;
>
> void doLongDescriptorWrapper(LookupLevel curr_lookup_level);
>
> bool fetchDescriptor(Addr descAddr, uint8_t *data, int numBytes,
> Request::Flags flags, int queueIndex, Event *event,
> void (TableWalker::*doDescriptor)());
>
> void insertTableEntry(DescriptorBase &descriptor, bool longDescriptor);
>
422a947,952
> Fault processWalkLPAE();
> static unsigned adjustTableSizeAArch64(unsigned tsz);
> /// Returns true if the address exceeds the range permitted by the
> /// system-wide setting or by the TCR_ELx IPS/PS setting
> static bool checkAddrSizeFaultAArch64(Addr addr, int currPhysAddrRange);
> Fault processWalkAArch64();
429d958
<