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:
Jordi Vaquero
2019-10-29 18:32:45 +01:00
parent 30666c20ba
commit 046645a4db
8 changed files with 259 additions and 9 deletions

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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)

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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);
}
};

View File

@@ -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() ||

View File

@@ -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,
};