arch-arm: Implementation of SelfHosted Debug Software step
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>
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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());
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -38,17 +38,19 @@
|
||||
// (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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,11 +48,9 @@
|
||||
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user