arch-arm: Implementation of Vector Catch debug exception
authorJordi Vaquero <jordi.vaquero@metempsy.com>
Tue, 29 Oct 2019 17:32:45 +0000 (18:32 +0100)
committerJordi Vaquero <jordi.vaquero@metempsy.com>
Mon, 6 Jul 2020 09:10:33 +0000 (09:10 +0000)
This commit implements Vector Catch exception as they are described
in Armv8 reference manual chapter G2. This exception is just for AArch32.

+ tlb.cc: Implements the entry point for vector catch in addres mode
+ faults.hh/cc: Implements the entry point for vector catch in exception trap mode.
+ miscregs.cc: enables the use of vector catch releated registers
+ miscregs_types.hh: New bitwise type for vector catch control registers.
+ types.hh: declaration of EC for vector catch exception
+ self_debug.hh/cc: Main implementation of the vector catch functions to
                    match address and exceptions type.

Change-Id: Idbef26b16eff059e94ff16fac13bf5708dfe647f
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/30618
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/arch/arm/faults.cc
src/arch/arm/faults.hh
src/arch/arm/miscregs.cc
src/arch/arm/miscregs_types.hh
src/arch/arm/self_debug.cc
src/arch/arm/self_debug.hh
src/arch/arm/tlb.cc
src/arch/arm/types.hh

index 6a3ee18ee6c3d6b80c7388a48fe7e9e1425b2d36..ecc9e4dd5dc095bb60975aa49dbb26c0261415ce 100644 (file)
@@ -42,6 +42,8 @@
 #include "arch/arm/faults.hh"
 
 #include "arch/arm/insts/static_inst.hh"
+#include "arch/arm/isa.hh"
+#include "arch/arm/self_debug.hh"
 #include "arch/arm/system.hh"
 #include "arch/arm/utility.hh"
 #include "base/compiler.hh"
@@ -480,7 +482,6 @@ ArmFault::update(ThreadContext *tc)
 void
 ArmFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
 {
-
     // Update fault state informations, like the starting mode (aarch32)
     // or EL (aarch64) and the ending mode or EL.
     // From the update function we are also evaluating if the fault must
@@ -493,6 +494,9 @@ ArmFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
         return;
     }
 
+    if (vectorCatch(tc, inst))
+        return;
+
     // ARMv7 (ARM ARM issue C B1.9)
 
     bool have_security       = ArmSystem::haveSecurity(tc);
@@ -716,6 +720,21 @@ ArmFault::invoke64(ThreadContext *tc, const StaticInstPtr &inst)
         setSyndrome(tc, getSyndromeReg64());
 }
 
+bool
+ArmFault::vectorCatch(ThreadContext *tc, const StaticInstPtr &inst)
+{
+    auto *isa = static_cast<ArmISA::ISA *>(tc->getIsaPtr());
+    SelfDebug * sd = isa->getSelfDebug();
+    VectorCatch* vc = sd->getVectorCatch(tc);
+    if (!vc->isVCMatch()) {
+        Fault fault = sd->testVectorCatch(tc, 0x0, this);
+        if (fault != NoFault)
+            fault->invoke(tc, inst);
+        return true;
+    }
+    return false;
+}
+
 ArmStaticInst *
 ArmFault::instrAnnotate(const StaticInstPtr &inst)
 {
@@ -1094,7 +1113,9 @@ AbortFault<T>::invoke(ThreadContext *tc, const StaticInstPtr &inst)
             tc->setMiscReg(T::FarIndex, faultAddr);
             if (debug == ArmFault::BRKPOINT){
                 Rext.moe = 0x1;
-            } else if (debug > ArmFault::BRKPOINT) {
+            } else if (debug == ArmFault::VECTORCATCH){
+                Rext.moe = 0x5;
+            } else if (debug > ArmFault::VECTORCATCH) {
                 Rext.moe = 0xa;
                 fsr.cm = (debug == ArmFault::WPOINT_CM)? 1 : 0;
             }
index 8a127ffdb72f4c6bd860b6b7800a8c13f861d9e9..a552757d52886da6f33bffe2ac01a6dfb69ac161 100644 (file)
@@ -154,6 +154,7 @@ class ArmFault : public FaultBase
     {
         NODEBUG = 0,
         BRKPOINT,
+        VECTORCATCH,
         WPOINT_CM,
         WPOINT_NOCM
     };
@@ -226,6 +227,8 @@ class ArmFault : public FaultBase
     void update(ThreadContext *tc);
     bool isResetSPSR(){ return bStep; }
 
+    bool vectorCatch(ThreadContext *tc, const StaticInstPtr &inst);
+
     ArmStaticInst *instrAnnotate(const StaticInstPtr &inst);
     virtual void annotate(AnnotationIDs id, uint64_t val) {}
     virtual FaultStat& countStat() = 0;
@@ -241,12 +244,13 @@ class ArmFault : public FaultBase
     virtual bool abortDisable(ThreadContext *tc) = 0;
     virtual bool fiqDisable(ThreadContext *tc) = 0;
     virtual ExceptionClass ec(ThreadContext *tc) const = 0;
+    virtual uint32_t vectorCatchFlag() const { return 0x0; }
     virtual uint32_t iss() const = 0;
     virtual bool isStage2() const { return false; }
     virtual FSR getFsr(ThreadContext *tc) const { return 0; }
     virtual void setSyndrome(ThreadContext *tc, MiscRegIndex syndrome_reg);
     virtual bool getFaultVAddr(Addr &va) const { return false; }
-
+    OperatingMode getToMode() const { return toMode; }
 };
 
 template<typename T>
@@ -323,6 +327,7 @@ class UndefinedInstruction : public ArmFaultVals<UndefinedInstruction>
     bool routeToHyp(ThreadContext *tc) const override;
     ExceptionClass ec(ThreadContext *tc) const override;
     uint32_t iss() const override;
+    uint32_t vectorCatchFlag() const override { return 0x02000002; }
 };
 
 class SupervisorCall : public ArmFaultVals<SupervisorCall>
@@ -343,6 +348,7 @@ class SupervisorCall : public ArmFaultVals<SupervisorCall>
     bool routeToHyp(ThreadContext *tc) const override;
     ExceptionClass ec(ThreadContext *tc) const override;
     uint32_t iss() const override;
+    uint32_t vectorCatchFlag() const override { return 0x04000404; }
 };
 
 class SecureMonitorCall : public ArmFaultVals<SecureMonitorCall>
@@ -358,6 +364,7 @@ class SecureMonitorCall : public ArmFaultVals<SecureMonitorCall>
                 StaticInst::nullStaticInstPtr) override;
     ExceptionClass ec(ThreadContext *tc) const override;
     uint32_t iss() const override;
+    uint32_t vectorCatchFlag() const override { return 0x00000400; }
 };
 
 class SupervisorTrap : public ArmFaultVals<SupervisorTrap>
@@ -400,6 +407,7 @@ class HypervisorCall : public ArmFaultVals<HypervisorCall>
     HypervisorCall(ExtMachInst _machInst, uint32_t _imm);
 
     ExceptionClass ec(ThreadContext *tc) const override;
+    uint32_t vectorCatchFlag() const override { return 0xFFFFFFFF; }
 };
 
 class HypervisorTrap : public ArmFaultVals<HypervisorTrap>
@@ -487,6 +495,7 @@ class PrefetchAbort : public AbortFault<PrefetchAbort>
     // @todo: external aborts should be routed if SCR.EA == 1
     bool routeToMonitor(ThreadContext *tc) const override;
     bool routeToHyp(ThreadContext *tc) const override;
+    uint32_t vectorCatchFlag() const override { return 0x08000808; }
 };
 
 class DataAbort : public AbortFault<DataAbort>
@@ -520,6 +529,7 @@ class DataAbort : public AbortFault<DataAbort>
     bool routeToHyp(ThreadContext *tc) const override;
     uint32_t iss() const override;
     void annotate(AnnotationIDs id, uint64_t val) override;
+    uint32_t vectorCatchFlag() const override { return 0x10001010; }
 };
 
 class VirtualDataAbort : public AbortFault<VirtualDataAbort>
@@ -543,6 +553,7 @@ class Interrupt : public ArmFaultVals<Interrupt>
     bool routeToMonitor(ThreadContext *tc) const override;
     bool routeToHyp(ThreadContext *tc) const override;
     bool abortDisable(ThreadContext *tc) override;
+    uint32_t vectorCatchFlag() const override { return 0x40004040; }
 };
 
 class VirtualInterrupt : public ArmFaultVals<VirtualInterrupt>
@@ -558,6 +569,7 @@ class FastInterrupt : public ArmFaultVals<FastInterrupt>
     bool routeToHyp(ThreadContext *tc) const override;
     bool abortDisable(ThreadContext *tc) override;
     bool fiqDisable(ThreadContext *tc) override;
+    uint32_t vectorCatchFlag() const override { return 0x80008080; }
 };
 
 class VirtualFastInterrupt : public ArmFaultVals<VirtualFastInterrupt>
index 2dd1d78e3bf5bf39ee6c335c4841e229b19c826c..cc451c6c185653aa7107b9b5d9e63c791912a230 100644 (file)
@@ -61,6 +61,8 @@ decodeCP14Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
                     return MISCREG_DBGDIDR;
                   case 1:
                     return MISCREG_DBGDSCRint;
+                  case 7:
+                    return MISCREG_DBGVCR;
                 }
                 break;
               case 2:
@@ -563,6 +565,12 @@ decodeCP15Reg(unsigned crn, unsigned opc1, unsigned crm, unsigned opc2)
                     return MISCREG_BPIALLIS;
                 }
                 break;
+              case 2:
+                switch (opc2) {
+                  case 7:
+                    return MISCREG_DBGDEVID0;
+                }
+                break;
               case 4:
                 if (opc2 == 0) {
                     return MISCREG_PAR;
@@ -3417,8 +3425,7 @@ ISA::initializeMiscRegMetadata()
       .unimplemented()
       .allPrivileges();
     InitReg(MISCREG_DBGVCR)
-      .unimplemented()
-      .allPrivileges();
+      .allPrivileges().exceptUserMode();
     InitReg(MISCREG_DBGDTRRXext)
       .unimplemented()
       .allPrivileges();
@@ -3625,7 +3632,6 @@ ISA::initializeMiscRegMetadata()
       .unimplemented()
       .allPrivileges().monSecureWrite(0).monNonSecureWrite(0);
     InitReg(MISCREG_DBGDEVID0)
-      .unimplemented()
       .allPrivileges().monSecureWrite(0).monNonSecureWrite(0);
     InitReg(MISCREG_TEECR)
       .unimplemented()
@@ -4532,7 +4538,7 @@ ISA::initializeMiscRegMetadata()
     InitReg(MISCREG_MDDTRRX_EL0)
       .allPrivileges();
     InitReg(MISCREG_DBGVCR32_EL2)
-      .allPrivileges()
+      .hyp().mon()
       .mapsTo(MISCREG_DBGVCR);
     InitReg(MISCREG_MDRAR_EL1)
       .allPrivileges().monSecureWrite(0).monNonSecureWrite(0)
index 301d6fb2effe71fb06c348fc60e1dab7f5f568ce..d3787ffae5768719524cbd297c67c0ca3213a861 100644 (file)
@@ -735,6 +735,44 @@ namespace ArmISA
         Bitfield<5, 2> moe;
         Bitfield<1, 0> res0_1;
    EndBitUnion(DBGDS32)
+
+   BitUnion32(DBGVCR)
+        Bitfield<31> nsf;
+        Bitfield<30> nsi;
+        Bitfield<29> res0_5;
+        Bitfield<28> nsd;
+        Bitfield<27> nsp;
+        Bitfield<26> nss;
+        Bitfield<25> nsu;
+        Bitfield<24, 16> res0_4;
+        Bitfield<15> mf;
+        Bitfield<14> mi;
+        Bitfield<13> res0_3;
+        Bitfield<12> md;
+        Bitfield<11> mp;
+        Bitfield<10> ms;
+        Bitfield<9,8> res0_2;
+        Bitfield<7> sf;
+        Bitfield<6> si;
+        Bitfield<5> res0_1;
+        Bitfield<4> sd;
+        Bitfield<3> sp;
+        Bitfield<2> ss;
+        Bitfield<1> su;
+        Bitfield<0> res0_0;
+   EndBitUnion(DBGVCR)
+
+   BitUnion32(DEVID)
+        Bitfield<31,28> cidmask;
+        Bitfield<27,24> auxregs;
+        Bitfield<23,20> doublelock;
+        Bitfield<19,16> virtextns;
+        Bitfield<15,12> vectorcatch;
+        Bitfield<11,8>  bpaddremask;
+        Bitfield<7,4>   wpaddrmask;
+        Bitfield<3,0>   pcsample;
+   EndBitUnion(DEVID)
+
 }
 
 #endif // __ARCH_ARM_MISCREGS_TYPES_HH__
index f0f420db514082701705b402895c86d04624b93e..9a60aab68d5c3cdb51bd2902a2b1cea5b65c1601 100644 (file)
@@ -618,3 +618,123 @@ SoftwareStep::advanceSS(ThreadContext * tc)
     return res;
 }
 
+Fault
+SelfDebug::testVectorCatch(ThreadContext *tc, Addr addr,
+                           ArmFault* fault)
+{
+
+    setAArch32(tc);
+    to32 = targetAArch32(tc);
+    if (!initialized)
+        init(tc);
+    if (!isDebugEnabled(tc) || !enableFlag || !aarch32)
+        return NoFault;
+
+    ExceptionLevel el = (ExceptionLevel) currEL(tc);
+    bool debug;
+    if (fault == nullptr)
+        debug = vcExcpt->addressMatching(tc, addr, el);
+    else
+        debug = vcExcpt->exceptionTrapping(tc, el, fault);
+    if (debug) {
+        if (enableTdeTge) {
+            return std::make_shared<HypervisorTrap>(0, 0x22,
+                                        EC_PREFETCH_ABORT_TO_HYP);
+        } else {
+            return std::make_shared<PrefetchAbort>(addr,
+                                       ArmFault::DebugEvent, false,
+                                       ArmFault::UnknownTran,
+                                       ArmFault::VECTORCATCH);
+        }
+    }
+
+    return NoFault;
+}
+
+bool
+VectorCatch::addressMatching(ThreadContext *tc, Addr addr, ExceptionLevel el)
+{
+    // Each bit position in this string corresponds to a bit in DBGVCR
+    // and an exception vector.
+    bool enabled;
+    if (conf->isAArch32() && ELIs32(tc, EL1) &&
+        (addr & 0x3) == 0 && el != EL2 ) {
+
+        DBGVCR match_word = 0x0;
+
+        Addr vbase = getVectorBase(tc, false);
+        Addr vaddress = addr & ~ 0x1f;
+        Addr low_addr = bits(addr, 5, 2);
+        if (vaddress == vbase) {
+            if (ArmSystem::haveEL(tc, EL3) && !inSecureState(tc)) {
+                uint32_t bmask = 1UL << (low_addr + 24);
+                match_word = match_word | (DBGVCR) bmask;
+                // Non-secure vectors
+            } else {
+                uint32_t bmask = 1UL << (low_addr);
+                match_word = match_word | (DBGVCR) bmask;
+                // Secure vectors (or no EL3)
+            }
+        }
+        uint32_t mvbase = getVectorBase(tc, true);
+        if (ArmSystem::haveEL(tc, EL3) && ELIs32(tc, EL3) &&
+            inSecureState(tc) && (vaddress == mvbase)) {
+            uint32_t bmask = 1UL << (low_addr + 8);
+            match_word = match_word | (DBGVCR) bmask;
+            // Monitor vectors
+        }
+
+        DBGVCR mask;
+
+        // Mask out bits not corresponding to vectors.
+        if (!ArmSystem::haveEL(tc, EL3)) {
+            mask = (DBGVCR) 0xDE;
+        } else if (!ELIs32(tc, EL3)) {
+            mask = (DBGVCR) 0xDE0000DE;
+        } else {
+            mask = (DBGVCR) 0xDE00DEDE;
+        }
+        DBGVCR dbgvcr = tc->readMiscReg(MISCREG_DBGVCR);
+        match_word = match_word & dbgvcr & mask;
+        enabled = match_word != 0x0;
+        // Check for UNPREDICTABLE case - match on Prefetch Abort and
+        // Data Abort vectors
+        ExceptionLevel ELd = debugTargetFrom(tc, inSecureState(tc));
+        if (((match_word & 0x18001818) != 0x0) && ELd == el) {
+            enabled = false;
+        }
+    } else {
+        enabled = false;
+    }
+    return enabled;
+}
+
+bool
+VectorCatch::exceptionTrapping(ThreadContext *tc, ExceptionLevel el,
+                               ArmFault* fault)
+{
+    if (conf->isAArch32() && ELIs32(tc, EL1) && el != EL2) {
+
+        DBGVCR dbgvcr = tc->readMiscReg(MISCREG_DBGVCR);
+        DBGVCR match_type = fault->vectorCatchFlag();
+        DBGVCR mask;
+
+        if (!ArmSystem::haveEL(tc, EL3)) {
+            mask = (DBGVCR) 0xDE;
+        } else if (ELIs32(tc, EL3) && fault->getToMode() == MODE_MON) {
+            mask = (DBGVCR) 0x0000DE00;
+        } else {
+            if (inSecureState(tc))
+                mask = (DBGVCR) 0x000000DE;
+            else
+                mask = (DBGVCR) 0xDE000000;
+        }
+        match_type = match_type & mask & dbgvcr;
+
+        if (match_type != 0x0) {
+            return true;
+        }
+    }
+    return false;
+}
+
index 48d784cd52bc9e3fc0f4507ee925c07831470f83..9739c77d75033c53a7dfc867270f9f44cb6ffaea 100644 (file)
@@ -257,12 +257,49 @@ class SoftwareStep
     }
 };
 
+class VectorCatch
+{
+  private:
+    bool vcmatch;
+    SelfDebug *conf;
+    std::vector<Fault *> vectorTypes();
+
+  public:
+    VectorCatch(bool _vcmatch, SelfDebug* s) : vcmatch(_vcmatch), conf(s)
+    {}
+
+    bool addressMatching(ThreadContext *tc, Addr addr, ExceptionLevel el);
+    bool exceptionTrapping(ThreadContext *tc, ExceptionLevel el,
+                           ArmFault* fault);
+    bool isVCMatch()
+    {
+        return vcmatch;
+    }
+
+  private:
+    Addr getVectorBase(ThreadContext *tc, bool monitor)
+    {
+        if (monitor) {
+            return tc->readMiscReg(MISCREG_MVBAR) & ~0x1F;
+        }
+        SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR_EL1);
+        if (sctlr.v) {
+            return (Addr) 0xFFFF0000;
+        } else {
+            Addr vbar = tc->readMiscReg(MISCREG_VBAR) & ~0x1F;
+            return vbar;
+        }
+    }
+
+};
+
 class SelfDebug
 {
   private:
     std::vector<BrkPoint> arBrkPoints;
     std::vector<WatchPoint> arWatchPoints;
     SoftwareStep * softStep;
+    VectorCatch * vcExcpt;
 
     bool initialized;
     bool enableTdeTge; // MDCR_EL2.TDE || HCR_EL2.TGE
@@ -287,6 +324,7 @@ class SelfDebug
     ~SelfDebug()
     {
         delete softStep;
+        delete vcExcpt;
     }
 
     Fault testBreakPoints(ThreadContext *tc, Addr vaddr);
@@ -387,6 +425,7 @@ class SelfDebug
     {
         softStep->setCPSRD(mask);
     }
+
     inline bool isAArch32()
     {
         return aarch32;
@@ -410,6 +449,12 @@ class SelfDebug
         return softStep;
     }
 
+    VectorCatch* getVectorCatch(ThreadContext* tc)
+    {
+        if (!initialized)
+            init(tc);
+        return vcExcpt;
+    }
 
     bool targetAArch32(ThreadContext * tc)
     {
@@ -468,6 +513,10 @@ class SelfDebug
         const HDCR mdcr  = tc->readMiscRegNoEffect(MISCREG_MDCR_EL2);
         setenableTDETGE(hcr, mdcr);
 
+        // Enable Vector Catch Exceptions
+        const DEVID dvid = tc->readMiscReg(MISCREG_DBGDEVID0);
+        vcExcpt = new VectorCatch(dvid.vectorcatch==0x0, this);
+
     }
 };
 
index 1a26ab5a1080989431f0daa7ce730a7761c21353..f92f8e00d365dfbd2d84f315c03f019a2d6884a0 100644 (file)
@@ -1196,10 +1196,13 @@ TLB::translateFs(const RequestPtr &req, ThreadContext *tc, Mode mode,
     if (fault == NoFault) {
         auto *isa = static_cast<ArmISA::ISA *>(tc->getIsaPtr());
         SelfDebug * sd = isa->getSelfDebug();
-        if (mode == Execute) {
+        if (mode == Execute)
+        {
             const bool d_step = sd->getSstep()->advanceSS(tc);
             if (!d_step) {
-                fault = sd->testBreakPoints(tc, req->getVaddr());
+                fault = sd->testVectorCatch(tc, req->getVaddr(), nullptr);
+                if (fault == NoFault)
+                    fault = sd->testBreakPoints(tc, req->getVaddr());
             }
         }
         else if (!req->isCacheMaintenance() ||
index 0119e4e66e82ce21d665502b68164f537f703c57..fa877be06a989e92c7fe944b9ba4f526d439d1b9 100644 (file)
@@ -693,6 +693,7 @@ namespace ArmISA
         EC_WATCHPOINT_LOWER_EL     = 0x34,
         EC_WATCHPOINT_CURR_EL      = 0x35,
         EC_SOFTWARE_BREAKPOINT     = 0x38,
+        EC_VECTOR_CATCH            = 0x3A,
         EC_SOFTWARE_BREAKPOINT_64  = 0x3C,
     };