TF-M Secure 启动文件

Secure 启动文件

platform/ext/target/arm/mps2/an521/cmsis_core/startup_an521.c 是 tfm_s 启动文件。可以看到 bl2 和 tfm_s 是同一个启动文件。虽然源码相同,但是 bl2 和 tfm_s 链接的时候,会根据不同的配置,生成不同的 elf 文件。

platform/ext/target/arm/mps2/an521/cmsis_core/startup_an521.c 中启动文件如下

c 复制代码
extern const VECTOR_TABLE_Type __VECTOR_TABLE[];
       const VECTOR_TABLE_Type __VECTOR_TABLE[] __VECTOR_TABLE_ATTRIBUTE = {
  (VECTOR_TABLE_Type)(&__INITIAL_SP),            /*      Initial Stack Pointer */
  Reset_Handler,                     /*      Reset Handler */
  NMI_Handler,                       /* -14: NMI Handler */
  HardFault_Handler,                 /* -13: Hard Fault Handler */
  MemManage_Handler,                 /* -12: MPU Fault Handler */
  BusFault_Handler,                  /* -11: Bus Fault Handler */
  UsageFault_Handler,                /* -10: Usage Fault Handler */
  SecureFault_Handler,               /*  -9: Secure Fault Handler */
  0,                                 /*  -8: Reserved */
  0,                                 /*  -7: Reserved */
  0,                                 /*  -6: Reserved */
  SVC_Handler,                       /*  -5: SVCall Handler */
  DebugMon_Handler,                  /*  -4: Debug Monitor Handler */
  0,                                 /*  -3: Reserved */
  PendSV_Handler,                    /*  -2: PendSV Handler */
  SysTick_Handler,                   /*  -1: SysTick Handler */

  NONSEC_WATCHDOG_RESET_Handler,     /*   0: Non-Secure Watchdog Reset Request Handler */
  NONSEC_WATCHDOG_Handler,           /*   1: Non-Secure Watchdog Interrupt Handler */
  S32K_TIMER_Handler,                /*   2: S32K Timer Handler */
  TFM_TIMER0_IRQ_Handler,            /*   3: TIMER 0 Handler */
  TIMER1_Handler,                    /*   4: TIMER 1 Handler */
  DUALTIMER_Handler,                 /*   5: Dual Timer Handler */
  MHU0_Handler,                      /*   6: Message Handling Unit 0 */
  MHU1_Handler,                      /*   7: Message Handling Unit 1 */
  0,                                 /*   8: Reserved */
  MPC_Handler,                       /*   9: MPC Combined (Secure) Handler */
  PPC_Handler,                       /*  10: PPC Combined (Secure) Handler */
  MSC_Handler,                       /*  11: MSC Combined (Secure) Handler */
  BRIDGE_ERROR_Handler,              /*  12: Bridge Error (Secure) Handler */
  INVALID_INSTR_CACHE_Handler,       /*  13: CPU Instruction Cache Invalidation Handler */
  0,                                 /*  14: Reserved */
  SYS_PPU_Handler,                   /*  15: SYS PPU Handler */
  CPU0_PPU_Handler,                  /*  16: CPU0 PPU Handler */
  CPU1_PPU_Handler,                  /*  17: CPU1 PPU Handler */
  CPU0_DBG_PPU_Handler,              /*  18: CPU0 DBG PPU_Handler */
  CPU1_DBG_PPU_Handler,              /*  19: CPU1 DBG PPU_Handler */
  CRYPT_PPU_Handler,                 /*  20: CRYPT PPU Handler */
  0,                                 /*  21: Reserved */
  RAM0_PPU_Handler,                  /*  22: RAM0 PPU Handler */
  RAM1_PPU_Handler,                  /*  23: RAM1 PPU Handler */
  RAM2_PPU_Handler,                  /*  24: RAM2 PPU Handler */
  RAM3_PPU_Handler,                  /*  25: RAM3 PPU Handler */
  DBG_PPU_Handler,                   /*  26: DBG PPU Handler */
  0,                                 /*  27: Reserved */
  CPU0_CTI_Handler,                  /*  28: CPU0 CTI Handler */
  CPU1_CTI_Handler,                  /*  29: CPU1 CTI Handler */
  0,                                 /*  30: Reserved */
  0,                                 /*  31: Reserved */

  /* External interrupts */
  UARTRX0_Handler,                   /*  32: UART 0 RX Handler */
  UARTTX0_Handler,                   /*  33: UART 0 TX Handler */
  UARTRX1_Handler,                   /*  34: UART 1 RX Handler */
  UARTTX1_Handler,                   /*  35: UART 1 TX Handler */
  UARTRX2_Handler,                   /*  36: UART 2 RX Handler */
  UARTTX2_Handler,                   /*  37: UART 2 TX Handler */
  UARTRX3_Handler,                   /*  38: UART 3 RX Handler */
  UARTTX3_Handler,                   /*  39: UART 3 TX Handler */
  UARTRX4_Handler,                   /*  40: UART 4 RX Handler */
  UARTTX4_Handler,                   /*  41: UART 4 TX Handler */
  UART0_Combined_Handler,            /*  42: UART 0 Combined Handler */
  UART1_Combined_Handler,            /*  43: UART 1 Combined Handler */
  UART2_Combined_Handler,            /*  44: UART 2 Combined Handler */
  UART3_Combined_Handler,            /*  45: UART 3 Combined Handler */
  UART4_Combined_Handler,            /*  46: UART 4 Combined Handler */
  UARTOVF_Handler,                   /*  47: UART 0, 1, 2, 3, 4 & 5 Overflow Handler */
  ETHERNET_Handler,                  /*  48: Ethernet Handler */
  I2S_Handler,                       /*  49: Audio I2S Handler */
  TOUCH_SCREEN_Handler,              /*  50: Touch Screen Handler */
  SPI0_Handler,                      /*  51: SPI 0 Handler */
  SPI1_Handler,                      /*  52: SPI 1 Handler */
  SPI2_Handler,                      /*  53: SPI 2 Handler */
  SPI3_Handler,                      /*  54: SPI 3 Handler */
  SPI4_Handler,                      /*  55: SPI 4 Handler */
  DMA0_ERROR_Handler,                /*  56: DMA 0 Error Handler */
  DMA0_TC_Handler,                   /*  57: DMA 0 Terminal Count Handler */
  DMA0_Handler,                      /*  58: DMA 0 Combined Handler */
  DMA1_ERROR_Handler,                /*  59: DMA 1 Error Handler */
  DMA1_TC_Handler,                   /*  60: DMA 1 Terminal Count Handler */
  DMA1_Handler,                      /*  61: DMA 1 Combined Handler */
  DMA2_ERROR_Handler,                /*  62: DMA 2 Error Handler */
  DMA2_TC_Handler,                   /*  63: DMA 2 Terminal Count Handler */
  DMA2_Handler,                      /*  64: DMA 2 Combined Handler */
  DMA3_ERROR_Handler,                /*  65: DMA 3 Error Handler */
  DMA3_TC_Handler,                   /*  66: DMA 3 Terminal Count Handler */
  DMA3_Handler,                      /*  67: DMA 3 Combined Handler */
  GPIO0_Combined_Handler,            /*  68: GPIO 0 Combined Handler */
  GPIO1_Combined_Handler,            /*  69: GPIO 1 Combined Handler */
  GPIO2_Combined_Handler,            /*  70: GPIO 2 Combined Handler */
  GPIO3_Combined_Handler,            /*  71: GPIO 3 Combined Handler */
  GPIO0_0_Handler,                   /*  72: GPIO0 Pin 0 Handler */
  GPIO0_1_Handler,                   /*  73: GPIO0 Pin 1 Handler */
  GPIO0_2_Handler,                   /*  74: GPIO0 Pin 2 Handler */
  GPIO0_3_Handler,                   /*  75: GPIO0 Pin 3 Handler */
  GPIO0_4_Handler,                   /*  76: GPIO0 Pin 4 Handler */
  GPIO0_5_Handler,                   /*  77: GPIO0 Pin 5 Handler */
  GPIO0_6_Handler,                   /*  78: GPIO0 Pin 6 Handler */
  GPIO0_7_Handler,                   /*  79: GPIO0 Pin 7 Handler */
  GPIO0_8_Handler,                   /*  80: GPIO0 Pin 8 Handler */
  GPIO0_9_Handler,                   /*  81: GPIO0 Pin 9 Handler */
  GPIO0_10_Handler,                  /*  82: GPIO0 Pin 10 Handler */
  GPIO0_11_Handler,                  /*  83: GPIO0 Pin 11 Handler */
  GPIO0_12_Handler,                  /*  84: GPIO0 Pin 12 Handler */
  GPIO0_13_Handler,                  /*  85: GPIO0 Pin 13 Handler */
  GPIO0_14_Handler,                  /*  86: GPIO0 Pin 14 Handler */
  GPIO0_15_Handler,                  /*  87: GPIO0 Pin 15 Handler */
  GPIO1_0_Handler,                   /*  88: GPIO1 Pin 0 Handler */
  GPIO1_1_Handler,                   /*  89: GPIO1 Pin 1 Handler */
  GPIO1_2_Handler,                   /*  90: GPIO1 Pin 2 Handler */
  GPIO1_3_Handler,                   /*  91: GPIO1 Pin 3 Handler */
  GPIO1_4_Handler,                   /*  92: GPIO1 Pin 4 Handler */
  GPIO1_5_Handler,                   /*  93: GPIO1 Pin 5 Handler */
  GPIO1_6_Handler,                   /*  94: GPIO1 Pin 6 Handler */
  GPIO1_7_Handler,                   /*  95: GPIO1 Pin 7 Handler */
};

build_an521_ninja/lib/ext/cmsis-src/CMSIS/Core/Include/m-profile/cmsis_gcc_m.h .vectors 段定义如下

c 复制代码
#ifndef __VECTOR_TABLE_ATTRIBUTE
#define __VECTOR_TABLE_ATTRIBUTE  __attribute__((used, section(".vectors")))
#endif

VECTOR_TABLE_Type 定义在 platform/ext/target/arm/mps2/an521/cmsis_core/system_core_init.h 中:

c 复制代码
typedef void(*VECTOR_TABLE_Type)(void);

所以

c 复制代码
extern const VECTOR_TABLE_Type __VECTOR_TABLE[];
       const VECTOR_TABLE_Type __VECTOR_TABLE[] __VECTOR_TABLE_ATTRIBUTE = {
  (VECTOR_TABLE_Type)(&__INITIAL_SP),            /*      Initial Stack Pointer */
  Reset_Handler,                                 /*      Reset Handler */
  • __VECTOR_TABLE 数组定义在 .vectors 段,数组元素类型是 VECTOR_TABLE_Type,数组放在 .vectors 段中。
  • 数组的第一个元素是初始栈指针
  • 数组的第二个元素是 Reset_Handler
  • 数组的第三个元素是 NMI_Handler
  • 以此类推,数组存放的元素是中断向量表。

硬件复位之后,第一个元素会被写入 MSP,这部分由硬件完成,然后开始执行 Reset_Handler。

设置 MSP,PSP

c 复制代码
    .msp_stack ALIGN(TFM_LINKER_MSP_STACK_ALIGNMENT) (NOLOAD) :
    {
        . += __msp_stack_size__ - STACKSEAL_SIZE;
    } > RAM
    Image$$ARM_LIB_STACK$$ZI$$Base = ADDR(.msp_stack);
    Image$$ARM_LIB_STACK$$ZI$$Limit = ADDR(.msp_stack) + SIZEOF(.msp_stack);
    PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit);
c 复制代码
#define __INITIAL_SP    Image$$ARM_LIB_STACK$$ZI$$Limit
#define __STACK_LIMIT   Image$$ARM_LIB_STACK$$ZI$$Base
  • 定义一个 msp_stack 段

  • Image$$ARM_LIB_STACK$$ZI$$Base 起始地址

  • Image$$ARM_LIB_STACK$$ZI$$Limit 结束地址

  • __INITIAL_SP 指向栈顶。Cortex-M33 使用满递减栈,硬件将这个值写入 MSP。

  • __STACK_LIMIT 指向栈底,用于设置 MSPLIM 和 PSPLIM。

GCC 构建通过 platform/include/cmsis_override.h 将 CMSIS 默认的 __INITIAL_SP 和 __STACK_LIMIT 重定义为上面的链接脚本符号。

platform/ext/target/arm/mps2/an521/cmsis_core/startup_an521.c 中,软件设置 PSP 和两个栈限制寄存器:

c 复制代码
    __set_PSP((uint32_t)(&__INITIAL_SP));

    __set_MSPLIM((uint32_t)(&__STACK_LIMIT));
    __set_PSPLIM((uint32_t)(&__STACK_LIMIT));

Reset_Handler

Reset_Handler 向量前面的第一个 word 是初始 SP,硬件会自动将它写入 MSP。当前 TrustZone 构建下,Reset_Handler 的软件部分如下:

c 复制代码
void Reset_Handler(void)
{
    __disable_irq();
    __set_PSP((uint32_t)(&__INITIAL_SP));

    __set_MSPLIM((uint32_t)(&__STACK_LIMIT));
    __set_PSPLIM((uint32_t)(&__STACK_LIMIT));

    __TZ_set_STACKSEAL_S((uint32_t *)(&__STACK_SEAL));

    SystemInit();                             /* CMSIS System Initialization */
    __PROGRAM_START();                        /* Enter PreMain (C library entry point) */
}

platform/ext/target/arm/mps2/an521/cmsis_core/system_core_init.c 中 SystemInit 简化后的函数如下

c 复制代码
void SystemInit(void)
{
    SCB->VTOR = (uint32_t) &(__VECTOR_TABLE[0]);

    SystemCoreClock = SYSTEM_CLOCK;
    PeripheralClock = PERIPHERAL_CLOCK;
}

在 GCC 构建中,__PROGRAM_START 在 build_an521_ninja/lib/ext/cmsis-src/CMSIS/Core/Include/m-profile/cmsis_gcc_m.h 中展开为 __cmsis_start。

c 复制代码
__STATIC_FORCEINLINE __NO_RETURN void __cmsis_start(void)
{
  extern void _start(void) __NO_RETURN;

  typedef struct __copy_table {
    uint32_t const* src;
    uint32_t* dest;
    uint32_t  wlen;
  } __copy_table_t;

  typedef struct __zero_table {
    uint32_t* dest;
    uint32_t  wlen;
  } __zero_table_t;

  extern const __copy_table_t __copy_table_start__;
  extern const __copy_table_t __copy_table_end__;
  extern const __zero_table_t __zero_table_start__;
  extern const __zero_table_t __zero_table_end__;

  for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) {
    for(uint32_t i=0u; i<pTable->wlen; ++i) {
      pTable->dest[i] = pTable->src[i];
    }
  }

  for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) {
    for(uint32_t i=0u; i<pTable->wlen; ++i) {
      pTable->dest[i] = 0u;
    }
  }

  _start();
}

#define __PROGRAM_START           __cmsis_start

__cmsis_start 根据链接脚本生成的 copy table 和 zero table,完成 .data 初始化和 .bss 清零,然后调用 _start。

因此,.data 的初始值从 Flash 复制到 RAM,.bss 在 RAM 中清零。

_start 函数实现在 secure_fw/partitions/lib/runtime/crt_start.c。

当前 GCC 构建不定义 __clang_major__,因此执行该文件中的 #else 分支。_start 通过符号调用 main,调用结束后停在死循环中。

c 复制代码
#else /* defined(__clang_major__) */
void _start(void)
{
    main(0, NULL);
    while (1)
        ;
}
#endif /* defined(__clang_major__) */

crt_start.c 中的声明是 main(int argc, char **argv),而 secure_fw/spm/core/main.c 中的定义是 main(void)。它们位于不同的编译单元,链接器只按符号名解析;TF-M 的 main 不读取参数,因此这里不会产生链接错误。

main 函数

secure_fw/spm/core/main.c 是 main 函数的实现文件。

c 复制代码
int main(void)
{
#ifdef CONFIG_TFM_ENABLE_PROFILING
    PROFILING_INIT();
#endif

    FIH_DECLARE(fih_rc, FIH_FAILURE);

    TFM_COVERITY_DEVIATE_LINE(MISRA_C_2023_Rule_2_2, "Parameters can be changed by user and this code will make effect")
    tfm_arch_config_branch_protection();

    /* set Main Stack Pointer limit */
    tfm_arch_set_msplim(SPM_BOOT_STACK_TOP);

    fih_delay_init();

    FIH_CALL(tfm_core_init, fih_rc);
    if (FIH_NOT_EQ(fih_rc, SPM_SUCCESS)) {
        tfm_core_panic();
    }

    /* All isolation should have been set up at this point */
    FIH_LABEL_CRITICAL_POINT();

    /*
     * Prioritise secure exceptions to avoid NS being able to preempt
     * secure SVC or SecureFault. Do it before PSA API initialization.
     */
    tfm_arch_set_secure_exception_priorities();

#ifdef TFM_FIH_PROFILE_ON
    /* Check secure exception priority */
    FIH_CALL(tfm_arch_verify_secure_exception_priorities, fih_rc);
    if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
         tfm_core_panic();
    }
#endif

    /* Further SPM initialization. */
    BACKEND_SPM_INIT();

    return 0;
}

main() 完成 SPM、隔离边界、OTP/provisioning 和异常优先级等初始化后返回,_start 随后进入死循环。

附录

链接脚本全文

链接脚本模板是 platform/ext/common/gcc/tfm_isolation_s.ld.template,CMake 配置后生成的文件是 build_an521_ninja/generated/platform/ext/common/gcc/tfm_isolation_s.ld。当前 tfm_s.axf 的链接命令使用生成后的 tfm_isolation_s.ld。

c 复制代码
;/*
; * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
; * Copyright (c) 2022-2024 Cypress Semiconductor Corporation (an Infineon company)
; * or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
; *
; * Licensed under the Apache License, Version 2.0 (the "License");
; * you may not use this file except in compliance with the License.
; * You may obtain a copy of the License at
; *
; *     http://www.apache.org/licenses/LICENSE-2.0
; *
; * Unless required by applicable law or agreed to in writing, software
; * distributed under the License is distributed on an "AS IS" BASIS,
; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; * See the License for the specific language governing permissions and
; * limitations under the License.
; *
; *
; * This file is derivative of CMSIS V5.00 gcc_arm.ld
; */

/***********  WARNING: This is an auto-generated file. Do not edit!  ***********/

/* Linker script to configure memory regions. */
/* This file will be run through the pre-processor. */

#include "region_defs.h"

/* Include file with definitions for section alignments.
 * Note: it should be included after region_defs.h to let platform define
 * default values if needed. */
#include "tfm_s_linker_alignments.h"

#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) || \
    defined(__ARM_ARCH_8_1M_MAIN__)
#define STACKSEAL_SIZE  0x8
#else
#define STACKSEAL_SIZE  0x0
#endif

/*
 * Program Header (PHDRS) definitions
 *
 * These define how different segments of the final image are mapped into
 * program headers for the ELF output. Each PHDR entry corresponds to a loadable
 * memory segment with specific access permissions (Read, Write, Execute), which is
 * defined by FLAGS(n):
 * - 0x1 - Executable
 * - 0x2 - Writable
 * - 0x4 - Readable
 *
 * - flash:            Loadable segment for executable code and read-only data (FLAGS(5) → R X)
 * - tfm_data:         TFM read/write data, (FLAGS(6) → R W)
 * - phdr_<partition>: Dynamically generated loadable segments for each runtime partition
 *                     with read/write permissions (FLAGS(6) → R W)
 * - itcm:             ITCM segment for executable code (FLAGS(5) → R X)
 * - coderam:          Executable segment placed in SRAM (FLAGS(5) → R X)
 *
 */
PHDRS
{
  flash  PT_LOAD FLAGS(5); /* R X */
  tfm_data  PT_LOAD FLAGS(6); /* R W */
  phdr_TFM_SP_PS PT_LOAD FLAGS(6); /* R W */
  phdr_TFM_SP_ITS PT_LOAD FLAGS(6); /* R W */
  phdr_TFM_SP_CRYPTO PT_LOAD FLAGS(6); /* R W */
  phdr_TFM_SP_PLATFORM PT_LOAD FLAGS(6); /* R W */
#ifdef S_RUNTIME_ITCM_START
  itcm   PT_LOAD FLAGS(5); /* R X */
#endif
  coderam PT_LOAD FLAGS(5); /* R X */
}

MEMORY
{
  FLASH    (rx)  : ORIGIN = S_CODE_START, LENGTH = S_CODE_SIZE
  RAM      (rw)  : ORIGIN = S_DATA_START, LENGTH = S_DATA_SIZE
#ifdef S_RAM_CODE_START
  CODE_RAM (rwx) : ORIGIN = S_RAM_CODE_START, LENGTH = S_RAM_CODE_SIZE
#endif
#ifdef S_RUNTIME_ITCM_START
  ITCM     (rx)  : ORIGIN = S_RUNTIME_ITCM_START, LENGTH = S_RUNTIME_ITCM_SIZE
  #define ITCM_FILES *tfm_spm*
#else
  #define ITCM_FILES
#endif
#ifdef S_RUNTIME_DTCM_START
  DTCM     (rw)  : ORIGIN = S_RUNTIME_DTCM_START, LENGTH = S_RUNTIME_DTCM_SIZE
#endif
}

/* For Cortex-M0+ VTOR: 256-byte vector table is at the offset 0x00 of the image.
 * To keep that table in one block, the image base must be a multiple of 0x100.
 * For reference: https://developer.arm.com/documentation/ddi0419/latest/
 */
#if defined(__ARM_ARCH_6M__)
CHECK_ALIGNMENT_256(S_CODE_START)
#endif

#ifndef TFM_LINKER_VENEERS_START
#define TFM_LINKER_VENEERS_START ALIGN(TFM_LINKER_VENEERS_ALIGNMENT)
#endif

#ifndef TFM_LINKER_VENEERS_END
#define TFM_LINKER_VENEERS_END ALIGN(TFM_LINKER_VENEERS_ALIGNMENT)
#endif

#define VENEERS() \
/* \
 * Place the CMSE Veneers (containing the SG instruction) after the code, in \
 * a separate at least 32 bytes aligned region so that the SAU can \
 * programmed to just set this region as Non-Secure Callable. \
 */ \
.gnu.sgstubs TFM_LINKER_VENEERS_START : \
{ \
    *(.gnu.sgstubs*) \
} > FLASH :flash \
/* GCC always places veneers at the end of .gnu.sgstubs section, so the only \
 * way to align the end of .gnu.sgstubs section is to align start of the \
 * next section */ \
.sgstubs_end : TFM_LINKER_VENEERS_END \
{ \
} > FLASH :flash

__msp_stack_size__ = S_MSP_STACK_SIZE;

ENTRY(Reset_Handler)

SECTIONS
{
    /* Position tag: Start of code + RO-data */
    Image$$PT_RO_START$$Base = ADDR(.TFM_VECTORS);

    .TFM_VECTORS : ALIGN(TFM_LINKER_TFM_VECTORS_ALIGNMENT)
    {
        __vectors_start__ = .;
        KEEP(*(.vectors))
        __vectors_end__ = .;
    } > FLASH :flash

    ASSERT(__vectors_start__ != __vectors_end__, ".vectors should not be empty")

#ifdef S_CODE_VECTOR_TABLE_SIZE
    ASSERT(. <= ADDR(.TFM_VECTORS) + S_CODE_VECTOR_TABLE_SIZE, ".TFM_VECTORS section size overflow.")
    . = ADDR(.TFM_VECTORS) + S_CODE_VECTOR_TABLE_SIZE;
#endif

    /* Position tag: Start of unprivileged code (shared, not PXN) */
    . = ALIGN(TFM_LINKER_PT_UNPRIV_CODE_ALIGNMENT);
    Image$$PT_UNPRIV_CODE_START$$Base = .;

#if defined(CONFIG_TFM_USE_TRUSTZONE) && !defined(TFM_LINKER_VENEERS_LOCATION_END)
    VENEERS()
#endif

    .ER_UNPRIV_CODE . :
    {
        /* Shared library code */
        *libgcc*:(SORT_BY_ALIGNMENT(.text*))
        *libc_nano*:(SORT_BY_ALIGNMENT(.text*))
        *libg_nano*:(SORT_BY_ALIGNMENT(.text*))
        *libtfm_sprt*:(SORT_BY_ALIGNMENT(.text*))
        *libqcbor*:(SORT_BY_ALIGNMENT(.text*))
        *libtfm_t_cose_s*:(SORT_BY_ALIGNMENT(.text*))

        KEEP(*(.init))
        KEEP(*(.fini))

        /* .ctors */
        *crtbegin.o(.ctors)
        *crtbegin?.o(.ctors)
        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
        *(SORT(.ctors.*))
        *(.ctors)

        /* .dtors */
        *crtbegin.o(.dtors)
        *crtbegin?.o(.dtors)
        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
        *(SORT(.dtors.*))
        *(.dtors)

        KEEP(*(.eh_frame*))
    } > FLASH :flash

    /* Position tag: End of unprivileged code (shared, not PXN) */
    . = ALIGN(TFM_LINKER_PT_UNPRIV_CODE_ALIGNMENT);
    Image$$PT_UNPRIV_CODE_END$$Base = .;

    /* Position tag: Start of Application RoT code (unprivileged, PXN) */
    . = ALIGN(TFM_LINKER_PT_APP_ROT_CODE_ALIGNMENT);
    Image$$PT_APP_ROT_CODE_START$$Base = .;

    .ER_APP_ROT_CODE . :
    {
        *tfm_app_rot_partition*:(SORT_BY_ALIGNMENT(.text*))
        *(TFM_*_APP-ROT_ATTR_FN)
        *tfm_*partition_ps.*:(SORT_BY_ALIGNMENT(.text*))
        *(TFM_SP_PS_APP-ROT_ATTR_FN)
    } > FLASH :flash

    /* Position tag: End of Application RoT code (unprivileged, PXN) */
    . = ALIGN(TFM_LINKER_PT_APP_ROT_CODE_ALIGNMENT);
    Image$$PT_APP_ROT_CODE_END$$Base = .;

    /* Position tag: Start of PSA RoT code (privileged) */
    . = ALIGN(TFM_LINKER_PT_PSA_ROT_CODE_ALIGNMENT);
    Image$$PT_PSA_ROT_CODE_START$$Base = .;

    .ER_PSA_ROT_CODE . :
    {
        *tfm_psa_rot_partition*:(SORT_BY_ALIGNMENT(.text*))
        *(TFM_*_PSA-ROT_ATTR_FN)
        *tfm_*partition_its.*:(SORT_BY_ALIGNMENT(.text*))
        *(TFM_SP_ITS_PSA-ROT_ATTR_FN)
        *tfm_*partition_crypto.*:(SORT_BY_ALIGNMENT(.text*))
        *tfpsacrypto.*:(SORT_BY_ALIGNMENT(.text*))
        *tfpsacrypto*acceleration.*:(SORT_BY_ALIGNMENT(.text*))
        *(TFM_SP_CRYPTO_PSA-ROT_ATTR_FN)
        *tfm_*partition_platform.*:(SORT_BY_ALIGNMENT(.text*))
        *(TFM_SP_PLATFORM_PSA-ROT_ATTR_FN)
    } > FLASH :flash

    .ARM.extab :
    {
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > FLASH :flash

    __exidx_start = .;
    .ARM.exidx :
    {
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    } > FLASH :flash
    __exidx_end = .;

    .ER_TFM_CODE ALIGN(4) (READONLY) :
    {
        . = ALIGN(4);
        /* preinit data */
        PROVIDE_HIDDEN (__preinit_array_start = .);
        KEEP(*(.preinit_array))
        PROVIDE_HIDDEN (__preinit_array_end = .);

        . = ALIGN(4);
        /* init data */
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP(*(SORT(.init_array.*)))
        KEEP(*(.init_array))
        PROVIDE_HIDDEN (__init_array_end = .);

        . = ALIGN(4);
        /* finit data */
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP(*(SORT(.fini_array.*)))
        KEEP(*(.fini_array))
        PROVIDE_HIDDEN (__fini_array_end = .);

        /* .copy.table */
        . = ALIGN(4);
        __copy_table_start__ = .;
#ifdef RAM_VECTORS_SUPPORT
        /* Copy interrupt vectors from flash to RAM */
        LONG (__vectors_start__)                            /* From */
        LONG (__ram_vectors_start__)                        /* To   */
        LONG ((__vectors_end__ - __vectors_start__) / 4)    /* Size, aligment checked after the section */
#endif
        LONG (LOADADDR(.TFM_DATA))
        LONG (ADDR(.TFM_DATA))
        LONG (SIZEOF(.TFM_DATA) / 4)    /* Aligment checked after the section */

        LONG (LOADADDR(.ER_TFM_SP_PS_DATA))
        LONG (ADDR(.ER_TFM_SP_PS_DATA))
        LONG (SIZEOF(.ER_TFM_SP_PS_DATA) / 4)    /* Aligment checked after the section */
        LONG (LOADADDR(.ER_TFM_SP_ITS_DATA))
        LONG (ADDR(.ER_TFM_SP_ITS_DATA))
        LONG (SIZEOF(.ER_TFM_SP_ITS_DATA) / 4)    /* Aligment checked after the section */
        LONG (LOADADDR(.ER_TFM_SP_CRYPTO_DATA))
        LONG (ADDR(.ER_TFM_SP_CRYPTO_DATA))
        LONG (SIZEOF(.ER_TFM_SP_CRYPTO_DATA) / 4)    /* Aligment checked after the section */
        LONG (LOADADDR(.ER_TFM_SP_PLATFORM_DATA))
        LONG (ADDR(.ER_TFM_SP_PLATFORM_DATA))
        LONG (SIZEOF(.ER_TFM_SP_PLATFORM_DATA) / 4)    /* Aligment checked after the section */

#ifdef S_RUNTIME_ITCM_START
        LONG (LOADADDR(.ER_ITCM_CODE))
        LONG (ADDR(.ER_ITCM_CODE))
        LONG (SIZEOF(.ER_ITCM_CODE) / 4)
#endif

#ifdef S_RAM_CODE_START
        LONG (LOADADDR(.ER_CODE_SRAM))
        LONG (ADDR(.ER_CODE_SRAM))
        LONG (SIZEOF(.ER_CODE_SRAM) / 4)    /* Aligment checked after the section */
#endif
        __copy_table_end__ = .;

        /* .zero.table */
        . = ALIGN(4);
        __zero_table_start__ = .;
        LONG (ADDR(.TFM_BSS))
        LONG (SIZEOF(.TFM_BSS) / 4)
        /* Aligment checked after the section */
        LONG (ADDR(.ER_TFM_SP_PS_BSS))
        LONG (SIZEOF(.ER_TFM_SP_PS_BSS) / 4)    /* Aligment checked after the section */
        LONG (ADDR(.ER_TFM_SP_ITS_BSS))
        LONG (SIZEOF(.ER_TFM_SP_ITS_BSS) / 4)    /* Aligment checked after the section */
        LONG (ADDR(.ER_TFM_SP_CRYPTO_BSS))
        LONG (SIZEOF(.ER_TFM_SP_CRYPTO_BSS) / 4)    /* Aligment checked after the section */
        LONG (ADDR(.ER_TFM_SP_PLATFORM_BSS))
        LONG (SIZEOF(.ER_TFM_SP_PLATFORM_BSS) / 4)    /* Aligment checked after the section */

#ifdef CONFIG_TFM_PARTITION_META
        LONG (ADDR(.TFM_SP_META_PTR))
        LONG (SIZEOF(.TFM_SP_META_PTR) / 4)    /* Aligment checked after the section */
#endif
        __zero_table_end__ = .;

        /* Capture all remaining code (except RAM code) in the privileged TF-M
         * code region.
         */
        *(SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libflash_drivers* ITCM_FILES) .text*))
    } > FLASH :flash

#ifdef RAM_VECTORS_SUPPORT
    CHECK_ALIGNMENT_4(__vectors_end__ - __vectors_start__)
#endif
    CHECK_ALIGNMENT_4(SIZEOF(.TFM_DATA))
#ifdef S_RAM_CODE_START
    CHECK_ALIGNMENT_4(SIZEOF(.ER_CODE_SRAM))
#endif
#ifdef CONFIG_TFM_PARTITION_META
    CHECK_ALIGNMENT_4(SIZEOF(.TFM_SP_META_PTR))
#endif
    CHECK_ALIGNMENT_4(SIZEOF(.ER_TFM_SP_PS_DATA))
    CHECK_ALIGNMENT_4(SIZEOF(.ER_TFM_SP_PS_BSS))
    CHECK_ALIGNMENT_4(SIZEOF(.ER_TFM_SP_ITS_DATA))
    CHECK_ALIGNMENT_4(SIZEOF(.ER_TFM_SP_ITS_BSS))
    CHECK_ALIGNMENT_4(SIZEOF(.ER_TFM_SP_CRYPTO_DATA))
    CHECK_ALIGNMENT_4(SIZEOF(.ER_TFM_SP_CRYPTO_BSS))
    CHECK_ALIGNMENT_4(SIZEOF(.ER_TFM_SP_PLATFORM_DATA))
    CHECK_ALIGNMENT_4(SIZEOF(.ER_TFM_SP_PLATFORM_BSS))

    /* Position tag: End of PSA RoT code (privileged) */
    . = ALIGN(TFM_LINKER_PT_PSA_ROT_CODE_ALIGNMENT);
    Image$$PT_PSA_ROT_CODE_END$$Base = .;

    /* Position tag: Start of RO-data (unprivileged, execute-never) */
    . = ALIGN(TFM_LINKER_PT_RO_DATA_ALIGNMENT);
    Image$$PT_RO_DATA_START$$Base = .;

    /* Collect all RO-data into a single unprivileged region */
    .ER_RO_DATA . :
    {
        *(SORT_BY_ALIGNMENT(EXCLUDE_FILE(*libflash_drivers* ITCM_FILES) .rodata*))
    } > FLASH :flash

    /**** Section for holding partition RO load data */
    /*
     * Sort the partition info by priority to guarantee the initing order.
     * The first loaded partition will be inited at last in SFN model.
     */
    .TFM_SP_LOAD_LIST ALIGN(TFM_LINKER_PT_RO_DATA_ALIGNMENT) :
    {
        KEEP(*(.part_load))
    } > FLASH :flash
    Image$$TFM_SP_LOAD_LIST$$RO$$Base = ADDR(.TFM_SP_LOAD_LIST);
    Image$$TFM_SP_LOAD_LIST$$RO$$Limit = ADDR(.TFM_SP_LOAD_LIST) + SIZEOF(.TFM_SP_LOAD_LIST);

    /* Position tag: End of RO-data (unprivileged, execute-never) */
    . = ALIGN(TFM_LINKER_PT_RO_DATA_ALIGNMENT);
    Image$$PT_RO_DATA_END$$Base = .;

#if defined(CONFIG_TFM_USE_TRUSTZONE) && defined(TFM_LINKER_VENEERS_LOCATION_END)
    VENEERS()
#endif

    /* Position tag: End of code + RO-data */
    . = ALIGN(TFM_LINKER_PT_RO_ALIGNMENT);
    Image$$PT_RO_END$$Base = .;

#ifdef S_RAM_CODE_START
    /* Flash drivers code that gets copied from Flash */
    .ER_CODE_SRAM ALIGN(S_RAM_CODE_START, TFM_LINKER_SRAM_CODE_ALIGNMENT) :
    {
        KEEP(*libflash_drivers*(SORT_BY_ALIGNMENT(.text*)))
        KEEP(*libflash_drivers*(SORT_BY_ALIGNMENT(.rodata*)))
        KEEP(*(.ramfunc))
#if defined(S_RAM_CODE_EXTRA_SECTION_NAME)
        KEEP(*(S_RAM_CODE_EXTRA_SECTION_NAME))
#endif
        . = ALIGN(4); /* This alignment is needed to make the section size 4 bytes aligned */
    } > CODE_RAM AT > FLASH :coderam

    ASSERT(S_RAM_CODE_START % 4 == 0, "S_RAM_CODE_START must be divisible by 4")

    Image$$ER_CODE_SRAM$$RO$$Base = ADDR(.ER_CODE_SRAM);
    Image$$ER_CODE_SRAM$$RO$$Limit = ADDR(.ER_CODE_SRAM) + SIZEOF(.ER_CODE_SRAM);
    Image$$ER_CODE_SRAM$$Base = ADDR(.ER_CODE_SRAM);
    Image$$ER_CODE_SRAM$$Limit = ADDR(.ER_CODE_SRAM) + SIZEOF(.ER_CODE_SRAM);
#endif

    /**** Base address of secure data area */
    .tfm_secure_data_start (NOLOAD):
    {
        /* Relocate current position to RAM */
        . = ALIGN(4);
    } > RAM

    /*
     * MPU on Armv6-M/v7-M core in multi-core topology may require more strict
     * alignment that MPU region base address must align with the MPU region
     * size.
     * As a result, on Armv6-M/v7-M cores, to save memory resource and MPU
     * regions, unprivileged data sections and privileged data sections can be
     * separated and gathered in unprivileged/privileged data area respectively
     * by defining S_DATA_PRIV_START. If so, the BL2 shared data area is moved
     * to the beginning of the privileged data area, otherwise it is kept at the
     * beginning of the secure data area.
     */
#ifndef S_DATA_PRIV_START
#ifdef CODE_SHARING
    /* The code sharing between bootloader and runtime requires to share the
     * global variables.
     */
    .TFM_SHARED_SYMBOLS (NOLOAD) ALIGN(TFM_LINKER_SHARED_SYMBOLS_ALIGNMENT) :
    {
        . += SHARED_SYMBOL_AREA_SIZE;
    } > RAM
#endif

#ifdef BOOT_TFM_SHARED_DATA_SIZE
    /* Shared area between BL2 and runtime to exchange data */
    .tfm_bl2_shared_data ALIGN(TFM_LINKER_BL2_SHARED_DATA_ALIGNMENT) (NOLOAD) :
    {
        . += BOOT_TFM_SHARED_DATA_SIZE;
    } > RAM
#endif
#endif /* !S_DATA_PRIV_START */

    /* Position tag: Start of Application RoT data (unprivileged) */
    . = ALIGN(TFM_LINKER_PT_APP_ROT_DATA_ALIGNMENT);
    Image$$PT_APP_ROT_DATA_START$$Base = .;

#ifdef CONFIG_TFM_PARTITION_META
    .TFM_SP_META_PTR ALIGN(TFM_LINKER_SP_META_PTR_ALIGNMENT) (NOLOAD) :
    {
        *(.bss.SP_META_PTR_SPRTL_INST)
        . = ALIGN(TFM_LINKER_SP_META_PTR_ALIGNMENT);
    } > RAM
    Image$$TFM_SP_META_PTR$$ZI$$Base = ADDR(.TFM_SP_META_PTR);
    Image$$TFM_SP_META_PTR$$ZI$$Limit = ADDR(.TFM_SP_META_PTR) + SIZEOF(.TFM_SP_META_PTR);
    /* This is needed for the uniform configuration of MPU region. */
    Image$$TFM_SP_META_PTR_END$$ZI$$Limit = Image$$TFM_SP_META_PTR$$ZI$$Limit;
#endif

#ifdef CONFIG_TFM_REUSE_COPY_AREA_FOR_SP_STACKS
    /* Record the FLASH load address right before the first entry of the copy area */
    .flash_marker1 : ALIGN(TFM_LINKER_PT_AROT_PART_PRIVATE_DATA_ALIGNMENT) { } > RAM AT > FLASH :flash
#endif


    .ER_TFM_SP_PS_DATA : ALIGN(TFM_LINKER_PT_AROT_PART_PRIVATE_DATA_ALIGNMENT)
    {
    /* Position tag: Start of Application RoT partition's private data */
    Image$$PT_TFM_SP_PS_PRIVATE_DATA_START$$Base = .;
        *tfm_*partition_ps.*:(SORT_BY_ALIGNMENT(.data*))
        *(TFM_SP_PS_APP-ROT_ATTR_RW)
        . = ALIGN(TFM_LINKER_PT_AROT_PART_PRIVATE_DATA_ALIGNMENT);
    } > RAM AT > FLASH :phdr_TFM_SP_PS

    .ER_TFM_SP_PS_BSS (NOLOAD) : ALIGN(TFM_LINKER_PT_AROT_PART_PRIVATE_DATA_ALIGNMENT)
    {
        start_of_TFM_SP_PS_bss = .;
        *tfm_*partition_ps.*:(SORT_BY_ALIGNMENT(.bss*))
        *tfm_*partition_ps.*:(COMMON)
        *(TFM_SP_PS_APP-ROT_ATTR_ZI)
        . += (. - start_of_TFM_SP_PS_bss) ? 0 : 4;
        . = ALIGN(TFM_LINKER_PT_AROT_PART_PRIVATE_DATA_ALIGNMENT);
    } > RAM

    /* Position tag: End of Application RoT partition's private data */
    . = ALIGN(TFM_LINKER_PT_AROT_PART_PRIVATE_DATA_ALIGNMENT);
    Image$$PT_TFM_SP_PS_PRIVATE_DATA_END$$Base = .;


    /* Position tag: End of Application RoT data (unprivileged) */
    . = ALIGN(TFM_LINKER_PT_APP_ROT_DATA_ALIGNMENT);
    Image$$PT_APP_ROT_DATA_END$$Base = .;

#ifdef S_DATA_PRIV_START
    /**** Privileged data area base address specified by Armv6-M/v7-M platform */
    .tfm_secure_priv_data_boundary (NOLOAD) :
    {
        . = ABSOLUTE(S_DATA_PRIV_START) ;
    } > RAM

    /*
     * Move BL2 shared area to the beginning of privileged data area on
     * Armv6-M/v7-M platforms.
     */
#ifdef BOOT_TFM_SHARED_DATA_SIZE
    /* Shared area between BL2 and runtime to exchange data */
    .tfm_bl2_shared_data ALIGN(TFM_LINKER_BL2_SHARED_DATA_ALIGNMENT) (NOLOAD) :
    {
        . += BOOT_TFM_SHARED_DATA_SIZE;
    } > RAM
#endif
#endif /* S_DATA_PRIV_START */

    /* Position tag: Start of PSA RoT data (privileged) */
    . = ALIGN(TFM_LINKER_PT_PSA_ROT_DATA_ALIGNMENT);
    Image$$PT_PSA_ROT_DATA_START$$Base = .;

    .msp_stack ALIGN(TFM_LINKER_MSP_STACK_ALIGNMENT) (NOLOAD) :
    {
        . += __msp_stack_size__ - STACKSEAL_SIZE;
    } > RAM
    Image$$ARM_LIB_STACK$$ZI$$Base = ADDR(.msp_stack);
    Image$$ARM_LIB_STACK$$ZI$$Limit = ADDR(.msp_stack) + SIZEOF(.msp_stack);
    PROVIDE(__stack = Image$$ARM_LIB_STACK$$ZI$$Limit);

#if defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__) || \
    defined(__ARM_ARCH_8_1M_MAIN__)
    .msp_stack_seal_res (NOLOAD) :
    {
        . += STACKSEAL_SIZE;
    } > RAM
    __StackSeal = ADDR(.msp_stack_seal_res);
#endif

#ifdef ENABLE_HEAP
    __heap_size__ = S_HEAP_SIZE;
    .heap ALIGN(TFM_LINKER_TFM_HEAP_ALIGNMENT) (NOLOAD) :
    {
        __end__ = .;
        PROVIDE(end = .);
        __HeapBase = .;
        . += __heap_size__;
        __HeapLimit = .;
        __heap_limit = .; /* Add for _sbrk */
    } > RAM
#endif

    .ER_TFM_SP_ITS_DATA : ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT)
    {
        /* Position tag: Start of PSA RoT partition's private data */
        Image$$PT_TFM_SP_ITS_PRIVATE_DATA_START$$Base = .;
        *tfm_*partition_its.*:(SORT_BY_ALIGNMENT(.data*))
        *(TFM_SP_ITS_PSA-ROT_ATTR_RW)
        . = ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT);
        } > RAM AT > FLASH :phdr_TFM_SP_ITS

    .ER_TFM_SP_ITS_BSS (NOLOAD) : ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT)
    {
        *tfm_*partition_its.*:(SORT_BY_ALIGNMENT(.bss*))
        *tfm_*partition_its.*:(COMMON)
        *(TFM_SP_ITS_PSA-ROT_ATTR_ZI)
        . = ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT);
        /* Position tag: End of PSA RoT partition's private data */
        Image$$PT_TFM_SP_ITS_PRIVATE_DATA_END$$Base = .;
        } > RAM
    .ER_TFM_SP_CRYPTO_DATA : ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT)
    {
        /* Position tag: Start of PSA RoT partition's private data */
        Image$$PT_TFM_SP_CRYPTO_PRIVATE_DATA_START$$Base = .;
        *tfm_*partition_crypto.*:(SORT_BY_ALIGNMENT(.data*))
        *tfpsacrypto.*:(SORT_BY_ALIGNMENT(.data*))
        *tfpsacrypto*acceleration.*:(SORT_BY_ALIGNMENT(.data*))
        *(TFM_SP_CRYPTO_PSA-ROT_ATTR_RW)
        . = ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT);
        } > RAM AT > FLASH :phdr_TFM_SP_CRYPTO

    .ER_TFM_SP_CRYPTO_BSS (NOLOAD) : ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT)
    {
        *tfm_*partition_crypto.*:(SORT_BY_ALIGNMENT(.bss*))
        *tfm_*partition_crypto.*:(COMMON)
        *tfpsacrypto.*:(SORT_BY_ALIGNMENT(.bss*))
        *tfpsacrypto.*:(COMMON)
        *tfpsacrypto*acceleration.*:(SORT_BY_ALIGNMENT(.bss*))
        *tfpsacrypto*acceleration.*:(COMMON)
        *(TFM_SP_CRYPTO_PSA-ROT_ATTR_ZI)
        . = ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT);
        /* Position tag: End of PSA RoT partition's private data */
        Image$$PT_TFM_SP_CRYPTO_PRIVATE_DATA_END$$Base = .;
        } > RAM
    .ER_TFM_SP_PLATFORM_DATA : ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT)
    {
        /* Position tag: Start of PSA RoT partition's private data */
        Image$$PT_TFM_SP_PLATFORM_PRIVATE_DATA_START$$Base = .;
        *tfm_*partition_platform.*:(SORT_BY_ALIGNMENT(.data*))
        *(TFM_SP_PLATFORM_PSA-ROT_ATTR_RW)
        . = ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT);
        } > RAM AT > FLASH :phdr_TFM_SP_PLATFORM

    .ER_TFM_SP_PLATFORM_BSS (NOLOAD) : ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT)
    {
        *tfm_*partition_platform.*:(SORT_BY_ALIGNMENT(.bss*))
        *tfm_*partition_platform.*:(COMMON)
        *(TFM_SP_PLATFORM_PSA-ROT_ATTR_ZI)
        . = ALIGN(TFM_LINKER_PT_PROT_PART_PRIVATE_DATA_ALIGNMENT);
        /* Position tag: End of PSA RoT partition's private data */
        Image$$PT_TFM_SP_PLATFORM_PRIVATE_DATA_END$$Base = .;
        } > RAM

    .TFM_DATA ALIGN(TFM_LINKER_TFM_DATA_ALIGNMENT) :
    {
        *(SORT_BY_ALIGNMENT(.data*))

        KEEP(*(.jcr*))
        . = ALIGN(TFM_LINKER_TFM_DATA_ALIGNMENT);
    } > RAM AT > FLASH :tfm_data

#ifdef S_RUNTIME_ITCM_START
    .ER_ITCM_CODE :
    {
        ITCM_FILES:(SORT_BY_ALIGNMENT(.text*))
        ITCM_FILES:(SORT_BY_ALIGNMENT(.rodata*))
        . = ALIGN(TFM_LINKER_ITCM_CODE_ALIGNMENT);
    } > ITCM AT > FLASH :itcm
#endif

#ifdef CONFIG_TFM_REUSE_COPY_AREA_FOR_SP_STACKS
    /*
     * Align the overlay load region in FLASH.
     * We can't rely on section placement alone, since we need the LMA
     * to be aligned.
     * This expression ensures the next section's load address starts at
     * a properly aligned boundary in FLASH for the overlay area.
     */
    Image$$PT_OVERLAY_AREA_BEGIN$$Base = LOADADDR(.flash_marker1);

    .tfm_runtime_sp_stacks Image$$PT_OVERLAY_AREA_BEGIN$$Base (NOLOAD) : ALIGN(TFM_LINKER_PT_AROT_PART_PRIVATE_DATA_ALIGNMENT)
    {
        KEEP(*(.tfm_runtime_sp_stacks*))
    } > FLASH
    Image$$PT_OVERLAY_AREA_END$$Base = .;
#endif /* CONFIG_TFM_REUSE_COPY_AREA_FOR_SP_STACKS */

    .TFM_BSS (NOLOAD) : ALIGN(TFM_LINKER_TFM_BSS_ALIGNMENT)
    {
        __bss_start__ = .;

        /* The runtime partition placed order is same as load partition */
        __partition_runtime_start__ = .;
        KEEP(*(.bss.part_runtime))
        __partition_runtime_end__ = .;
        . = ALIGN(TFM_LINKER_TFM_BSS_ALIGNMENT);

        /* The runtime service placed order is same as load partition */
        __service_runtime_start__ = .;
        KEEP(*(.bss.serv_runtime))
        __service_runtime_end__ = .;
        *(SORT_BY_ALIGNMENT(.bss*))
        *(COMMON)

        *(SORT_BY_ALIGNMENT(.noinit*))       /* Uninitialized RAM */
        *(SORT_BY_ALIGNMENT(.cy_sharedmem*)) /* Cypress shared memory */

        . = ALIGN(TFM_LINKER_TFM_BSS_ALIGNMENT);
        __bss_end__ = .;
    } > RAM
    Image$$ER_PART_RT_POOL$$ZI$$Base = __partition_runtime_start__;
    Image$$ER_PART_RT_POOL$$ZI$$Limit = __partition_runtime_end__;
    Image$$ER_SERV_RT_POOL$$ZI$$Base = __service_runtime_start__;
    Image$$ER_SERV_RT_POOL$$ZI$$Limit = __service_runtime_end__;

    /* Position tag: End of PSA RoT data (privileged) */
    . = ALIGN(TFM_LINKER_PT_PSA_ROT_DATA_ALIGNMENT);
    Image$$PT_PSA_ROT_DATA_END$$Base = .;

#ifdef RAM_VECTORS_SUPPORT
    .ramVectors ALIGN(TFM_LINKER_RAM_VECTORS_ALIGNMENT) (NOLOAD) :
    {
        __ram_vectors_start__ = .;
        KEEP(*(.ram_vectors))
        __ram_vectors_end__   = .;
    } > RAM
#endif

#ifdef CONFIG_TFM_USE_TRUSTZONE
    Image$$ER_VENEER$$Base = ADDR(.gnu.sgstubs);
    Image$$VENEER_ALIGN$$Limit = ADDR(.sgstubs_end);

#ifdef TFM_LINKER_VENEERS_SIZE
    ASSERT ((Image$$VENEER_ALIGN$$Limit - Image$$ER_VENEER$$Base) <= TFM_LINKER_VENEERS_SIZE, "Veneer region overflowed")
#endif
#endif

    Load$$LR$$LR_NS_PARTITION$$Base = NS_PARTITION_START;

#ifdef BL2
    Load$$LR$$LR_SECONDARY_PARTITION$$Base = SECONDARY_PARTITION_START;
#endif /* BL2 */
}
相关推荐
tyustli1 天前
TF-M BL2 和 TFM_S 的配置和编译
qemu·tf-m·bl2·mps2-an521·tfm_s
tyustli2 天前
TF-M BL2 RAM 布局
qemu·tf-m·bl2·mps2-an521
tyustli5 天前
TF-M 使用 make 构建
qemu·make·mcuboot·tf-m·mps2-an521
张一西1 个月前
QEMU 模拟器学习(二)之 USB 设备之BOT & UAS协议
qemu·uas·bot
张一西1 个月前
QEMU 模拟器学习(二)之 USB 设备模拟与协议学习
qemu·usb·uas·bot
shimly1234561 个月前
(undone) 解析 qemu-6.0.0 源码 (4) 添加 niubi board - 2
qemu
冰山一脚20131 个月前
cirrus显卡驱动笔记
qemu·drm
shimly1234561 个月前
(done) 解析 qemu-6.0.0 源码 (2) 寻找入口函数 main
qemu
ggaofeng2 个月前
QEMU中硬盘用哪种协议读写速度快
qemu·磁盘类型