mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-19 02:54:24 +00:00

During cold boot, the initial translation tables are created with data caches disabled, so all modifications go to memory directly. After the MMU is enabled and data cache is enabled, any modification to the tables goes to data cache, and eventually may get flushed to memory. If CPU0 modifies the tables while CPU1 is off, CPU0 will have the modified tables in its data cache. When CPU1 is powered on, the MMU is enabled, then it enables coherency, and then it enables the data cache. Until this is done, CPU1 isn't in coherency, and the translation tables it sees can be outdated if CPU0 still has some modified entries in its data cache. This can be a problem in some cases. For example, the warm boot code uses only the tables mapped during cold boot, which don't normally change. However, if they are modified (and a RO page is made RW, or a XN page is made executable) the CPU will see the old attributes and crash when it tries to access it. This doesn't happen in systems with HW_ASSISTED_COHERENCY or WARMBOOT_ENABLE_DCACHE_EARLY. In these systems, the data cache is enabled at the same time as the MMU. As soon as this happens, the CPU is in coherency. There was an attempt of a fix in psci_helpers.S, but it didn't solve the problem. That code has been deleted. The code was introduced in commit <264410306381> ("Invalidate TLB entries during warm boot"). Now, during a map or unmap operation, the memory associated to each modified table is flushed. Traversing a table will also flush it's memory, as there is no way to tell in the current implementation if the table that has been traversed has also been modified. Change-Id: I4b520bca27502f1018878061bc5fb82af740bb92 Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
148 lines
4.3 KiB
ArmAsm
148 lines
4.3 KiB
ArmAsm
/*
|
|
* Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <asm_macros.S>
|
|
#include <platform_def.h>
|
|
#include <psci.h>
|
|
|
|
.globl psci_do_pwrdown_cache_maintenance
|
|
.globl psci_do_pwrup_cache_maintenance
|
|
.globl psci_power_down_wfi
|
|
|
|
/* -----------------------------------------------------------------------
|
|
* void psci_do_pwrdown_cache_maintenance(unsigned int power level);
|
|
*
|
|
* This function performs cache maintenance for the specified power
|
|
* level. The levels of cache affected are determined by the power
|
|
* level which is passed as the argument i.e. level 0 results
|
|
* in a flush of the L1 cache. Both the L1 and L2 caches are flushed
|
|
* for a higher power level.
|
|
*
|
|
* Additionally, this function also ensures that stack memory is correctly
|
|
* flushed out to avoid coherency issues due to a change in its memory
|
|
* attributes after the data cache is disabled.
|
|
* -----------------------------------------------------------------------
|
|
*/
|
|
func psci_do_pwrdown_cache_maintenance
|
|
push {r4, lr}
|
|
|
|
/* ----------------------------------------------
|
|
* Turn OFF cache and do stack maintenance
|
|
* prior to cpu operations . This sequence is
|
|
* different from AArch64 because in AArch32 the
|
|
* assembler routines for cpu operations utilize
|
|
* the stack whereas in AArch64 it doesn't.
|
|
* ----------------------------------------------
|
|
*/
|
|
mov r4, r0
|
|
bl do_stack_maintenance
|
|
|
|
/* ---------------------------------------------
|
|
* Invoke CPU-specifc power down operations for
|
|
* the appropriate level
|
|
* ---------------------------------------------
|
|
*/
|
|
mov r0, r4
|
|
pop {r4, lr}
|
|
b prepare_cpu_pwr_dwn
|
|
endfunc psci_do_pwrdown_cache_maintenance
|
|
|
|
|
|
/* -----------------------------------------------------------------------
|
|
* void psci_do_pwrup_cache_maintenance(void);
|
|
*
|
|
* This function performs cache maintenance after this cpu is powered up.
|
|
* Currently, this involves managing the used stack memory before turning
|
|
* on the data cache.
|
|
* -----------------------------------------------------------------------
|
|
*/
|
|
func psci_do_pwrup_cache_maintenance
|
|
/* r12 is pushed to meet the 8 byte stack alignment requirement */
|
|
push {r12, lr}
|
|
|
|
/* ---------------------------------------------
|
|
* Ensure any inflight stack writes have made it
|
|
* to main memory.
|
|
* ---------------------------------------------
|
|
*/
|
|
dmb st
|
|
|
|
/* ---------------------------------------------
|
|
* Calculate and store the size of the used
|
|
* stack memory in r1. Calculate and store the
|
|
* stack base address in r0.
|
|
* ---------------------------------------------
|
|
*/
|
|
bl plat_get_my_stack
|
|
mov r1, sp
|
|
sub r1, r0, r1
|
|
mov r0, sp
|
|
bl inv_dcache_range
|
|
|
|
/* ---------------------------------------------
|
|
* Enable the data cache.
|
|
* ---------------------------------------------
|
|
*/
|
|
ldcopr r0, SCTLR
|
|
orr r0, r0, #SCTLR_C_BIT
|
|
stcopr r0, SCTLR
|
|
isb
|
|
|
|
pop {r12, pc}
|
|
endfunc psci_do_pwrup_cache_maintenance
|
|
|
|
/* ---------------------------------------------
|
|
* void do_stack_maintenance(void)
|
|
* Do stack maintenance by flushing the used
|
|
* stack to the main memory and invalidating the
|
|
* remainder.
|
|
* ---------------------------------------------
|
|
*/
|
|
func do_stack_maintenance
|
|
push {r4, lr}
|
|
bl plat_get_my_stack
|
|
|
|
/* Turn off the D-cache */
|
|
ldcopr r1, SCTLR
|
|
bic r1, #SCTLR_C_BIT
|
|
stcopr r1, SCTLR
|
|
isb
|
|
|
|
/* ---------------------------------------------
|
|
* Calculate and store the size of the used
|
|
* stack memory in r1.
|
|
* ---------------------------------------------
|
|
*/
|
|
mov r4, r0
|
|
mov r1, sp
|
|
sub r1, r0, r1
|
|
mov r0, sp
|
|
bl flush_dcache_range
|
|
|
|
/* ---------------------------------------------
|
|
* Calculate and store the size of the unused
|
|
* stack memory in r1. Calculate and store the
|
|
* stack base address in r0.
|
|
* ---------------------------------------------
|
|
*/
|
|
sub r0, r4, #PLATFORM_STACK_SIZE
|
|
sub r1, sp, r0
|
|
bl inv_dcache_range
|
|
|
|
pop {r4, pc}
|
|
endfunc do_stack_maintenance
|
|
|
|
/* -----------------------------------------------------------------------
|
|
* This function is called to indicate to the power controller that it
|
|
* is safe to power down this cpu. It should not exit the wfi and will
|
|
* be released from reset upon power up.
|
|
* -----------------------------------------------------------------------
|
|
*/
|
|
func psci_power_down_wfi
|
|
dsb sy // ensure write buffer empty
|
|
wfi
|
|
no_ret plat_panic_handler
|
|
endfunc psci_power_down_wfi
|