From ef10db5a3e5546f17a16f1a6869e9d46f147a002 Mon Sep 17 00:00:00 2001 From: Giacomo Travaglini Date: Tue, 5 Mar 2024 18:19:56 +0000 Subject: [PATCH] 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 --- src/dev/arm/smmu_v3_transl.cc | 45 +++++++++++++---------- src/dev/arm/smmu_v3_transl.hh | 68 ++++++++++++++++++++++++++++++----- 2 files changed, 86 insertions(+), 27 deletions(-) diff --git a/src/dev/arm/smmu_v3_transl.cc b/src/dev/arm/smmu_v3_transl.cc index c453dd9a93..ba0757f3d9 100644 --- a/src/dev/arm/smmu_v3_transl.cc +++ b/src/dev/arm/smmu_v3_transl.cc @@ -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; } diff --git a/src/dev/arm/smmu_v3_transl.hh b/src/dev/arm/smmu_v3_transl.hh index bb98b1a832..33a4fab2c0 100644 --- a/src/dev/arm/smmu_v3_transl.hh +++ b/src/dev/arm/smmu_v3_transl.hh @@ -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;