arm-trusted-firmware/bl31/bl31.ld.S
Ye Li 86acbbe2d8 build(bl31): support separated memory for RW DATA
Update linker file and init codes to allow using separated
memory region for RW DATA. Init codes will copy the RW DATA
from the image to the linked address.

On some NXP platforms, after the BL31 image has been verified,
the bl31 image space will be locked/protected as RO only, so
need to move the RW DATA and NOBITS out of the bl31 image.

Signed-off-by: Ye Li <ye.li@nxp.com>
Reviewed-by: Peng Fan <peng.fan@nxp.com>
Signed-off-by: Jacky Bai <ping.bai@nxp.com>
Change-Id: I361d9a715890961bf30790a3325f8085a40c0c39
2024-11-05 17:24:41 +08:00

256 lines
6.7 KiB
ArmAsm

/*
* Copyright (c) 2013-2023, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/bl_common.ld.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(bl31_entrypoint)
MEMORY {
RAM (rwx): ORIGIN = BL31_BASE, LENGTH = BL31_LIMIT - BL31_BASE
#if SEPARATE_NOBITS_REGION
NOBITS (rw!a): ORIGIN = BL31_NOBITS_BASE, LENGTH = BL31_NOBITS_LIMIT - BL31_NOBITS_BASE
#else /* SEPARATE_NOBITS_REGION */
# define NOBITS RAM
#endif /* SEPARATE_NOBITS_REGION */
#if SEPARATE_RWDATA_REGION
RAM_RW (rw): ORIGIN = BL31_RWDATA_BASE, LENGTH = BL31_RWDATA_LIMIT - BL31_RWDATA_BASE
#else /* SEPARATE_RWDATA_REGION */
#define RAM_RW RAM
#endif /* SEPARATE_RWDATA_REGION */
}
#ifdef PLAT_EXTRA_LD_SCRIPT
# include <plat.ld.S>
#endif /* PLAT_EXTRA_LD_SCRIPT */
SECTIONS {
RAM_REGION_START = ORIGIN(RAM);
RAM_REGION_LENGTH = LENGTH(RAM);
. = BL31_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"BL31_BASE address is not aligned on a page boundary.")
__BL31_START__ = .;
#if SEPARATE_CODE_AND_RODATA
.text . : {
ASSERT(. == ALIGN(PAGE_SIZE),
".text is not aligned on a page boundary.");
__TEXT_START__ = .;
*bl31_entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(SORT(.text*)))
*(.vectors)
__TEXT_END_UNALIGNED__ = .;
. = ALIGN(PAGE_SIZE);
__TEXT_END__ = .;
} >RAM
.rodata . : {
__RODATA_START__ = .;
*(SORT_BY_ALIGNMENT(.rodata*))
# if PLAT_EXTRA_RODATA_INCLUDES
# include <plat.ld.rodata.inc>
# endif /* PLAT_EXTRA_RODATA_INCLUDES */
RODATA_COMMON
. = ALIGN(8);
# include <lib/el3_runtime/pubsub_events.h>
__RODATA_END_UNALIGNED__ = .;
. = ALIGN(PAGE_SIZE);
__RODATA_END__ = .;
} >RAM
#else /* SEPARATE_CODE_AND_RODATA */
.ro . : {
ASSERT(. == ALIGN(PAGE_SIZE),
".ro is not aligned on a page boundary.");
__RO_START__ = .;
*bl31_entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(.text*))
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
. = ALIGN(8);
# include <lib/el3_runtime/pubsub_events.h>
*(.vectors)
__RO_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked as read-only,
* executable. No RW data from the next section must creep in. Ensure
* that the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__RO_END__ = .;
} >RAM
#endif /* SEPARATE_CODE_AND_RODATA */
ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
"cpu_ops not defined for this platform.")
#if SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP)
# ifndef SPM_SHIM_EXCEPTIONS_VMA
# define SPM_SHIM_EXCEPTIONS_VMA RAM
# endif /* SPM_SHIM_EXCEPTIONS_VMA */
/*
* Exception vectors of the SPM shim layer. They must be aligned to a 2K
* address but we need to place them in a separate page so that we can set
* individual permissions on them, so the actual alignment needed is the
* page size.
*
* There's no need to include this into the RO section of BL31 because it
* doesn't need to be accessed by BL31.
*/
.spm_shim_exceptions : ALIGN(PAGE_SIZE) {
__SPM_SHIM_EXCEPTIONS_START__ = .;
*(.spm_shim_exceptions)
. = ALIGN(PAGE_SIZE);
__SPM_SHIM_EXCEPTIONS_END__ = .;
} >SPM_SHIM_EXCEPTIONS_VMA AT>RAM
PROVIDE(__SPM_SHIM_EXCEPTIONS_LMA__ = LOADADDR(.spm_shim_exceptions));
. = LOADADDR(.spm_shim_exceptions) + SIZEOF(.spm_shim_exceptions);
#endif /* SPM_MM || (SPMC_AT_EL3 && SPMC_AT_EL3_SEL0_SP) */
#if SEPARATE_RWDATA_REGION
. = BL31_RWDATA_BASE;
ASSERT(BL31_RWDATA_BASE == ALIGN(PAGE_SIZE),
"BL31_RWDATA_BASE address is not aligned on a page boundary.")
/*
* Define a linker symbol to mark the start of the RW memory area for this
* image.
*/
__RW_START__ = . ;
DATA_SECTION >RAM_RW AT>RAM
__DATA_RAM_START__ = __DATA_START__;
__DATA_RAM_END__ = __DATA_END__;
__DATA_ROM_START__ = LOADADDR(.data);
. = ALIGN(PAGE_SIZE);
__RW_END__ = .;
RELA_SECTION >RAM
#else /* SEPARATE_RWDATA_REGION */
/*
* Define a linker symbol to mark the start of the RW memory area for this
* image.
*/
__RW_START__ = . ;
DATA_SECTION >RAM
RELA_SECTION >RAM
#endif /* SEPARATE_RWDATA_REGION */
#ifdef BL31_PROGBITS_LIMIT
ASSERT(
. <= BL31_PROGBITS_LIMIT,
"BL31 progbits has exceeded its limit. Consider disabling some features."
)
#endif /* BL31_PROGBITS_LIMIT */
#if SEPARATE_NOBITS_REGION
. = ALIGN(PAGE_SIZE);
#if !SEPARATE_RWDATA_REGION
__RW_END__ = .;
#endif /* SEPARATE_RWDATA_REGION */
__BL31_END__ = .;
ASSERT(. <= BL31_LIMIT, "BL31 image has exceeded its limit.")
. = BL31_NOBITS_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"BL31 NOBITS base address is not aligned on a page boundary.")
__NOBITS_START__ = .;
#endif /* SEPARATE_NOBITS_REGION */
STACK_SECTION >NOBITS
BSS_SECTION >NOBITS
XLAT_TABLE_SECTION >NOBITS
#if USE_COHERENT_MEM
/*
* The base address of the coherent memory section must be page-aligned to
* guarantee that the coherent data are stored on their own pages and are
* not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
.coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
/*
* Bakery locks are stored in coherent memory. Each lock's data is
* contiguous and fully allocated by the compiler.
*/
*(.bakery_lock)
*(.tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked as device
* memory. No other unexpected data must creep in. Ensure the rest of
* the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >NOBITS
#endif /* USE_COHERENT_MEM */
#if SEPARATE_NOBITS_REGION
__NOBITS_END__ = .;
ASSERT(. <= BL31_NOBITS_LIMIT, "BL31 NOBITS region has exceeded its limit.")
#else /* SEPARATE_NOBITS_REGION */
/*
* Define a linker symbol to mark the end of the RW memory area for this
* image.
*/
#if !SEPARATE_RWDATA_REGION
__RW_END__ = .;
#endif /* SEPARATE_RWDATA_REGION */
__BL31_END__ = .;
ASSERT(. <= BL31_LIMIT, "BL31 image has exceeded its limit.")
#endif /* SEPARATE_NOBITS_REGION */
RAM_REGION_END = .;
/DISCARD/ : {
*(.dynsym .dynstr .hash .gnu.hash)
}
}