arch-arm: Implementation of Vector Catch debug exception
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>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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() ||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user