From 65cf6b0a1c28644513f7bbb4192f732d84a0757c Mon Sep 17 00:00:00 2001 From: Giacomo Travaglini Date: Tue, 30 Jan 2024 10:33:39 +0000 Subject: [PATCH 1/3] arch-arm: Cache the highestEL in the ISA object This is for fast retrieval of the highest implemented exception level Change-Id: Id631c2b999d46a8b79570e4043ae04bc2b2e7531 Signed-off-by: Giacomo Travaglini Reviewed-by: Richard Cooper --- src/arch/arm/isa.cc | 4 +++- src/arch/arm/isa.hh | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc index f76f14997f..bf7d1b0a9c 100644 --- a/src/arch/arm/isa.cc +++ b/src/arch/arm/isa.cc @@ -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 @@ -106,6 +106,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 +115,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; diff --git a/src/arch/arm/isa.hh b/src/arch/arm/isa.hh index 8ed37ba861..7b041f61b2 100644 --- a/src/arch/arm/isa.hh +++ b/src/arch/arm/isa.hh @@ -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; From c988642ca8efaccf16a73e677b6424f97cca6f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Herrera?= Date: Fri, 2 Apr 2021 15:39:30 +0100 Subject: [PATCH 2/3] arch-arm: Define system registers for FEAT_MPAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is adding FEAT_MPAM register definition/decoding. Co-authored-by: Hristo Belchev Co-authored-by: Giacomo Travaglini Change-Id: I70483fcc758419365f4b3762479684c6c52f4d62 Signed-off-by: Adrián Herrera Reviewed-by: Richard Cooper --- src/arch/arm/ArmISA.py | 4 + src/arch/arm/ArmSystem.py | 1 + src/arch/arm/isa.cc | 28 +++- src/arch/arm/regs/misc.cc | 211 +++++++++++++++++++++++++++- src/arch/arm/regs/misc.hh | 36 +++++ src/arch/arm/regs/misc_accessors.hh | 9 ++ src/arch/arm/regs/misc_types.hh | 54 ++++++- 7 files changed, 333 insertions(+), 10 deletions(-) diff --git a/src/arch/arm/ArmISA.py b/src/arch/arm/ArmISA.py index 9f296983d0..e7f215822c 100644 --- a/src/arch/arm/ArmISA.py +++ b/src/arch/arm/ArmISA.py @@ -170,6 +170,10 @@ class ArmISA(BaseISA): 0x0000000000010010, "AArch64 Memory Model Feature Register 2" ) + # HAS_SDEFLT | HAS_FORCE_NS | HAS_TIDR | PMG_MAX = 64 | + # VPMR_MAX = 7 | HAS_HCR | PARTID_MAX = 256 + mpamidr_el1 = Param.UInt64(0x34000040001E0100, "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. diff --git a/src/arch/arm/ArmSystem.py b/src/arch/arm/ArmSystem.py index e260ac1b28..94cbb496aa 100644 --- a/src/arch/arm/ArmSystem.py +++ b/src/arch/arm/ArmSystem.py @@ -115,6 +115,7 @@ class ArmExtension(ScopedEnum): "LPAE", "VIRTUALIZATION", "TME", + "FEAT_MPAM", ] diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc index bf7d1b0a9c..69ca95d306 100644 --- a/src/arch/arm/isa.cc +++ b/src/arch/arm/isa.cc @@ -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 { @@ -269,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())) { @@ -358,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; @@ -602,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( + tc, highestEL).mpamEn; + mpam1.el1.forcedNs = isSecure(tc) ? + readRegisterNoEffect(tc, EL3).el3.forceNs : 0; + return mpam1; + } + case MISCREG_MPAM2_EL2: + { + MPAM mpam2 = readMiscRegNoEffect(MISCREG_MPAM2_EL2); + mpam2.mpamEn = readRegisterNoEffect( + tc, highestEL).mpamEn; + return mpam2; + } + case MISCREG_RNDR: tc->setReg(cc_reg::Nz, (RegVal)0); tc->setReg(cc_reg::C, (RegVal)0); @@ -733,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; diff --git a/src/arch/arm/regs/misc.cc b/src/arch/arm/regs/misc.cc index 929ccf1169..d29a8bc367 100644 --- a/src/arch/arm/regs/misc.cc +++ b/src/arch/arm/regs/misc.cc @@ -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 lookUpMiscReg(NUM_MISCREGS); namespace { - // The map is translating a MiscRegIndex into AArch64 system register // numbers (op0, op1, crn, crm, op2) std::unordered_map idxToMiscRegNum; @@ -1032,6 +1032,9 @@ std::unordered_map 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 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 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 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 diff --git a/src/arch/arm/regs/misc.hh b/src/arch/arm/regs/misc.hh index fc18e3f8e1..93005aa0e1 100644 --- a/src/arch/arm/regs/misc.hh +++ b/src/arch/arm/regs/misc.hh @@ -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 diff --git a/src/arch/arm/regs/misc_accessors.hh b/src/arch/arm/regs/misc_accessors.hh index 47bd0209d5..710f6139ab 100644 --- a/src/arch/arm/regs/misc_accessors.hh +++ b/src/arch/arm/regs/misc_accessors.hh @@ -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 MiscRegIndex getRegVersion(ExceptionLevel el) diff --git a/src/arch/arm/regs/misc_types.hh b/src/arch/arm/regs/misc_types.hh index f2b246288a..0f3a9f558c 100644 --- a/src/arch/arm/regs/misc_types.hh +++ b/src/arch/arm/regs/misc_types.hh @@ -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 From b8e414f14db43f24712a854c49c6e27ae647f618 Mon Sep 17 00:00:00 2001 From: Giacomo Travaglini Date: Fri, 26 Jan 2024 23:15:24 +0000 Subject: [PATCH 3/3] arch-arm: Implement FEAT_MPAM With this patch we are adding the specific logic required to tag memory requests from the PE with MPAM data. This is happening within the MMU before a translation is completed Change-Id: Ifecb285244dd469a639150d69a7e884fe3c441be Signed-off-by: Giacomo Travaglini Reviewed-by: Richard Cooper --- src/arch/arm/ArmISA.py | 4 +- src/arch/arm/SConscript | 3 +- src/arch/arm/mmu.cc | 3 + src/arch/arm/mpam.cc | 196 ++++++++++++++++++++++++++++++++++- src/arch/arm/mpam.hh | 29 +++++- src/arch/arm/table_walker.cc | 9 ++ src/arch/arm/table_walker.hh | 2 + 7 files changed, 241 insertions(+), 5 deletions(-) diff --git a/src/arch/arm/ArmISA.py b/src/arch/arm/ArmISA.py index e7f215822c..8b9cf25b25 100644 --- a/src/arch/arm/ArmISA.py +++ b/src/arch/arm/ArmISA.py @@ -170,9 +170,9 @@ class ArmISA(BaseISA): 0x0000000000010010, "AArch64 Memory Model Feature Register 2" ) - # HAS_SDEFLT | HAS_FORCE_NS | HAS_TIDR | PMG_MAX = 64 | + # HAS_SDEFLT | HAS_FORCE_NS | HAS_TIDR | PMG_MAX = 128 | # VPMR_MAX = 7 | HAS_HCR | PARTID_MAX = 256 - mpamidr_el1 = Param.UInt64(0x34000040001E0100, "MPAM ID Register (EL1)") + 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. diff --git a/src/arch/arm/SConscript b/src/arch/arm/SConscript index 47d0b54348..948cefb4e4 100644 --- a/src/arch/arm/SConscript +++ b/src/arch/arm/SConscript @@ -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. diff --git a/src/arch/arm/mmu.cc b/src/arch/arm/mmu.cc index b0ad4f1737..f94a18423a 100644 --- a/src/arch/arm/mmu.cc +++ b/src/arch/arm/mmu.cc @@ -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) { diff --git a/src/arch/arm/mpam.cc b/src/arch/arm/mpam.cc index e47b4f80ad..4c618d2f85 100644 --- a/src/arch/arm/mpam.cc +++ b/src/arch/arm/mpam.cc @@ -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 + #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(tc, el); + return ind ? reg.partidI : reg.partidD; +} + +static PMG +getPMG(ThreadContext *tc, ExceptionLevel el, bool ind) +{ + MPAM reg = readRegister(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 +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 +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 +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(tc, ArmSystem::highestEL(tc)); + return reg.mpamEn; +} + +static std::shared_ptr +genExtensionDefault() +{ + // tag with partID data + auto ext = std::make_shared(); + ext->setPartitionID(DEFAULT_PARTITION_ID); + ext->setPartitionMonitoringID(DEFAULT_PARTITION_MONITORING_ID); + return ext; +} + +static std::shared_ptr +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 diff --git a/src/arch/arm/mpam.hh b/src/arch/arm/mpam.hh index 613a53777c..a3d47e48ef 100644 --- a/src/arch/arm/mpam.hh +++ b/src/arch/arm/mpam.hh @@ -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 ExtensiontaskId(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, diff --git a/src/arch/arm/table_walker.hh b/src/arch/arm/table_walker.hh index ee56cb81f1..32f05ac316 100644 --- a/src/arch/arm/table_walker.hh +++ b/src/arch/arm/table_walker.hh @@ -1201,6 +1201,8 @@ class TableWalker : public ClockedObject static uint8_t pageSizeNtoStatBin(uint8_t N); + void mpamTagTableWalk(RequestPtr &req) const; + public: /* Testing */ TlbTestInterface *test;