blob: fc9b68f0be0d1d8501ff52938e693966b3c15dfe [file] [log] [blame]
/*
* Copyright (c) 2010-2013, 2016, 2019-2022 Arm Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ARCH_ARM_TLB_HH__
#define __ARCH_ARM_TLB_HH__
#include "arch/arm/faults.hh"
#include "arch/arm/pagetable.hh"
#include "arch/arm/utility.hh"
#include "arch/generic/tlb.hh"
#include "base/statistics.hh"
#include "enums/TypeTLB.hh"
#include "mem/request.hh"
#include "params/ArmTLB.hh"
#include "sim/probe/pmu.hh"
namespace gem5
{
class ThreadContext;
namespace ArmISA {
class TableWalker;
class TLB;
class TLBIOp;
class TlbTestInterface
{
public:
TlbTestInterface() {}
virtual ~TlbTestInterface() {}
/**
* Check if a TLB translation should be forced to fail.
*
* @param req Request requiring a translation.
* @param is_priv Access from a privileged mode (i.e., not EL0)
* @param mode Access type
* @param domain Domain type
*/
virtual Fault translationCheck(const RequestPtr &req, bool is_priv,
BaseMMU::Mode mode,
TlbEntry::DomainType domain) = 0;
/**
* Check if a page table walker access should be forced to fail.
*
* @param pa Physical address the walker is accessing
* @param size Walker access size
* @param va Virtual address that initiated the walk
* @param is_secure Access from secure state
* @param is_priv Access from a privileged mode (i.e., not EL0)
* @param mode Access type
* @param domain Domain type
* @param lookup_level Page table walker level
*/
virtual Fault walkCheck(Addr pa, Addr size, Addr va, bool is_secure,
Addr is_priv, BaseMMU::Mode mode,
TlbEntry::DomainType domain,
enums::ArmLookupLevel lookup_level) = 0;
};
class TLB : public BaseTLB
{
protected:
TlbEntry* table;
/** TLB Size */
int size;
/** Indicates this TLB caches IPA->PA translations */
bool isStage2;
/**
* Hash map containing one entry per lookup level
* The TLB is caching partial translations from the key lookup level
* if the matching value is true.
*/
std::unordered_map<enums::ArmLookupLevel, bool> partialLevels;
/**
* True if the TLB caches partial translations
*/
bool _walkCache;
TableWalker *tableWalker;
struct TlbStats : public statistics::Group
{
TlbStats(TLB &parent);
const TLB &tlb;
// Access Stats
mutable statistics::Scalar partialHits;
mutable statistics::Scalar instHits;
mutable statistics::Scalar instMisses;
mutable statistics::Scalar readHits;
mutable statistics::Scalar readMisses;
mutable statistics::Scalar writeHits;
mutable statistics::Scalar writeMisses;
mutable statistics::Scalar inserts;
mutable statistics::Scalar flushTlb;
mutable statistics::Scalar flushedEntries;
statistics::Formula readAccesses;
statistics::Formula writeAccesses;
statistics::Formula instAccesses;
statistics::Formula hits;
statistics::Formula misses;
statistics::Formula accesses;
} stats;
/** PMU probe for TLB refills */
probing::PMUUPtr ppRefills;
int rangeMRU; //On lookup, only move entries ahead when outside rangeMRU
vmid_t vmid;
public:
using Params = ArmTLBParams;
using Lookup = TlbEntry::Lookup;
using LookupLevel = enums::ArmLookupLevel;
TLB(const Params &p);
TLB(const Params &p, int _size, TableWalker *_walker);
/** Lookup an entry in the TLB
* @return pointer to TLB entry if it exists
*/
TlbEntry *lookup(const Lookup &lookup_data);
/** Lookup an entry in the TLB and in the next levels by
* following the nextLevel pointer
*
* @param mode to differentiate between read/writes/fetches.
* @return pointer to TLB entry if it exists
*/
TlbEntry *multiLookup(const Lookup &lookup_data);
virtual ~TLB();
void takeOverFrom(BaseTLB *otlb) override;
void setTableWalker(TableWalker *table_walker);
TableWalker *getTableWalker() { return tableWalker; }
int getsize() const { return size; }
bool walkCache() const { return _walkCache; }
void setVMID(vmid_t _vmid) { vmid = _vmid; }
/** Insert a PTE in the current TLB */
void insert(TlbEntry &pte);
/** Insert a PTE in the current TLB and in the higher levels */
void multiInsert(TlbEntry &pte);
/** Reset the entire TLB. Used for CPU switching to prevent stale
* translations after multiple switches
*/
void flushAll() override;
/** Flush TLB entries
*/
void flush(const TLBIOp &tlbi_op);
Fault trickBoxCheck(const RequestPtr &req, BaseMMU::Mode mode,
TlbEntry::DomainType domain);
Fault walkTrickBoxCheck(Addr pa, bool is_secure, Addr va, Addr sz,
bool is_exec, bool is_write,
TlbEntry::DomainType domain,
LookupLevel lookup_level);
void printTlb() const;
void demapPage(Addr vaddr, uint64_t asn) override
{
// needed for x86 only
panic("demapPage() is not implemented.\n");
}
Fault
translateAtomic(const RequestPtr &req, ThreadContext *tc,
BaseMMU::Mode mode) override
{
panic("unimplemented");
}
void
translateTiming(const RequestPtr &req, ThreadContext *tc,
BaseMMU::Translation *translation,
BaseMMU::Mode mode) override
{
panic("unimplemented");
}
Fault
finalizePhysical(const RequestPtr &req, ThreadContext *tc,
BaseMMU::Mode mode) const override
{
panic("unimplemented");
}
void regProbePoints() override;
/**
* Get the table walker port. This is used for migrating
* port connections during a CPU takeOverFrom() call. For
* architectures that do not have a table walker, NULL is
* returned, hence the use of a pointer rather than a
* reference. For ARM this method will always return a valid port
* pointer.
*
* @return A pointer to the walker request port
*/
Port *getTableWalkerPort() override;
// Caching misc register values here.
// Writing to misc registers needs to invalidate them.
// translateFunctional/translateSe/translateFs checks if they are
// invalid and call updateMiscReg if necessary.
private:
/** Remove any entries that match both a va and asn
* @param mva virtual address to flush
* @param asn contextid/asn to flush on match
* @param secure_lookup if the operation affects the secure world
* @param ignore_asn if the flush should ignore the asn
* @param in_host if hcr.e2h == 1 and hcr.tge == 1 for VHE.
* @param entry_type type of entry to flush (instruction/data/unified)
*/
void _flushMva(Addr mva, uint64_t asn, bool secure_lookup,
bool ignore_asn, ExceptionLevel target_el,
bool in_host, TypeTLB entry_type);
/** Check if the tlb entry passed as an argument needs to
* be "promoted" as a unified entry:
* this should happen if we are hitting an instruction TLB entry on a
* data access or a data TLB entry on an instruction access:
*/
void checkPromotion(TlbEntry *entry, BaseMMU::Mode mode);
/** Helper function looking up for a matching TLB entry
* Does not update stats; see lookup method instead */
TlbEntry *match(const Lookup &lookup_data);
};
} // namespace ArmISA
} // namespace gem5
#endif // __ARCH_ARM_TLB_HH__