arch: arm: cortex_a_r: Fix memory corruption when disabling dcache
On the Xilinx MPSoC (Cortex-R5) platform, erratic operation was often seen when an operation which disabled the dcache, such as sys_reboot, was performed. Usually this manifested as an undefined instruction trap due to the CPU jumping to an invalid memory address. It appears the problem was due to dirty cache lines being present at the time the cache is disabled. Once the cache is disabled, the CPU will ignore the cache contents and read the possibly out-of-date data in main memory. Likewise, since the cache was being cleaned after it was already disabled, if the CPU had already written through changes to some memory locations, cleaning the cache at that point would potentially overwrite those changes with older data. The fact that the arch_dcache_flush_and_invd_all function was being called to do the cleaning and invalidation also contributed to this problem, because it is a non-inline function which means the compiler will generate memory writes to the stack when the function is called and returns. Corruption of the stack can result in the CPU ending up jumping to garbage addresses when trying to return from functions. To avoid this problem, the cache is now cleaned and invalidated prior to the dcache being disabled. This is done by directly calling the L1C_CleanInvalidateDCacheAll function, which, as it is declared as force inline, should help ensure there are no memory accesses, which would populate new cache lines, between the cache cleaning and disabling the cache. Ideally, for maximum safety, the cache cleaning and cache disabling should be done in assembler code, to guarantee that there are no memory accesses generated by the compiler during these operations. However, the present change does appear to solve this issue. Signed-off-by: Robert Hancock <robert.hancock@calian.com>
This commit is contained in:
parent
d0aa263c1d
commit
0e248419b7
1 changed files with 2 additions and 2 deletions
|
@ -63,13 +63,13 @@ void arch_dcache_disable(void)
|
|||
{
|
||||
uint32_t val;
|
||||
|
||||
L1C_CleanInvalidateDCacheAll();
|
||||
|
||||
val = __get_SCTLR();
|
||||
val &= ~SCTLR_C_Msk;
|
||||
barrier_dsync_fence_full();
|
||||
__set_SCTLR(val);
|
||||
barrier_isync_fence_full();
|
||||
|
||||
arch_dcache_flush_and_invd_all();
|
||||
}
|
||||
|
||||
int arch_dcache_flush_all(void)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue