From 142d562b2f3df36401f3a5b2b68ef6026a599717 Mon Sep 17 00:00:00 2001 From: Sascha Bischoff Date: Wed, 3 Aug 2022 14:57:33 +0100 Subject: [PATCH] arch-arm: Implement SME access traps and extend the SVE ones We add the SME access checks and trapping, which roughly mirrors that used by SVE. SME adds a new mode called streaming mode. When a core is in streaming mode the behaviour of the SVE instructions changes such that they check the SME traps and enables as opposed to the SVE ones. We therefore update the existing SVE trap/access checking code to check the SME equivalents when a core is in streaming mode. Else, the original behaviour is preserved. Jira Issue: https://gem5.atlassian.net/browse/GEM5-1289 Change-Id: I7eba70da9d41d2899b753fababbd6074ed732501 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/64337 Reviewed-by: Giacomo Travaglini Maintainer: Giacomo Travaglini Tested-by: kokoro --- src/arch/arm/insts/static_inst.cc | 127 +++++++++++++++++++++++++++++ src/arch/arm/insts/static_inst.hh | 29 +++++++ src/arch/arm/isa/templates/sve.isa | 4 +- src/arch/arm/types.hh | 1 + 4 files changed, 160 insertions(+), 1 deletion(-) diff --git a/src/arch/arm/insts/static_inst.cc b/src/arch/arm/insts/static_inst.cc index 446f2afd18..54045f2fb1 100644 --- a/src/arch/arm/insts/static_inst.cc +++ b/src/arch/arm/insts/static_inst.cc @@ -1026,6 +1026,13 @@ ArmStaticInst::sveAccessTrap(ExceptionLevel el) const Fault ArmStaticInst::checkSveEnabled(ThreadContext *tc, CPSR cpsr, CPACR cpacr) const { + // We first check if we are in streaming mode or not. If we are in + // streaming mode, we actually check the SME traps, not the SVE traps! + SVCR svcr_sm_check = tc->readMiscReg(MISCREG_SVCR); + if (svcr_sm_check.sm) { + return checkSmeEnabled(tc, cpsr, cpacr); + } + const ExceptionLevel el = (ExceptionLevel) (uint8_t) cpsr.el; // Check if access disabled in CPACR_EL1 if (el <= EL1 && !ELIsInHost(tc, el)) { @@ -1073,6 +1080,126 @@ ArmStaticInst::checkSveEnabled(ThreadContext *tc, CPSR cpsr, CPACR cpacr) const return NoFault; } +Fault +ArmStaticInst::smeAccessTrap(ExceptionLevel el, uint32_t iss) const +{ + switch (el) { + case EL1: + return std::make_shared( + machInst, iss, ExceptionClass::TRAPPED_SME); + case EL2: + return std::make_shared( + machInst, iss, ExceptionClass::TRAPPED_SME); + case EL3: + return std::make_shared( + machInst, iss, ExceptionClass::TRAPPED_SME); + + default: + panic("Illegal EL in smeAccessTrap\n"); + } +} + +Fault +ArmStaticInst::checkSmeEnabled(ThreadContext *tc, CPSR cpsr, CPACR cpacr) const +{ + const ExceptionLevel el = (ExceptionLevel) (uint8_t) cpsr.el; + // Check if access disabled in CPACR_EL1 + if (el <= EL1 && !ELIsInHost(tc, el)) { + if ((el == EL0 && cpacr.smen == 0x1) || + (!(cpacr.smen & 0x1))) + return smeAccessTrap(EL1); + + if ((el == EL0 && cpacr.fpen == 0x1) || + (!(cpacr.fpen & 0x1))) + return advSIMDFPAccessTrap64(EL1); + } + + // Check if access disabled in CPTR_EL2 + if (el <= EL2 && EL2Enabled(tc)) { + CPTR cptr_en_check = tc->readMiscReg(MISCREG_CPTR_EL2); + HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); + if (HaveExt(tc, ArmExtension::FEAT_VHE) && hcr.e2h) { + if (((cptr_en_check.smen & 0x1) == 0x0) || + (cptr_en_check.smen == 0x1 && el == EL0 && + hcr.tge == 0x1)) { + return smeAccessTrap(EL2); + } + if (((cptr_en_check.fpen & 0x1) == 0x0) || + (cptr_en_check.fpen == 0x1 && el == EL0 && + hcr.tge == 0x1)) { + return advSIMDFPAccessTrap64(EL2); + } + } else { + if (cptr_en_check.tsm == 1) + return smeAccessTrap(EL2); + if (cptr_en_check.tfp == 1) + return advSIMDFPAccessTrap64(EL2); + } + } + + // Check if access disabled in CPTR_EL3 + if (ArmSystem::haveEL(tc, EL3)) { + CPTR cptr_en_check = tc->readMiscReg(MISCREG_CPTR_EL3); + if (!cptr_en_check.esm) + return smeAccessTrap(EL3); + if (cptr_en_check.tfp) + return advSIMDFPAccessTrap64(EL3); + } + + return NoFault; +} + +Fault +ArmStaticInst::checkSmeAccess(ThreadContext *tc, CPSR cpsr, CPACR cpacr) const +{ + const ExceptionLevel el = (ExceptionLevel) (uint8_t) cpsr.el; + // Check if access disabled in CPACR_EL1 + if (el <= EL1 && !ELIsInHost(tc, el)) { + if ((el == EL0 && cpacr.smen == 0x1) || (!(cpacr.smen & 0x1))) { + return smeAccessTrap(EL1); + } + } + + // Check if access disabled in CPTR_EL2 + if (el <= EL2 && EL2Enabled(tc)) { + CPTR cptr_en_check = tc->readMiscReg(MISCREG_CPTR_EL2); + HCR hcr = tc->readMiscReg(MISCREG_HCR_EL2); + if (HaveExt(tc, ArmExtension::FEAT_VHE) && hcr.e2h) { + if (((cptr_en_check.smen & 0x1) == 0x0) || + (cptr_en_check.smen == 0x1 && el == EL0 && + hcr.tge == 0x1)) { + return smeAccessTrap(EL2); + } + } else { + if (cptr_en_check.tsm == 1) + return smeAccessTrap(EL2); + } + } + + // Check if access disabled in CPTR_EL3 + if (ArmSystem::haveEL(tc, EL3)) { + CPTR cptr_en_check = tc->readMiscReg(MISCREG_CPTR_EL3); + if (!cptr_en_check.esm) + return smeAccessTrap(EL3); + } + + return NoFault; +} + +Fault +ArmStaticInst::checkSveSmeEnabled(ThreadContext *tc, CPSR cpsr, + CPACR cpacr) const +{ + // If we are not in streaming mode, check the SVE traps, else check the SME + // traps. + SVCR svcr = tc->readMiscReg(MISCREG_SVCR); + if (!svcr.sm) { + return checkSveEnabled(tc, cpsr, cpacr); + } else { + return checkSmeEnabled(tc, cpsr, cpacr); + } +} + static uint8_t getRestoredITBits(ThreadContext *tc, CPSR spsr) { diff --git a/src/arch/arm/insts/static_inst.hh b/src/arch/arm/insts/static_inst.hh index 3b67e6b253..cc96dd9269 100644 --- a/src/arch/arm/insts/static_inst.hh +++ b/src/arch/arm/insts/static_inst.hh @@ -513,6 +513,35 @@ class ArmStaticInst : public StaticInst */ Fault checkSveEnabled(ThreadContext *tc, CPSR cpsr, CPACR cpacr) const; + + /** + * Trap an access to SME registers due to access control bits. + * + * @param el Target EL for the trap. + * @param iss ISS to be used for the trap. + */ + Fault smeAccessTrap(ExceptionLevel el, uint32_t iss = 0) const; + + /** + * Check if SME is enabled by checking the SME and FP bits of + * CPACR_EL1, CPTR_EL2, and CPTR_EL3 + */ + Fault checkSmeEnabled(ThreadContext *tc, CPSR cpsr, CPACR cpacr) const; + + /** + * Check an SME access against CPACR_EL1, CPTR_EL2, and CPTR_EL3. + * This is purely used from the management instructions as it should + * be possible to call SMSTART/SMSTOP without having the floating + * point flags correctly set up. + */ + Fault checkSmeAccess(ThreadContext *tc, CPSR cpsr, CPACR cpacr) const; + + /** + * Check an SVE access against CPACR_EL1, CPTR_EL2, and CPTR_EL3, but + * choosing the correct set of traps to check based on Streaming Mode + */ + Fault checkSveSmeEnabled(ThreadContext *tc, CPSR cpsr, CPACR cpacr) const; + /** * Get the new PSTATE from a SPSR register in preparation for an * exception return. diff --git a/src/arch/arm/isa/templates/sve.isa b/src/arch/arm/isa/templates/sve.isa index 87316f1440..fc38a2b979 100644 --- a/src/arch/arm/isa/templates/sve.isa +++ b/src/arch/arm/isa/templates/sve.isa @@ -36,7 +36,9 @@ let {{ sveEnabledCheckCode = ''' if (FullSystem) { - fault = this->checkSveEnabled(xc->tcBase(), Cpsr, Cpacr64); + // Check an SVE inst against the appropriate traps/enables based + // on the Streaming Mode. + fault = this->checkSveSmeEnabled(xc->tcBase(), Cpsr, Cpacr64); if (fault != NoFault) { return fault; } diff --git a/src/arch/arm/types.hh b/src/arch/arm/types.hh index 50db9bc9af..2251d57c0b 100644 --- a/src/arch/arm/types.hh +++ b/src/arch/arm/types.hh @@ -323,6 +323,7 @@ namespace ArmISA SMC_64 = 0x17, TRAPPED_MSR_MRS_64 = 0x18, TRAPPED_SVE = 0x19, + TRAPPED_SME = 0x1D, PREFETCH_ABORT_TO_HYP = 0x20, PREFETCH_ABORT_LOWER_EL = 0x20, // AArch64 alias PREFETCH_ABORT_FROM_HYP = 0x21,