The USDHC data interrupt handler, USDHC_TransferHandleData(), contains an unconditional D-Cache invalidate on completed USDHC transfer, presumably to ensure the CPU sees data written by DMA if the line was pulled back into the cache since the clean+invalidate in USDHC_TransferNonBlocking():
|
#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL |
|
if (handle->data->rxData != NULL) |
|
{ |
|
DCACHE_InvalidateByRange((uintptr_t)(handle->data->rxData), |
|
(handle->data->blockSize) * (handle->data->blockCount)); |
|
} |
|
#endif |
But that causes significant memory unsafety: if the transfer did not use DMA, the transfer function never cleaned it to begin with, meaning the new invalidate discards writes elsewhere in that line from an arbitrarily long period prior to the transfer! This happens when the if branch here is taken:
|
/* if the DMA desciptor configure fail or not needed , disable it */ |
|
if (error != kStatus_Success) |
|
{ |
|
/* disable DMA, using polling mode in this situation */ |
|
USDHC_EnableInternalDMA(base, false); |
|
enDMA = false; |
|
} |
|
#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL |
|
else |
|
{ |
|
if (data->txData != NULL) |
|
{ |
|
/* clear the DCACHE */ |
|
DCACHE_CleanByRange((uintptr_t)data->txData, (data->blockSize) * (data->blockCount)); |
|
} |
|
else |
|
{ |
|
/* clear the DCACHE */ |
|
DCACHE_CleanInvalidateByRange((uintptr_t)data->rxData, (data->blockSize) * (data->blockCount)); |
|
} |
|
} |
|
#endif |
In fact, I don't believe the invalidate is safe even when DMA is used: I don't see any requirement that DMA buffers be the only thing in their cache line, so it may still discard writes, just over a bounded time period.
I have a 100% reproducible crash in Zephyr due to stack corruption caused by this bug when using the Infineon AIROC Wi-Fi driver on an i.MX RT1061.
The USDHC data interrupt handler,
USDHC_TransferHandleData(), contains an unconditional D-Cache invalidate on completed USDHC transfer, presumably to ensure the CPU sees data written by DMA if the line was pulled back into the cache since the clean+invalidate inUSDHC_TransferNonBlocking():mcuxsdk-core/drivers/usdhc/fsl_usdhc.c
Lines 2358 to 2364 in 3b91d61
But that causes significant memory unsafety: if the transfer did not use DMA, the transfer function never cleaned it to begin with, meaning the new invalidate discards writes elsewhere in that line from an arbitrarily long period prior to the transfer! This happens when the
ifbranch here is taken:mcuxsdk-core/drivers/usdhc/fsl_usdhc.c
Lines 1929 to 1950 in 3b91d61
In fact, I don't believe the invalidate is safe even when DMA is used: I don't see any requirement that DMA buffers be the only thing in their cache line, so it may still discard writes, just over a bounded time period.
I have a 100% reproducible crash in Zephyr due to stack corruption caused by this bug when using the Infineon AIROC Wi-Fi driver on an i.MX RT1061.