diff --git a/include/drivers/smmu/smmuv2.h b/include/drivers/smmu/smmuv2.h
index 67a18f03f..b9956c414 100644
--- a/include/drivers/smmu/smmuv2.h
+++ b/include/drivers/smmu/smmuv2.h
@@ -424,3 +424,7 @@ void smmu_tlb_invalidate_all(void);
void smmu_tlb_invalidate_cb(int cb, asid_t asid);
void smmu_cb_disable(word_t cb, asid_t asid);
void smmu_sid_unbind(word_t sid);
+void smmu_read_fault_state(uint32_t *status, uint32_t *syndrome_0, uint32_t *syndrome_1);
+void smmu_clear_fault_state(void);
+void smmu_cb_read_fault_state(int cb, uint32_t *status, word_t *address);
+void smmu_cb_clear_fault_state(int cb);
diff --git a/libsel4/arch_include/arm/interfaces/sel4arch.xml b/libsel4/arch_include/arm/interfaces/sel4arch.xml
index 0b9829fdd..3bff3a9d0 100644
--- a/libsel4/arch_include/arm/interfaces/sel4arch.xml
+++ b/libsel4/arch_include/arm/interfaces/sel4arch.xml
@@ -319,6 +319,29 @@
+
+
+ Get the fault status of the SMMU.
+
+
+ A struct that contains a
+ , which holds the global fault status of the SMMU,
+ , which holds the global fault syndrome 0 of the SMMU,
+ , which holds the global fault syndrome 1 of the SMMU,
+ and . See for a description
+ of the message register and tag contents upon error.
+
+
+
+
+
+
+
+ Clear the fault status of the SMMU.
+
+
+
+
+ Get the fault status of the context bank.
+
+
+ A struct that contains a
+ , which holds the fault status of the context bank,
+ , which holds the faulty address,
+ and . See for a description
+ of the message register and tag contents upon error.
+
+
+
+
+
+
+ Clear the fault status of the context bank.
+
+
diff --git a/src/arch/arm/object/smmu.c b/src/arch/arm/object/smmu.c
index d632aca05..e0f447a55 100644
--- a/src/arch/arm/object/smmu.c
+++ b/src/arch/arm/object/smmu.c
@@ -27,6 +27,24 @@ exception_t decodeARMSIDControlInvocation(word_t label, unsigned int length, cpt
cap_t cnodeCap;
lookupSlot_ret_t lu_ret;
exception_t status;
+ uint32_t faultStatus, faultSyndrome_0, faultSyndrome_1;
+
+ if (label == ARMSIDGetFault) {
+ smmu_read_fault_state(&faultStatus, &faultSyndrome_0, &faultSyndrome_1);
+ setRegister(NODE_STATE(ksCurThread), msgRegisters[0], faultStatus);
+ setRegister(NODE_STATE(ksCurThread), msgRegisters[1], faultSyndrome_0);
+ setRegister(NODE_STATE(ksCurThread), msgRegisters[2], faultSyndrome_1);
+ setRegister(NODE_STATE(ksCurThread), msgInfoRegister,
+ wordFromMessageInfo(seL4_MessageInfo_new(0, 0, 0, 3)));
+ setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
+ return EXCEPTION_NONE;
+ }
+
+ if (label == ARMSIDClearFault) {
+ smmu_clear_fault_state();
+ setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
+ return EXCEPTION_NONE;
+ }
if (label != ARMSIDIssueSIDManager) {
userError("SIDControl: Illegal operation.");
@@ -234,6 +252,8 @@ exception_t decodeARMCBInvocation(word_t label, unsigned int length, cptr_t cptr
cte_t *cbSlot;
exception_t status;
word_t cb;
+ uint32_t faultStatus;
+ word_t faultAddress;
switch (label) {
case ARMCBTLBInvalidate:
@@ -297,6 +317,21 @@ exception_t decodeARMCBInvocation(word_t label, unsigned int length, cptr_t cptr
}
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return EXCEPTION_NONE;
+
+ case ARMCBGetFault:
+ smmu_cb_read_fault_state(cap_cb_cap_get_capCB(cap), &faultStatus, &faultAddress);
+ setRegister(NODE_STATE(ksCurThread), msgRegisters[0], faultStatus);
+ setRegister(NODE_STATE(ksCurThread), msgRegisters[1], faultAddress);
+ setRegister(NODE_STATE(ksCurThread), msgInfoRegister,
+ wordFromMessageInfo(seL4_MessageInfo_new(0, 0, 0, 2)));
+ setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
+ return EXCEPTION_NONE;
+
+ case ARMCBClearFault:
+ smmu_cb_clear_fault_state(cap_cb_cap_get_capCB(cap));
+ setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
+ return EXCEPTION_NONE;
+
default:
userError("ARMCBInvocation: Illegal operation.");
current_syscall_error.type = seL4_IllegalOperation;
diff --git a/src/drivers/smmu/smmuv2.c b/src/drivers/smmu/smmuv2.c
index ad1af7416..aaa0c6c58 100644
--- a/src/drivers/smmu/smmuv2.c
+++ b/src/drivers/smmu/smmuv2.c
@@ -259,13 +259,17 @@ BOOT_CODE static void smmu_config_prob(void)
}
+
BOOT_CODE static void smmu_dev_reset(void)
{
- uint32_t reg;
+ uint32_t reg = 0;
pptr_t cb_bank_ptr;
uint32_t major;
- /*clear the global FSR by writing back the read value*/
+ /*clear the fault syndrom registers*/
+ smmu_write_reg32(SMMU_GR0_PPTR, SMMU_sGFSYNR0, reg);
+ smmu_write_reg32(SMMU_GR0_PPTR, SMMU_sGFSYNR1, reg);
+ /*clear the global FSR by writing back the read value*/
reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_sGFSR);
smmu_write_reg32(SMMU_GR0_PPTR, SMMU_sGFSR, reg);
@@ -306,8 +310,9 @@ BOOT_CODE static void smmu_dev_reset(void)
cb_bank_ptr = SMMU_CBn_BASE_PPTR(i);
/*disable context banks and clear the context bank fault registers*/
smmu_write_reg32(cb_bank_ptr, SMMU_CBn_SCTLR, 0);
+ /*clear the syndrom register*/
+ smmu_write_reg64(cb_bank_ptr, SMMU_CBn_FAR, 0ULL);
smmu_write_reg32(cb_bank_ptr, SMMU_CBn_FSR, CBn_FSR_CLEAR_ALL);
-
/*special init requested by the smmu-500: start*/
/*disable MMU-500's next page prefetch due to errata 841119 and 826419*/
reg = smmu_read_reg32(cb_bank_ptr, SMMU_CBn_ACTLR);
@@ -567,3 +572,28 @@ void smmu_tlb_invalidate_cb(int cb, asid_t asid) {
smmu_tlb_sync(SMMU_CBn_BASE_PPTR(cb), SMMU_CBn_TLBSYNC, SMMU_CBn_TLBSTATUS);
#endif
}
+
+void smmu_read_fault_state(uint32_t *status, uint32_t *syndrome_0, uint32_t *syndrome_1)
+{
+ *status = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_sGFSR);
+ *syndrome_0 = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_sGFSYNR0);
+ *syndrome_1 = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_sGFSYNR1);
+}
+
+void smmu_clear_fault_state(void)
+{
+ uint32_t reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_sGFSR);
+ smmu_write_reg32(SMMU_GR0_PPTR, SMMU_sGFSR, reg);
+}
+
+void smmu_cb_read_fault_state(int cb, uint32_t *status, word_t *address)
+{
+ *status = smmu_read_reg32(SMMU_CBn_BASE_PPTR(cb), SMMU_CBn_FSR);
+ *address = smmu_read_reg64(SMMU_CBn_BASE_PPTR(cb),SMMU_CBn_FAR);
+}
+
+void smmu_cb_clear_fault_state(int cb)
+{
+ smmu_write_reg32(SMMU_CBn_BASE_PPTR(cb), SMMU_CBn_FSR, CBn_FSR_CLEAR_ALL);
+}
+