SMMU: supporting probing fault status

Providing system calls that enquiry the fault status in context
banks and in SMMU overall.

Signed-off-by: Oliver Scott <Oliver.Scott@data61.csiro.au>
This commit is contained in:
Qian Ge 2020-02-05 11:11:50 +11:00 committed by Oliver Scott
parent 35bb485e29
commit 81f9a88ff7
4 changed files with 116 additions and 3 deletions

View file

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

View file

@ -319,6 +319,29 @@
<param dir="in" name="index" type="seL4_Word" description="CPTR to the destination slot. Resolved from the root of the destination CSpace."/>
<param dir="in" name="depth" type="seL4_Uint8" description="Number of bits of dest_index to resolve to find the destination slot."/>
</method>
<method id="ARMSIDGetFault" name="GetFault" manual_name="GetFault"
manual_label="sid_controlgetfault">
<brief>
Get the fault status of the SMMU.
</brief>
<return>
A <texttt text='seL4_ARM_SMMU_GetFault_t'/> struct that contains a
<texttt text='seL4_Word status'/>, which holds the global fault status of the SMMU,
<texttt text='seL4_Word syndrome_0'/>, which holds the global fault syndrome 0 of the SMMU,
<texttt text='seL4_Word syndrome_1'/>, which holds the global fault syndrome 1 of the SMMU,
and <texttt text='int error'/>.<docref> See <autoref label='sec:errors'/> for a description
of the message register and tag contents upon error.</docref>
</return>
<param dir="out" name="status" type="seL4_Word"/>
<param dir="out" name="syndrome_0" type="seL4_Word"/>
<param dir="out" name="syndrome_1" type="seL4_Word"/>
</method>
<method id="ARMSIDClearFault" name="ClearFault" manual_name="ClearFault"
manual_label="sid_controlclearfault">
<brief>
Clear the fault status of the SMMU.
</brief>
</method>
</interface>
<interface name="seL4_ARM_SID" manual_name="SID" cap_description="A SID capability. This gives you the authority to make this call.">
<method id="ARMSIDBindCB" name="BindCB" manual_name="BindCB"
@ -375,5 +398,26 @@
Invalidating TLB entries used by the current ASID in this context bank.
</brief>
</method>
<method id="ARMCBGetFault" name="CBGetFault" manual_name="CBGetFault"
manual_label="cb_getfault">
<brief>
Get the fault status of the context bank.
</brief>
<return>
A <texttt text='seL4_ARM_SMMU_CB_GetFault_t'/> struct that contains a
<texttt text='seL4_Word status'/>, which holds the fault status of the context bank,
<texttt text='seL4_Word address'/>, which holds the faulty address,
and <texttt text='int error'/>.<docref> See <autoref label='sec:errors'/> for a description
of the message register and tag contents upon error.</docref>
</return>
<param dir="out" name="status" type="seL4_Word"/>
<param dir="out" name="address" type="seL4_Word"/>
</method>
<method id="ARMCBClearFault" name="CBClearFault" manual_name="CBClearFault"
manual_label="cb_clearfault">
<brief>
Clear the fault status of the context bank.
</brief>
</method>
</interface>
</api>

View file

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

View file

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