From: Andreas Sandberg Date: Thu, 2 Jun 2016 12:38:30 +0000 (+0100) Subject: arm: Correctly check FP/SIMD access permission in aarch32 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f48ad5b29d6f291b4f3679ff5fb7b5beae10d6fa;p=gem5.git 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 Reviewed-by: Mitch Hayenga Reviewed-by: Nathanael Premillieu --- 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(machInst, 0x1E00000, + EC_TRAPPED_SIMD_FP); + case EL2: + return std::make_shared(machInst, 0x1E00000, + EC_TRAPPED_SIMD_FP); + case EL3: + return std::make_shared(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( + machInst, iss, + EC_TRAPPED_HCPTR, mnemonic); + } else { + return std::make_shared( + 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( - machInst, issEnCheck, - EC_TRAPPED_HCPTR); - } else { - if (!inSecureState(Scr, Cpsr)) { - return std::make_shared( - 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( - machInst, issEnCheck, - EC_TRAPPED_HCPTR, mnemonic); - } else { - if (!inSecureState(Scr, Cpsr)) { - return std::make_shared( - 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(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(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(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( - machInst, issEnCheck, - EC_TRAPPED_HCPTR, mnemonic); - } else { - if (!inSecureState(Scr, Cpsr)) { - return std::make_shared( - 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( - machInst, issEnCheck, - EC_TRAPPED_HCPTR, mnemonic); - } else { - if (!inSecureState(Scr, Cpsr)) { - return std::make_shared( - 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( - machInst, issEnCheck, - EC_TRAPPED_HCPTR, mnemonic); - } else { - if (!inSecureState(Scr, Cpsr)) { - return std::make_shared( - 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 @@ -869,91 +869,6 @@ decodeMrsMsrBankedReg(uint8_t sysM, bool r, bool &isIntReg, int ®Idx, return (ok); } -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) { 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);