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();
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;
"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,
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;
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);
pc.aarch64(!cpsr.width);
pc.nextAArch64(!cpsr.width);
pc.illegalExec(false);
+ pc.stepped(false);
tc->pcState(pc);
// Save exception syndrome
HypervisorCall::HypervisorCall(ExtMachInst _machInst, uint32_t _imm) :
ArmFaultVals<HypervisorCall>(_machInst, _imm)
-{}
+{
+ bStep = true;
+}
ExceptionClass
HypervisorCall::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");
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>;
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
};
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
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) {}
ExceptionClass _overrideEc = EC_INVALID) :
ArmFaultVals<SupervisorCall>(_machInst, _iss),
overrideEc(_overrideEc)
- {}
+ {
+ bStep = true;
+ }
void invoke(ThreadContext *tc, const StaticInstPtr &inst =
StaticInst::nullStaticInstPtr) override;
public:
SecureMonitorCall(ExtMachInst _machInst) :
ArmFaultVals<SecureMonitorCall>(_machInst)
- {}
+ {
+ bStep = true;
+ }
void invoke(ThreadContext *tc, const StaticInstPtr &inst =
StaticInst::nullStaticInstPtr) override;
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>
{
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;
/**
{
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());
+
+}
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
#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"
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,
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)) {
new_cpsr.el = spsr.el;
new_cpsr.sp = spsr.sp;
}
+ dest = (ExceptionLevel)(uint8_t) spsr.el;
}
new_cpsr.nz = spsr.nz;
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;
}
pc.nextThumb(cpsr.t);
pc.nextJazelle(cpsr.j);
pc.illegalExec(cpsr.il == 1);
+ selfDebug->setDebugMask(cpsr.d == 1);
tc->getDecoderPtr()->setSveLen((getCurSveVecLenInBits() >> 7) - 1);
// Opcode fields
def bitfield DECODERFAULT decoderFault;
def bitfield ILLEGALEXEC illegalExecution;
+def bitfield DEBUGSTEP debugStep;
def bitfield ENCODING encoding;
def bitfield OPCODE opcode;
// (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"
}
}
}
decode_block = 'return new IllegalExecInst(machInst);\n'
}};
+////////////////////////////////////////////////////////////////////
+//
+// Debug Step handling
+//
+
+def format DebugStep() {{
+ decode_block = 'return new DebugStep(machInst);\n'
+}};
+
////////////////////////////////////////////////////////////////////
//
// Unknown instruction handling
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
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
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
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
}
}
+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;
+}
+
class ThreadContext;
-
namespace ArmISA
{
-
class SelfDebug;
class BrkPoint
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
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,
{
enableFlag = bits(val, 15);
bKDE = bits(val, 13);
+ softStep->setEnableSS((bool)bits(val, 0));
}
inline void setMDBGen(RegVal val)
arWatchPoints[index].updateControl(val);
}
+ inline void setDebugMask(bool mask)
+ {
+ softStep->setCPSRD(mask);
+ }
inline bool isAArch32()
{
return aarch32;
aarch32 = ELIs32(tc, fromEL);
return;
}
+ SoftwareStep * getSstep()
+ {
+ return softStep;
+ }
+
bool targetAArch32(ThreadContext * tc)
{
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),
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);
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(),
// 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
// 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
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
}
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
_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
{
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
SERIALIZE_SCALAR(_itstate);
SERIALIZE_SCALAR(_nextItstate);
SERIALIZE_SCALAR(_illegalExec);
+ SERIALIZE_SCALAR(_debugStep);
+ SERIALIZE_SCALAR(_stepped);
}
void
UNSERIALIZE_SCALAR(_itstate);
UNSERIALIZE_SCALAR(_nextItstate);
UNSERIALIZE_SCALAR(_illegalExec);
+ UNSERIALIZE_SCALAR(_debugStep);
+ UNSERIALIZE_SCALAR(_stepped);
}
};
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,