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