#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"
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
return;
}
+ if (vectorCatch(tc, inst))
+ return;
+
// ARMv7 (ARM ARM issue C B1.9)
bool have_security = ArmSystem::haveSecurity(tc);
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)
{
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;
}
{
NODEBUG = 0,
BRKPOINT,
+ VECTORCATCH,
WPOINT_CM,
WPOINT_NOCM
};
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;
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>
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>
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>
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>
HypervisorCall(ExtMachInst _machInst, uint32_t _imm);
ExceptionClass ec(ThreadContext *tc) const override;
+ uint32_t vectorCatchFlag() const override { return 0xFFFFFFFF; }
};
class HypervisorTrap : public ArmFaultVals<HypervisorTrap>
// @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>
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>
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>
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>
return MISCREG_DBGDIDR;
case 1:
return MISCREG_DBGDSCRint;
+ case 7:
+ return MISCREG_DBGVCR;
}
break;
case 2:
return MISCREG_BPIALLIS;
}
break;
+ case 2:
+ switch (opc2) {
+ case 7:
+ return MISCREG_DBGDEVID0;
+ }
+ break;
case 4:
if (opc2 == 0) {
return MISCREG_PAR;
.unimplemented()
.allPrivileges();
InitReg(MISCREG_DBGVCR)
- .unimplemented()
- .allPrivileges();
+ .allPrivileges().exceptUserMode();
InitReg(MISCREG_DBGDTRRXext)
.unimplemented()
.allPrivileges();
.unimplemented()
.allPrivileges().monSecureWrite(0).monNonSecureWrite(0);
InitReg(MISCREG_DBGDEVID0)
- .unimplemented()
.allPrivileges().monSecureWrite(0).monNonSecureWrite(0);
InitReg(MISCREG_TEECR)
.unimplemented()
InitReg(MISCREG_MDDTRRX_EL0)
.allPrivileges();
InitReg(MISCREG_DBGVCR32_EL2)
- .allPrivileges()
+ .hyp().mon()
.mapsTo(MISCREG_DBGVCR);
InitReg(MISCREG_MDRAR_EL1)
.allPrivileges().monSecureWrite(0).monNonSecureWrite(0)
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__
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;
+}
+
}
};
+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
~SelfDebug()
{
delete softStep;
+ delete vcExcpt;
}
Fault testBreakPoints(ThreadContext *tc, Addr vaddr);
{
softStep->setCPSRD(mask);
}
+
inline bool isAArch32()
{
return aarch32;
return softStep;
}
+ VectorCatch* getVectorCatch(ThreadContext* tc)
+ {
+ if (!initialized)
+ init(tc);
+ return vcExcpt;
+ }
bool targetAArch32(ThreadContext * tc)
{
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);
+
}
};
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() ||
EC_WATCHPOINT_LOWER_EL = 0x34,
EC_WATCHPOINT_CURR_EL = 0x35,
EC_SOFTWARE_BREAKPOINT = 0x38,
+ EC_VECTOR_CATCH = 0x3A,
EC_SOFTWARE_BREAKPOINT_64 = 0x3C,
};