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 <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Sascha Bischoff
2022-08-03 14:57:33 +01:00
committed by Giacomo Travaglini
parent 72e4f614a2
commit 142d562b2f
4 changed files with 160 additions and 1 deletions

View File

@@ -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<SupervisorTrap>(
machInst, iss, ExceptionClass::TRAPPED_SME);
case EL2:
return std::make_shared<HypervisorTrap>(
machInst, iss, ExceptionClass::TRAPPED_SME);
case EL3:
return std::make_shared<SecureMonitorTrap>(
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)
{

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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,