arch-arm: Implementation of SelfHosted Debug Software step
authorJordi Vaquero <jordi.vaquero@metempsy.com>
Tue, 29 Oct 2019 15:28:30 +0000 (16:28 +0100)
committerJordi Vaquero <jordi.vaquero@metempsy.com>
Thu, 2 Jul 2020 11:53:15 +0000 (11:53 +0000)
This commit implements SelfHosted Debug Software step as is defined in
Armv8 Reference manual chapter D2.

+ decoder.hh/cc/isa: Checks the software step bit in order to skip the instruction
              before its decode.
+ faults.hh/cc: implemented SoftwareStep exception and proper modification
                of spsr during the invoke of other exceptions
+ isa.cc: Set debug mask if needed during cpsr modification
+ tlb.cc: Checks if software step is in ACTIVE state to avoid trigger
          breakpoint or watchpoint exception
+ self_debug.hh/cc: Implementation of State change and ss bit based during eret.
+ types.hh: Define sofware step flags like step, load or stepped to check the different flags
        that triggering software step should use for the ISS code.
+ pseudo.hh/isa: Triggers the sofware step esception after decode.
+ static_inst.cc: Call debugExceptionReturnsSS durint eret routine.

Change-Id: I3a64507c64842c34c76ad7f6daa5f4306bd55d2c
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/30617
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
16 files changed:
src/arch/arm/decoder.cc
src/arch/arm/faults.cc
src/arch/arm/faults.hh
src/arch/arm/insts/pseudo.cc
src/arch/arm/insts/pseudo.hh
src/arch/arm/insts/static_inst.cc
src/arch/arm/isa.cc
src/arch/arm/isa/bitfields.isa
src/arch/arm/isa/decoder/decoder.isa
src/arch/arm/isa/formats/pseudo.isa
src/arch/arm/isa/insts/ldr.isa
src/arch/arm/isa/insts/ldr64.isa
src/arch/arm/self_debug.cc
src/arch/arm/self_debug.hh
src/arch/arm/tlb.cc
src/arch/arm/types.hh

index 8f37e63dbebca56a38871770accb0cd840ad5c92..d7de6a255e76c322370ed6bf34622a97662b2001 100644 (file)
@@ -53,7 +53,8 @@ namespace ArmISA
 GenericISA::BasicDecodeCache Decoder::defaultCache;
 
 Decoder::Decoder(ISA* isa)
-    : data(0), fpscrLen(0), fpscrStride(0), decoderFlavor(isa->decoderFlavor())
+    : data(0), fpscrLen(0), fpscrStride(0),
+      decoderFlavor(isa->decoderFlavor())
 {
     reset();
 
@@ -181,7 +182,7 @@ Decoder::decode(ArmISA::PCState &pc)
         pc.nextItstate(itBits);
     this_emi.itstate = pc.itstate();
     this_emi.illegalExecution = pc.illegalExec() ? 1 : 0;
-
+    this_emi.debugStep = pc.debugStep() ? 1 : 0;
     pc.size(inst_size);
 
     emi = 0;
index ce9675aee7aeff918e83af1c220ed8d165768eb3..6a3ee18ee6c3d6b80c7388a48fe7e9e1425b2d36 100644 (file)
@@ -289,6 +289,10 @@ template<> ArmFault::FaultVals ArmFaultVals<Watchpoint>::vals(
     "Watchpoint",   0x000, 0x000, 0x200, 0x400, 0x600, MODE_SVC,
     0, 0, 0, 0, true, false, false,  EC_WATCHPOINT
 );
+template<> ArmFault::FaultVals ArmFaultVals<SoftwareStepFault>::vals(
+    "SoftwareStep",   0x000, 0x000, 0x200, 0x400, 0x600, MODE_SVC,
+    0, 0, 0, 0, true, false, false,  EC_SOFTWARE_STEP
+);
 template<> ArmFault::FaultVals ArmFaultVals<ArmSev>::vals(
     // Some dummy values
     "ArmSev Flush",          0x000, 0x000, 0x000, 0x000, 0x000, MODE_SVC,
@@ -649,6 +653,7 @@ ArmFault::invoke64(ThreadContext *tc, const StaticInstPtr &inst)
     spsr.nz = tc->readCCReg(CCREG_NZ);
     spsr.c = tc->readCCReg(CCREG_C);
     spsr.v = tc->readCCReg(CCREG_V);
+    spsr.ss = isResetSPSR() ? 0: cpsr.ss;
     if (from64) {
         // Force some bitfields to 0
         spsr.q = 0;
@@ -662,8 +667,6 @@ ArmFault::invoke64(ThreadContext *tc, const StaticInstPtr &inst)
         ITSTATE it = tc->pcState().itstate();
         spsr.it2 = it.top6;
         spsr.it1 = it.bottom2;
-        // Force some bitfields to 0
-        spsr.ss = 0;
     }
     tc->setMiscReg(spsr_idx, spsr);
 
@@ -705,6 +708,7 @@ ArmFault::invoke64(ThreadContext *tc, const StaticInstPtr &inst)
     pc.aarch64(!cpsr.width);
     pc.nextAArch64(!cpsr.width);
     pc.illegalExec(false);
+    pc.stepped(false);
     tc->pcState(pc);
 
     // Save exception syndrome
@@ -911,7 +915,9 @@ UndefinedInstruction::ec(ThreadContext *tc) const
 
 HypervisorCall::HypervisorCall(ExtMachInst _machInst, uint32_t _imm) :
         ArmFaultVals<HypervisorCall>(_machInst, _imm)
-{}
+{
+    bStep = true;
+}
 
 ExceptionClass
 HypervisorCall::ec(ThreadContext *tc) const
@@ -1739,6 +1745,52 @@ Watchpoint::ec(ThreadContext *tc) const
             return EC_WATCHPOINT_LOWER_EL;
 }
 
+SoftwareStepFault::SoftwareStepFault(ExtMachInst _mach_inst, bool is_ldx,
+                                     bool _stepped)
+    : ArmFaultVals<SoftwareStepFault>(_mach_inst), isldx(is_ldx),
+                                      stepped(_stepped)
+{
+    bStep = true;
+}
+
+bool
+SoftwareStepFault::routeToHyp(ThreadContext *tc) const
+{
+    const bool have_el2 = ArmSystem::haveVirtualization(tc);
+
+    const HCR hcr  = tc->readMiscRegNoEffect(MISCREG_HCR_EL2);
+    const HDCR mdcr  = tc->readMiscRegNoEffect(MISCREG_MDCR_EL2);
+
+    return have_el2 && !inSecureState(tc) && fromEL <= EL1 &&
+        (hcr.tge || mdcr.tde);
+}
+
+ExceptionClass
+SoftwareStepFault::ec(ThreadContext *tc) const
+{
+    // AArch64
+    if (toEL == fromEL)
+        return EC_SOFTWARE_STEP_CURR_EL;
+    else
+        return EC_SOFTWARE_STEP_LOWER_EL;
+}
+
+uint32_t
+SoftwareStepFault::iss() const
+{
+    uint32_t iss= 0x0022;
+    if (stepped) {
+        iss |= 0x1000000;
+    }
+
+    if (isldx) {
+        iss |= 0x40;
+    }
+
+    return iss;
+
+}
+
 void
 ArmSev::invoke(ThreadContext *tc, const StaticInstPtr &inst) {
     DPRINTF(Faults, "Invoking ArmSev Fault\n");
@@ -1774,6 +1826,7 @@ template class ArmFaultVals<SystemError>;
 template class ArmFaultVals<SoftwareBreakpoint>;
 template class ArmFaultVals<HardwareBreakpoint>;
 template class ArmFaultVals<Watchpoint>;
+template class ArmFaultVals<SoftwareStepFault>;
 template class ArmFaultVals<ArmSev>;
 template class AbortFault<PrefetchAbort>;
 template class AbortFault<DataAbort>;
index 2e1f3387bd04cd4ab72c1051d38794573aec4ff4..8a127ffdb72f4c6bd860b6b7800a8c13f861d9e9 100644 (file)
@@ -64,6 +64,7 @@ class ArmFault : public FaultBase
     uint32_t issRaw;
 
     // Helper variables for ARMv8 exception handling
+    bool bStep; // True if the Arm Faul exception is a software Step exception
     bool from64;  // True if the exception is generated from the AArch64 state
     bool to64;  // True if the exception is taken in AArch64 state
     ExceptionLevel fromEL;  // Source exception level
@@ -207,8 +208,8 @@ class ArmFault : public FaultBase
     };
 
     ArmFault(ExtMachInst _machInst = 0, uint32_t _iss = 0) :
-        machInst(_machInst), issRaw(_iss), from64(false), to64(false),
-        fromEL(EL0), toEL(EL0), fromMode(MODE_UNDEFINED),
+        machInst(_machInst), issRaw(_iss), bStep(false), from64(false),
+        to64(false), fromEL(EL0), toEL(EL0), fromMode(MODE_UNDEFINED),
         faultUpdated(false), hypRouted(false), span(false) {}
 
     // Returns the actual syndrome register to use based on the target
@@ -223,6 +224,7 @@ class ArmFault : public FaultBase
     void invoke64(ThreadContext *tc, const StaticInstPtr &inst =
                   StaticInst::nullStaticInstPtr);
     void update(ThreadContext *tc);
+    bool isResetSPSR(){ return bStep; }
 
     ArmStaticInst *instrAnnotate(const StaticInstPtr &inst);
     virtual void annotate(AnnotationIDs id, uint64_t val) {}
@@ -332,7 +334,9 @@ class SupervisorCall : public ArmFaultVals<SupervisorCall>
                    ExceptionClass _overrideEc = EC_INVALID) :
         ArmFaultVals<SupervisorCall>(_machInst, _iss),
         overrideEc(_overrideEc)
-    {}
+    {
+        bStep = true;
+    }
 
     void invoke(ThreadContext *tc, const StaticInstPtr &inst =
                 StaticInst::nullStaticInstPtr) override;
@@ -346,7 +350,9 @@ class SecureMonitorCall : public ArmFaultVals<SecureMonitorCall>
   public:
     SecureMonitorCall(ExtMachInst _machInst) :
         ArmFaultVals<SecureMonitorCall>(_machInst)
-    {}
+    {
+        bStep = true;
+    }
 
     void invoke(ThreadContext *tc, const StaticInstPtr &inst =
                 StaticInst::nullStaticInstPtr) override;
@@ -632,6 +638,19 @@ class Watchpoint : public ArmFaultVals<Watchpoint>
     void annotate(AnnotationIDs id, uint64_t val);
 };
 
+class SoftwareStepFault : public ArmFaultVals<SoftwareStepFault>
+{
+  private:
+    bool isldx;
+    bool stepped;
+
+  public:
+    SoftwareStepFault(ExtMachInst _mach_inst, bool is_ldx, bool stepped);
+    bool routeToHyp(ThreadContext *tc) const override;
+    uint32_t iss() const override;
+    ExceptionClass ec(ThreadContext *tc) const override;
+};
+
 // A fault that flushes the pipe, excluding the faulting instructions
 class ArmSev : public ArmFaultVals<ArmSev>
 {
@@ -674,6 +693,7 @@ template<> ArmFault::FaultVals ArmFaultVals<SystemError>::vals;
 template<> ArmFault::FaultVals ArmFaultVals<SoftwareBreakpoint>::vals;
 template<> ArmFault::FaultVals ArmFaultVals<HardwareBreakpoint>::vals;
 template<> ArmFault::FaultVals ArmFaultVals<Watchpoint>::vals;
+template<> ArmFault::FaultVals ArmFaultVals<SoftwareStepFault>::vals;
 template<> ArmFault::FaultVals ArmFaultVals<ArmSev>::vals;
 
 /**
index 5c2702b5b7199685c4189f62bace96b43fc76e3e..3fe2dfa1115b12f97e9debd7cc858b3574677832 100644 (file)
@@ -190,3 +190,20 @@ IllegalExecInst::execute(ExecContext *xc, Trace::InstRecord *traceData) const
 {
     return std::make_shared<IllegalInstSetStateFault>();
 }
+
+DebugStep::DebugStep(ExtMachInst _machInst)
+    : ArmStaticInst("DebugStep", _machInst, No_OpClass)
+{ }
+
+Fault
+DebugStep::execute(ExecContext *xc, Trace::InstRecord *traceData) const
+{
+    PCState pc_state(xc->pcState());
+    pc_state.debugStep(false);
+    xc->pcState(pc_state);
+    auto *isa = static_cast<ArmISA::ISA *>(xc->tcBase()->getIsaPtr());
+    bool ldx = isa->getSelfDebug()->getSstep()->getLdx();
+    return std::make_shared<SoftwareStepFault>(machInst, ldx,
+                                               pc_state.stepped());
+
+}
index 76dca20b050257e8986b08905072ed21cd982d9b..7b385f10908f9a29142f71090acd0b267e70ed2d 100644 (file)
@@ -131,4 +131,12 @@ class IllegalExecInst : public ArmStaticInst
     Fault execute(ExecContext *xc, Trace::InstRecord *traceData) const;
 };
 
+class DebugStep : public ArmStaticInst
+{
+  public:
+    DebugStep(ExtMachInst _machInst);
+
+    Fault execute(ExecContext *xc, Trace::InstRecord *traceData) const;
+};
+
 #endif
index f23cc797819a95af564b79c810ce71e40065ef1f..f18898790b930f24234e9317921fdfdb1c70b4a7 100644 (file)
@@ -43,6 +43,8 @@
 
 #include "arch/arm/faults.hh"
 #include "arch/arm/isa.hh"
+#include "arch/arm/self_debug.hh"
+#include "arch/arm/utility.hh"
 #include "base/condcodes.hh"
 #include "base/cprintf.hh"
 #include "base/loader/symtab.hh"
@@ -1106,10 +1108,7 @@ CPSR
 ArmStaticInst::getPSTATEFromPSR(ThreadContext *tc, CPSR cpsr, CPSR spsr) const
 {
     CPSR new_cpsr = 0;
-
-    // gem5 doesn't implement single-stepping, so force the SS bit to
-    // 0.
-    new_cpsr.ss = 0;
+    ExceptionLevel dest;
 
     if (illegalExceptionReturn(tc, cpsr, spsr)) {
         // If the SPSR specifies an illegal exception return,
@@ -1123,6 +1122,7 @@ ArmStaticInst::getPSTATEFromPSR(ThreadContext *tc, CPSR cpsr, CPSR spsr) const
             new_cpsr.el = cpsr.el;
             new_cpsr.sp = cpsr.sp;
         }
+        dest = currEL(tc);
     } else {
         new_cpsr.il = spsr.il;
         if (spsr.width && unknownMode32((OperatingMode)(uint8_t)spsr.mode)) {
@@ -1133,6 +1133,7 @@ ArmStaticInst::getPSTATEFromPSR(ThreadContext *tc, CPSR cpsr, CPSR spsr) const
             new_cpsr.el = spsr.el;
             new_cpsr.sp = spsr.sp;
         }
+        dest = (ExceptionLevel)(uint8_t) spsr.el;
     }
 
     new_cpsr.nz = spsr.nz;
@@ -1154,6 +1155,10 @@ ArmStaticInst::getPSTATEFromPSR(ThreadContext *tc, CPSR cpsr, CPSR spsr) const
         new_cpsr.daif = spsr.daif;
     }
 
+    auto *isa = static_cast<ArmISA::ISA *>(tc->getIsaPtr());
+    SoftwareStep * ss = (isa->getSelfDebug())->getSstep();
+    new_cpsr.ss = ss->debugExceptionReturnSS(tc, spsr, dest, new_cpsr.width);
+
     return new_cpsr;
 }
 
index 07713be8a9e58951fdb125d06108cb980e2ab17f..82d936924fb554eea060dbdf35977b0790ce5732 100644 (file)
@@ -836,6 +836,7 @@ ISA::setMiscReg(int misc_reg, RegVal val)
         pc.nextThumb(cpsr.t);
         pc.nextJazelle(cpsr.j);
         pc.illegalExec(cpsr.il == 1);
+        selfDebug->setDebugMask(cpsr.d == 1);
 
         tc->getDecoderPtr()->setSveLen((getCurSveVecLenInBits() >> 7) - 1);
 
index 903bb678744b8ec07bde013c31b499efa8fce4ad..e1fc8bfed0738d46785461e55ec0fca7c7b4f3a7 100644 (file)
@@ -46,6 +46,7 @@
 // Opcode fields
 def bitfield DECODERFAULT  decoderFault;
 def bitfield ILLEGALEXEC   illegalExecution;
+def bitfield DEBUGSTEP     debugStep;
 
 def bitfield ENCODING      encoding;
 def bitfield OPCODE        opcode;
index 184150579b21efebb8fb88402db9471dd8913f10..2a979ea172d31f617d0b7d8c1123bf780d0b9d03 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-decode ILLEGALEXEC default IllegalExec::illegalExec() {
-    0: decode DECODERFAULT default DecoderFault::decoderFault() {
-        0: decode THUMB default Unknown::unknown() {
-            0: decode AARCH64 {
-                0:
-                ##include "arm.isa"
+decode DEBUGSTEP default DebugStep::debugStep() {
+    0: decode ILLEGALEXEC default IllegalExec::illegalExec() {
+        0: decode DECODERFAULT default DecoderFault::decoderFault() {
+            0: decode THUMB default Unknown::unknown() {
+                0: decode AARCH64 {
+                    0:
+                    ##include "arm.isa"
+                    1:
+                    ##include "aarch64.isa"
+                }
                 1:
-                ##include "aarch64.isa"
+                ##include "thumb.isa"
             }
-            1:
-            ##include "thumb.isa"
         }
     }
 }
index a1ee8ecbd75192106dbb8593e022f7868815d3b1..d827aa40009e754edde7fd92f29ee6d25337a748 100644 (file)
@@ -59,6 +59,15 @@ def format IllegalExec() {{
     decode_block = 'return new IllegalExecInst(machInst);\n'
 }};
 
+////////////////////////////////////////////////////////////////////
+//
+// Debug Step handling
+//
+
+def format DebugStep() {{
+    decode_block = 'return new DebugStep(machInst);\n'
+}};
+
 ////////////////////////////////////////////////////////////////////
 //
 // Unknown instruction handling
index d828fcff063cf17dfc5a0b81d2ef8773d83ae0e0..37abb6456f5db4c1c5b4f7f896ecdfef06e3ff42 100644 (file)
@@ -209,6 +209,13 @@ let {{
                 accCode = "IWDest = cSwap(Mem%s, ((CPSR)Cpsr).e);"
             accCode = accCode % buildMemSuffix(self.sign, self.size)
 
+            if self.flavor in ('exclusive', 'acex'):
+                accCode += '''
+           auto *isa = static_cast<ArmISA::ISA *>(xc->tcBase()->getIsaPtr());
+           SelfDebug * sd = isa->getSelfDebug();
+           sd->getSstep()->setLdx();
+              '''
+
             self.codeBlobs["memacc_code"] = accCode
 
             # Push it out to the output files
@@ -284,6 +291,12 @@ let {{
                 FpDest_uw = (uint32_t)swappedMem;
                 FpDest2_uw = (uint32_t)(swappedMem >> 32);
                 '''
+            if self.flavor in ('exclusive', 'acex'):
+                accCode += '''
+             auto *isa = static_cast<ArmISA::ISA *>(xc->tcBase()->getIsaPtr());
+             SelfDebug * sd = isa->getSelfDebug();
+             sd->getSstep()->setLdx();
+             '''
 
             self.codeBlobs["memacc_code"] = accCode
 
index fc4f34f0ccfb2c353a32571bddd7b30ca1511d0a..a2c1bae86d00b67ebac27f8aed929c8589cbaf8c 100644 (file)
@@ -236,7 +236,12 @@ let {{
                 accCode = "WDest = cSwap(Mem%s, isBigEndian64(xc->tcBase()));"
 
             accCode = accCode % buildMemSuffix(self.sign, self.size)
-
+            if self.flavor in ('exclusive', 'acex'):
+                accCode += '''
+             auto *isa = static_cast<ArmISA::ISA *>(xc->tcBase()->getIsaPtr());
+             SelfDebug * sd = isa->getSelfDebug();
+             sd->getSstep()->setLdx();
+             '''
             self.codeBlobs["memacc_code"] = accCode
             if accEpilogCode:
                 self.codeBlobs["memacc_epilog_code"] = accEpilogCode
@@ -332,6 +337,12 @@ let {{
                             XDest2 = cSwap(Mem_tud[1],
                                            isBigEndian64(xc->tcBase()));
                         '''
+            if self.flavor in ('exp', 'acexp'):
+                accCode += '''
+             auto *isa = static_cast<ArmISA::ISA *>(xc->tcBase()->getIsaPtr());
+             SelfDebug * sd = isa->getSelfDebug();
+             sd->getSstep()->setLdx();
+             '''
             self.codeBlobs["memacc_code"] = accCode
             if accEpilogCode:
                 self.codeBlobs["memacc_epilog_code"] = accEpilogCode
index 85c6656bbbb8c5c43c6a5e528874a021470fa278..f0f420db514082701705b402895c86d04624b93e 100644 (file)
@@ -547,3 +547,74 @@ WatchPoint::compareAddress(ThreadContext *tc, Addr in_addr, uint8_t bas,
     }
 }
 
+bool
+SoftwareStep::debugExceptionReturnSS(ThreadContext *tc, CPSR spsr,
+                                     ExceptionLevel dest, bool aarch32)
+{
+    bool SS_bit = false;
+    bool enabled_src = false;
+    if (bSS) {
+        enabled_src = conf->isDebugEnabled(tc);
+
+        bool enabled_dst = false;
+        bool secure = isSecureBelowEL3(tc) || dest == EL3;
+        CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
+        if (cpsr.width) {
+            enabled_dst = conf->isDebugEnabledForEL32(tc, dest, secure,
+                                                      spsr.d == 1);
+        } else {
+            enabled_dst = conf->isDebugEnabledForEL64(tc, dest, secure,
+                                                      spsr.d == 1);
+        }
+        ExceptionLevel ELd = debugTargetFrom(tc, secure);
+
+        if (!ELIs32(tc, ELd) && !enabled_src && enabled_dst) {
+            SS_bit = spsr.ss;
+            if (SS_bit == 0x0) {
+                stateSS = ACTIVE_PENDING_STATE;
+            } else {
+                stateSS = ACTIVE_NOT_PENDING_STATE;
+            }
+        }
+    }
+    return SS_bit;
+}
+
+bool
+SoftwareStep::advanceSS(ThreadContext * tc)
+{
+
+    PCState pc = tc->pcState();
+    bool res = false;
+    switch (stateSS){
+      case INACTIVE_STATE:
+        pc.debugStep(false);
+        break;
+
+      case ACTIVE_NOT_PENDING_STATE:
+        pc.debugStep(false);
+        if (cpsrD == 1 || !bSS) {
+            stateSS = INACTIVE_STATE;
+        } else {
+            pc.stepped(true);
+            stateSS = ACTIVE_PENDING_STATE;
+            tc->pcState(pc);
+        }
+        break;
+
+      case ACTIVE_PENDING_STATE:
+        if (!cpsrD && bSS) {
+            pc.debugStep(true);
+            res = true;
+            tc->pcState(pc);
+        }
+        stateSS = INACTIVE_STATE;
+        clearLdx();
+        break;
+
+      default:
+            break;
+    }
+    return res;
+}
+
index c8ae711c1bc2e6871902517831e36e3cb5f84c52..48d784cd52bc9e3fc0f4507ee925c07831470f83 100644 (file)
 
 class ThreadContext;
 
-
 namespace ArmISA
 {
 
-
 class SelfDebug;
 
 class BrkPoint
@@ -201,12 +199,70 @@ class WatchPoint
               bool atomic, unsigned size);
 };
 
+class SoftwareStep
+{
+
+  private:
+    static const uint8_t INACTIVE_STATE = 0;
+    static const uint8_t ACTIVE_PENDING_STATE = 1;
+    static const uint8_t ACTIVE_NOT_PENDING_STATE = 2;
+
+
+    bool bSS;
+    int stateSS;
+    SelfDebug * conf;
+    bool steppedLdx;
+    bool prevSteppedLdx;
+    bool cpsrD;
+
+    bool ctrStepped;
+    bool ctrActivate;
+
+
+  public:
+    SoftwareStep(SelfDebug* s): bSS(false), stateSS(INACTIVE_STATE),
+                                conf(s), steppedLdx(false) { }
+
+    ~SoftwareStep() { }
+
+    bool debugExceptionReturnSS(ThreadContext *tc, CPSR spsr,
+                                ExceptionLevel dest, bool aarch32);
+    bool advanceSS(ThreadContext * tc);
+
+    inline void setCPSRD(bool val)
+    {
+        cpsrD = val;
+    }
+
+    inline void setEnableSS(bool val)
+    {
+        bSS = val;
+    }
+
+    void setLdx()
+    {
+        prevSteppedLdx = steppedLdx;
+        steppedLdx = true;
+    }
+
+    void clearLdx()
+    {
+        prevSteppedLdx = steppedLdx;
+        steppedLdx = false;
+    }
+
+    bool getLdx()
+    {
+        return prevSteppedLdx;
+    }
+};
 
 class SelfDebug
 {
   private:
     std::vector<BrkPoint> arBrkPoints;
     std::vector<WatchPoint> arWatchPoints;
+    SoftwareStep * softStep;
 
     bool initialized;
     bool enableTdeTge; // MDCR_EL2.TDE || HCR_EL2.TGE
@@ -224,9 +280,14 @@ class SelfDebug
   public:
     SelfDebug(): initialized(false), enableTdeTge(false),
                  enableFlag(false), bSDD(false), bKDE(false), oslk(false)
-    {}
+    {
+        softStep = new SoftwareStep(this);
+    }
 
-    ~SelfDebug(){}
+    ~SelfDebug()
+    {
+        delete softStep;
+    }
 
     Fault testBreakPoints(ThreadContext *tc, Addr vaddr);
     Fault testWatchPoints(ThreadContext *tc, Addr vaddr, bool write,
@@ -294,6 +355,7 @@ class SelfDebug
     {
         enableFlag = bits(val, 15);
         bKDE = bits(val, 13);
+        softStep->setEnableSS((bool)bits(val, 0));
     }
 
     inline void setMDBGen(RegVal val)
@@ -321,6 +383,10 @@ class SelfDebug
         arWatchPoints[index].updateControl(val);
     }
 
+    inline void setDebugMask(bool mask)
+    {
+        softStep->setCPSRD(mask);
+    }
     inline bool isAArch32()
     {
         return aarch32;
@@ -339,6 +405,11 @@ class SelfDebug
             aarch32 = ELIs32(tc, fromEL);
         return;
     }
+    SoftwareStep * getSstep()
+    {
+        return softStep;
+    }
+
 
     bool targetAArch32(ThreadContext * tc)
     {
@@ -358,7 +429,7 @@ class SelfDebug
         const AA64MMFR1 mm_fr1 = tc->readMiscReg(MISCREG_ID_AA64MMFR1_EL1);
         const uint8_t nCtxtAwareBp = dfr.ctx_cmps;
         const bool VMIDBits = mm_fr1.vmidbits;
-        for (int i=0; i<=dfr.brps; i++){
+        for (int i=0; i<=dfr.brps; i++) {
             const bool isctxaw = i>=(dfr.brps-nCtxtAwareBp);
 
             BrkPoint  bkp = BrkPoint((MiscRegIndex)(MISCREG_DBGBCR0_EL1+i),
@@ -372,7 +443,7 @@ class SelfDebug
             arBrkPoints.push_back(bkp);
         }
 
-        for (int i=0; i<=dfr.wrps; i++){
+        for (int i=0; i<=dfr.wrps; i++) {
             WatchPoint  wtp = WatchPoint((MiscRegIndex)(MISCREG_DBGWCR0+i),
                                          (MiscRegIndex)(MISCREG_DBGWVR0+i),
                                          this, (bool)mm_fr2.varange, aarch32);
index fc7a7545b53e038617e6e0dfad4002676e4ba78d..1a26ab5a1080989431f0daa7ce730a7761c21353 100644 (file)
@@ -1197,11 +1197,13 @@ TLB::translateFs(const RequestPtr &req, ThreadContext *tc, Mode mode,
         auto *isa = static_cast<ArmISA::ISA *>(tc->getIsaPtr());
         SelfDebug * sd = isa->getSelfDebug();
         if (mode == Execute) {
-            fault = sd->testBreakPoints(tc, req->getVaddr());
+            const bool d_step = sd->getSstep()->advanceSS(tc);
+            if (!d_step) {
+                fault = sd->testBreakPoints(tc, req->getVaddr());
+            }
         }
         else if (!req->isCacheMaintenance() ||
-                 (req->isCacheInvalidate() && !req->isCacheClean()))
-        {
+                 (req->isCacheInvalidate() && !req->isCacheClean())) {
             bool md = mode == Write ? true: false;
             fault = sd->testWatchPoints(tc, req->getVaddr(), md,
                                         req->isAtomic(),
@@ -1291,7 +1293,9 @@ TLB::translateComplete(const RequestPtr &req, ThreadContext *tc,
     // stage 2 translation we prevent marking the translation as delayed twice,
     // one when the translation starts and again when the stage 1 translation
     // completes.
-    if (translation && (callFromS2 || !stage2Req || req->hasPaddr() || fault != NoFault)) {
+
+    if (translation && (callFromS2 || !stage2Req || req->hasPaddr() ||
+        fault != NoFault)) {
         if (!delay)
             translation->finish(fault, req, tc, mode);
         else
index 3a5e74151a77085149587fcc8ed87e352866cd80..0119e4e66e82ce21d665502b68164f537f703c57 100644 (file)
@@ -69,6 +69,7 @@ namespace ArmISA
         // Decoder state
         Bitfield<63, 62> decoderFault; // See DecoderFault
         Bitfield<61> illegalExecution;
+        Bitfield<60> debugStep;
 
         // SVE vector length, encoded in the same format as the ZCR_EL<x>.LEN
         // bitfields
@@ -228,9 +229,15 @@ namespace ArmISA
         uint8_t _nextItstate;
         uint8_t _size;
         bool _illegalExec;
+
+        // Software Step flags
+        bool _debugStep;
+        bool _stepped;
+
       public:
         PCState() : flags(0), nextFlags(0), _itstate(0), _nextItstate(0),
-                    _size(0), _illegalExec(false)
+                    _size(0), _illegalExec(false), _debugStep(false),
+                    _stepped(false)
         {}
 
         void
@@ -241,7 +248,8 @@ namespace ArmISA
         }
 
         PCState(Addr val) : flags(0), nextFlags(0), _itstate(0),
-                            _nextItstate(0), _size(0), _illegalExec(false)
+                            _nextItstate(0), _size(0), _illegalExec(false),
+                            _debugStep(false), _stepped(false)
         { set(val); }
 
         bool
@@ -256,6 +264,30 @@ namespace ArmISA
             _illegalExec = val;
         }
 
+        bool
+        debugStep() const
+        {
+            return _debugStep;
+        }
+
+        void
+        debugStep(bool val)
+        {
+            _debugStep = val;
+        }
+
+        bool
+        stepped() const
+        {
+            return _stepped;
+        }
+
+        void
+        stepped(bool val)
+        {
+            _stepped = val;
+        }
+
         bool
         thumb() const
         {
@@ -491,7 +523,9 @@ namespace ArmISA
                 flags == opc.flags && nextFlags == opc.nextFlags &&
                 _itstate == opc._itstate &&
                 _nextItstate == opc._nextItstate &&
-                _illegalExec == opc._illegalExec;
+                _illegalExec == opc._illegalExec &&
+                _debugStep == opc._debugStep &&
+                _stepped == opc._stepped;
         }
 
         bool
@@ -510,6 +544,8 @@ namespace ArmISA
             SERIALIZE_SCALAR(_itstate);
             SERIALIZE_SCALAR(_nextItstate);
             SERIALIZE_SCALAR(_illegalExec);
+            SERIALIZE_SCALAR(_debugStep);
+            SERIALIZE_SCALAR(_stepped);
         }
 
         void
@@ -522,6 +558,8 @@ namespace ArmISA
             UNSERIALIZE_SCALAR(_itstate);
             UNSERIALIZE_SCALAR(_nextItstate);
             UNSERIALIZE_SCALAR(_illegalExec);
+            UNSERIALIZE_SCALAR(_debugStep);
+            UNSERIALIZE_SCALAR(_stepped);
         }
     };
 
@@ -648,6 +686,9 @@ namespace ArmISA
         EC_HW_BREAKPOINT           = 0x30,
         EC_HW_BREAKPOINT_LOWER_EL  = 0x30,
         EC_HW_BREAKPOINT_CURR_EL   = 0x31,
+        EC_SOFTWARE_STEP           = 0x32,
+        EC_SOFTWARE_STEP_LOWER_EL  = 0x32,
+        EC_SOFTWARE_STEP_CURR_EL   = 0x33,
         EC_WATCHPOINT              = 0x34,
         EC_WATCHPOINT_LOWER_EL     = 0x34,
         EC_WATCHPOINT_CURR_EL      = 0x35,