arm: Correctly check FP/SIMD access permission in aarch32
authorAndreas Sandberg <andreas.sandberg@arm.com>
Thu, 2 Jun 2016 12:38:30 +0000 (13:38 +0100)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Thu, 2 Jun 2016 12:38:30 +0000 (13:38 +0100)
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>
src/arch/arm/insts/static_inst.cc
src/arch/arm/insts/static_inst.hh
src/arch/arm/isa/insts/fp.isa
src/arch/arm/isa/templates/neon.isa
src/arch/arm/isa/templates/vfp.isa
src/arch/arm/utility.cc
src/arch/arm/utility.hh

index 6fdd07ff6da5e0beb28b5a968b25b5acd5e942fb..d4ea1bcdfea9a8e92741a8905c61ab79e521cc89 100644 (file)
@@ -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;
+}
+
+
 }
index d4684c78fd92408c6d675e38da1dd6638c997a77..9ca64d1fed359b35e7d14eea556ffa084afa8215 100644 (file)
@@ -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) {}
index 9a7f3f8a0d053e9e4cb6d2fa44577c865ac546fb..34dff51393163eeefc4c8d3fd08dd942e9cc95b4 100644 (file)
@@ -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;
index 45df741e7c5c1d9a3867b52c3677b4e95f5547a4..9e9b7995710ec559f8458e821f7e18b2dc407af0 100644 (file)
@@ -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
 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;
     }
     '''
 }};
index 4da00e8d529e1b73c438e544ca3e50fd7bc63090..1c945cddc7672515228115f3fab36e16c2797130 100644 (file)
@@ -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
 
 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;
+    }
     '''
 }};
 
index a4ae849c12f8a2a60fe9fcb243f607c223744a9c..df00e8bcca736b1c8076f2462ed4ad78bc42eed1 100644 (file)
@@ -869,91 +869,6 @@ decodeMrsMsrBankedReg(uint8_t sysM, bool r, bool &isIntReg, int &regIdx,
     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)
 {
index 9268a0d5cf6a7245e810a6145cccc4ba8d69e66c..8fb6558beea3c6b2a3f19d2b9562cc30ba73a866 100644 (file)
@@ -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);