dev-arm: Record additional information in the TranslResult
A faulting translation should return additional information (other than the fault type). This will be used by future patches to properly populate the SMMU event record of the event queue As we currenlty support two faults only: 1) F_TRANSLATION 2) F_PERMISSION We add to TranslResult the relevant fault information only: type, class, stage and ipa Change-Id: I0a81d5fc202e1b6135cecdcd6dfd2239c2f1ba7e Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
This commit is contained in:
@@ -243,7 +243,7 @@ SMMUTranslationProcess::TranslResult
|
||||
SMMUTranslationProcess::bypass(Addr addr) const
|
||||
{
|
||||
TranslResult tr;
|
||||
tr.fault = FAULT_NONE;
|
||||
tr.fault = Fault(FAULT_NONE);
|
||||
tr.addr = addr;
|
||||
tr.addrMask = 0;
|
||||
tr.writable = 1;
|
||||
@@ -336,8 +336,8 @@ SMMUTranslationProcess::microTLBLookup(Yield &yield, TranslResult &tr)
|
||||
"micro TLB hit vaddr=%#x amask=%#x sid=%#x ssid=%#x paddr=%#x\n",
|
||||
request.addr, e->vaMask, request.sid, request.ssid, e->pa);
|
||||
|
||||
tr.fault = FAULT_NONE;
|
||||
tr.addr = e->pa + (request.addr & ~e->vaMask);;
|
||||
tr.fault = Fault(FAULT_NONE);
|
||||
tr.addr = e->pa + (request.addr & ~e->vaMask);;
|
||||
tr.addrMask = e->vaMask;
|
||||
tr.writable = e->permissions;
|
||||
|
||||
@@ -370,7 +370,7 @@ SMMUTranslationProcess::ifcTLBLookup(Yield &yield, TranslResult &tr,
|
||||
"paddr=%#x\n", request.addr, e->vaMask, request.sid,
|
||||
request.ssid, e->pa);
|
||||
|
||||
tr.fault = FAULT_NONE;
|
||||
tr.fault = Fault(FAULT_NONE);
|
||||
tr.addr = e->pa + (request.addr & ~e->vaMask);;
|
||||
tr.addrMask = e->vaMask;
|
||||
tr.writable = e->permissions;
|
||||
@@ -402,7 +402,7 @@ SMMUTranslationProcess::smmuTLBLookup(Yield &yield, TranslResult &tr)
|
||||
"SMMU TLB hit vaddr=%#x amask=%#x asid=%#x vmid=%#x paddr=%#x\n",
|
||||
request.addr, e->vaMask, context.asid, context.vmid, e->pa);
|
||||
|
||||
tr.fault = FAULT_NONE;
|
||||
tr.fault = Fault(FAULT_NONE);
|
||||
tr.addr = e->pa + (request.addr & ~e->vaMask);;
|
||||
tr.addrMask = e->vaMask;
|
||||
tr.writable = e->permissions;
|
||||
@@ -767,7 +767,7 @@ SMMUTranslationProcess::walkStage1And2(Yield &yield, Addr addr,
|
||||
DPRINTF(SMMUv3, "S1 PTE not valid - fault\n");
|
||||
|
||||
TranslResult tr;
|
||||
tr.fault = FAULT_TRANSLATION;
|
||||
tr.fault = Fault(FAULT_TRANSLATION, FaultClass::IN, false);
|
||||
return tr;
|
||||
}
|
||||
|
||||
@@ -777,7 +777,7 @@ SMMUTranslationProcess::walkStage1And2(Yield &yield, Addr addr,
|
||||
DPRINTF(SMMUv3, "S1 page not writable - fault\n");
|
||||
|
||||
TranslResult tr;
|
||||
tr.fault = FAULT_PERMISSION;
|
||||
tr.fault = Fault(FAULT_PERMISSION, FaultClass::IN, false);
|
||||
return tr;
|
||||
}
|
||||
|
||||
@@ -799,15 +799,17 @@ SMMUTranslationProcess::walkStage1And2(Yield &yield, Addr addr,
|
||||
}
|
||||
|
||||
TranslResult tr;
|
||||
tr.fault = FAULT_NONE;
|
||||
tr.fault = Fault(FAULT_NONE);
|
||||
tr.addrMask = pt_ops->pageMask(pte, level);
|
||||
tr.addr = walkPtr + (addr & ~tr.addrMask);
|
||||
tr.writable = pt_ops->isWritable(pte, level, false);
|
||||
|
||||
if (context.stage2Enable) {
|
||||
TranslResult s2tr = translateStage2(yield, tr.addr, true);
|
||||
if (s2tr.isFaulting())
|
||||
if (s2tr.isFaulting()) {
|
||||
s2tr.fault.clss = FaultClass::IN;
|
||||
return s2tr;
|
||||
}
|
||||
|
||||
tr = combineTranslations(tr, s2tr);
|
||||
}
|
||||
@@ -852,7 +854,7 @@ SMMUTranslationProcess::walkStage2(Yield &yield, Addr addr, bool final_tr,
|
||||
DPRINTF(SMMUv3, " S2 PTE not valid - fault\n");
|
||||
|
||||
TranslResult tr;
|
||||
tr.fault = FAULT_TRANSLATION;
|
||||
tr.fault = Fault(FAULT_TRANSLATION, FaultClass::TT, true, addr);
|
||||
return tr;
|
||||
}
|
||||
|
||||
@@ -862,7 +864,7 @@ SMMUTranslationProcess::walkStage2(Yield &yield, Addr addr, bool final_tr,
|
||||
DPRINTF(SMMUv3, " S2 PTE not writable = fault\n");
|
||||
|
||||
TranslResult tr;
|
||||
tr.fault = FAULT_PERMISSION;
|
||||
tr.fault = Fault(FAULT_PERMISSION, FaultClass::TT, true, addr);
|
||||
return tr;
|
||||
}
|
||||
|
||||
@@ -877,7 +879,7 @@ SMMUTranslationProcess::walkStage2(Yield &yield, Addr addr, bool final_tr,
|
||||
}
|
||||
|
||||
TranslResult tr;
|
||||
tr.fault = FAULT_NONE;
|
||||
tr.fault = Fault(FAULT_NONE);
|
||||
tr.addrMask = pt_ops->pageMask(pte, level);
|
||||
tr.addr = walkPtr + (addr & ~tr.addrMask);
|
||||
tr.writable = pt_ops->isWritable(pte, level, true);
|
||||
@@ -913,7 +915,7 @@ SMMUTranslationProcess::translateStage1And2(Yield &yield, Addr addr)
|
||||
TranslResult tr;
|
||||
if (walk_ep) {
|
||||
if (walk_ep->leaf) {
|
||||
tr.fault = FAULT_NONE;
|
||||
tr.fault = Fault(FAULT_NONE);
|
||||
tr.addr = walk_ep->pa + (addr & ~walk_ep->vaMask);
|
||||
tr.addrMask = walk_ep->vaMask;
|
||||
tr.writable = walk_ep->permissions;
|
||||
@@ -924,8 +926,9 @@ SMMUTranslationProcess::translateStage1And2(Yield &yield, Addr addr)
|
||||
Addr table_addr = context.ttb0;
|
||||
if (context.stage2Enable) {
|
||||
TranslResult s2tr = translateStage2(yield, table_addr, false);
|
||||
if (s2tr.isFaulting())
|
||||
if (s2tr.isFaulting()) {
|
||||
return s2tr;
|
||||
}
|
||||
|
||||
table_addr = s2tr.addr;
|
||||
}
|
||||
@@ -957,7 +960,7 @@ SMMUTranslationProcess::translateStage2(Yield &yield, Addr addr, bool final_tr)
|
||||
|
||||
if (ipa_ep) {
|
||||
TranslResult tr;
|
||||
tr.fault = FAULT_NONE;
|
||||
tr.fault = Fault(FAULT_NONE);
|
||||
tr.addr = ipa_ep->pa + (addr & ~ipa_ep->ipaMask);
|
||||
tr.addrMask = ipa_ep->ipaMask;
|
||||
tr.writable = ipa_ep->permissions;
|
||||
@@ -995,7 +998,7 @@ SMMUTranslationProcess::translateStage2(Yield &yield, Addr addr, bool final_tr)
|
||||
TranslResult tr;
|
||||
if (walk_ep) {
|
||||
if (walk_ep->leaf) {
|
||||
tr.fault = FAULT_NONE;
|
||||
tr.fault = Fault(FAULT_NONE);
|
||||
tr.addr = walk_ep->pa + (addr & ~walk_ep->vaMask);
|
||||
tr.addrMask = walk_ep->vaMask;
|
||||
tr.writable = walk_ep->permissions;
|
||||
@@ -1040,7 +1043,7 @@ SMMUTranslationProcess::combineTranslations(const TranslResult &s1tr,
|
||||
assert(!s1tr.isFaulting());
|
||||
|
||||
TranslResult tr;
|
||||
tr.fault = FAULT_NONE;
|
||||
tr.fault = Fault(FAULT_NONE);
|
||||
tr.addr = s2tr.addr;
|
||||
tr.addrMask = s1tr.addrMask | s2tr.addrMask;
|
||||
tr.writable = s1tr.writable & s2tr.writable;
|
||||
@@ -1429,8 +1432,10 @@ SMMUTranslationProcess::doReadCD(Yield &yield,
|
||||
|
||||
if (context.stage2Enable) {
|
||||
tr = translateStage2(yield, l2_addr, false);
|
||||
if (tr.isFaulting())
|
||||
if (tr.isFaulting()) {
|
||||
tr.fault.clss = FaultClass::CD;
|
||||
return tr;
|
||||
}
|
||||
|
||||
l2_addr = tr.addr;
|
||||
}
|
||||
@@ -1451,8 +1456,10 @@ SMMUTranslationProcess::doReadCD(Yield &yield,
|
||||
|
||||
if (context.stage2Enable) {
|
||||
tr = translateStage2(yield, cd_addr, false);
|
||||
if (tr.isFaulting())
|
||||
if (tr.isFaulting()) {
|
||||
tr.fault.clss = FaultClass::CD;
|
||||
return tr;
|
||||
}
|
||||
|
||||
cd_addr = tr.addr;
|
||||
}
|
||||
|
||||
@@ -83,21 +83,73 @@ class SMMUTranslationProcess : public SMMUProcess
|
||||
uint8_t s2t0sz;
|
||||
};
|
||||
|
||||
enum FaultType
|
||||
enum FaultType : uint8_t
|
||||
{
|
||||
FAULT_NONE,
|
||||
FAULT_TRANSLATION, // F_TRANSLATION
|
||||
FAULT_PERMISSION, // F_PERMISSION
|
||||
FAULT_UUT = 0x1, // F_UUT = Unsupported Upstream Transaction
|
||||
FAULT_BAD_STREAMID = 0x2, // C_BAD_STREAMID = Transaction streamID out of range
|
||||
FAULT_STE_FETCH = 0x3, // F_STE_FETCH = Fetch of STE caused external abort
|
||||
FAULT_BAD_STE = 0x4, // C_BAD_STE = Invalid STE
|
||||
FAULT_BAD_ATS_TREQ = 0x5, // F_BAD_ATS_TREQ
|
||||
FAULT_STREAM_DISABLED = 0x6, // F_STREAM_DISABLED = Non-substream trans disabled
|
||||
FAULT_TRANSL_FORBIDDEN = 0x7, // F_TRANSL_FORBIDDEN = SMMU bypass not allowed
|
||||
FAULT_BAD_SUBSTREAMID = 0x8, // F_BAD_SUBSTREAMID = Bad substreamID
|
||||
FAULT_CD_FETCH = 0x9, // F_CD_FETCH = Fetch of CD caused external abort
|
||||
FAULT_BAD_CD = 0xa, // C_BAD_CD = Invalid CD
|
||||
FAULT_WALK_EABT = 0xb, // F_WALK_EABT = Table walk/update caused external abort
|
||||
FAULT_TRANSLATION = 0x10, // F_TRANSLATION = Translation Fault
|
||||
FAULT_ADDR_SIZE = 0x11, // F_ADDR_SIZE = Address Size fault
|
||||
FAULT_ACCESS = 0x12, // F_ACCESS = Access flag fault
|
||||
FAULT_PERMISSION = 0x13, // F_PERMISSION = Permission fault
|
||||
FAULT_TLB_CONFLICT = 0x20, // F_TLB_CONFLICT = TLB conflict
|
||||
FAULT_CFG_CONFLICT = 0x21, // F_CFG_CONFLICT = Config cache conflict
|
||||
FAULT_PAGE_REQUEST = 0x24, // E_PAGE_REQUEST
|
||||
FAULT_VMS_FETCH = 0x25, // F_VMS_FETCH
|
||||
};
|
||||
|
||||
/* The class of the operation that caused the fault */
|
||||
enum FaultClass
|
||||
{
|
||||
CD = 0x0, // CD fetch
|
||||
TT = 0x1, // Stage1 translation table fetch
|
||||
IN = 0x2, // Input address caused fault
|
||||
RESERVED = 0x3
|
||||
};
|
||||
|
||||
struct Fault
|
||||
{
|
||||
explicit Fault(FaultType _type,
|
||||
FaultClass _clss=FaultClass::RESERVED,
|
||||
bool _stage2=false, Addr _ipa=0)
|
||||
: type(_type), clss(_clss), stage2(_stage2), ipa(_ipa)
|
||||
{}
|
||||
|
||||
Fault(const Fault &rhs) = default;
|
||||
Fault& operator=(const Fault &rhs) = default;
|
||||
|
||||
bool isFaulting() const { return type != FAULT_NONE; }
|
||||
|
||||
FaultType type;
|
||||
FaultClass clss;
|
||||
bool stage2;
|
||||
Addr ipa;
|
||||
};
|
||||
|
||||
struct TranslResult
|
||||
{
|
||||
FaultType fault;
|
||||
Addr addr;
|
||||
Addr addrMask;
|
||||
bool writable;
|
||||
TranslResult()
|
||||
: fault(FaultType::FAULT_NONE),
|
||||
addr(0), addrMask(0), writable(false)
|
||||
{}
|
||||
|
||||
bool isFaulting() const { return fault != FAULT_NONE; }
|
||||
TranslResult& operator=(const TranslResult &rhs) = default;
|
||||
|
||||
bool isFaulting() const { return fault.isFaulting(); }
|
||||
|
||||
Fault fault;
|
||||
Addr addr;
|
||||
Addr addrMask;
|
||||
bool writable;
|
||||
};
|
||||
|
||||
SMMUv3DeviceInterface &ifc;
|
||||
|
||||
Reference in New Issue
Block a user