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:
committed by
Giacomo Travaglini
parent
72e4f614a2
commit
142d562b2f
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user