summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Sandberg <andreas.sandberg@arm.com>2016-06-02 13:38:30 +0100
committerAndreas Sandberg <andreas.sandberg@arm.com>2016-06-02 13:38:30 +0100
commitf48ad5b29d6f291b4f3679ff5fb7b5beae10d6fa (patch)
treed08e72f1eeeea81b33b60b6bd0f90f1cbd9f174d /src
parent53ae19bb5dce904915385515d87ff3c9a69ee170 (diff)
downloadgem5-f48ad5b29d6f291b4f3679ff5fb7b5beae10d6fa.tar.xz
arm: Correctly check FP/SIMD access permission in aarch32
The current implementation of aarch32 FP/SIMD in gem5 assumes that EL1 and higher are all 32-bit. This breaks interprocessing since an aarch64 EL1 uses different enable/disable bits. This change updates the permission checks to according to what is prescribed by the ARM ARM. Change-Id: Icdcef31b00644cfeebec00216b3993aa1de12b88 Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com> Reviewed-by: Mitch Hayenga <mitch.hayenga@arm.com> Reviewed-by: Nathanael Premillieu <nathanael.premillieu@arm.com>
Diffstat (limited to 'src')
-rw-r--r--src/arch/arm/insts/static_inst.cc134
-rw-r--r--src/arch/arm/insts/static_inst.hh43
-rw-r--r--src/arch/arm/isa/insts/fp.isa2
-rw-r--r--src/arch/arm/isa/templates/neon.isa27
-rw-r--r--src/arch/arm/isa/templates/vfp.isa154
-rw-r--r--src/arch/arm/utility.cc85
-rw-r--r--src/arch/arm/utility.hh14
7 files changed, 227 insertions, 232 deletions
diff --git a/src/arch/arm/insts/static_inst.cc b/src/arch/arm/insts/static_inst.cc
index 6fdd07ff6..d4ea1bcdf 100644
--- a/src/arch/arm/insts/static_inst.cc
+++ b/src/arch/arm/insts/static_inst.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2014 ARM Limited
+ * Copyright (c) 2010-2014, 2016 ARM Limited
* Copyright (c) 2013 Advanced Micro Devices, Inc.
* All rights reserved
*
@@ -595,4 +595,136 @@ ArmStaticInst::generateDisassembly(Addr pc,
printMnemonic(ss);
return ss.str();
}
+
+
+Fault
+ArmStaticInst::advSIMDFPAccessTrap64(ExceptionLevel el) const
+{
+ switch (el) {
+ case EL1:
+ return std::make_shared<SupervisorTrap>(machInst, 0x1E00000,
+ EC_TRAPPED_SIMD_FP);
+ case EL2:
+ return std::make_shared<HypervisorTrap>(machInst, 0x1E00000,
+ EC_TRAPPED_SIMD_FP);
+ case EL3:
+ return std::make_shared<SecureMonitorTrap>(machInst, 0x1E00000,
+ EC_TRAPPED_SIMD_FP);
+
+ default:
+ panic("Illegal EL in advSIMDFPAccessTrap64\n");
+ }
+}
+
+
+Fault
+ArmStaticInst::checkFPAdvSIMDTrap64(ThreadContext *tc, CPSR cpsr) const
+{
+ const ExceptionLevel el = (ExceptionLevel) (uint8_t)cpsr.el;
+
+ if (ArmSystem::haveVirtualization(tc) && el <= EL2) {
+ HCPTR cptrEnCheck = tc->readMiscReg(MISCREG_CPTR_EL2);
+ if (cptrEnCheck.tfp)
+ return advSIMDFPAccessTrap64(EL2);
+ }
+
+ if (ArmSystem::haveSecurity(tc)) {
+ HCPTR cptrEnCheck = tc->readMiscReg(MISCREG_CPTR_EL3);
+ if (cptrEnCheck.tfp)
+ return advSIMDFPAccessTrap64(EL3);
+ }
+
+ return NoFault;
+}
+
+Fault
+ArmStaticInst::checkFPAdvSIMDEnabled64(ThreadContext *tc,
+ CPSR cpsr, CPACR cpacr) const
+{
+ const ExceptionLevel el = (ExceptionLevel) (uint8_t)cpsr.el;
+ if ((el == EL0 && cpacr.fpen != 0x3) ||
+ (el == EL1 && !(cpacr.fpen & 0x1)))
+ return advSIMDFPAccessTrap64(EL1);
+
+ return checkFPAdvSIMDTrap64(tc, cpsr);
+}
+
+Fault
+ArmStaticInst::checkAdvSIMDOrFPEnabled32(ThreadContext *tc,
+ CPSR cpsr, CPACR cpacr,
+ NSACR nsacr, FPEXC fpexc,
+ bool fpexc_check, bool advsimd) const
+{
+ const bool have_virtualization = ArmSystem::haveVirtualization(tc);
+ const bool have_security = ArmSystem::haveSecurity(tc);
+ const bool is_secure = inSecureState(tc);
+ const ExceptionLevel cur_el = opModeToEL(currOpMode(tc));
+
+ if (cur_el == EL0 && ELIs64(tc, EL1))
+ return checkFPAdvSIMDEnabled64(tc, cpsr, cpacr);
+
+ uint8_t cpacr_cp10 = cpacr.cp10;
+ bool cpacr_asedis = cpacr.asedis;
+
+ if (have_security && !ELIs64(tc, EL3) && !is_secure) {
+ if (nsacr.nsasedis)
+ cpacr_asedis = true;
+ if (nsacr.cp10 == 0)
+ cpacr_cp10 = 0;
+ }
+
+ if (cur_el != EL2) {
+ if (advsimd && cpacr_asedis)
+ return disabledFault();
+
+ if ((cur_el == EL0 && cpacr_cp10 != 0x3) ||
+ (cur_el != EL0 && !(cpacr_cp10 & 0x1)))
+ return disabledFault();
+ }
+
+ if (fpexc_check && !fpexc.en)
+ return disabledFault();
+
+ // -- aarch32/exceptions/traps/AArch32.CheckFPAdvSIMDTrap --
+
+ if (have_virtualization && !is_secure && ELIs64(tc, EL2))
+ return checkFPAdvSIMDTrap64(tc, cpsr);
+
+ if (have_virtualization && !is_secure) {
+ HCPTR hcptr = tc->readMiscReg(MISCREG_HCPTR);
+ bool hcptr_cp10 = hcptr.tcp10;
+ bool hcptr_tase = hcptr.tase;
+
+ if (have_security && !ELIs64(tc, EL3) && !is_secure) {
+ if (nsacr.nsasedis)
+ hcptr_tase = true;
+ if (nsacr.cp10)
+ hcptr_cp10 = true;
+ }
+
+ if ((advsimd && hcptr_tase) || hcptr_cp10) {
+ const uint32_t iss = advsimd ? (1 << 5) : 0xA;
+ if (cur_el == EL2) {
+ return std::make_shared<UndefinedInstruction>(
+ machInst, iss,
+ EC_TRAPPED_HCPTR, mnemonic);
+ } else {
+ return std::make_shared<HypervisorTrap>(
+ machInst, iss,
+ EC_TRAPPED_HCPTR);
+ }
+
+ }
+ }
+
+ if (have_security && ELIs64(tc, EL3)) {
+ HCPTR cptrEnCheck = tc->readMiscReg(MISCREG_CPTR_EL3);
+ if (cptrEnCheck.tfp)
+ return advSIMDFPAccessTrap64(EL3);
+ }
+
+ return NoFault;
+}
+
+
}
diff --git a/src/arch/arm/insts/static_inst.hh b/src/arch/arm/insts/static_inst.hh
index d4684c78f..9ca64d1fe 100644
--- a/src/arch/arm/insts/static_inst.hh
+++ b/src/arch/arm/insts/static_inst.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2013 ARM Limited
+ * Copyright (c) 2010-2013, 2016 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -363,6 +363,47 @@ class ArmStaticInst : public StaticInst
mnemonic, true);
}
+ /**
+ * Trap an access to Advanced SIMD or FP registers due to access
+ * control bits.
+ *
+ * See aarch64/exceptions/traps/AArch64.AdvSIMDFPAccessTrap in the
+ * ARM ARM psueodcode library.
+ *
+ * @param el Target EL for the trap
+ */
+ Fault advSIMDFPAccessTrap64(ExceptionLevel el) const;
+
+
+ /**
+ * Check an Advaned SIMD access against CPTR_EL2 and CPTR_EL3.
+ *
+ * See aarch64/exceptions/traps/AArch64.CheckFPAdvSIMDTrap in the
+ * ARM ARM psueodcode library.
+ */
+ Fault checkFPAdvSIMDTrap64(ThreadContext *tc, CPSR cpsr) const;
+
+ /**
+ * Check an Advaned SIMD access against CPACR_EL1, CPTR_EL2, and
+ * CPTR_EL3.
+ *
+ * See aarch64/exceptions/traps/AArch64.CheckFPAdvSIMDEnabled in the
+ * ARM ARM psueodcode library.
+ */
+ Fault checkFPAdvSIMDEnabled64(ThreadContext *tc,
+ CPSR cpsr, CPACR cpacr) const;
+
+ /**
+ * Check if a VFP/SIMD access from aarch32 should be allowed.
+ *
+ * See aarch32/exceptions/traps/AArch32.CheckAdvSIMDOrFPEnabled in the
+ * ARM ARM psueodcode library.
+ */
+ Fault checkAdvSIMDOrFPEnabled32(ThreadContext *tc,
+ CPSR cpsr, CPACR cpacr,
+ NSACR nsacr, FPEXC fpexc,
+ bool fpexc_check, bool advsimd) const;
+
public:
virtual void
annotateFault(ArmFault *fault) {}
diff --git a/src/arch/arm/isa/insts/fp.isa b/src/arch/arm/isa/insts/fp.isa
index 9a7f3f8a0..34dff5139 100644
--- a/src/arch/arm/isa/insts/fp.isa
+++ b/src/arch/arm/isa/insts/fp.isa
@@ -260,7 +260,7 @@ let {{
decoder_output += FpRegRegOpConstructor.subst(vmrsFpscrIop);
exec_output += PredOpExecute.subst(vmrsFpscrIop);
- vmrsApsrFpscrCode = vmrsApsrEnabledCheckCode + '''
+ vmrsApsrFpscrCode = vfpEnabledCheckCode + '''
FPSCR fpscr = FpCondCodes;
CondCodesNZ = (fpscr.n << 1) | fpscr.z;
CondCodesC = fpscr.c;
diff --git a/src/arch/arm/isa/templates/neon.isa b/src/arch/arm/isa/templates/neon.isa
index 45df741e7..9e9b79957 100644
--- a/src/arch/arm/isa/templates/neon.isa
+++ b/src/arch/arm/isa/templates/neon.isa
@@ -1,6 +1,6 @@
// -*- mode:c++ -*-
-// Copyright (c) 2010-2012 ARM Limited
+// Copyright (c) 2010-2012, 2016 ARM Limited
// All rights reserved
//
// The license below extends only to copyright in the software and shall
@@ -40,26 +40,11 @@
let {{
simdEnabledCheckCode = '''
{
- uint32_t issEnCheck;
- bool trapEnCheck;
- uint32_t seq;
- if (!vfpNeonEnabled(seq, Hcptr, Nsacr, Cpacr, Cpsr, issEnCheck,
- trapEnCheck, xc->tcBase(), Fpexc, true))
- {return disabledFault();}
- if (trapEnCheck) {
- CPSR cpsrEnCheck = Cpsr;
- if (cpsrEnCheck.mode == MODE_HYP) {
- return std::make_shared<UndefinedInstruction>(
- machInst, issEnCheck,
- EC_TRAPPED_HCPTR);
- } else {
- if (!inSecureState(Scr, Cpsr)) {
- return std::make_shared<HypervisorTrap>(
- machInst, issEnCheck,
- EC_TRAPPED_HCPTR);
- }
- }
- }
+ Fault fault = checkAdvSIMDOrFPEnabled32(xc->tcBase(),
+ Cpsr, Cpacr, Nsacr, Fpexc,
+ true, true);
+ if (fault != NoFault)
+ return fault;
}
'''
}};
diff --git a/src/arch/arm/isa/templates/vfp.isa b/src/arch/arm/isa/templates/vfp.isa
index 4da00e8d5..1c945cddc 100644
--- a/src/arch/arm/isa/templates/vfp.isa
+++ b/src/arch/arm/isa/templates/vfp.isa
@@ -1,6 +1,6 @@
// -*- mode:c++ -*-
-// Copyright (c) 2010-2013 ARM Limited
+// Copyright (c) 2010-2013, 2016 ARM Limited
// All rights reserved
//
// The license below extends only to copyright in the software and shall
@@ -39,125 +39,61 @@
let {{
vfpEnabledCheckCode = '''
- uint32_t issEnCheck;
- bool trapEnCheck;
- uint32_t seq;
- if (!vfpNeonEnabled(seq,Hcptr, Nsacr, Cpacr, Cpsr, issEnCheck,
- trapEnCheck, xc->tcBase(), Fpexc))
- {return disabledFault();}
- if (trapEnCheck) {
- CPSR cpsrEnCheck = Cpsr;
- if (cpsrEnCheck.mode == MODE_HYP) {
- return std::make_shared<UndefinedInstruction>(
- machInst, issEnCheck,
- EC_TRAPPED_HCPTR, mnemonic);
- } else {
- if (!inSecureState(Scr, Cpsr)) {
- return std::make_shared<HypervisorTrap>(
- machInst, issEnCheck,
- EC_TRAPPED_HCPTR);
- }
- }
- }
+ {
+ Fault fault = checkAdvSIMDOrFPEnabled32(xc->tcBase(),
+ Cpsr, Cpacr, Nsacr, Fpexc,
+ true, false);
+ if (fault != NoFault)
+ return fault;
+ }
'''
vfp64EnabledCheckCode = '''
- CPSR cpsrEnCheck = Cpsr;
- ExceptionLevel el = (ExceptionLevel) (uint8_t) cpsrEnCheck.el;
- if (!vfpNeon64Enabled(Cpacr64, el))
- return std::make_shared<SupervisorTrap>(machInst, 0x1E00000,
- EC_TRAPPED_SIMD_FP);
-
- if (ArmSystem::haveVirtualization(xc->tcBase()) && el <= EL2) {
- HCPTR cptrEnCheck = xc->tcBase()->readMiscReg(MISCREG_CPTR_EL2);
- if (cptrEnCheck.tfp)
- return std::make_shared<HypervisorTrap>(machInst, 0x1E00000,
- EC_TRAPPED_SIMD_FP);
- }
-
- if (ArmSystem::haveSecurity(xc->tcBase())) {
- HCPTR cptrEnCheck = xc->tcBase()->readMiscReg(MISCREG_CPTR_EL3);
- if (cptrEnCheck.tfp)
- return std::make_shared<SecureMonitorTrap>(machInst, 0x1E00000,
- EC_TRAPPED_SIMD_FP);
- }
+ {
+ Fault fault = checkFPAdvSIMDEnabled64(xc->tcBase(), Cpsr, Cpacr64);
+ if (fault != NoFault)
+ return fault;
+ }
'''
vmsrEnabledCheckCode = '''
- uint32_t issEnCheck;
- bool trapEnCheck;
- uint32_t seq;
- if (!vfpNeonEnabled(seq,Hcptr, Nsacr, Cpacr, Cpsr, issEnCheck,
- trapEnCheck, xc->tcBase()))
- if (dest != (int)MISCREG_FPEXC && dest != (int)MISCREG_FPSID)
- {return disabledFault();}
- if (!inPrivilegedMode(Cpsr))
- if (dest != (int)MISCREG_FPSCR)
- return disabledFault();
- if (trapEnCheck) {
- CPSR cpsrEnCheck = Cpsr;
- if (cpsrEnCheck.mode == MODE_HYP) {
- return std::make_shared<UndefinedInstruction>(
- machInst, issEnCheck,
- EC_TRAPPED_HCPTR, mnemonic);
- } else {
- if (!inSecureState(Scr, Cpsr)) {
- return std::make_shared<HypervisorTrap>(
- machInst, issEnCheck,
- EC_TRAPPED_HCPTR);
- }
- }
+ {
+ Fault fault = NoFault;
+ if (dest == (int)MISCREG_FPSCR) {
+ fault = checkAdvSIMDOrFPEnabled32(xc->tcBase(),
+ Cpsr, Cpacr, Nsacr, Fpexc,
+ true, false);
+ } else if (!inPrivilegedMode(Cpsr)) {
+ fault = disabledFault();
+ } else {
+ fault = checkAdvSIMDOrFPEnabled32(xc->tcBase(),
+ Cpsr, Cpacr, Nsacr, Fpexc,
+ false, false);
}
+
+ if (fault != NoFault)
+ return fault;
+ }
'''
vmrsEnabledCheckCode = '''
- uint32_t issEnCheck;
- bool trapEnCheck;
- uint32_t seq;
- if (!vfpNeonEnabled(seq,Hcptr, Nsacr, Cpacr, Cpsr, issEnCheck,
- trapEnCheck, xc->tcBase()))
- if (op1 != (int)MISCREG_FPEXC && op1 != (int)MISCREG_FPSID &&
- op1 != (int)MISCREG_MVFR0 && op1 != (int)MISCREG_MVFR1)
- {return disabledFault();}
- if (!inPrivilegedMode(Cpsr))
- if (op1 != (int)MISCREG_FPSCR)
- return disabledFault();
- if (trapEnCheck) {
- CPSR cpsrEnCheck = Cpsr;
- if (cpsrEnCheck.mode == MODE_HYP) {
- return std::make_shared<UndefinedInstruction>(
- machInst, issEnCheck,
- EC_TRAPPED_HCPTR, mnemonic);
- } else {
- if (!inSecureState(Scr, Cpsr)) {
- return std::make_shared<HypervisorTrap>(
- machInst, issEnCheck,
- EC_TRAPPED_HCPTR);
- }
- }
- }
- '''
- vmrsApsrEnabledCheckCode = '''
- uint32_t issEnCheck;
- bool trapEnCheck;
- uint32_t seq;
- if (!vfpNeonEnabled(seq,Hcptr, Nsacr, Cpacr, Cpsr, issEnCheck,
- trapEnCheck, xc->tcBase()))
- {return disabledFault();}
- if (trapEnCheck) {
- CPSR cpsrEnCheck = Cpsr;
- if (cpsrEnCheck.mode == MODE_HYP) {
- return std::make_shared<UndefinedInstruction>(
- machInst, issEnCheck,
- EC_TRAPPED_HCPTR, mnemonic);
- } else {
- if (!inSecureState(Scr, Cpsr)) {
- return std::make_shared<HypervisorTrap>(
- machInst, issEnCheck,
- EC_TRAPPED_HCPTR);
- }
- }
+ {
+ Fault fault = NoFault;
+ if (op1 == (int)MISCREG_FPSCR) {
+ fault = checkAdvSIMDOrFPEnabled32(xc->tcBase(),
+ Cpsr, Cpacr, Nsacr, Fpexc,
+ true, false);
+ } else if (!inPrivilegedMode(Cpsr)) {
+ fault = disabledFault();
+ } else {
+ fault = checkAdvSIMDOrFPEnabled32(xc->tcBase(),
+ Cpsr, Cpacr, Nsacr, Fpexc,
+ false, false);
}
+
+ if (fault != NoFault)
+ return fault;
+ }
'''
}};
diff --git a/src/arch/arm/utility.cc b/src/arch/arm/utility.cc
index a4ae849c1..df00e8bcc 100644
--- a/src/arch/arm/utility.cc
+++ b/src/arch/arm/utility.cc
@@ -870,91 +870,6 @@ decodeMrsMsrBankedReg(uint8_t sysM, bool r, bool &isIntReg, int &regIdx,
}
bool
-vfpNeonEnabled(uint32_t &seq, HCPTR hcptr, NSACR nsacr, CPACR cpacr, CPSR cpsr,
- uint32_t &iss, bool &trap, ThreadContext *tc, FPEXC fpexc,
- bool isSIMD)
-{
- iss = 0;
- trap = false;
- bool undefined = false;
- bool haveSecurity = ArmSystem::haveSecurity(tc);
- bool haveVirtualization = ArmSystem::haveVirtualization(tc);
- bool isSecure = inSecureState(tc);
-
- // Non-secure view of CPACR and HCPTR determines behavior
- // Copy register values
- uint8_t cpacr_cp10 = cpacr.cp10;
- bool cpacr_asedis = cpacr.asedis;
- bool hcptr_cp10 = false;
- bool hcptr_tase = false;
-
- bool cp10_enabled = cpacr.cp10 == 0x3
- || (cpacr.cp10 == 0x1 && inPrivilegedMode(cpsr));
-
- bool cp11_enabled = cpacr.cp11 == 0x3
- || (cpacr.cp11 == 0x1 && inPrivilegedMode(cpsr));
-
- if (cp11_enabled) {
- undefined |= !(fpexc.en && cp10_enabled);
- } else {
- undefined |= !(fpexc.en && cp10_enabled && (cpacr.cp11 == cpacr.cp10));
- }
-
- if (haveVirtualization) {
- hcptr_cp10 = hcptr.tcp10;
- undefined |= hcptr.tcp10 != hcptr.tcp11;
- hcptr_tase = hcptr.tase;
- }
-
- if (haveSecurity) {
- undefined |= nsacr.cp10 != nsacr.cp11;
- if (!isSecure) {
- // Modify register values to the Non-secure view
- if (!nsacr.cp10) {
- cpacr_cp10 = 0;
- if (haveVirtualization) {
- hcptr_cp10 = true;
- }
- }
- if (nsacr.nsasedis) {
- cpacr_asedis = true;
- if (haveVirtualization) {
- hcptr_tase = true;
- }
- }
- }
- }
-
- // Check Coprocessor Access Control Register for permission to use CP10/11.
- if (!haveVirtualization || (cpsr.mode != MODE_HYP)) {
- switch (cpacr_cp10)
- {
- case 0:
- undefined = true;
- break;
- case 1:
- undefined |= inUserMode(cpsr);
- break;
- }
-
- // Check if SIMD operations are disabled
- if (isSIMD && cpacr_asedis) undefined = true;
- }
-
- // If required, check FPEXC enabled bit.
- undefined |= !fpexc.en;
-
- if (haveSecurity && haveVirtualization && !isSecure) {
- if (hcptr_cp10 || (isSIMD && hcptr_tase)) {
- iss = isSIMD ? (1 << 5) : 0xA;
- trap = true;
- }
- }
-
- return (!undefined);
-}
-
-bool
SPAlignmentCheckEnabled(ThreadContext* tc)
{
switch (opModeToEL(currOpMode(tc))) {
diff --git a/src/arch/arm/utility.hh b/src/arch/arm/utility.hh
index 9268a0d5c..8fb6558be 100644
--- a/src/arch/arm/utility.hh
+++ b/src/arch/arm/utility.hh
@@ -260,20 +260,6 @@ bool msrMrs64TrapToHyp(const MiscRegIndex miscReg, bool isRead, CPTR cptr,
bool msrMrs64TrapToMon(const MiscRegIndex miscReg, CPTR cptr,
ExceptionLevel el, bool * isVfpNeon);
-bool
-vfpNeonEnabled(uint32_t &seq, HCPTR hcptr, NSACR nsacr, CPACR cpacr, CPSR cpsr,
- uint32_t &iss, bool &trap, ThreadContext *tc,
- FPEXC fpexc = (1<<30), bool isSIMD = false);
-
-static inline bool
-vfpNeon64Enabled(CPACR cpacr, ExceptionLevel el)
-{
- if ((el == EL0 && cpacr.fpen != 0x3) ||
- (el == EL1 && !(cpacr.fpen & 0x1)))
- return false;
- return true;
-}
-
bool SPAlignmentCheckEnabled(ThreadContext* tc);
uint64_t getArgument(ThreadContext *tc, int &number, uint16_t size, bool fp);