arch-arm: Implement FEAT_MPAM in CPU (#1082)

This PR implements FEAT_MPAM on the CPU side. We define a MPAM system
registers and a mechanism
for tagging memory requests with the MPAM information bundle as
specified in existing documentation [1].

What this PR is *not* covering is the MPAM implementation in a MSC
(Memory System Component).
Which means at the moment it's only possible to have static partitioning
schemes (via the PartitioningPolicies
already part of gem5) and there is currently no way to dynamically
program partitions at runtime.

[1]: https://developer.arm.com/documentation/ddi0487/latest/
This commit is contained in:
Ivana Mitrovic
2024-05-13 08:56:23 -07:00
committed by GitHub
14 changed files with 577 additions and 15 deletions

View File

@@ -170,6 +170,10 @@ class ArmISA(BaseISA):
0x0000000000010010, "AArch64 Memory Model Feature Register 2"
)
# HAS_SDEFLT | HAS_FORCE_NS | HAS_TIDR | PMG_MAX = 128 |
# VPMR_MAX = 7 | HAS_HCR | PARTID_MAX = 256
mpamidr_el1 = Param.UInt64(0x34000080001E0100, "MPAM ID Register (EL1)")
# Any access (read/write) to an unimplemented
# Implementation Defined registers is not causing an Undefined Instruction.
# It is rather executed as a NOP.

View File

@@ -115,6 +115,7 @@ class ArmExtension(ScopedEnum):
"LPAE",
"VIRTUALIZATION",
"TME",
"FEAT_MPAM",
]

View File

@@ -1,6 +1,6 @@
# -*- mode:python -*-
# Copyright (c) 2009, 2012-2013, 2017-2018, 2020 ARM Limited
# Copyright (c) 2009, 2012-2013, 2017-2018, 2020, 2024 Arm Limited
# All rights reserved.
#
# The license below extends only to copyright in the software and shall
@@ -134,6 +134,7 @@ SimObject('ArmCPU.py', sim_objects=[], tags='arm isa')
DebugFlag('Arm', tags='arm isa')
DebugFlag('ArmTme', 'Transactional Memory Extension', tags='arm isa')
DebugFlag('MPAM', 'MPAM debug flag', tags='arm isa')
DebugFlag('PMUVerbose', "Performance Monitor", tags='arm isa')
# Add files generated by the ISA description.

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2023 Arm Limited
* Copyright (c) 2010-2024 Arm Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -44,6 +44,7 @@
#include "arch/arm/mmu.hh"
#include "arch/arm/pmu.hh"
#include "arch/arm/regs/misc.hh"
#include "arch/arm/regs/misc_accessors.hh"
#include "arch/arm/self_debug.hh"
#include "arch/arm/system.hh"
#include "arch/arm/utility.hh"
@@ -72,6 +73,8 @@ namespace gem5
namespace ArmISA
{
using namespace misc_regs;
namespace
{
@@ -106,6 +109,7 @@ ISA::ISA(const Params &p) : BaseISA(p, "arm"), system(NULL),
// Cache system-level properties
if (FullSystem && system) {
highestELIs64 = system->highestELIs64();
highestEL = system->highestEL();
haveLargeAsid64 = system->haveLargeAsid64();
physAddrRange = system->physAddrRange();
sveVL = system->sveVL();
@@ -114,6 +118,7 @@ ISA::ISA(const Params &p) : BaseISA(p, "arm"), system(NULL),
release = system->releaseFS();
} else {
highestELIs64 = true; // ArmSystem::highestELIs64 does the same
highestEL = EL1; // ArmSystem::highestEL does the same
haveLargeAsid64 = false;
physAddrRange = 32; // dummy value
sveVL = p.sve_vl_se;
@@ -267,6 +272,8 @@ ISA::redirectRegVHE(int misc_reg)
return currEL() == EL2 ? MISCREG_CONTEXTIDR_EL2 : misc_reg;
case MISCREG_CNTKCTL_EL1:
return currEL() == EL2 ? MISCREG_CNTHCTL_EL2 : misc_reg;
case MISCREG_MPAM1_EL1:
return currEL() == EL2 ? MISCREG_MPAM2_EL2 : misc_reg;
case MISCREG_CNTP_TVAL:
case MISCREG_CNTP_TVAL_EL0:
if (ELIsInHost(tc, currEL())) {
@@ -356,6 +363,8 @@ ISA::redirectRegVHE(int misc_reg)
return MISCREG_CONTEXTIDR_EL1;
case MISCREG_CNTKCTL_EL12:
return MISCREG_CNTKCTL_EL1;
case MISCREG_MPAM1_EL12:
return MISCREG_MPAM1_EL1;
// _EL02 registers
case MISCREG_CNTP_TVAL_EL02:
return MISCREG_CNTP_TVAL_EL0;
@@ -600,6 +609,23 @@ ISA::readMiscReg(RegIndex idx)
case MISCREG_HIFAR: // alias for secure IFAR
return readMiscRegNoEffect(MISCREG_IFAR_S);
case MISCREG_MPAM1_EL1:
{
MPAM mpam1 = readMiscRegNoEffect(MISCREG_MPAM1_EL1);
mpam1.mpamEn = readRegisterNoEffect<MpamAccessor>(
tc, highestEL).mpamEn;
mpam1.el1.forcedNs = isSecure(tc) ?
readRegisterNoEffect<MpamAccessor>(tc, EL3).el3.forceNs : 0;
return mpam1;
}
case MISCREG_MPAM2_EL2:
{
MPAM mpam2 = readMiscRegNoEffect(MISCREG_MPAM2_EL2);
mpam2.mpamEn = readRegisterNoEffect<MpamAccessor>(
tc, highestEL).mpamEn;
return mpam2;
}
case MISCREG_RNDR:
tc->setReg(cc_reg::Nz, (RegVal)0);
tc->setReg(cc_reg::C, (RegVal)0);
@@ -731,8 +757,8 @@ ISA::setMiscReg(RegIndex idx, RegVal val)
const uint32_t ones = (uint32_t)(-1);
CPACR cpacrMask = 0;
// Only cp10, cp11, and ase are implemented, nothing else should
// be writable
// Only cp10, cp11, and ase are implemented
// nothing else should be writable
cpacrMask.cp10 = ones;
cpacrMask.cp11 = ones;
cpacrMask.asedis = ones;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2012-2023 Arm Limited
* Copyright (c) 2010, 2012-2024 Arm Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -90,6 +90,7 @@ namespace ArmISA
// Cached copies of system-level properties
bool highestELIs64;
ExceptionLevel highestEL;
bool haveLargeAsid64;
uint8_t physAddrRange;

View File

@@ -41,6 +41,7 @@
#include "arch/arm/mmu.hh"
#include "arch/arm/isa.hh"
#include "arch/arm/mpam.hh"
#include "arch/arm/reg_abi.hh"
#include "arch/arm/stage2_lookup.hh"
#include "arch/arm/table_walker.hh"
@@ -208,6 +209,8 @@ MMU::testAndFinalize(const RequestPtr &req,
// is not enabled
auto domain = te ? te-> domain : TlbEntry::DomainType::NoAccess;
mpam::tagRequest(tc, req, mode == Execute);
// Check for a tester generated address fault
Fault fault = testTranslation(req, mode, domain, state);
if (fault != NoFault) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 ARM Limited
* Copyright (c) 2024 Arm Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -35,8 +35,20 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <optional>
#include "arch/arm/mpam.hh"
#include "arch/arm/regs/misc.hh"
#include "arch/arm/regs/misc_accessors.hh"
#include "arch/arm/regs/misc_types.hh"
#include "arch/arm/system.hh"
#include "arch/arm/types.hh"
#include "arch/arm/utility.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "debug/MPAM.hh"
namespace gem5::ArmISA::mpam
{
@@ -58,6 +70,12 @@ PartitionFieldExtension::getPartitionMonitoringID() const
return this->_partitionMonitoringID;
}
bool
PartitionFieldExtension::getMpamNS() const
{
return this->_ns;
}
void
PartitionFieldExtension::setPartitionID(uint64_t id)
{
@@ -70,4 +88,180 @@ PartitionFieldExtension::setPartitionMonitoringID(uint64_t id)
this->_partitionMonitoringID = id;
}
void
PartitionFieldExtension::setMpamNS(bool ns)
{
this->_ns = ns;
}
namespace
{
using namespace misc_regs;
static PartID
getPARTID(ThreadContext *tc, ExceptionLevel el, bool ind)
{
MPAM reg = readRegister<MpamAccessor>(tc, el);
return ind ? reg.partidI : reg.partidD;
}
static PMG
getPMG(ThreadContext *tc, ExceptionLevel el, bool ind)
{
MPAM reg = readRegister<MpamAccessor>(tc, el);
return ind ? reg.pmgI : reg.pmgD;
}
static bool
useVirtualPartitions(ThreadContext *tc, ExceptionLevel el, MPAMIDR mpamidr)
{
const MPAMHCR mpamhcr = tc->readMiscReg(MISCREG_MPAMHCR_EL2);
return mpamidr.hasHcr && EL2Enabled(tc) &&
((el == EL0 && !ELIsInHost(tc, EL0) && mpamhcr.el0Vpmen) || // EL0 case
(el == EL1 && mpamhcr.el1Vpmen)); // EL1 case
}
static PartID
mapVpmv(ThreadContext *tc, PartID vpartid)
{
uint8_t reg_index = vpartid / 4;
uint8_t reg_field = vpartid % 4;
// Register field size in bits
size_t reg_field_size = sizeof(PartID) * 8;
// LSB of the register field (Every field is 16bits)
uint8_t lsb = reg_field * reg_field_size;
uint8_t msb = lsb + reg_field_size - 1;
const RegVal vpmv = tc->readMiscReg(MISCREG_MPAMVPM0_EL2 + reg_index);
return bits(vpmv, msb ,lsb);
}
static std::optional<PartID>
virtToPhysPart(ThreadContext *tc, PartID vpartid, MPAMIDR mpamidr)
{
// vpmrMax refers to the register index. Extract vpartid max
const uint8_t vpartid_max = (mpamidr.vpmrMax << 2) + 3;
const RegVal mpam_vpmv = tc->readMiscReg(MISCREG_MPAMVPMV_EL2);
if (vpartid > vpartid_max) {
vpartid = vpartid % (vpartid_max + 1);
}
PartID phys_partid = 0;
if (bits(mpam_vpmv, vpartid)) {
// Valid mapping entry for virtual partition vpartid
phys_partid = mapVpmv(tc, vpartid);
} else if (bits(mpam_vpmv, 0)) {
// Default virtual partition valid
phys_partid = mapVpmv(tc, 0);
} else {
// Error
return std::nullopt;
}
return phys_partid > mpamidr.partidMax ?
std::nullopt : std::make_optional(phys_partid);
}
static std::optional<PartID>
genPARTID(ThreadContext *tc, ExceptionLevel el, bool ind)
{
const MPAMIDR mpamidr = tc->readMiscReg(MISCREG_MPAMIDR_EL1);
auto partid = getPARTID(tc, el, ind);
if (partid > mpamidr.partidMax) {
return std::nullopt;
} else if (useVirtualPartitions(tc, el, mpamidr)) {
return virtToPhysPart(tc, partid, mpamidr);
} else {
return partid;
}
}
static std::optional<PMG>
genPMG(ThreadContext *tc, ExceptionLevel el, bool ind)
{
const MPAMIDR mpamidr = tc->readMiscReg(MISCREG_MPAMIDR_EL1);
PMG pgroup = getPMG(tc, el, ind);
return pgroup > mpamidr.pmgMax ? std::nullopt : std::make_optional(pgroup);
}
static bool
isEnabled(ThreadContext *tc)
{
MPAM reg = readRegister<MpamAccessor>(tc, ArmSystem::highestEL(tc));
return reg.mpamEn;
}
static std::shared_ptr<PartitionFieldExtension>
genExtensionDefault()
{
// tag with partID data
auto ext = std::make_shared<PartitionFieldExtension>();
ext->setPartitionID(DEFAULT_PARTITION_ID);
ext->setPartitionMonitoringID(DEFAULT_PARTITION_MONITORING_ID);
return ext;
}
static std::shared_ptr<PartitionFieldExtension>
genExtension(ThreadContext *tc, bool ind)
{
ExceptionLevel curr_el = currEL(tc);
const MPAMHCR mpamhcr = tc->readMiscReg(MISCREG_MPAMHCR_EL2);
const HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2);
bool gstplk = curr_el == EL0 && EL2Enabled(tc) &&
mpamhcr.gstappPlk && !hcr.tge;
if (gstplk) {
curr_el = EL1;
}
// tag with partID data
auto ext = std::make_shared<
PartitionFieldExtension>();
auto part_id = genPARTID(tc, curr_el, ind).value_or(
DEFAULT_PARTITION_ID);
auto part_mon_id = genPMG(tc, curr_el, ind).value_or(
DEFAULT_PARTITION_MONITORING_ID);
ext->setPartitionID(part_id);
ext->setPartitionMonitoringID(part_mon_id);
return ext;
}
} // namespace
void
tagRequest(ThreadContext *tc, const RequestPtr &req, bool ind)
{
if (!HaveExt(tc, ArmExtension::FEAT_MPAM) || !isEnabled(tc))
return;
const MPAMIDR mpamidr = tc->readMiscReg(MISCREG_MPAMIDR_EL1);
const MPAM mpam3 = tc->readMiscReg(MISCREG_MPAM3_EL3);
auto ext = mpamidr.hasSdeflt && mpam3.el3.sdeflt && isSecure(tc) ?
genExtensionDefault() :
genExtension(tc, ind);
DPRINTFS(MPAM, tc->getCpuPtr(),
"MPAM Tagging req %#x => PART_ID: %d, PART_MON_ID: %d\n",
req->getPaddr(),
ext->getPartitionID(),
ext->getPartitionMonitoringID());
bool mpam_ns = !isSecure(tc);
if (!mpam_ns && mpam3.el3.forceNs) {
mpam_ns = true;
}
ext->setMpamNS(mpam_ns);
req->setExtension(ext);
}
} // namespace gem5::ArmISA::mpam

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 ARM Limited
* Copyright (c) 2024 Arm Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -67,6 +67,13 @@ class PartitionFieldExtension : public Extension<Request,
*/
uint64_t getPartitionMonitoringID() const;
/**
* MPAM_NS getter
* @return True if targeting Non-Secure MPAM partition
*/
bool getMpamNS() const;
/**
* _partitionID setter
* @param id Partition ID to set for the extension
@@ -79,11 +86,31 @@ class PartitionFieldExtension : public Extension<Request,
*/
void setPartitionMonitoringID(uint64_t id);
/**
* MPAM_NS setter
* @param ns True if targeting Non-Secure MPAM partition
*/
void setMpamNS(bool ns);
private:
uint64_t _partitionID = DEFAULT_PARTITION_ID;
uint64_t _partitionMonitoringID = DEFAULT_PARTITION_MONITORING_ID;
bool _ns = true;
};
/** Partition ID data type */
using PartID = uint16_t;
/** Partition Manager data type */
using PMG = uint8_t;
/** Tag a memory request with MPAM information
* @param tc pointer to the ThreadContext
* @param req reference to the pointer of the memory request to be tagged
* @param ind "instruction not data" to differentiate between
* a fetch request and a data memory access
*/
void tagRequest(ThreadContext *tc, const RequestPtr &req, bool ind);
} // namespace gem5::ArmISA::mpam
#endif // __ARCH_ARM_MPAM_HH__

View File

@@ -41,11 +41,12 @@
#include "arch/arm/insts/misc64.hh"
#include "arch/arm/isa.hh"
#include "base/bitfield.hh"
#include "base/logging.hh"
#include "cpu/thread_context.hh"
#include "dev/arm/gic_v3_cpu_interface.hh"
#include "sim/full_system.hh"
#include "params/ArmISA.hh"
#include "sim/full_system.hh"
namespace gem5
{
@@ -735,7 +736,6 @@ checkFaultAccessAArch64SysReg(MiscRegIndex reg, CPSR cpsr,
std::vector<struct MiscRegLUTEntry> lookUpMiscReg(NUM_MISCREGS);
namespace {
// The map is translating a MiscRegIndex into AArch64 system register
// numbers (op0, op1, crn, crm, op2)
std::unordered_map<MiscRegIndex, MiscRegNum64> idxToMiscRegNum;
@@ -1032,6 +1032,9 @@ std::unordered_map<MiscRegNum64, MiscRegIndex> miscRegNumToIdx{
{ MiscRegNum64(3, 0, 9, 14, 2), MISCREG_PMINTENCLR_EL1 },
{ MiscRegNum64(3, 0, 10, 2, 0), MISCREG_MAIR_EL1 },
{ MiscRegNum64(3, 0, 10, 3, 0), MISCREG_AMAIR_EL1 },
{ MiscRegNum64(3, 0, 10, 4, 4), MISCREG_MPAMIDR_EL1 },
{ MiscRegNum64(3, 0, 10, 5, 0), MISCREG_MPAM1_EL1 },
{ MiscRegNum64(3, 0, 10, 5, 1), MISCREG_MPAM0_EL1 },
{ MiscRegNum64(3, 0, 10, 5, 3), MISCREG_MPAMSM_EL1 },
{ MiscRegNum64(3, 0, 12, 0, 0), MISCREG_VBAR_EL1 },
{ MiscRegNum64(3, 0, 12, 0, 1), MISCREG_RVBAR_EL1 },
@@ -1181,6 +1184,17 @@ std::unordered_map<MiscRegNum64, MiscRegIndex> miscRegNumToIdx{
{ MiscRegNum64(3, 4, 6, 0, 4), MISCREG_HPFAR_EL2 },
{ MiscRegNum64(3, 4, 10, 2, 0), MISCREG_MAIR_EL2 },
{ MiscRegNum64(3, 4, 10, 3, 0), MISCREG_AMAIR_EL2 },
{ MiscRegNum64(3, 4, 10, 4, 0), MISCREG_MPAMHCR_EL2 },
{ MiscRegNum64(3, 4, 10, 4, 1), MISCREG_MPAMVPMV_EL2 },
{ MiscRegNum64(3, 4, 10, 5, 0), MISCREG_MPAM2_EL2 },
{ MiscRegNum64(3, 4, 10, 6, 0), MISCREG_MPAMVPM0_EL2 },
{ MiscRegNum64(3, 4, 10, 6, 1), MISCREG_MPAMVPM1_EL2 },
{ MiscRegNum64(3, 4, 10, 6, 2), MISCREG_MPAMVPM2_EL2 },
{ MiscRegNum64(3, 4, 10, 6, 3), MISCREG_MPAMVPM3_EL2 },
{ MiscRegNum64(3, 4, 10, 6, 4), MISCREG_MPAMVPM4_EL2 },
{ MiscRegNum64(3, 4, 10, 6, 5), MISCREG_MPAMVPM5_EL2 },
{ MiscRegNum64(3, 4, 10, 6, 6), MISCREG_MPAMVPM6_EL2 },
{ MiscRegNum64(3, 4, 10, 6, 7), MISCREG_MPAMVPM7_EL2 },
{ MiscRegNum64(3, 4, 12, 0, 0), MISCREG_VBAR_EL2 },
{ MiscRegNum64(3, 4, 12, 0, 1), MISCREG_RVBAR_EL2 },
{ MiscRegNum64(3, 4, 12, 1, 1), MISCREG_VDISR_EL2 },
@@ -1248,6 +1262,7 @@ std::unordered_map<MiscRegNum64, MiscRegIndex> miscRegNumToIdx{
{ MiscRegNum64(3, 5, 6, 0, 0), MISCREG_FAR_EL12 },
{ MiscRegNum64(3, 5, 10, 2, 0), MISCREG_MAIR_EL12 },
{ MiscRegNum64(3, 5, 10, 3, 0), MISCREG_AMAIR_EL12 },
{ MiscRegNum64(3, 5, 10, 5, 0), MISCREG_MPAM1_EL12 },
{ MiscRegNum64(3, 5, 12, 0, 0), MISCREG_VBAR_EL12 },
{ MiscRegNum64(3, 5, 13, 0, 1), MISCREG_CONTEXTIDR_EL12 },
{ MiscRegNum64(3, 5, 14, 1, 0), MISCREG_CNTKCTL_EL12 },
@@ -1277,6 +1292,7 @@ std::unordered_map<MiscRegNum64, MiscRegIndex> miscRegNumToIdx{
{ MiscRegNum64(3, 6, 6, 0, 0), MISCREG_FAR_EL3 },
{ MiscRegNum64(3, 6, 10, 2, 0), MISCREG_MAIR_EL3 },
{ MiscRegNum64(3, 6, 10, 3, 0), MISCREG_AMAIR_EL3 },
{ MiscRegNum64(3, 6, 10, 5, 0), MISCREG_MPAM3_EL3 },
{ MiscRegNum64(3, 6, 12, 0, 0), MISCREG_VBAR_EL3 },
{ MiscRegNum64(3, 6, 12, 0, 1), MISCREG_RVBAR_EL3 },
{ MiscRegNum64(3, 6, 12, 0, 2), MISCREG_RMR_EL3 },
@@ -2620,6 +2636,113 @@ faultIdst(const MiscRegLUTEntry &entry,
}
}
Fault
faultMpamIdrEL1(const MiscRegLUTEntry &entry,
ThreadContext *tc, const MiscRegOp64 &inst)
{
if (HaveExt(tc, ArmExtension::FEAT_MPAM)) {
MPAM mpam2 = tc->readMiscReg(MISCREG_MPAM2_EL2);
MPAM mpam3 = tc->readMiscReg(MISCREG_MPAM3_EL3);
MPAMIDR mpamidr = tc->readMiscReg(MISCREG_MPAMIDR_EL1);
MPAMHCR mpamhcr = tc->readMiscReg(MISCREG_MPAMHCR_EL2);
if (ArmSystem::haveEL(tc, EL3) && mpam3.el3.trapLower) {
return inst.generateTrap(EL3);
} else if (EL2Enabled(tc) && mpamidr.hasHcr && mpamhcr.trapMpamIdrEL1) {
return inst.generateTrap(EL2);
} else if (EL2Enabled(tc) && mpamidr.hasTidr && mpam2.el2.tidr) {
return inst.generateTrap(EL2);
} else {
return NoFault;
}
} else {
return inst.undefined();
}
}
Fault
faultMpam0EL1(const MiscRegLUTEntry &entry,
ThreadContext *tc, const MiscRegOp64 &inst)
{
if (HaveExt(tc, ArmExtension::FEAT_MPAM)) {
MPAM mpam2 = tc->readMiscReg(MISCREG_MPAM2_EL2);
MPAM mpam3 = tc->readMiscReg(MISCREG_MPAM3_EL3);
if (ArmSystem::haveEL(tc, EL3) && mpam3.el3.trapLower) {
return inst.generateTrap(EL3);
} else if (EL2Enabled(tc) && mpam2.el2.trapMpam0EL1) {
return inst.generateTrap(EL2);
} else {
return NoFault;
}
} else {
return inst.undefined();
}
}
Fault
faultMpam1EL1(const MiscRegLUTEntry &entry,
ThreadContext *tc, const MiscRegOp64 &inst)
{
if (HaveExt(tc, ArmExtension::FEAT_MPAM)) {
MPAM mpam2 = tc->readMiscReg(MISCREG_MPAM2_EL2);
MPAM mpam3 = tc->readMiscReg(MISCREG_MPAM3_EL3);
if (ArmSystem::haveEL(tc, EL3) && mpam3.el3.trapLower) {
return inst.generateTrap(EL3);
} else if (EL2Enabled(tc) && mpam2.el2.trapMpam1EL1) {
return inst.generateTrap(EL2);
} else {
return NoFault;
}
} else {
return inst.undefined();
}
}
Fault
faultMpamEL2(const MiscRegLUTEntry &entry,
ThreadContext *tc, const MiscRegOp64 &inst)
{
if (HaveExt(tc, ArmExtension::FEAT_MPAM)) {
MPAM mpam3 = tc->readMiscReg(MISCREG_MPAM3_EL3);
if (ArmSystem::haveEL(tc, EL3) && mpam3.el3.trapLower) {
return inst.generateTrap(EL3);
} else {
return NoFault;
}
} else {
return inst.undefined();
}
}
Fault
faultMpam12EL2(const MiscRegLUTEntry &entry,
ThreadContext *tc, const MiscRegOp64 &inst)
{
if (ELIsInHost(tc, EL2)) {
return faultMpamEL2(entry, tc, inst);
} else {
return inst.undefined();
}
}
Fault
faultMpamsmEL1(const MiscRegLUTEntry &entry,
ThreadContext *tc, const MiscRegOp64 &inst)
{
if (HaveExt(tc, ArmExtension::FEAT_MPAM)) {
MPAM mpam2 = tc->readMiscReg(MISCREG_MPAM2_EL2);
MPAM mpam3 = tc->readMiscReg(MISCREG_MPAM3_EL3);
if (ArmSystem::haveEL(tc, EL3) && mpam3.el3.trapLower) {
return inst.generateTrap(EL3);
} else if (EL2Enabled(tc) && mpam2.el2.enMpamSm) {
return inst.generateTrap(EL2);
} else {
return NoFault;
}
} else {
return inst.undefined();
}
}
}
MiscRegIndex
@@ -4567,10 +4690,14 @@ ISA::initializeMiscRegMetadata()
AA64PFR0 pfr0_el1 = 0;
pfr0_el1.el0 = 0x2;
pfr0_el1.el1 = 0x2;
pfr0_el1.el2 = release->has(ArmExtension::VIRTUALIZATION) ? 0x2 : 0x0;
pfr0_el1.el2 = release->has(ArmExtension::VIRTUALIZATION)
? 0x2 : 0x0;
pfr0_el1.el3 = release->has(ArmExtension::SECURITY) ? 0x2 : 0x0;
pfr0_el1.sve = release->has(ArmExtension::FEAT_SVE) ? 0x1 : 0x0;
pfr0_el1.sel2 = release->has(ArmExtension::FEAT_SEL2) ? 0x1 : 0x0;
// See MPAM frac in MISCREG_ID_AA64PFR1_EL1. Currently supporting
// MPAMv0p1
pfr0_el1.mpam = 0x0;
pfr0_el1.gic = FullSystem && getGICv3CPUInterface(tc) ? 0x1 : 0;
return pfr0_el1;
}())
@@ -4579,8 +4706,13 @@ ISA::initializeMiscRegMetadata()
.faultRead(EL1, faultHcrEL1<&HCR::tid3>)
.allPrivileges().writes(0);
InitReg(MISCREG_ID_AA64PFR1_EL1)
.reset(release->has(ArmExtension::FEAT_SME) ?
0x1 << 24 : 0)
.reset([release=release](){
AA64PFR1 pfr1_el1 = 0;
pfr1_el1.sme = release->has(ArmExtension::FEAT_SME) ? 0x1 : 0x0;
pfr1_el1.mpamFrac = release->has(ArmExtension::FEAT_MPAM) ?
0x1 : 0x0;
return pfr1_el1;
}())
.unserialize(0)
.faultRead(EL0, faultIdst)
.faultRead(EL1, faultHcrEL1<&HCR::tid3>)
@@ -6314,8 +6446,6 @@ ISA::initializeMiscRegMetadata()
.allPrivileges().exceptUserMode();
InitReg(MISCREG_TPIDR2_EL0)
.allPrivileges();
InitReg(MISCREG_MPAMSM_EL1)
.allPrivileges().exceptUserMode();
InitReg(MISCREG_RNDR)
.faultRead(EL0, faultRng)
@@ -6396,6 +6526,73 @@ ISA::initializeMiscRegMetadata()
.warnNotFail()
.fault(faultUnimplemented);
// MPAM extension
InitReg(MISCREG_MPAMIDR_EL1)
.reset(p.mpamidr_el1)
.res0(mask(63, 62) | mask(56, 40) | mask(31, 21) | mask(16, 16))
.faultRead(EL1, faultMpamIdrEL1)
.faultRead(EL2, faultMpamEL2)
.allPrivileges().exceptUserMode().writes(0);
InitReg(MISCREG_MPAM0_EL1)
.res0(mask(63, 48))
.fault(EL1, faultMpam0EL1)
.fault(EL2, faultMpamEL2)
.priv().hyp().mon();
InitReg(MISCREG_MPAM1_EL1)
.res0(mask(62, 61) | mask(59, 48))
.fault(EL1, faultMpam1EL1)
.fault(EL2, faultMpamEL2)
.priv().hyp().mon();
InitReg(MISCREG_MPAM1_EL12)
.res0(mask(59, 48))
.fault(EL2, faultMpam12EL2)
.fault(EL3, defaultFaultE2H_EL3)
.hyp().mon();
InitReg(MISCREG_MPAM2_EL2)
.res0(mask(62, 59) | mask(57, 50))
.fault(EL2, faultMpamEL2)
.hyp().mon();
InitReg(MISCREG_MPAMHCR_EL2)
.res0(mask(63, 32) | mask(30, 9) | mask(7, 2))
.fault(EL2, faultMpamEL2)
.hyp().mon();
InitReg(MISCREG_MPAMVPM0_EL2)
.fault(EL2, faultMpamEL2)
.hyp().mon();
InitReg(MISCREG_MPAMVPM1_EL2)
.fault(EL2, faultMpamEL2)
.hyp().mon();
InitReg(MISCREG_MPAMVPM2_EL2)
.fault(EL2, faultMpamEL2)
.hyp().mon();
InitReg(MISCREG_MPAMVPM3_EL2)
.fault(EL2, faultMpamEL2)
.hyp().mon();
InitReg(MISCREG_MPAMVPM4_EL2)
.fault(EL2, faultMpamEL2)
.hyp().mon();
InitReg(MISCREG_MPAMVPM5_EL2)
.fault(EL2, faultMpamEL2)
.hyp().mon();
InitReg(MISCREG_MPAMVPM6_EL2)
.fault(EL2, faultMpamEL2)
.hyp().mon();
InitReg(MISCREG_MPAMVPM7_EL2)
.fault(EL2, faultMpamEL2)
.hyp().mon();
InitReg(MISCREG_MPAMVPMV_EL2)
.res0(mask(63, 32))
.fault(EL2, faultMpamEL2)
.hyp().mon();
InitReg(MISCREG_MPAM3_EL3)
.res0(mask(59, 48))
.mon();
InitReg(MISCREG_MPAMSM_EL1)
.res0(mask(63, 48) | mask(39, 32) | mask(15, 0))
.fault(EL1, faultMpamsmEL1)
.fault(EL2, faultMpamEL2)
.allPrivileges().exceptUserMode();
// Register mappings for some unimplemented registers:
// ESR_EL1 -> DFSR
// RMR_EL1 -> RMR

View File

@@ -1142,6 +1142,24 @@ namespace ArmISA
MISCREG_HDFGRTR_EL2,
MISCREG_HDFGWTR_EL2,
// FEAT_MPAM
MISCREG_MPAMIDR_EL1,
MISCREG_MPAM0_EL1,
MISCREG_MPAM1_EL1,
MISCREG_MPAM2_EL2,
MISCREG_MPAM3_EL3,
MISCREG_MPAM1_EL12,
MISCREG_MPAMHCR_EL2,
MISCREG_MPAMVPMV_EL2,
MISCREG_MPAMVPM0_EL2,
MISCREG_MPAMVPM1_EL2,
MISCREG_MPAMVPM2_EL2,
MISCREG_MPAMVPM3_EL2,
MISCREG_MPAMVPM4_EL2,
MISCREG_MPAMVPM5_EL2,
MISCREG_MPAMVPM6_EL2,
MISCREG_MPAMVPM7_EL2,
// NUM_PHYS_MISCREGS specifies the number of actual physical
// registers, not considering the following pseudo-registers
// (dummy registers), like MISCREG_UNKNOWN, MISCREG_IMPDEF_UNIMPL.
@@ -2859,6 +2877,24 @@ namespace ArmISA
"hdfgrtr_el2",
"hdfgwtr_el2",
// FEAT_MPAM
"mpamidr_el1",
"mpam0_el1",
"mpam1_el1",
"mpam2_el2",
"mpam3_el3",
"mpam1_el12",
"mpamhcr_el2",
"mpamvpmv_el2",
"mpamvpm0_el2",
"mpamvpm1_el2",
"mpamvpm2_el2",
"mpamvpm3_el2",
"mpamvpm4_el2",
"mpamvpm5_el2",
"mpamvpm6_el2",
"mpamvpm7_el2",
"num_phys_regs",
// Dummy registers

View File

@@ -59,6 +59,15 @@ struct FarAccessor
static const MiscRegIndex el3 = MISCREG_FAR_EL3;
};
struct MpamAccessor
{
using type = MPAM;
static const MiscRegIndex el0 = MISCREG_MPAM0_EL1;
static const MiscRegIndex el1 = MISCREG_MPAM1_EL1;
static const MiscRegIndex el2 = MISCREG_MPAM2_EL2;
static const MiscRegIndex el3 = MISCREG_MPAM3_EL3;
};
template <typename RegAccessor>
MiscRegIndex
getRegVersion(ExceptionLevel el)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2023 Arm Limited
* Copyright (c) 2010-2024 Arm Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -226,6 +226,11 @@ namespace ArmISA
Bitfield<3, 0> el0;
EndBitUnion(AA64PFR0)
BitUnion64(AA64PFR1)
Bitfield<27, 24> sme;
Bitfield<19, 16> mpamFrac;
EndBitUnion(AA64PFR1)
BitUnion64(AA64ZFR0)
Bitfield<59, 56> f64mm;
Bitfield<55, 52> f32mm;
@@ -1085,6 +1090,53 @@ namespace ArmISA
Bitfield<14> tcr2En;
EndBitUnion(HCRX)
BitUnion64(MPAMIDR)
Bitfield<61> hasSdeflt;
Bitfield<60> hasForceNs;
Bitfield<58> hasTidr;
Bitfield<39,32> pmgMax;
Bitfield<20,18> vpmrMax;
Bitfield<17> hasHcr;
Bitfield<15,0> partidMax;
EndBitUnion(MPAMIDR)
// Generic view of MPAMx_ELy
BitUnion64(MPAM)
Bitfield<63> mpamEn;
// MPAM1_EL1 only
SubBitUnion(el1, 62, 48)
Bitfield<60> forcedNs;
EndSubBitUnion(el1)
// MPAM2_EL2 only
SubBitUnion(el2, 62, 48)
Bitfield<58> tidr;
Bitfield<50> enMpamSm;
Bitfield<49> trapMpam0EL1;
Bitfield<48> trapMpam1EL1;
EndSubBitUnion(el2)
// MPAM3_EL3 only
SubBitUnion(el3, 62, 48)
Bitfield<62> trapLower;
Bitfield<61> sdeflt;
Bitfield<60> forceNs;
EndSubBitUnion(el3)
Bitfield<47,40> pmgD;
Bitfield<39,32> pmgI;
Bitfield<31,16> partidD;
Bitfield<15,0> partidI;
EndBitUnion(MPAM)
BitUnion64(MPAMHCR)
Bitfield<31> trapMpamIdrEL1;
Bitfield<8> gstappPlk;
Bitfield<1> el1Vpmen;
Bitfield<0> el0Vpmen;
EndBitUnion(MPAMHCR)
} // namespace ArmISA
} // namespace gem5

View File

@@ -41,6 +41,7 @@
#include "arch/arm/faults.hh"
#include "arch/arm/mmu.hh"
#include "arch/arm/mpam.hh"
#include "arch/arm/pagetable.hh"
#include "arch/arm/system.hh"
#include "arch/arm/tlb.hh"
@@ -2114,6 +2115,8 @@ TableWalker::fetchDescriptor(Addr desc_addr,
desc_addr, num_bytes, flags, requestorId);
req->taskId(context_switch_task_id::DMA);
mpamTagTableWalk(req);
Fault fault = testWalk(req, descriptor.domain(),
lookup_level);
@@ -2387,6 +2390,12 @@ TableWalker::readDataUntimed(ThreadContext *tc, Addr vaddr, Addr desc_addr,
return fault;
}
void
TableWalker::mpamTagTableWalk(RequestPtr &req) const
{
mpam::tagRequest(currState->tc, req, currState->isFetch);
}
void
TableWalker::readDataTimed(ThreadContext *tc, Addr desc_addr,
Stage2Walk *translation, int num_bytes,

View File

@@ -1201,6 +1201,8 @@ class TableWalker : public ClockedObject
static uint8_t pageSizeNtoStatBin(uint8_t N);
void mpamTagTableWalk(RequestPtr &req) const;
public: /* Testing */
TlbTestInterface *test;