arm-trusted-firmware/lib/aarch64/misc_helpers.S

585 lines
16 KiB
ArmAsm
Raw Normal View History

2013-10-25 09:08:21 +01:00
/*
Increase type widths to satisfy width requirements Usually, C has no problem up-converting types to larger bit sizes. MISRA rule 10.7 requires that you not do this, or be very explicit about this. This resolves the following required rule: bl1/aarch64/bl1_context_mgmt.c:81:[MISRA C-2012 Rule 10.7 (required)]<None> The width of the composite expression "0U | ((mode & 3U) << 2U) | 1U | 0x3c0U" (32 bits) is less that the right hand operand "18446744073709547519ULL" (64 bits). This also resolves MISRA defects such as: bl2/aarch64/bl2arch_setup.c:18:[MISRA C-2012 Rule 12.2 (required)] In the expression "3U << 20", shifting more than 7 bits, the number of bits in the essential type of the left expression, "3U", is not allowed. Further, MISRA requires that all shifts don't overflow. The definition of PAGE_SIZE was (1U << 12), and 1U is 8 bits. This caused about 50 issues. This fixes the violation by changing the definition to 1UL << 12. Since this uses 32bits, it should not create any issues for aarch32. This patch also contains a fix for a build failure in the sun50i_a64 platform. Specifically, these misra fixes removed a single and instruction, 92407e73 and x19, x19, #0xffffffff from the cm_setup_context function caused a relocation in psci_cpus_on_start to require a linker-generated stub. This increased the size of the .text section and caused an alignment later on to go over a page boundary and round up to the end of RAM before placing the .data section. This sectionn is of non-zero size and therefore causes a link error. The fix included in this reorders the functions during link time without changing their ording with respect to alignment. Change-Id: I76b4b662c3d262296728a8b9aab7a33b02087f16 Signed-off-by: Jimmy Brisson <jimmy.brisson@arm.com>
2020-08-04 22:18:52 +01:00
* Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
2013-10-25 09:08:21 +01:00
*
* SPDX-License-Identifier: BSD-3-Clause
2013-10-25 09:08:21 +01:00
*/
#include <arch.h>
#include <asm_macros.S>
#include <assert_macros.S>
#include <common/bl_common.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
2013-10-25 09:08:21 +01:00
.globl smc
Introduce unified API to zero memory Introduce zeromem_dczva function on AArch64 that can handle unaligned addresses and make use of DC ZVA instruction to zero a whole block at a time. This zeroing takes place directly in the cache to speed it up without doing external memory access. Remove the zeromem16 function on AArch64 and replace it with an alias to zeromem. This zeromem16 function is now deprecated. Remove the 16-bytes alignment constraint on __BSS_START__ in firmware-design.md as it is now not mandatory anymore (it used to comply with zeromem16 requirements). Change the 16-bytes alignment constraints in SP min's linker script to a 8-bytes alignment constraint as the AArch32 zeromem implementation is now more efficient on 8-bytes aligned addresses. Introduce zero_normalmem and zeromem helpers in platform agnostic header that are implemented this way: * AArch32: * zero_normalmem: zero using usual data access * zeromem: alias for zero_normalmem * AArch64: * zero_normalmem: zero normal memory using DC ZVA instruction (needs MMU enabled) * zeromem: zero using usual data access Usage guidelines: in most cases, zero_normalmem should be preferred. There are 2 scenarios where zeromem (or memset) must be used instead: * Code that must run with MMU disabled (which means all memory is considered device memory for data accesses). * Code that fills device memory with null bytes. Optionally, the following rule can be applied if performance is important: * Code zeroing small areas (few bytes) that are not secrets should use memset to take advantage of compiler optimizations. Note: Code zeroing security-related critical information should use zero_normalmem/zeromem instead of memset to avoid removal by compilers' optimizations in some cases or misbehaving versions of GCC. Fixes ARM-software/tf-issues#408 Change-Id: Iafd9663fc1070413c3e1904e54091cf60effaa82 Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
2016-12-02 13:51:54 +00:00
.globl zero_normalmem
.globl zeromem
.globl memcpy16
2013-10-25 09:08:21 +01:00
.globl disable_mmu_el1
.globl disable_mmu_el3
.globl disable_mmu_icache_el1
.globl disable_mmu_icache_el3
.globl fixup_gdt_reloc
#if SUPPORT_VFP
.globl enable_vfp
#endif
func smc
2013-10-25 09:08:21 +01:00
smc #0
endfunc smc
Introduce unified API to zero memory Introduce zeromem_dczva function on AArch64 that can handle unaligned addresses and make use of DC ZVA instruction to zero a whole block at a time. This zeroing takes place directly in the cache to speed it up without doing external memory access. Remove the zeromem16 function on AArch64 and replace it with an alias to zeromem. This zeromem16 function is now deprecated. Remove the 16-bytes alignment constraint on __BSS_START__ in firmware-design.md as it is now not mandatory anymore (it used to comply with zeromem16 requirements). Change the 16-bytes alignment constraints in SP min's linker script to a 8-bytes alignment constraint as the AArch32 zeromem implementation is now more efficient on 8-bytes aligned addresses. Introduce zero_normalmem and zeromem helpers in platform agnostic header that are implemented this way: * AArch32: * zero_normalmem: zero using usual data access * zeromem: alias for zero_normalmem * AArch64: * zero_normalmem: zero normal memory using DC ZVA instruction (needs MMU enabled) * zeromem: zero using usual data access Usage guidelines: in most cases, zero_normalmem should be preferred. There are 2 scenarios where zeromem (or memset) must be used instead: * Code that must run with MMU disabled (which means all memory is considered device memory for data accesses). * Code that fills device memory with null bytes. Optionally, the following rule can be applied if performance is important: * Code zeroing small areas (few bytes) that are not secrets should use memset to take advantage of compiler optimizations. Note: Code zeroing security-related critical information should use zero_normalmem/zeromem instead of memset to avoid removal by compilers' optimizations in some cases or misbehaving versions of GCC. Fixes ARM-software/tf-issues#408 Change-Id: Iafd9663fc1070413c3e1904e54091cf60effaa82 Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
2016-12-02 13:51:54 +00:00
/* -----------------------------------------------------------------------
* void zero_normalmem(void *mem, unsigned int length);
*
* Initialise a region in normal memory to 0. This functions complies with the
* AAPCS and can be called from C code.
*
* NOTE: MMU must be enabled when using this function as it can only operate on
* normal memory. It is intended to be mainly used from C code when MMU
* is usually enabled.
* -----------------------------------------------------------------------
*/
.equ zero_normalmem, zeromem_dczva
/* -----------------------------------------------------------------------
* void zeromem(void *mem, unsigned int length);
*
* Initialise a region of device memory to 0. This functions complies with the
* AAPCS and can be called from C code.
*
* NOTE: When data caches and MMU are enabled, zero_normalmem can usually be
* used instead for faster zeroing.
*
* -----------------------------------------------------------------------
*/
func zeromem
/* x2 is the address past the last zeroed address */
add x2, x0, x1
/*
* Uses the fallback path that does not use DC ZVA instruction and
* therefore does not need enabled MMU
*/
b .Lzeromem_dczva_fallback_entry
endfunc zeromem
/* -----------------------------------------------------------------------
* void zeromem_dczva(void *mem, unsigned int length);
*
* Fill a region of normal memory of size "length" in bytes with null bytes.
* MMU must be enabled and the memory be of
* normal type. This is because this function internally uses the DC ZVA
* instruction, which generates an Alignment fault if used on any type of
* Device memory (see section D3.4.9 of the ARMv8 ARM, issue k). When the MMU
* is disabled, all memory behaves like Device-nGnRnE memory (see section
* D4.2.8), hence the requirement on the MMU being enabled.
* NOTE: The code assumes that the block size as defined in DCZID_EL0
* register is at least 16 bytes.
*
* -----------------------------------------------------------------------
*/
func zeromem_dczva
/*
* The function consists of a series of loops that zero memory one byte
* at a time, 16 bytes at a time or using the DC ZVA instruction to
* zero aligned block of bytes, which is assumed to be more than 16.
* In the case where the DC ZVA instruction cannot be used or if the
* first 16 bytes loop would overflow, there is fallback path that does
* not use DC ZVA.
* Note: The fallback path is also used by the zeromem function that
* branches to it directly.
*
* +---------+ zeromem_dczva
* | entry |
* +----+----+
* |
* v
* +---------+
* | checks |>o-------+ (If any check fails, fallback)
* +----+----+ |
* | |---------------+
* v | Fallback path |
* +------+------+ |---------------+
* | 1 byte loop | |
* +------+------+ .Lzeromem_dczva_initial_1byte_aligned_end
* | |
* v |
* +-------+-------+ |
* | 16 bytes loop | |
* +-------+-------+ |
* | |
* v |
* +------+------+ .Lzeromem_dczva_blocksize_aligned
* | DC ZVA loop | |
* +------+------+ |
* +--------+ | |
* | | | |
* | v v |
* | +-------+-------+ .Lzeromem_dczva_final_16bytes_aligned
* | | 16 bytes loop | |
* | +-------+-------+ |
* | | |
* | v |
* | +------+------+ .Lzeromem_dczva_final_1byte_aligned
* | | 1 byte loop | |
* | +-------------+ |
* | | |
* | v |
* | +---+--+ |
* | | exit | |
* | +------+ |
* | |
* | +--------------+ +------------------+ zeromem
* | | +----------------| zeromem function |
* | | | +------------------+
* | v v
* | +-------------+ .Lzeromem_dczva_fallback_entry
* | | 1 byte loop |
* | +------+------+
* | |
* +-----------+
*/
/*
* Readable names for registers
*
* Registers x0, x1 and x2 are also set by zeromem which
* branches into the fallback path directly, so cursor, length and
* stop_address should not be retargeted to other registers.
*/
cursor .req x0 /* Start address and then current address */
length .req x1 /* Length in bytes of the region to zero out */
/* Reusing x1 as length is never used after block_mask is set */
block_mask .req x1 /* Bitmask of the block size read in DCZID_EL0 */
stop_address .req x2 /* Address past the last zeroed byte */
block_size .req x3 /* Size of a block in bytes as read in DCZID_EL0 */
tmp1 .req x4
tmp2 .req x5
#if ENABLE_ASSERTIONS
Introduce unified API to zero memory Introduce zeromem_dczva function on AArch64 that can handle unaligned addresses and make use of DC ZVA instruction to zero a whole block at a time. This zeroing takes place directly in the cache to speed it up without doing external memory access. Remove the zeromem16 function on AArch64 and replace it with an alias to zeromem. This zeromem16 function is now deprecated. Remove the 16-bytes alignment constraint on __BSS_START__ in firmware-design.md as it is now not mandatory anymore (it used to comply with zeromem16 requirements). Change the 16-bytes alignment constraints in SP min's linker script to a 8-bytes alignment constraint as the AArch32 zeromem implementation is now more efficient on 8-bytes aligned addresses. Introduce zero_normalmem and zeromem helpers in platform agnostic header that are implemented this way: * AArch32: * zero_normalmem: zero using usual data access * zeromem: alias for zero_normalmem * AArch64: * zero_normalmem: zero normal memory using DC ZVA instruction (needs MMU enabled) * zeromem: zero using usual data access Usage guidelines: in most cases, zero_normalmem should be preferred. There are 2 scenarios where zeromem (or memset) must be used instead: * Code that must run with MMU disabled (which means all memory is considered device memory for data accesses). * Code that fills device memory with null bytes. Optionally, the following rule can be applied if performance is important: * Code zeroing small areas (few bytes) that are not secrets should use memset to take advantage of compiler optimizations. Note: Code zeroing security-related critical information should use zero_normalmem/zeromem instead of memset to avoid removal by compilers' optimizations in some cases or misbehaving versions of GCC. Fixes ARM-software/tf-issues#408 Change-Id: Iafd9663fc1070413c3e1904e54091cf60effaa82 Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
2016-12-02 13:51:54 +00:00
/*
* Check for M bit (MMU enabled) of the current SCTLR_EL(1|3)
* register value and panic if the MMU is disabled.
*/
#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3)
Introduce unified API to zero memory Introduce zeromem_dczva function on AArch64 that can handle unaligned addresses and make use of DC ZVA instruction to zero a whole block at a time. This zeroing takes place directly in the cache to speed it up without doing external memory access. Remove the zeromem16 function on AArch64 and replace it with an alias to zeromem. This zeromem16 function is now deprecated. Remove the 16-bytes alignment constraint on __BSS_START__ in firmware-design.md as it is now not mandatory anymore (it used to comply with zeromem16 requirements). Change the 16-bytes alignment constraints in SP min's linker script to a 8-bytes alignment constraint as the AArch32 zeromem implementation is now more efficient on 8-bytes aligned addresses. Introduce zero_normalmem and zeromem helpers in platform agnostic header that are implemented this way: * AArch32: * zero_normalmem: zero using usual data access * zeromem: alias for zero_normalmem * AArch64: * zero_normalmem: zero normal memory using DC ZVA instruction (needs MMU enabled) * zeromem: zero using usual data access Usage guidelines: in most cases, zero_normalmem should be preferred. There are 2 scenarios where zeromem (or memset) must be used instead: * Code that must run with MMU disabled (which means all memory is considered device memory for data accesses). * Code that fills device memory with null bytes. Optionally, the following rule can be applied if performance is important: * Code zeroing small areas (few bytes) that are not secrets should use memset to take advantage of compiler optimizations. Note: Code zeroing security-related critical information should use zero_normalmem/zeromem instead of memset to avoid removal by compilers' optimizations in some cases or misbehaving versions of GCC. Fixes ARM-software/tf-issues#408 Change-Id: Iafd9663fc1070413c3e1904e54091cf60effaa82 Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
2016-12-02 13:51:54 +00:00
mrs tmp1, sctlr_el3
#else
mrs tmp1, sctlr_el1
#endif
Introduce unified API to zero memory Introduce zeromem_dczva function on AArch64 that can handle unaligned addresses and make use of DC ZVA instruction to zero a whole block at a time. This zeroing takes place directly in the cache to speed it up without doing external memory access. Remove the zeromem16 function on AArch64 and replace it with an alias to zeromem. This zeromem16 function is now deprecated. Remove the 16-bytes alignment constraint on __BSS_START__ in firmware-design.md as it is now not mandatory anymore (it used to comply with zeromem16 requirements). Change the 16-bytes alignment constraints in SP min's linker script to a 8-bytes alignment constraint as the AArch32 zeromem implementation is now more efficient on 8-bytes aligned addresses. Introduce zero_normalmem and zeromem helpers in platform agnostic header that are implemented this way: * AArch32: * zero_normalmem: zero using usual data access * zeromem: alias for zero_normalmem * AArch64: * zero_normalmem: zero normal memory using DC ZVA instruction (needs MMU enabled) * zeromem: zero using usual data access Usage guidelines: in most cases, zero_normalmem should be preferred. There are 2 scenarios where zeromem (or memset) must be used instead: * Code that must run with MMU disabled (which means all memory is considered device memory for data accesses). * Code that fills device memory with null bytes. Optionally, the following rule can be applied if performance is important: * Code zeroing small areas (few bytes) that are not secrets should use memset to take advantage of compiler optimizations. Note: Code zeroing security-related critical information should use zero_normalmem/zeromem instead of memset to avoid removal by compilers' optimizations in some cases or misbehaving versions of GCC. Fixes ARM-software/tf-issues#408 Change-Id: Iafd9663fc1070413c3e1904e54091cf60effaa82 Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
2016-12-02 13:51:54 +00:00
tst tmp1, #SCTLR_M_BIT
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
Introduce unified API to zero memory Introduce zeromem_dczva function on AArch64 that can handle unaligned addresses and make use of DC ZVA instruction to zero a whole block at a time. This zeroing takes place directly in the cache to speed it up without doing external memory access. Remove the zeromem16 function on AArch64 and replace it with an alias to zeromem. This zeromem16 function is now deprecated. Remove the 16-bytes alignment constraint on __BSS_START__ in firmware-design.md as it is now not mandatory anymore (it used to comply with zeromem16 requirements). Change the 16-bytes alignment constraints in SP min's linker script to a 8-bytes alignment constraint as the AArch32 zeromem implementation is now more efficient on 8-bytes aligned addresses. Introduce zero_normalmem and zeromem helpers in platform agnostic header that are implemented this way: * AArch32: * zero_normalmem: zero using usual data access * zeromem: alias for zero_normalmem * AArch64: * zero_normalmem: zero normal memory using DC ZVA instruction (needs MMU enabled) * zeromem: zero using usual data access Usage guidelines: in most cases, zero_normalmem should be preferred. There are 2 scenarios where zeromem (or memset) must be used instead: * Code that must run with MMU disabled (which means all memory is considered device memory for data accesses). * Code that fills device memory with null bytes. Optionally, the following rule can be applied if performance is important: * Code zeroing small areas (few bytes) that are not secrets should use memset to take advantage of compiler optimizations. Note: Code zeroing security-related critical information should use zero_normalmem/zeromem instead of memset to avoid removal by compilers' optimizations in some cases or misbehaving versions of GCC. Fixes ARM-software/tf-issues#408 Change-Id: Iafd9663fc1070413c3e1904e54091cf60effaa82 Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
2016-12-02 13:51:54 +00:00
/* stop_address is the address past the last to zero */
add stop_address, cursor, length
/*
* Get block_size = (log2(<block size>) >> 2) (see encoding of
* dczid_el0 reg)
*/
mrs block_size, dczid_el0
/*
* Select the 4 lowest bits and convert the extracted log2(<block size
* in words>) to <block size in bytes>
*/
ubfx block_size, block_size, #0, #4
mov tmp2, #(1 << 2)
lsl block_size, tmp2, block_size
#if ENABLE_ASSERTIONS
Introduce unified API to zero memory Introduce zeromem_dczva function on AArch64 that can handle unaligned addresses and make use of DC ZVA instruction to zero a whole block at a time. This zeroing takes place directly in the cache to speed it up without doing external memory access. Remove the zeromem16 function on AArch64 and replace it with an alias to zeromem. This zeromem16 function is now deprecated. Remove the 16-bytes alignment constraint on __BSS_START__ in firmware-design.md as it is now not mandatory anymore (it used to comply with zeromem16 requirements). Change the 16-bytes alignment constraints in SP min's linker script to a 8-bytes alignment constraint as the AArch32 zeromem implementation is now more efficient on 8-bytes aligned addresses. Introduce zero_normalmem and zeromem helpers in platform agnostic header that are implemented this way: * AArch32: * zero_normalmem: zero using usual data access * zeromem: alias for zero_normalmem * AArch64: * zero_normalmem: zero normal memory using DC ZVA instruction (needs MMU enabled) * zeromem: zero using usual data access Usage guidelines: in most cases, zero_normalmem should be preferred. There are 2 scenarios where zeromem (or memset) must be used instead: * Code that must run with MMU disabled (which means all memory is considered device memory for data accesses). * Code that fills device memory with null bytes. Optionally, the following rule can be applied if performance is important: * Code zeroing small areas (few bytes) that are not secrets should use memset to take advantage of compiler optimizations. Note: Code zeroing security-related critical information should use zero_normalmem/zeromem instead of memset to avoid removal by compilers' optimizations in some cases or misbehaving versions of GCC. Fixes ARM-software/tf-issues#408 Change-Id: Iafd9663fc1070413c3e1904e54091cf60effaa82 Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
2016-12-02 13:51:54 +00:00
/*
* Assumes block size is at least 16 bytes to avoid manual realignment
* of the cursor at the end of the DCZVA loop.
*/
cmp block_size, #16
ASM_ASSERT(hs)
#endif
/*
* Not worth doing all the setup for a region less than a block and
* protects against zeroing a whole block when the area to zero is
* smaller than that. Also, as it is assumed that the block size is at
* least 16 bytes, this also protects the initial aligning loops from
* trying to zero 16 bytes when length is less than 16.
*/
cmp length, block_size
b.lo .Lzeromem_dczva_fallback_entry
/*
* Calculate the bitmask of the block alignment. It will never
* underflow as the block size is between 4 bytes and 2kB.
* block_mask = block_size - 1
*/
sub block_mask, block_size, #1
/*
* length alias should not be used after this point unless it is
* defined as a register other than block_mask's.
*/
.unreq length
/*
* If the start address is already aligned to zero block size, go
* straight to the cache zeroing loop. This is safe because at this
* point, the length cannot be smaller than a block size.
*/
tst cursor, block_mask
b.eq .Lzeromem_dczva_blocksize_aligned
/*
* Calculate the first block-size-aligned address. It is assumed that
* the zero block size is at least 16 bytes. This address is the last
* address of this initial loop.
*/
orr tmp1, cursor, block_mask
add tmp1, tmp1, #1
/*
* If the addition overflows, skip the cache zeroing loops. This is
* quite unlikely however.
*/
cbz tmp1, .Lzeromem_dczva_fallback_entry
/*
* If the first block-size-aligned address is past the last address,
* fallback to the simpler code.
*/
cmp tmp1, stop_address
b.hi .Lzeromem_dczva_fallback_entry
/*
* If the start address is already aligned to 16 bytes, skip this loop.
* It is safe to do this because tmp1 (the stop address of the initial
* 16 bytes loop) will never be greater than the final stop address.
*/
tst cursor, #0xf
b.eq .Lzeromem_dczva_initial_1byte_aligned_end
/* Calculate the next address aligned to 16 bytes */
orr tmp2, cursor, #0xf
add tmp2, tmp2, #1
/* If it overflows, fallback to the simple path (unlikely) */
cbz tmp2, .Lzeromem_dczva_fallback_entry
/*
* Next aligned address cannot be after the stop address because the
* length cannot be smaller than 16 at this point.
*/
/* First loop: zero byte per byte */
1:
strb wzr, [cursor], #1
cmp cursor, tmp2
b.ne 1b
.Lzeromem_dczva_initial_1byte_aligned_end:
/*
* Second loop: we need to zero 16 bytes at a time from cursor to tmp1
* before being able to use the code that deals with block-size-aligned
* addresses.
*/
cmp cursor, tmp1
b.hs 2f
1:
stp xzr, xzr, [cursor], #16
cmp cursor, tmp1
b.lo 1b
2:
/*
* Third loop: zero a block at a time using DC ZVA cache block zeroing
* instruction.
*/
.Lzeromem_dczva_blocksize_aligned:
/*
* Calculate the last block-size-aligned address. If the result equals
* to the start address, the loop will exit immediately.
*/
bic tmp1, stop_address, block_mask
cmp cursor, tmp1
b.hs 2f
1:
/* Zero the block containing the cursor */
dc zva, cursor
/* Increment the cursor by the size of a block */
add cursor, cursor, block_size
cmp cursor, tmp1
b.lo 1b
2:
/*
* Fourth loop: zero 16 bytes at a time and then byte per byte the
* remaining area
*/
.Lzeromem_dczva_final_16bytes_aligned:
/*
* Calculate the last 16 bytes aligned address. It is assumed that the
* block size will never be smaller than 16 bytes so that the current
* cursor is aligned to at least 16 bytes boundary.
*/
bic tmp1, stop_address, #15
cmp cursor, tmp1
b.hs 2f
1:
stp xzr, xzr, [cursor], #16
cmp cursor, tmp1
b.lo 1b
2:
/* Fifth and final loop: zero byte per byte */
.Lzeromem_dczva_final_1byte_aligned:
cmp cursor, stop_address
b.eq 2f
1:
strb wzr, [cursor], #1
cmp cursor, stop_address
b.ne 1b
2:
ret
Introduce unified API to zero memory Introduce zeromem_dczva function on AArch64 that can handle unaligned addresses and make use of DC ZVA instruction to zero a whole block at a time. This zeroing takes place directly in the cache to speed it up without doing external memory access. Remove the zeromem16 function on AArch64 and replace it with an alias to zeromem. This zeromem16 function is now deprecated. Remove the 16-bytes alignment constraint on __BSS_START__ in firmware-design.md as it is now not mandatory anymore (it used to comply with zeromem16 requirements). Change the 16-bytes alignment constraints in SP min's linker script to a 8-bytes alignment constraint as the AArch32 zeromem implementation is now more efficient on 8-bytes aligned addresses. Introduce zero_normalmem and zeromem helpers in platform agnostic header that are implemented this way: * AArch32: * zero_normalmem: zero using usual data access * zeromem: alias for zero_normalmem * AArch64: * zero_normalmem: zero normal memory using DC ZVA instruction (needs MMU enabled) * zeromem: zero using usual data access Usage guidelines: in most cases, zero_normalmem should be preferred. There are 2 scenarios where zeromem (or memset) must be used instead: * Code that must run with MMU disabled (which means all memory is considered device memory for data accesses). * Code that fills device memory with null bytes. Optionally, the following rule can be applied if performance is important: * Code zeroing small areas (few bytes) that are not secrets should use memset to take advantage of compiler optimizations. Note: Code zeroing security-related critical information should use zero_normalmem/zeromem instead of memset to avoid removal by compilers' optimizations in some cases or misbehaving versions of GCC. Fixes ARM-software/tf-issues#408 Change-Id: Iafd9663fc1070413c3e1904e54091cf60effaa82 Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
2016-12-02 13:51:54 +00:00
/* Fallback for unaligned start addresses */
.Lzeromem_dczva_fallback_entry:
/*
* If the start address is already aligned to 16 bytes, skip this loop.
*/
tst cursor, #0xf
b.eq .Lzeromem_dczva_final_16bytes_aligned
/* Calculate the next address aligned to 16 bytes */
orr tmp1, cursor, #15
add tmp1, tmp1, #1
/* If it overflows, fallback to byte per byte zeroing */
cbz tmp1, .Lzeromem_dczva_final_1byte_aligned
/* If the next aligned address is after the stop address, fall back */
cmp tmp1, stop_address
b.hs .Lzeromem_dczva_final_1byte_aligned
/* Fallback entry loop: zero byte per byte */
1:
strb wzr, [cursor], #1
cmp cursor, tmp1
b.ne 1b
b .Lzeromem_dczva_final_16bytes_aligned
.unreq cursor
/*
* length is already unreq'ed to reuse the register for another
* variable.
*/
.unreq stop_address
.unreq block_size
.unreq block_mask
.unreq tmp1
.unreq tmp2
endfunc zeromem_dczva
/* --------------------------------------------------------------------------
* void memcpy16(void *dest, const void *src, unsigned int length)
*
* Copy length bytes from memory area src to memory area dest.
* The memory areas should not overlap.
* Destination and source addresses must be 16-byte aligned.
* --------------------------------------------------------------------------
*/
func memcpy16
#if ENABLE_ASSERTIONS
orr x3, x0, x1
tst x3, #0xf
ASM_ASSERT(eq)
#endif
/* copy 16 bytes at a time */
m_loop16:
cmp x2, #16
b.lo m_loop1
ldp x3, x4, [x1], #16
stp x3, x4, [x0], #16
sub x2, x2, #16
b m_loop16
/* copy byte per byte */
m_loop1:
cbz x2, m_end
ldrb w3, [x1], #1
strb w3, [x0], #1
subs x2, x2, #1
b.ne m_loop1
m_end:
ret
endfunc memcpy16
/* ---------------------------------------------------------------------------
* Disable the MMU at EL3
* ---------------------------------------------------------------------------
*/
func disable_mmu_el3
mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT)
do_disable_mmu_el3:
mrs x0, sctlr_el3
bic x0, x0, x1
msr sctlr_el3, x0
isb /* ensure MMU is off */
Make generic code work in presence of system caches On the ARMv8 architecture, cache maintenance operations by set/way on the last level of integrated cache do not affect the system cache. This means that such a flush or clean operation could result in the data being pushed out to the system cache rather than main memory. Another CPU could access this data before it enables its data cache or MMU. Such accesses could be serviced from the main memory instead of the system cache. If the data in the sysem cache has not yet been flushed or evicted to main memory then there could be a loss of coherency. The only mechanism to guarantee that the main memory will be updated is to use cache maintenance operations to the PoC by MVA(See section D3.4.11 (System level caches) of ARMv8-A Reference Manual (Issue A.g/ARM DDI0487A.G). This patch removes the reliance of Trusted Firmware on the flush by set/way operation to ensure visibility of data in the main memory. Cache maintenance operations by MVA are now used instead. The following are the broad category of changes: 1. The RW areas of BL2/BL31/BL32 are invalidated by MVA before the C runtime is initialised. This ensures that any stale cache lines at any level of cache are removed. 2. Updates to global data in runtime firmware (BL31) by the primary CPU are made visible to secondary CPUs using a cache clean operation by MVA. 3. Cache maintenance by set/way operations are only used prior to power down. NOTE: NON-UPSTREAM TRUSTED FIRMWARE CODE SHOULD MAKE EQUIVALENT CHANGES IN ORDER TO FUNCTION CORRECTLY ON PLATFORMS WITH SUPPORT FOR SYSTEM CACHES. Fixes ARM-software/tf-issues#205 Change-Id: I64f1b398de0432813a0e0881d70f8337681f6e9a
2015-09-11 16:03:13 +01:00
dsb sy
ret
endfunc disable_mmu_el3
func disable_mmu_icache_el3
mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
b do_disable_mmu_el3
endfunc disable_mmu_icache_el3
/* ---------------------------------------------------------------------------
* Disable the MMU at EL1
* ---------------------------------------------------------------------------
*/
func disable_mmu_el1
mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT)
do_disable_mmu_el1:
mrs x0, sctlr_el1
bic x0, x0, x1
msr sctlr_el1, x0
isb /* ensure MMU is off */
dsb sy
ret
endfunc disable_mmu_el1
func disable_mmu_icache_el1
mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT)
b do_disable_mmu_el1
endfunc disable_mmu_icache_el1
/* ---------------------------------------------------------------------------
* Enable the use of VFP at EL3
* ---------------------------------------------------------------------------
*/
#if SUPPORT_VFP
func enable_vfp
mrs x0, cpacr_el1
orr x0, x0, #CPACR_VFP_BITS
msr cpacr_el1, x0
mrs x0, cptr_el3
mov x1, #AARCH64_CPTR_TFP
bic x0, x0, x1
msr cptr_el3, x0
isb
ret
endfunc enable_vfp
#endif
/* ---------------------------------------------------------------------------
* Helper to fixup Global Descriptor table (GDT) and dynamic relocations
* (.rela.dyn) at runtime.
*
* This function is meant to be used when the firmware is compiled with -fpie
* and linked with -pie options. We rely on the linker script exporting
* appropriate markers for start and end of the section. For GOT, we
* expect __GOT_START__ and __GOT_END__. Similarly for .rela.dyn, we expect
* __RELA_START__ and __RELA_END__.
*
* The function takes the limits of the memory to apply fixups to as
* arguments (which is usually the limits of the relocable BL image).
* x0 - the start of the fixup region
* x1 - the limit of the fixup region
* These addresses have to be page (4KB aligned).
* ---------------------------------------------------------------------------
*/
func fixup_gdt_reloc
mov x6, x0
mov x7, x1
/* Test if the limits are 4K aligned */
#if ENABLE_ASSERTIONS
orr x0, x0, x1
Increase type widths to satisfy width requirements Usually, C has no problem up-converting types to larger bit sizes. MISRA rule 10.7 requires that you not do this, or be very explicit about this. This resolves the following required rule: bl1/aarch64/bl1_context_mgmt.c:81:[MISRA C-2012 Rule 10.7 (required)]<None> The width of the composite expression "0U | ((mode & 3U) << 2U) | 1U | 0x3c0U" (32 bits) is less that the right hand operand "18446744073709547519ULL" (64 bits). This also resolves MISRA defects such as: bl2/aarch64/bl2arch_setup.c:18:[MISRA C-2012 Rule 12.2 (required)] In the expression "3U << 20", shifting more than 7 bits, the number of bits in the essential type of the left expression, "3U", is not allowed. Further, MISRA requires that all shifts don't overflow. The definition of PAGE_SIZE was (1U << 12), and 1U is 8 bits. This caused about 50 issues. This fixes the violation by changing the definition to 1UL << 12. Since this uses 32bits, it should not create any issues for aarch32. This patch also contains a fix for a build failure in the sun50i_a64 platform. Specifically, these misra fixes removed a single and instruction, 92407e73 and x19, x19, #0xffffffff from the cm_setup_context function caused a relocation in psci_cpus_on_start to require a linker-generated stub. This increased the size of the .text section and caused an alignment later on to go over a page boundary and round up to the end of RAM before placing the .data section. This sectionn is of non-zero size and therefore causes a link error. The fix included in this reorders the functions during link time without changing their ording with respect to alignment. Change-Id: I76b4b662c3d262296728a8b9aab7a33b02087f16 Signed-off-by: Jimmy Brisson <jimmy.brisson@arm.com>
2020-08-04 22:18:52 +01:00
tst x0, #(PAGE_SIZE_MASK)
ASM_ASSERT(eq)
#endif
/*
* Calculate the offset based on return address in x30.
* Assume that this function is called within a page at the start of
* fixup region.
*/
Increase type widths to satisfy width requirements Usually, C has no problem up-converting types to larger bit sizes. MISRA rule 10.7 requires that you not do this, or be very explicit about this. This resolves the following required rule: bl1/aarch64/bl1_context_mgmt.c:81:[MISRA C-2012 Rule 10.7 (required)]<None> The width of the composite expression "0U | ((mode & 3U) << 2U) | 1U | 0x3c0U" (32 bits) is less that the right hand operand "18446744073709547519ULL" (64 bits). This also resolves MISRA defects such as: bl2/aarch64/bl2arch_setup.c:18:[MISRA C-2012 Rule 12.2 (required)] In the expression "3U << 20", shifting more than 7 bits, the number of bits in the essential type of the left expression, "3U", is not allowed. Further, MISRA requires that all shifts don't overflow. The definition of PAGE_SIZE was (1U << 12), and 1U is 8 bits. This caused about 50 issues. This fixes the violation by changing the definition to 1UL << 12. Since this uses 32bits, it should not create any issues for aarch32. This patch also contains a fix for a build failure in the sun50i_a64 platform. Specifically, these misra fixes removed a single and instruction, 92407e73 and x19, x19, #0xffffffff from the cm_setup_context function caused a relocation in psci_cpus_on_start to require a linker-generated stub. This increased the size of the .text section and caused an alignment later on to go over a page boundary and round up to the end of RAM before placing the .data section. This sectionn is of non-zero size and therefore causes a link error. The fix included in this reorders the functions during link time without changing their ording with respect to alignment. Change-Id: I76b4b662c3d262296728a8b9aab7a33b02087f16 Signed-off-by: Jimmy Brisson <jimmy.brisson@arm.com>
2020-08-04 22:18:52 +01:00
and x2, x30, #~(PAGE_SIZE_MASK)
sub x0, x2, x6 /* Diff(S) = Current Address - Compiled Address */
adrp x1, __GOT_START__
add x1, x1, :lo12:__GOT_START__
adrp x2, __GOT_END__
add x2, x2, :lo12:__GOT_END__
/*
* GOT is an array of 64_bit addresses which must be fixed up as
* new_addr = old_addr + Diff(S).
* The new_addr is the address currently the binary is executing from
* and old_addr is the address at compile time.
*/
1:
ldr x3, [x1]
/* Skip adding offset if address is < lower limit */
cmp x3, x6
b.lo 2f
/* Skip adding offset if address is >= upper limit */
cmp x3, x7
b.ge 2f
add x3, x3, x0
str x3, [x1]
2:
add x1, x1, #8
cmp x1, x2
b.lo 1b
/* Starting dynamic relocations. Use adrp/adr to get RELA_START and END */
adrp x1, __RELA_START__
add x1, x1, :lo12:__RELA_START__
adrp x2, __RELA_END__
add x2, x2, :lo12:__RELA_END__
/*
* According to ELF-64 specification, the RELA data structure is as
* follows:
* typedef struct
* {
* Elf64_Addr r_offset;
* Elf64_Xword r_info;
* Elf64_Sxword r_addend;
* } Elf64_Rela;
*
* r_offset is address of reference
* r_info is symbol index and type of relocation (in this case
* 0x403 which corresponds to R_AARCH64_RELATIVE).
* r_addend is constant part of expression.
*
* Size of Elf64_Rela structure is 24 bytes.
*/
1:
/* Assert that the relocation type is R_AARCH64_RELATIVE */
#if ENABLE_ASSERTIONS
ldr x3, [x1, #8]
cmp x3, #0x403
ASM_ASSERT(eq)
#endif
ldr x3, [x1] /* r_offset */
add x3, x0, x3
ldr x4, [x1, #16] /* r_addend */
/* Skip adding offset if r_addend is < lower limit */
cmp x4, x6
b.lo 2f
/* Skip adding offset if r_addend entry is >= upper limit */
cmp x4, x7
b.ge 2f
add x4, x0, x4 /* Diff(S) + r_addend */
str x4, [x3]
2: add x1, x1, #24
cmp x1, x2
b.lo 1b
ret
endfunc fixup_gdt_reloc