feat(esp_system): allow .bss to spill over into L2MEM above 0x4ff40000

This commit introduce SOC_MEM_NON_CONTIGUOUS_SRAM flag (that enebled for
esp32p4). If SOC_MEM_NON_CONTIGUOUS_SRAM is enabled:

- LDFLAGS+=--enable-non-contiguous-regions
- ldgen.py replaces "arrays[*]" from sections.ld.in with objects under
  SURROUND keyword. (e.g. from linker.lf: data -> dram0_data SURROUND(foo))
- "mapping[*]" - refers to all other data

If SOC_MEM_NON_CONTIGUOUS_SRAM, sections.ld.in file should contain at
least one block of code like this (otherwise it does not make sense):

  .dram0.bss (NOLOAD) :
  {
    arrays[dram0_bss]
    mapping[dram0_bss]
  } > sram_low

  .dram1.bss (NOLOAD) :
  {
    /* do not place here arrays[dram0_bss] because it may be splited
     * between segments */
    mapping[dram0_bss]
  } > sram_high
This commit is contained in:
Alexey Lapshin 2024-02-12 09:51:25 +04:00
parent 4b5b064caf
commit 824c8e0593
47 changed files with 604 additions and 554 deletions

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -10,7 +10,11 @@
#include "sdkconfig.h"
// Bootloader version info
const __attribute__((weak)) __attribute__((section(".data_bootloader_desc"))) esp_bootloader_desc_t esp_bootloader_desc = {
#if BOOTLOADER_BUILD
__attribute__((section(".data_bootloader_desc")))
#endif
__attribute__((weak))
const esp_bootloader_desc_t esp_bootloader_desc = {
.magic_byte = ESP_BOOTLOADER_DESC_MAGIC_BYTE,
.reserved = { 0 },
.version = CONFIG_BOOTLOADER_PROJECT_VER,

View File

@ -143,3 +143,7 @@ if(NOT BOOTLOADER_BUILD)
idf_component_optional_requires(PRIVATE esp_psram)
endif()
endif()
if(CONFIG_SOC_MEM_NON_CONTIGUOUS_SRAM)
target_link_options(${COMPONENT_LIB} INTERFACE "-Wl,--enable-non-contiguous-regions")
endif()

View File

@ -3,6 +3,9 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "ld.common"
/* Default entry point: */
ENTRY(call_start_cpu0);
@ -296,6 +299,7 @@ SECTIONS
* will be merged when creating the final bin image. */
. = ALIGN(ALIGNOF(.flash.rodata));
} >default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.appdesc, .flash.rodata)
.flash.rodata : ALIGN(0x10)
{

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "ld.common"
/* Default entry point */
ENTRY(call_start_cpu0);
@ -93,20 +95,9 @@ SECTIONS
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
/* ldgen places all bss-related data to mapping[dram0_bss] (See esp_system/app.lf). */
mapping[dram0_bss]
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.share.mem)
*(.gnu.linkonce.b.*)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
} > dram0_0_seg
@ -174,7 +165,8 @@ SECTIONS
* section will match .flash.rodata's begin address. Thus, both sections
* will be merged when creating the final bin image. */
. = ALIGN(ALIGNOF(.flash.rodata));
} >default_rodata_seg
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.appdesc, .flash.rodata)
.flash.rodata : ALIGN(0x10)
{
@ -234,7 +226,12 @@ SECTIONS
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
. = ALIGN(ALIGNOF(.flash.tls));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.rodata, .flash.tls)
.flash.tls : ALIGN(8)
{
_thread_local_start = ABSOLUTE(.);
*(.tdata)
*(.tdata.*)
@ -243,6 +240,7 @@ SECTIONS
_thread_local_end = ABSOLUTE(.);
. = ALIGN(ALIGNOF(.eh_frame));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.tls, .eh_frame)
/* Keep this section shall be at least aligned on 4 */
.eh_frame : ALIGN(8)
@ -254,6 +252,7 @@ SECTIONS
* them adjacent. */
. = ALIGN(ALIGNOF(.eh_frame_hdr));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.eh_frame, .eh_frame_hdr)
/* To avoid any exception in C++ exception frame unwinding code, this section
* shall be aligned on 8. */

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "ld.common"
/* Default entry point */
ENTRY(call_start_cpu0);
@ -206,20 +208,9 @@ SECTIONS
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
/* ldgen places all bss-related data to mapping[dram0_bss] (See esp_system/app.lf). */
mapping[dram0_bss]
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.share.mem)
*(.gnu.linkonce.b.*)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
} > dram0_0_seg
@ -287,7 +278,8 @@ SECTIONS
* section will match .flash.rodata's begin address. Thus, both sections
* will be merged when creating the final bin image. */
. = ALIGN(ALIGNOF(.flash.rodata));
} >default_rodata_seg
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.appdesc, .flash.rodata)
.flash.rodata : ALIGN(0x10)
{
@ -347,7 +339,12 @@ SECTIONS
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
. = ALIGN(ALIGNOF(.flash.tls));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.rodata, .flash.tls)
.flash.tls : ALIGN(8)
{
_thread_local_start = ABSOLUTE(.);
*(.tdata)
*(.tdata.*)
@ -356,6 +353,7 @@ SECTIONS
_thread_local_end = ABSOLUTE(.);
. = ALIGN(ALIGNOF(.eh_frame));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.tls, .eh_frame)
/* Keep this section shall be at least aligned on 4 */
.eh_frame : ALIGN(8)
@ -367,6 +365,7 @@ SECTIONS
* them adjacent. */
. = ALIGN(ALIGNOF(.eh_frame_hdr));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.eh_frame, .eh_frame_hdr)
/* To avoid any exception in C++ exception frame unwinding code, this section
* shall be aligned on 8. */

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "ld.common"
/* Default entry point */
ENTRY(call_start_cpu0);
@ -46,6 +48,7 @@ SECTIONS
*(.rtc.force_fast .rtc.force_fast.*)
. = ALIGN(4) ;
_rtc_force_fast_end = ABSOLUTE(.);
} > lp_ram_seg
@ -241,21 +244,10 @@ SECTIONS
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
/* ldgen places all bss-related data to mapping[dram0_bss] (See esp_system/app.lf). */
mapping[dram0_bss]
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.share.mem)
*(.gnu.linkonce.b.*)
. = ALIGN (8);
. = ALIGN(4);
_bss_end = ABSOLUTE(.);
} > dram0_0_seg
@ -322,7 +314,8 @@ SECTIONS
* section will match .flash.rodata's begin address. Thus, both sections
* will be merged when creating the final bin image. */
. = ALIGN(ALIGNOF(.flash.rodata));
} >default_rodata_seg
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.appdesc, .flash.rodata)
.flash.rodata : ALIGN(0x10)
{
@ -382,7 +375,12 @@ SECTIONS
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
. = ALIGN(ALIGNOF(.flash.tls));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.rodata, .flash.tls)
.flash.tls : ALIGN(8)
{
_thread_local_start = ABSOLUTE(.);
*(.tdata)
*(.tdata.*)
@ -391,6 +389,7 @@ SECTIONS
_thread_local_end = ABSOLUTE(.);
. = ALIGN(ALIGNOF(.eh_frame));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.tls, .eh_frame)
/* Keep this section shall be at least aligned on 4 */
.eh_frame : ALIGN(8)
@ -402,6 +401,7 @@ SECTIONS
* them adjacent. */
. = ALIGN(ALIGNOF(.eh_frame_hdr));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.eh_frame, .eh_frame_hdr)
/* To avoid any exception in C++ exception frame unwinding code, this section
* shall be aligned on 8. */

View File

@ -15,20 +15,9 @@
#include "sdkconfig.h"
#include "ld.common"
/**
* physical memory is mapped twice to the vritual address (IRAM and DRAM).
* `I_D_SRAM_OFFSET` is the offset between the two locations of the same physical memory
*/
#define SRAM_IRAM_START 0x40800000
#define SRAM_DRAM_START 0x40800000
#define I_D_SRAM_OFFSET (SRAM_IRAM_START - SRAM_DRAM_START)
#define SRAM_DRAM_END 0x4086E610 - I_D_SRAM_OFFSET /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_IRAM_ORG (SRAM_IRAM_START)
#define SRAM_DRAM_ORG (SRAM_DRAM_START)
#define I_D_SRAM_SIZE SRAM_DRAM_END - SRAM_DRAM_ORG
#define SRAM_SEG_START 0x40800000
#define SRAM_SEG_END 0x4086E610 /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_SEG_SIZE SRAM_SEG_END - SRAM_SEG_START
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/*
@ -37,8 +26,6 @@
#define IDRAM0_2_SEG_SIZE (CONFIG_MMU_PAGE_SIZE << 8)
#endif
#define DRAM0_0_SEG_LEN I_D_SRAM_SIZE
MEMORY
{
/**
@ -47,9 +34,6 @@ MEMORY
* are connected to the data port of the CPU and eg allow byte-wise access.
*/
/* IRAM for PRO CPU. */
iram0_0_seg (RX) : org = SRAM_IRAM_ORG, len = I_D_SRAM_SIZE
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped instruction data */
irom_seg (RX) : org = 0x42000020, len = IDRAM0_2_SEG_SIZE - 0x20
@ -67,7 +51,7 @@ MEMORY
* Shared data RAM, excluding memory reserved for ROM bss/data/stack.
* Enabling Bluetooth & Trace Memory features in menuconfig will decrease the amount of RAM available.
*/
dram0_0_seg (RW) : org = SRAM_DRAM_ORG, len = DRAM0_0_SEG_LEN
sram_seg (RWX) : org = SRAM_SEG_START, len = SRAM_SEG_SIZE
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped constant data */
@ -96,7 +80,7 @@ MEMORY
lp_reserved_seg(RW) : org = 0x50000000 + 0x4000 - RESERVE_RTC_MEM, len = RESERVE_RTC_MEM
}
/* Heap ends at top of dram0_0_seg */
/* Heap ends at top of sram_seg */
_heap_end = 0x40000000;
_data_seg_org = ORIGIN(rtc_data_seg);
@ -115,13 +99,13 @@ REGION_ALIAS("rtc_reserved_seg", lp_reserved_seg );
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_code_seg", irom_seg);
#else
REGION_ALIAS("default_code_seg", iram0_0_seg);
REGION_ALIAS("default_code_seg", sram_seg);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_rodata_seg", drom_seg);
#else
REGION_ALIAS("default_rodata_seg", dram0_0_seg);
REGION_ALIAS("default_rodata_seg", sram_seg);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/**

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "ld.common"
/* Default entry point */
ENTRY(call_start_cpu0);
@ -158,7 +160,7 @@ SECTIONS
mapping[iram0_text]
} > iram0_0_seg
} > sram_seg
/* Marks the end of IRAM code segment */
.iram0.text_end (NOLOAD) :
@ -169,7 +171,7 @@ SECTIONS
/* iram_end_test section exists for use by memprot unit tests only */
*(.iram_end_test)
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
} > sram_seg
.iram0.data :
{
@ -179,7 +181,7 @@ SECTIONS
mapping[iram0_data]
_iram_data_end = ABSOLUTE(.);
} > iram0_0_seg
} > sram_seg
.iram0.bss (NOLOAD) :
{
@ -191,16 +193,7 @@ SECTIONS
_iram_bss_end = ABSOLUTE(.);
. = ALIGN(16);
_iram_end = ABSOLUTE(.);
} > iram0_0_seg
/**
* This section is required to skip .iram0.text area because iram0_0_seg and
* dram0_0_seg reflect the same address space on different buses.
*/
.dram0.dummy (NOLOAD):
{
. = ORIGIN(dram0_0_seg) + _iram_end - _iram_start;
} > dram0_0_seg
} > sram_seg
.dram0.data :
{
@ -218,7 +211,7 @@ SECTIONS
_data_end = ABSOLUTE(.);
. = ALIGN(4);
} > dram0_0_seg
} > sram_seg
/**
* This section holds data that should not be initialized at power up.
@ -233,7 +226,7 @@ SECTIONS
*(.noinit .noinit.*)
. = ALIGN(4) ;
_noinit_end = ABSOLUTE(.);
} > dram0_0_seg
} > sram_seg
/* Shared RAM */
.dram0.bss (NOLOAD) :
@ -241,25 +234,12 @@ SECTIONS
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
/* ldgen places all bss-related data to mapping[dram0_bss] (See esp_system/app.lf). */
mapping[dram0_bss]
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.share.mem)
*(.gnu.linkonce.b.*)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
} > dram0_0_seg
ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), "DRAM segment data does not fit.")
} > sram_seg
.flash.text :
{
@ -322,7 +302,8 @@ SECTIONS
* section will match .flash.rodata's begin address. Thus, both sections
* will be merged when creating the final bin image. */
. = ALIGN(ALIGNOF(.flash.rodata));
} >default_rodata_seg
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.appdesc, .flash.rodata)
.flash.rodata : ALIGN(0x10)
{
@ -382,7 +363,12 @@ SECTIONS
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
. = ALIGN(ALIGNOF(.flash.tls));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.rodata, .flash.tls)
.flash.tls : ALIGN(8)
{
_thread_local_start = ABSOLUTE(.);
*(.tdata)
*(.tdata.*)
@ -391,6 +377,7 @@ SECTIONS
_thread_local_end = ABSOLUTE(.);
. = ALIGN(ALIGNOF(.eh_frame));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.tls, .eh_frame)
/* Keep this section shall be at least aligned on 4 */
.eh_frame : ALIGN(8)
@ -402,6 +389,7 @@ SECTIONS
* them adjacent. */
. = ALIGN(ALIGNOF(.eh_frame_hdr));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.eh_frame, .eh_frame_hdr)
/* To avoid any exception in C++ exception frame unwinding code, this section
* shall be aligned on 8. */
@ -432,11 +420,5 @@ SECTIONS
{
. = ALIGN (16);
_heap_start = ABSOLUTE(.);
} > dram0_0_seg
} > sram_seg
}
ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)),
"IRAM0 segment data does not fit.")
ASSERT(((_heap_start - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)),
"DRAM segment data does not fit.")

View File

@ -15,20 +15,9 @@
#include "sdkconfig.h"
#include "ld.common"
/**
* physical memory is mapped twice to the vritual address (IRAM and DRAM).
* `I_D_SRAM_OFFSET` is the offset between the two locations of the same physical memory
*/
#define SRAM_IRAM_START 0x40800000
#define SRAM_DRAM_START 0x40800000
#define I_D_SRAM_OFFSET (SRAM_IRAM_START - SRAM_DRAM_START)
#define SRAM_DRAM_END 0x4083EFD0 - I_D_SRAM_OFFSET /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_IRAM_ORG (SRAM_IRAM_START)
#define SRAM_DRAM_ORG (SRAM_DRAM_START)
#define I_D_SRAM_SIZE SRAM_DRAM_END - SRAM_DRAM_ORG
#define SRAM_SEG_START 0x40800000
#define SRAM_SEG_END 0x4083EFD0 /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_SEG_SIZE SRAM_SEG_END - SRAM_SEG_START
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/*
@ -37,8 +26,6 @@
#define IDRAM0_2_SEG_SIZE (CONFIG_MMU_PAGE_SIZE << 8)
#endif
#define DRAM0_0_SEG_LEN I_D_SRAM_SIZE
MEMORY
{
/**
@ -47,9 +34,6 @@ MEMORY
* are connected to the data port of the CPU and eg allow byte-wise access.
*/
/* IRAM for PRO CPU. */
iram0_0_seg (RX) : org = SRAM_IRAM_ORG, len = I_D_SRAM_SIZE
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped instruction data */
irom_seg (RX) : org = 0x42000020, len = IDRAM0_2_SEG_SIZE - 0x20
@ -67,7 +51,7 @@ MEMORY
* Shared data RAM, excluding memory reserved for ROM bss/data/stack.
* Enabling Bluetooth & Trace Memory features in menuconfig will decrease the amount of RAM available.
*/
dram0_0_seg (RW) : org = SRAM_DRAM_ORG, len = DRAM0_0_SEG_LEN
sram_seg (RWX) : org = SRAM_SEG_START, len = SRAM_SEG_SIZE
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped constant data */
@ -92,7 +76,7 @@ MEMORY
lp_reserved_seg(RW) : org = 0x50000000 + 0x1000 - RESERVE_RTC_MEM, len = RESERVE_RTC_MEM
}
/* Heap ends at top of dram0_0_seg */
/* Heap ends at top of sram_seg */
_heap_end = 0x40000000;
_data_seg_org = ORIGIN(rtc_data_seg);
@ -110,13 +94,13 @@ REGION_ALIAS("rtc_reserved_seg", lp_reserved_seg );
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_code_seg", irom_seg);
#else
REGION_ALIAS("default_code_seg", iram0_0_seg);
REGION_ALIAS("default_code_seg", sram_seg);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_rodata_seg", drom_seg);
#else
REGION_ALIAS("default_rodata_seg", dram0_0_seg);
REGION_ALIAS("default_rodata_seg", sram_seg);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/**

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "ld.common"
/* Default entry point */
ENTRY(call_start_cpu0);
@ -158,7 +160,7 @@ SECTIONS
mapping[iram0_text]
} > iram0_0_seg
} > sram_seg
/* Marks the end of IRAM code segment */
.iram0.text_end (NOLOAD) :
@ -169,7 +171,7 @@ SECTIONS
/* iram_end_test section exists for use by memprot unit tests only */
*(.iram_end_test)
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
} > sram_seg
.iram0.data :
{
@ -179,7 +181,7 @@ SECTIONS
mapping[iram0_data]
_iram_data_end = ABSOLUTE(.);
} > iram0_0_seg
} > sram_seg
.iram0.bss (NOLOAD) :
{
@ -191,16 +193,7 @@ SECTIONS
_iram_bss_end = ABSOLUTE(.);
. = ALIGN(16);
_iram_end = ABSOLUTE(.);
} > iram0_0_seg
/**
* This section is required to skip .iram0.text area because iram0_0_seg and
* dram0_0_seg reflect the same address space on different buses.
*/
.dram0.dummy (NOLOAD):
{
. = ORIGIN(dram0_0_seg) + _iram_end - _iram_start;
} > dram0_0_seg
} > sram_seg
.dram0.data :
{
@ -218,7 +211,7 @@ SECTIONS
_data_end = ABSOLUTE(.);
. = ALIGN(4);
} > dram0_0_seg
} > sram_seg
/**
* This section holds data that should not be initialized at power up.
@ -233,7 +226,7 @@ SECTIONS
*(.noinit .noinit.*)
. = ALIGN(4) ;
_noinit_end = ABSOLUTE(.);
} > dram0_0_seg
} > sram_seg
/* Shared RAM */
.dram0.bss (NOLOAD) :
@ -241,25 +234,12 @@ SECTIONS
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
/* ldgen places all bss-related data to mapping[dram0_bss] (See esp_system/app.lf). */
mapping[dram0_bss]
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.share.mem)
*(.gnu.linkonce.b.*)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
} > dram0_0_seg
ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), "DRAM segment data does not fit.")
} > sram_seg
.flash.text :
{
@ -322,7 +302,8 @@ SECTIONS
* section will match .flash.rodata's begin address. Thus, both sections
* will be merged when creating the final bin image. */
. = ALIGN(ALIGNOF(.flash.rodata));
} >default_rodata_seg
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.appdesc, .flash.rodata)
.flash.rodata : ALIGN(0x10)
{
@ -381,7 +362,12 @@ SECTIONS
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
. = ALIGN(ALIGNOF(.flash.tls));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.rodata, .flash.tls)
.flash.tls : ALIGN(8)
{
_thread_local_start = ABSOLUTE(.);
*(.tdata)
*(.tdata.*)
@ -391,6 +377,7 @@ SECTIONS
_rodata_reserved_end = ABSOLUTE(.);
. = ALIGN(ALIGNOF(.eh_frame));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.tls, .eh_frame)
/* Keep this section shall be at least aligned on 4 */
.eh_frame : ALIGN(8)
@ -402,6 +389,7 @@ SECTIONS
* them adjacent. */
. = ALIGN(ALIGNOF(.eh_frame_hdr));
} > default_rodata_seg
ASSERT_SECTIONS_GAP(.eh_frame, .eh_frame_hdr)
/* To avoid any exception in C++ exception frame unwinding code, this section
* shall be aligned on 8. */
@ -423,11 +411,5 @@ SECTIONS
{
. = ALIGN (16);
_heap_start = ABSOLUTE(.);
} > dram0_0_seg
} > sram_seg
}
ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)),
"IRAM0 segment data does not fit.")
ASSERT(((_heap_start - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)),
"DRAM segment data does not fit.")

View File

@ -15,20 +15,17 @@
#include "sdkconfig.h"
#include "ld.common"
/**
* physical memory is mapped twice to the vritual address (IRAM and DRAM).
* `I_D_SRAM_OFFSET` is the offset between the two locations of the same physical memory
#define SRAM_LOW_START 0x4FF00000
#define SRAM_LOW_END 0x4FF2CBD0 /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_LOW_SIZE SRAM_LOW_END - SRAM_LOW_START
/* If the cache size is less than 512KB, then there is a region of RAM
* above the ROM-reserved region and below the start of the cache.
*/
#define SRAM_IRAM_START 0x4ff00000
#define SRAM_DRAM_START 0x4ff00000
#define SRAM_HIGH_START 0x4FF40000
#define SRAM_HIGH_SIZE 0x80000 - CONFIG_CACHE_L2_CACHE_SIZE
#define SRAM_HIGH_END SRAM_HIGH_START + SRAM_HIGH_SIZE
#define I_D_SRAM_OFFSET (SRAM_IRAM_START - SRAM_DRAM_START)
#define SRAM_DRAM_END 0x4FF2CBD0 - I_D_SRAM_OFFSET /* 2nd stage bootloader iram_loader_seg start address */
#define SRAM_IRAM_ORG (SRAM_IRAM_START)
#define SRAM_DRAM_ORG (SRAM_DRAM_START)
#define I_D_SRAM_SIZE SRAM_DRAM_END - SRAM_DRAM_ORG
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/**
@ -37,8 +34,6 @@
#define IDROM_SEG_SIZE (CONFIG_MMU_PAGE_SIZE << 10)
#endif
#define DRAM0_0_SEG_LEN I_D_SRAM_SIZE
MEMORY
{
/**
@ -49,9 +44,6 @@ MEMORY
/* TCM */
tcm_idram_seg (RX) : org = 0x30100000, len = 0x2000
/* IRAM for PRO CPU. */
iram0_0_seg (RX) : org = SRAM_IRAM_ORG, len = I_D_SRAM_SIZE
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped instruction data */
irom_seg (RX) : org = 0x40000020, len = IDROM_SEG_SIZE - 0x20
@ -69,7 +61,9 @@ MEMORY
* Shared data RAM, excluding memory reserved for ROM bss/data/stack.
* Enabling Bluetooth & Trace Memory features in menuconfig will decrease the amount of RAM available.
*/
dram0_0_seg (RW) : org = SRAM_DRAM_ORG, len = DRAM0_0_SEG_LEN
sram_low (RWX) : org = SRAM_LOW_START, len = SRAM_LOW_SIZE
sram_high (RW) : org = SRAM_HIGH_START, len = SRAM_HIGH_SIZE
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped constant data */
@ -115,15 +109,17 @@ REGION_ALIAS("rtc_data_location", rtc_iram_seg );
REGION_ALIAS("rtc_reserved_seg", lp_reserved_seg );
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_code_seg", irom_seg);
REGION_ALIAS("text_seg_low", irom_seg);
#else
REGION_ALIAS("default_code_seg", iram0_0_seg);
REGION_ALIAS("text_seg_low", sram_low);
REGION_ALIAS("text_seg_high", sram_high);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("default_rodata_seg", drom_seg);
REGION_ALIAS("rodata_seg_low", drom_seg);
#else
REGION_ALIAS("default_rodata_seg", dram0_0_seg);
REGION_ALIAS("rodata_seg_low", sram_low);
REGION_ALIAS("rodata_seg_high", sram_high);
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/**
@ -131,7 +127,7 @@ REGION_ALIAS("rtc_reserved_seg", lp_reserved_seg );
* also be first in the segment.
*/
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
ASSERT(_flash_rodata_dummy_start == ORIGIN(default_rodata_seg),
ASSERT(_flash_rodata_dummy_start == ORIGIN(rodata_seg_low),
".flash_rodata_dummy section must be placed at the beginning of the rodata segment.")
#endif

View File

@ -4,6 +4,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "ld.common"
/* Default entry point */
ENTRY(call_start_cpu0);
@ -18,6 +21,7 @@ SECTIONS
. = ALIGN(4);
_rtc_fast_start = ABSOLUTE(.);
arrays[rtc_text]
mapping[rtc_text]
*rtc_wake_stub*.*(.literal .text .literal.* .text.*)
@ -40,10 +44,12 @@ SECTIONS
. = ALIGN(4);
_rtc_force_fast_start = ABSOLUTE(.);
arrays[rtc_force_fast]
mapping[rtc_force_fast]
*(.rtc.force_fast .rtc.force_fast.*)
. = ALIGN(4) ;
_rtc_force_fast_end = ABSOLUTE(.);
} > lp_ram_seg
@ -57,6 +63,7 @@ SECTIONS
{
_rtc_data_start = ABSOLUTE(.);
arrays[rtc_data]
mapping[rtc_data]
*rtc_wake_stub*.*(.data .rodata .data.* .rodata.* .srodata.*)
@ -70,6 +77,7 @@ SECTIONS
*rtc_wake_stub*.*(.bss .bss.* .sbss .sbss.*)
*rtc_wake_stub*.*(COMMON)
arrays[rtc_bss]
mapping[rtc_bss]
_rtc_bss_end = ABSOLUTE(.);
@ -145,6 +153,7 @@ SECTIONS
/* Code marked as running out of TCM */
_tcm_text_start = ABSOLUTE(.);
arrays[tcm_text]
mapping[tcm_text]
_tcm_text_end = ABSOLUTE(.);
@ -155,6 +164,7 @@ SECTIONS
{
_tcm_data_start = ABSOLUTE(.);
arrays[tcm_data]
mapping[tcm_data]
_tcm_data_end = ABSOLUTE(.);
@ -177,9 +187,10 @@ SECTIONS
/* Code marked as running out of IRAM */
_iram_text_start = ABSOLUTE(.);
arrays[iram0_text]
mapping[iram0_text]
} > iram0_0_seg
} > sram_low
/* Marks the end of IRAM code segment */
.iram0.text_end (NOLOAD) :
@ -190,38 +201,31 @@ SECTIONS
/* iram_end_test section exists for use by memprot unit tests only */
*(.iram_end_test)
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
} > sram_low
.iram0.data :
{
. = ALIGN(16);
_iram_data_start = ABSOLUTE(.);
arrays[iram0_data]
mapping[iram0_data]
_iram_data_end = ABSOLUTE(.);
} > iram0_0_seg
} > sram_low
.iram0.bss (NOLOAD) :
{
. = ALIGN(16);
_iram_bss_start = ABSOLUTE(.);
arrays[iram0_bss]
mapping[iram0_bss]
_iram_bss_end = ABSOLUTE(.);
. = ALIGN(16);
_iram_end = ABSOLUTE(.);
} > iram0_0_seg
/**
* This section is required to skip .iram0.text area because iram0_0_seg and
* dram0_0_seg reflect the same address space on different buses.
*/
.dram0.dummy (NOLOAD):
{
. = ORIGIN(dram0_0_seg) + _iram_end - _iram_start;
} > dram0_0_seg
} > sram_low
.dram0.data :
{
@ -235,11 +239,12 @@ SECTIONS
*(.gnu.linkonce.s2.*)
*(.jcr)
arrays[dram0_data]
mapping[dram0_data]
_data_end = ABSOLUTE(.);
. = ALIGN(4);
} > dram0_0_seg
} > sram_low
/**
* This section holds data that should not be initialized at power up.
@ -254,33 +259,7 @@ SECTIONS
*(.noinit .noinit.*)
. = ALIGN(4) ;
_noinit_end = ABSOLUTE(.);
} > dram0_0_seg
/* Shared RAM */
.dram0.bss (NOLOAD) :
{
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
mapping[dram0_bss]
*(.dynsbss)
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
*(.scommon)
*(.sbss2)
*(.sbss2.*)
*(.gnu.linkonce.sb2.*)
*(.dynbss)
*(.share.mem)
*(.gnu.linkonce.b.*)
. = ALIGN (8);
_bss_end = ABSOLUTE(.);
} > dram0_0_seg
ASSERT(((_bss_end - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)), "DRAM segment data does not fit.")
} > sram_low
.flash.text :
{
@ -288,6 +267,7 @@ SECTIONS
_instruction_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.text start, this can be used for mmu driver to maintain virtual address */
_text_start = ABSOLUTE(.);
arrays[flash_text]
mapping[flash_text]
*(.stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
@ -313,7 +293,7 @@ SECTIONS
* the flash.text segment.
*/
_flash_cache_start = ABSOLUTE(0);
} > default_code_seg
} > text_seg_low
/**
* This dummy section represents the .flash.text section but in default_rodata_seg.
@ -329,7 +309,7 @@ SECTIONS
/* Prepare the alignment of the section above. Few bytes (0x20) must be
* added for the mapping header. */
. = ALIGN(_esp_mmu_block_size) + 0x20;
} > default_rodata_seg
} > rodata_seg_low
.flash.appdesc : ALIGN(0x10)
{
@ -343,12 +323,14 @@ SECTIONS
* section will match .flash.rodata's begin address. Thus, both sections
* will be merged when creating the final bin image. */
. = ALIGN(ALIGNOF(.flash.rodata));
} > default_rodata_seg
} > rodata_seg_low
ASSERT_SECTIONS_GAP(.flash.appdesc, .flash.rodata)
.flash.rodata : ALIGN(0x10)
{
_flash_rodata_start = ABSOLUTE(.);
arrays[flash_rodata]
mapping[flash_rodata]
*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
@ -359,6 +341,10 @@ SECTIONS
*(.gcc_except_table .gcc_except_table.*)
*(.gnu.linkonce.e.*)
*(.gnu.version_r)
} > rodata_seg_low
.flash.init_array :
{
. = (. + 7) & ~ 3;
/*
* C++ constructor and destructor tables
@ -403,7 +389,12 @@ SECTIONS
*(.lit4.*)
*(.gnu.linkonce.lit4.*)
_lit4_end = ABSOLUTE(.);
. = ALIGN(4);
. = ALIGN(ALIGNOF(.flash.tls));
} > rodata_seg_low
ASSERT_SECTIONS_GAP(.flash.init_array, .flash.tls)
.flash.tls : ALIGN(8)
{
_thread_local_start = ABSOLUTE(.);
*(.tdata)
*(.tdata.*)
@ -411,7 +402,8 @@ SECTIONS
*(.tbss.*)
_thread_local_end = ABSOLUTE(.);
. = ALIGN(ALIGNOF(.eh_frame));
} > default_rodata_seg
} > rodata_seg_low
ASSERT_SECTIONS_GAP(.flash.tls, .eh_frame)
/* Keep this section shall be at least aligned on 4 */
.eh_frame : ALIGN(8)
@ -422,7 +414,8 @@ SECTIONS
/* Guarantee that this section and the next one will be merged by making
* them adjacent. */
. = ALIGN(ALIGNOF(.eh_frame_hdr));
} > default_rodata_seg
} > rodata_seg_low
ASSERT_SECTIONS_GAP(.eh_frame, .eh_frame_hdr)
/* To avoid any exception in C++ exception frame unwinding code, this section
* shall be aligned on 8. */
@ -431,7 +424,8 @@ SECTIONS
__eh_frame_hdr = ABSOLUTE(.);
KEEP (*(.eh_frame_hdr))
__eh_frame_hdr_end = ABSOLUTE(.);
} > default_rodata_seg
. = ALIGN(ALIGNOF(.flash.rodata));
} > rodata_seg_low
/*
This section is a place where we dump all the rodata which aren't used at runtime,
@ -445,19 +439,46 @@ SECTIONS
*/
_rodata_reserved_end = ABSOLUTE(.);
. = ALIGN (4);
arrays[rodata_noload]
mapping[rodata_noload]
} > default_rodata_seg
} > rodata_seg_low
.dram0.bss (NOLOAD) :
{
. = ALIGN(4);
_bss_start_low = ABSOLUTE(.);
/* ldgen places all bss-related data to mapping[dram0_bss] (See esp_system/app.lf). */
arrays[dram0_bss]
mapping[dram0_bss]
. = ALIGN(4);
_bss_end_low = ABSOLUTE(.);
} > sram_low
.dram1.bss (NOLOAD) :
{
. = ALIGN(4);
_bss_start_high = ABSOLUTE(.);
/* ldgen places all bss-related data to mapping[dram0_bss] (See esp_system/app.lf). */
mapping[dram0_bss]
. = ALIGN(4);
_bss_end_high = ABSOLUTE(.);
} > sram_high
/* Marks the end of data, bss and possibly rodata */
.dram0.heap_start (NOLOAD) :
.dram0.heap_start_low (NOLOAD) :
{
. = ALIGN (16);
_heap_start = ABSOLUTE(.);
} > dram0_0_seg
_heap_start_low = ABSOLUTE(.);
} > sram_low
/* Marks the end of data, bss and possibly rodata */
.dram1.heap_start_high (NOLOAD) :
{
. = ALIGN (16);
_heap_start_high = ABSOLUTE(.);
} > sram_high
}
ASSERT(((_iram_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)),
"IRAM0 segment data does not fit.")
ASSERT(((_heap_start - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)),
"DRAM segment data does not fit.")

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "ld.common"
/* Default entry point: */
ENTRY(call_start_cpu0);
@ -295,6 +297,7 @@ SECTIONS
* will be merged when creating the final bin image. */
. = ALIGN(ALIGNOF(.flash.rodata));
} >default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.appdesc, .flash.rodata)
.flash.rodata : ALIGN(0x10)
{

View File

@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "ld.common"
/* Default entry point */
ENTRY(call_start_cpu0);
@ -324,6 +326,7 @@ SECTIONS
* will be merged when creating the final bin image. */
. = ALIGN(ALIGNOF(.flash.rodata));
} >default_rodata_seg
ASSERT_SECTIONS_GAP(.flash.appdesc, .flash.rodata)
.flash.rodata : ALIGN(0x10)
{

View File

@ -1,33 +1,51 @@
# For each supported target, a memory.ld.in and sections.ld.in is processed and dictate the
# memory layout of the app.
#
# memory.ld.in goes through the preprocessor
# sections.ld.in goes through linker script generator
idf_build_get_property(target IDF_TARGET)
idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER)
set(ld_input "${CMAKE_CURRENT_LIST_DIR}/${target}/memory.ld.in")
set(ld_output "${CMAKE_CURRENT_BINARY_DIR}/ld/memory.ld")
target_linker_script(${COMPONENT_LIB} INTERFACE "${ld_output}")
idf_build_get_property(config_dir CONFIG_DIR)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/ld")
# Process the template file through the linker script generation mechanism, and use the output for linking the
# final binary
target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_LIST_DIR}/${target}/sections.ld.in"
# Cmake script that generates linker script from "*.ld.in" scripts using compiler preprocessor
set(linker_script_generator "${CMAKE_CURRENT_BINARY_DIR}/ld/linker_script_generator.cmake")
file(WRITE ${linker_script_generator}
[=[
execute_process(COMMAND "${CC}" "-C" "-P" "-x" "c" "-E" "-I" "${CONFIG_DIR}" "-I" "${LD_DIR}" "${SOURCE}"
RESULT_VARIABLE RET_CODE
OUTPUT_VARIABLE PREPROCESSED_LINKER_SCRIPT
ERROR_VARIABLE ERROR_VAR)
if(RET_CODE AND NOT RET_CODE EQUAL 0)
message(FATAL_ERROR "Can't generate ${TARGET}\nRET_CODE: ${RET_CODE}\nERROR_MESSAGE: ${ERROR_VAR}")
endif()
string(REPLACE "\\n" "\n" TEXT "${PREPROCESSED_LINKER_SCRIPT}")
file(WRITE "${TARGET}" "${TEXT}")
]=])
function(preprocess_linker_file name_in name_out out_path)
set(script_in "${CMAKE_CURRENT_LIST_DIR}/${target}/${name_in}")
set(script_out "${CMAKE_CURRENT_BINARY_DIR}/ld/${name_out}")
set(${out_path} ${script_out} PARENT_SCOPE)
add_custom_command(
OUTPUT ${script_out}
COMMAND ${CMAKE_COMMAND}
"-DCC=${CMAKE_C_COMPILER}"
"-DSOURCE=${script_in}"
"-DTARGET=${script_out}"
"-DCONFIG_DIR=${config_dir}"
"-DLD_DIR=${CMAKE_CURRENT_LIST_DIR}"
-P "${linker_script_generator}"
MAIN_DEPENDENCY ${script_in}
DEPENDS ${sdkconfig_header}
COMMENT "Generating ${script_out} linker script..."
VERBATIM)
add_custom_target("${name_out}" DEPENDS "${script_out}")
add_dependencies(${COMPONENT_LIB} "${name_out}")
endfunction()
# Generage memory.ld
preprocess_linker_file("memory.ld.in" "memory.ld" ld_out_path)
target_linker_script(${COMPONENT_LIB} INTERFACE "${ld_out_path}")
# Generage sections.ld.in and pass it through linker script generator
preprocess_linker_file("sections.ld.in" "sections.ld.in" ld_out_path)
target_linker_script(${COMPONENT_LIB} INTERFACE "${ld_out_path}"
PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/sections.ld")
idf_build_get_property(config_dir CONFIG_DIR)
# Preprocess memory.ld.in linker script to include configuration, becomes memory.ld
add_custom_command(
OUTPUT ${ld_output}
COMMAND "${CMAKE_C_COMPILER}" -C -P -x c -E -o ${ld_output} -I ${config_dir}
-I "${CMAKE_CURRENT_LIST_DIR}" ${ld_input}
MAIN_DEPENDENCY ${ld_input}
DEPENDS ${sdkconfig_header}
COMMENT "Generating memory.ld linker script..."
VERBATIM)
add_custom_target(memory_ld DEPENDS ${ld_output})
add_dependencies(${COMPONENT_LIB} memory_ld)

View File

@ -7,26 +7,26 @@
#include "sdkconfig.h"
/* CPU instruction prefetch padding size for flash mmap scenario */
_esp_flash_mmap_prefetch_pad_size = 16;
#define _esp_flash_mmap_prefetch_pad_size 16
/* CPU instruction prefetch padding size for memory protection scenario */
#ifdef CONFIG_SOC_MEMPROT_CPU_PREFETCH_PAD_SIZE
_esp_memprot_prefetch_pad_size = CONFIG_SOC_MEMPROT_CPU_PREFETCH_PAD_SIZE;
#define _esp_memprot_prefetch_pad_size CONFIG_SOC_MEMPROT_CPU_PREFETCH_PAD_SIZE
#else
_esp_memprot_prefetch_pad_size = 0;
#define _esp_memprot_prefetch_pad_size 0
#endif
/* Memory alignment size for PMS */
#ifdef CONFIG_SOC_MEMPROT_MEM_ALIGN_SIZE
_esp_memprot_align_size = CONFIG_SOC_MEMPROT_MEM_ALIGN_SIZE;
#define _esp_memprot_align_size CONFIG_SOC_MEMPROT_MEM_ALIGN_SIZE
#else
_esp_memprot_align_size = 0;
#define _esp_memprot_align_size 0
#endif
#if CONFIG_APP_BUILD_TYPE_RAM
_esp_mmu_block_size = 0;
#define _esp_mmu_block_size 0
#else
_esp_mmu_block_size = (CONFIG_MMU_PAGE_SIZE);
#define _esp_mmu_block_size CONFIG_MMU_PAGE_SIZE
#endif
#if CONFIG_SOC_RTC_MEM_SUPPORTED
@ -49,3 +49,8 @@ _esp_mmu_block_size = (CONFIG_MMU_PAGE_SIZE);
#define RESERVE_RTC_MEM (ESP_BOOTLOADER_RESERVE_RTC + RTC_TIMER_RESERVE_RTC)
#endif
#endif // SOC_RTC_MEM_SUPPORTED
#define QUOTED_STRING(STRING) #STRING
#define ASSERT_SECTIONS_GAP(PREV_SECTION, NEXT_SECTION) \
ASSERT((ADDR(NEXT_SECTION) == ADDR(PREV_SECTION) + SIZEOF(PREV_SECTION)), \
QUOTED_STRING(The gap between PREV_SECTION and NEXT_SECTION must not exist to produce the final bin image.))

View File

@ -123,8 +123,13 @@
#include "esp_private/startup_internal.h"
#include "esp_private/system_internal.h"
#if SOC_MEM_NON_CONTIGUOUS_SRAM
extern int _bss_start_low, _bss_start_high;
extern int _bss_end_low, _bss_end_high;
#else
extern int _bss_start;
extern int _bss_end;
#endif // SOC_MEM_NON_CONTIGUOUS_SRAM
extern int _rtc_bss_start;
extern int _rtc_bss_end;
#if CONFIG_BT_LE_RELEASE_IRAM_SUPPORTED
@ -413,7 +418,12 @@ void IRAM_ATTR call_start_cpu0(void)
#endif
//Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this.
#if SOC_MEM_NON_CONTIGUOUS_SRAM
memset(&_bss_start_low, 0, (&_bss_end_low - &_bss_start_low) * sizeof(_bss_start_low));
memset(&_bss_start_high, 0, (&_bss_end_high - &_bss_start_high) * sizeof(_bss_start_high));
#else
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
#endif // SOC_MEM_NON_CONTIGUOUS_SRAM
#if CONFIG_BT_LE_RELEASE_IRAM_SUPPORTED
// Clear Bluetooth bss

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -330,18 +330,14 @@ void vPortEndScheduler(void)
FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, uint32_t *ret_threadptr_reg_init)
{
/*
TLS layout at link-time, where 0xNNN is the offset that the linker calculates to a particular TLS variable.
LOW ADDRESS
|---------------------------| Linker Symbols
| Section | --------------
| .flash.rodata |
0x0|---------------------------| <- _flash_rodata_start
^ | Other Data |
| |---------------------------| <- _thread_local_start
| | .tbss | ^
V | | |
0xNNN | int example; | | tls_area_size
| .flash.tls |
0x0|---------------------------| <- _thread_local_start
| .tbss | ^
| | |
| int example; | | tls_area_size
| | |
| .tdata | V
|---------------------------| <- _thread_local_end
@ -351,7 +347,7 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u
HIGH ADDRESS
*/
// Calculate TLS area size and round up to multiple of 16 bytes.
extern char _thread_local_start, _thread_local_end, _flash_rodata_start;
extern char _thread_local_start, _thread_local_end;
const uint32_t tls_area_size = ALIGNUP(16, (uint32_t)&_thread_local_end - (uint32_t)&_thread_local_start);
// TODO: check that TLS area fits the stack
@ -360,27 +356,8 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u
// Initialize the TLS area with the initialization values of each TLS variable
memcpy((void *)uxStackPointer, &_thread_local_start, tls_area_size);
/*
Calculate the THREADPTR register's initialization value based on the link-time offset and the TLS area allocated on
the stack.
HIGH ADDRESS
|---------------------------|
| .tdata (*) |
^ | int example; |
| | |
| | .tbss (*) |
| |---------------------------| <- uxStackPointer (start of TLS area)
0xNNN | | | ^
| | | |
| ... | _thread_local_start - _rodata_start
| | | |
| | | V
V | | <- threadptr register's value
LOW ADDRESS
*/
*ret_threadptr_reg_init = (uint32_t)uxStackPointer - ((uint32_t)&_thread_local_start - (uint32_t)&_flash_rodata_start);
// Save tls start address
*ret_threadptr_reg_init = (uint32_t)uxStackPointer;
return uxStackPointer;
}

View File

@ -189,18 +189,14 @@ void vPortEndScheduler(void)
FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, uint32_t *ret_threadptr_reg_init)
{
/*
TLS layout at link-time, where 0xNNN is the offset that the linker calculates to a particular TLS variable.
LOW ADDRESS
|---------------------------| Linker Symbols
| Section | --------------
| .flash.rodata |
0x0|---------------------------| <- _flash_rodata_start
^ | Other Data |
| |---------------------------| <- _thread_local_start
| | .tbss | ^
V | | |
0xNNN | int example; | | tls_area_size
| .flash.tls |
0x0|---------------------------| <- _thread_local_start
| .tbss | ^
| | |
| int example; | | tls_area_size
| | |
| .tdata | V
|---------------------------| <- _thread_local_end
@ -210,7 +206,7 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u
HIGH ADDRESS
*/
// Calculate TLS area size and round up to multiple of 16 bytes.
extern char _thread_local_start, _thread_local_end, _flash_rodata_start;
extern char _thread_local_start, _thread_local_end;
const uint32_t tls_area_size = ALIGNUP(16, (uint32_t)&_thread_local_end - (uint32_t)&_thread_local_start);
// TODO: check that TLS area fits the stack
@ -219,27 +215,8 @@ FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, u
// Initialize the TLS area with the initialization values of each TLS variable
memcpy((void *)uxStackPointer, &_thread_local_start, tls_area_size);
/*
Calculate the THREADPTR register's initialization value based on the link-time offset and the TLS area allocated on
the stack.
HIGH ADDRESS
|---------------------------|
| .tdata (*) |
^ | int example; |
| | |
| | .tbss (*) |
| |---------------------------| <- uxStackPointer (start of TLS area)
0xNNN | | | ^
| | | |
| ... | _thread_local_start - _rodata_start
| | | |
| | | V
V | | <- threadptr register's value
LOW ADDRESS
*/
*ret_threadptr_reg_init = (uint32_t)uxStackPointer - ((uint32_t)&_thread_local_start - (uint32_t)&_flash_rodata_start);
// Save tls start address
*ret_threadptr_reg_init = (uint32_t)uxStackPointer;
return uxStackPointer;
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -89,7 +89,7 @@ const soc_memory_region_t soc_memory_regions[] = {
const size_t soc_memory_region_count = sizeof(soc_memory_regions) / sizeof(soc_memory_region_t);
extern int _data_start, _heap_start, _iram_start, _iram_end, _rtc_force_slow_end;
extern int _data_start, _bss_start_high, _heap_start_low, _heap_start_high, _iram_start, _iram_end, _rtc_force_slow_end;
extern int _tcm_text_start, _tcm_data_end;
extern int _rtc_reserved_start, _rtc_reserved_end;
@ -100,7 +100,8 @@ extern int _rtc_reserved_start, _rtc_reserved_end;
*/
// Static data region. DRAM used by data+bss and possibly rodata
SOC_RESERVE_MEMORY_REGION((intptr_t)&_data_start, (intptr_t)&_heap_start, dram_data);
SOC_RESERVE_MEMORY_REGION((intptr_t)&_data_start, (intptr_t)&_heap_start_low, dram_data_low);
SOC_RESERVE_MEMORY_REGION((intptr_t)&_bss_start_high, (intptr_t)&_heap_start_high, dram_data_high);
// Target has a shared D/IRAM virtual address, no need to calculate I_D_OFFSET like previous chips
SOC_RESERVE_MEMORY_REGION((intptr_t)&_iram_start, (intptr_t)&_iram_end, iram_code);

View File

@ -1403,6 +1403,10 @@ config SOC_MEM_TCM_SUPPORTED
bool
default y
config SOC_MEM_NON_CONTIGUOUS_SRAM
bool
default y
config SOC_EMAC_USE_IO_MUX
bool
default y

View File

@ -592,7 +592,7 @@
#define SOC_TSENS_IS_INDEPENDENT_FROM_ADC (1) /*!< Temperature sensor is a separate module, not share regs with ADC */
/*-------------------------- Memory CAPS --------------------------*/
#define SOC_MEM_TCM_SUPPORTED (1)
#define SOC_MEM_TCM_SUPPORTED (1)
#define SOC_MEM_NON_CONTIGUOUS_SRAM (1)
/*--------------------------- EMAC --------------------------------*/
#define SOC_EMAC_USE_IO_MUX (1) /*!< GPIO matrix is used to select GPIO pads */

View File

@ -532,26 +532,53 @@ The linker script template is the skeleton in which the generated placement rule
To reference the placement rules collected under a ``target`` token, the following syntax is used:
.. code-block:: none
.. only:: SOC_MEM_NON_CONTIGUOUS_SRAM
mapping[target]
.. code-block:: none
arrays[target] /* refers to objects under the SURROUND keyword */
mapping[target] /* refers to all other data */
.. only:: not SOC_MEM_NON_CONTIGUOUS_SRAM
.. code-block:: none
mapping[target]
Example:
The example below is an excerpt from a possible linker script template. It defines an output section ``.iram0.text``, and inside is a marker referencing the target ``iram0_text``.
.. code-block:: none
.. only:: SOC_MEM_NON_CONTIGUOUS_SRAM
.iram0.text :
{
/* Code marked as runnning out of IRAM */
_iram_text_start = ABSOLUTE(.);
.. code-block:: none
/* Marker referencing iram0_text */
mapping[iram0_text]
.iram0.text :
{
/* Code marked as runnning out of IRAM */
_iram_text_start = ABSOLUTE(.);
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
/* Markers referencing iram0_text */
arrays[iram0_text]
mapping[iram0_text]
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
.. only:: not SOC_MEM_NON_CONTIGUOUS_SRAM
.. code-block:: none
.iram0.text :
{
/* Code marked as runnning out of IRAM */
_iram_text_start = ABSOLUTE(.);
/* Marker referencing iram0_text */
mapping[iram0_text]
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
Suppose the generator collected the fragment definitions below:

View File

@ -532,26 +532,53 @@
如需引用一个 ``目标`` 标记下的所有存放规则,请使用以下语法:
.. code-block:: none
.. only:: SOC_MEM_NON_CONTIGUOUS_SRAM
mapping[target]
.. code-block:: none
arrays[target]
mapping[target]
.. only:: not SOC_MEM_NON_CONTIGUOUS_SRAM
.. code-block:: none
mapping[target]
示例:
以下示例是某个链接器脚本模板的摘录,定义了输出段 ``.iram0.text``,该输出段包含一个引用目标 ``iram0_text`` 的标记。
.. code-block:: none
.. only:: SOC_MEM_NON_CONTIGUOUS_SRAM
.iram0.text :
{
/* 标记 IRAM 空间不足 */
_iram_text_start = ABSOLUTE(.);
.. code-block:: none
/* 引用 iram0_text */
mapping[iram0_text]
.iram0.text :
{
/* 标记 IRAM 空间不足 */
_iram_text_start = ABSOLUTE(.);
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
/* 引用 iram0_text */
arrays[iram0_text]
mapping[iram0_text]
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
.. only:: not SOC_MEM_NON_CONTIGUOUS_SRAM
.. code-block:: none
.iram0.text :
{
/* 标记 IRAM 空间不足 */
_iram_text_start = ABSOLUTE(.);
/* 引用 iram0_text */
mapping[iram0_text]
_iram_text_end = ABSOLUTE(.);
} > iram0_0_seg
假设链接器脚本生成器收集到了以下片段定义:

View File

@ -1246,7 +1246,6 @@ tools/ldgen/test/data/linker_script.ld
tools/templates/sample_component/include/main.h
tools/templates/sample_component/main.c
tools/test_apps/build_system/embed_test/main/test_main.c
tools/test_apps/build_system/ldalign_test/main/test_main.c
tools/test_apps/build_system/ldgen_test/main/src1.c
tools/test_apps/build_system/ldgen_test/main/src2.c
tools/test_apps/build_system/ldgen_test/main/test_main.c

View File

@ -1,9 +1,8 @@
#!/usr/bin/env python
#
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
#
import argparse
import errno
import json
@ -19,7 +18,8 @@ from ldgen.generation import Generation
from ldgen.ldgen_common import LdGenFailure
from ldgen.linker_script import LinkerScript
from ldgen.sdkconfig import SDKConfig
from pyparsing import ParseException, ParseFatalException
from pyparsing import ParseException
from pyparsing import ParseFatalException
def _update_environment(args):
@ -148,7 +148,8 @@ def main():
raise LdGenFailure('failed to parse %s\n%s' % (fragment_file, str(e)))
generation_model.add_fragments_from_file(fragment_file)
mapping_rules = generation_model.generate(sections_infos)
non_contiguous_sram = sdkconfig.evaluate_expression('SOC_MEM_NON_CONTIGUOUS_SRAM')
mapping_rules = generation_model.generate(sections_infos, non_contiguous_sram)
script_model = LinkerScript(input_file)
script_model.fill(mapping_rules)

View File

@ -1,17 +1,22 @@
#
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
#
import collections
import fnmatch
import itertools
from collections import namedtuple
from .entity import Entity
from .fragments import Keep, Scheme, Sections, Sort, Surround
from .fragments import Keep
from .fragments import Scheme
from .fragments import Sections
from .fragments import Sort
from .fragments import Surround
from .ldgen_common import LdGenFailure
from .output_commands import AlignAtAddress, InputSectionDesc, SymbolAtAddress
from .output_commands import AlignAtAddress
from .output_commands import InputSectionDesc
from .output_commands import SymbolAtAddress
class Placement:
@ -149,7 +154,7 @@ class EntityNode:
return child
def get_output_commands(self):
def get_output_commands(self, non_contiguous_sram):
commands = collections.defaultdict(list)
def process_commands(cmds):
@ -157,18 +162,18 @@ class EntityNode:
commands[target].extend(commands_list)
# Process the commands generated from this node
node_commands = self.get_node_output_commands()
node_commands = self.get_node_output_commands(non_contiguous_sram)
process_commands(node_commands)
# Process the commands generated from this node's children
# recursively
for child in sorted(self.children, key=lambda c: c.name):
children_commands = child.get_output_commands()
children_commands = child.get_output_commands(non_contiguous_sram)
process_commands(children_commands)
return commands
def get_node_output_commands(self):
def get_node_output_commands(self, non_contiguous_sram):
commands = collections.defaultdict(list)
for sections in self.get_output_sections():
@ -176,6 +181,7 @@ class EntityNode:
if placement.is_significant():
assert placement.node == self
tied = False
keep = False
sort = None
surround_type = []
@ -188,14 +194,16 @@ class EntityNode:
elif isinstance(flag, Sort):
sort = (flag.first, flag.second)
else: # SURROUND or ALIGN
if non_contiguous_sram and isinstance(flag, Surround):
tied = True
surround_type.append(flag)
for flag in surround_type:
if flag.pre:
if isinstance(flag, Surround):
commands[placement.target].append(SymbolAtAddress('_%s_start' % flag.symbol))
commands[placement.target].append(SymbolAtAddress(f'_{flag.symbol}_start', tied))
else: # ALIGN
commands[placement.target].append(AlignAtAddress(flag.alignment))
commands[placement.target].append(AlignAtAddress(flag.alignment, tied))
# This is for expanded object node and symbol node placements without checking for
# the type.
@ -203,7 +211,7 @@ class EntityNode:
command_sections = sections if sections == placement_sections else placement_sections
command = InputSectionDesc(placement.node.entity, command_sections,
[e.node.entity for e in placement.exclusions], keep, sort)
[e.node.entity for e in placement.exclusions], keep, sort, tied)
commands[placement.target].append(command)
# Generate commands for intermediate, non-explicit exclusion placements here,
@ -211,15 +219,15 @@ class EntityNode:
for subplacement in placement.subplacements:
if not subplacement.flags and not subplacement.explicit:
command = InputSectionDesc(subplacement.node.entity, subplacement.sections,
[e.node.entity for e in subplacement.exclusions], keep, sort)
[e.node.entity for e in subplacement.exclusions], keep, sort, tied)
commands[placement.target].append(command)
for flag in surround_type:
if flag.post:
if isinstance(flag, Surround):
commands[placement.target].append(SymbolAtAddress('_%s_end' % flag.symbol))
commands[placement.target].append(SymbolAtAddress(f'_{flag.symbol}_end', tied))
else: # ALIGN
commands[placement.target].append(AlignAtAddress(flag.alignment))
commands[placement.target].append(AlignAtAddress(flag.alignment, tied))
return commands
@ -504,7 +512,7 @@ class Generation:
res.sort(key=lambda m: m.entity)
return res
def generate(self, entities):
def generate(self, entities, non_contiguous_sram):
scheme_dictionary = self._prepare_scheme_dictionary()
entity_mappings = self._prepare_entity_mappings(scheme_dictionary, entities)
root_node = RootNode()
@ -516,7 +524,7 @@ class Generation:
raise GenerationException(str(e))
# Traverse the tree, creating the placements
commands = root_node.get_output_commands()
commands = root_node.get_output_commands(non_contiguous_sram)
return commands

View File

@ -1,12 +1,13 @@
#
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
#
import collections
import os
from pyparsing import ParseException, Suppress, White
from pyparsing import ParseException
from pyparsing import Suppress
from pyparsing import White
from .fragments import Fragment
from .generation import GenerationException
@ -21,7 +22,8 @@ class LinkerScript:
The <target> is where output commands (see output_commands.py) are placed.
"""
Marker = collections.namedtuple('Marker', 'target indent rules')
MappingMarker = collections.namedtuple('MappingMarker', 'target indent rules')
ArraysMarker = collections.namedtuple('ArraysMarker', 'target indent rules')
def __init__(self, template_file):
self.members = []
@ -33,30 +35,39 @@ class LinkerScript:
lines = template_file.readlines()
target = Fragment.IDENTIFIER
reference = Suppress('mapping') + Suppress('[') + target + Suppress(']')
pattern = White(' \t') + reference
pattern_mapping = White(' \t') + Suppress('mapping') + Suppress('[') + target + Suppress(']')
pattern_arrays = White(' \t') + Suppress('arrays') + Suppress('[') + target + Suppress(']')
# Find the markers in the template file line by line. If line does not match marker grammar,
# set it as a literal to be copied as is to the output file.
for line in lines:
try:
parsed = pattern.parse_string(line)
except ParseException:
# Does not match marker syntax
parsed = False
for pattern in (pattern_arrays, pattern_mapping):
try:
indent, target = pattern.parse_string(line)
if pattern is pattern_arrays:
marker = LinkerScript.ArraysMarker(target, indent, [])
else:
marker = LinkerScript.MappingMarker(target, indent, [])
self.members.append(marker)
parsed = True
except ParseException:
continue
if not parsed:
# Does not match markers syntax
self.members.append(line)
else:
indent, target = parsed
marker = LinkerScript.Marker(target, indent, [])
self.members.append(marker)
def fill(self, mapping_rules):
for member in self.members:
target = None
try:
target = member.target
rules = member.rules
rules.extend(mapping_rules[target])
if isinstance(member, self.ArraysMarker):
rules = [x for x in mapping_rules[target] if x.tied]
else:
rules = [x for x in mapping_rules[target] if not x.tied]
member.rules.extend(rules)
except KeyError:
message = GenerationException.UNDEFINED_REFERENCE + " to target '" + target + "'."
raise GenerationException(message)

View File

@ -1,8 +1,7 @@
#
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
#
from .entity import Entity
# Contains classes for output section commands referred to in
@ -20,8 +19,9 @@ class AlignAtAddress:
command to be emitted.
"""
def __init__(self, alignment):
def __init__(self, alignment, tied=False):
self.alignment = alignment
self.tied = tied
def __str__(self):
return ('. = ALIGN(%d);' % self.alignment)
@ -43,8 +43,9 @@ class SymbolAtAddress:
an InputSectionDesc.
"""
def __init__(self, symbol):
def __init__(self, symbol, tied=False):
self.symbol = symbol
self.tied = tied
def __str__(self):
return ('%s = ABSOLUTE(.);' % self.symbol)
@ -64,7 +65,7 @@ class InputSectionDesc:
the emitted input section description.
"""
def __init__(self, entity, sections, exclusions=None, keep=False, sort=None):
def __init__(self, entity, sections, exclusions=None, keep=False, sort=None, tied=False):
assert entity.specificity != Entity.Specificity.SYMBOL
self.entity = entity
@ -81,6 +82,7 @@ class InputSectionDesc:
self.keep = keep
self.sort = sort
self.tied = tied
def __str__(self):
sections_string = '( )'

View File

@ -1,9 +1,8 @@
#!/usr/bin/env python
#
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
#
import collections
import fnmatch
import os
@ -123,7 +122,7 @@ class DefaultMappingTest(GenerationTest):
# Checks that default rules are generated from
# the default scheme properly and even if no mappings
# are defined.
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
self.compare_rules(expected, actual)
@ -234,7 +233,7 @@ entries:
* (noflash) #1
"""
self.add_fragments(alt if alt else mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -272,7 +271,7 @@ entries:
"""
self.add_fragments(alt if alt else mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -311,7 +310,7 @@ entries:
croutine:prvCheckPendingReadyList (noflash) #1
"""
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -367,7 +366,7 @@ entries:
"""
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -428,7 +427,7 @@ entries:
croutine:prvCheckPendingReadyList (default) #2
"""
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -497,7 +496,7 @@ entries:
"""
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -591,7 +590,7 @@ entries:
"""
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -642,7 +641,7 @@ entries:
"""
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
# Generate default command A
@ -690,7 +689,7 @@ entries:
croutine (noflash_data) #2
"""
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -744,7 +743,7 @@ entries:
croutine (noflash_data) #2
"""
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -783,7 +782,7 @@ entries:
self.add_fragments(alt if alt else mapping)
with self.assertRaises(GenerationException):
self.generation.generate(self.entities)
self.generation.generate(self.entities, False)
def test_same_entity_conflicting_section(self):
# Test same entity being mapped by scheme conflicting with another.
@ -862,7 +861,7 @@ entries:
"""
self.add_fragments(alt if alt else mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -951,7 +950,7 @@ entries:
"""
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -1048,7 +1047,7 @@ entries:
"""
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -1090,7 +1089,7 @@ entries:
self.add_fragments(mapping)
with self.assertRaises(GenerationException):
self.generation.generate(self.entities)
self.generation.generate(self.entities, False)
def test_root_mapping_fragment_conflict(self):
# Test that root mapping fragments are also checked for
@ -1111,7 +1110,7 @@ entries:
self.add_fragments(mapping)
with self.assertRaises(GenerationException):
self.generation.generate(self.entities)
self.generation.generate(self.entities, False)
def test_root_mapping_fragment_duplicate(self):
# Same root mappings have no effect.
@ -1135,7 +1134,7 @@ entries:
"""
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
# Generate default command A
@ -1180,7 +1179,7 @@ entries:
self.add_fragments(scheme)
self.add_fragments(alt if alt else mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
if perf >= 1:
@ -1231,7 +1230,7 @@ entries:
self.generation.mappings = {}
self.add_fragments(alt if alt else mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
if perf_level < 4 and perf_level > 0:
@ -1331,7 +1330,7 @@ entries:
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -1394,7 +1393,7 @@ entries:
self.generation.mappings = {}
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -1451,7 +1450,7 @@ entries:
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -1507,7 +1506,7 @@ entries:
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -1564,7 +1563,7 @@ entries:
self.generation.mappings = {}
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -1621,7 +1620,7 @@ entries:
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -1665,7 +1664,7 @@ entries:
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -1692,7 +1691,7 @@ entries:
self.add_fragments(mapping)
actual = self.generation.generate(self.entities)
actual = self.generation.generate(self.entities, False)
expected = self.generate_default_rules()
flash_text = expected['flash_text']
@ -1719,7 +1718,7 @@ entries:
self.add_fragments(mapping)
with self.assertRaises(GenerationException):
self.generation.generate(self.entities)
self.generation.generate(self.entities, False)
if __name__ == '__main__':

View File

@ -16,6 +16,10 @@ tools/test_apps/build_system/embed_test:
temporary: false
reason: Hardware independent feature, no need to test on all targets
tools/test_apps/build_system/ld_non_contiguous_memory:
disable:
- if: SOC_MEM_NON_CONTIGUOUS_SRAM != 1
tools/test_apps/linux_compatible/driver_mock:
enable:
- if: IDF_TARGET == "linux"

View File

@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_non_contiguous_regions)

View File

@ -0,0 +1,2 @@
| Supported Targets | ESP32-P4 |
| ----------------- | -------- |

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "test_app_main.c"
LDFRAGMENTS "linker.lf")

View File

@ -0,0 +1,13 @@
[sections:main_dram]
entries:
buf1
buf2
[scheme:main_dram_config]
entries:
main_dram -> dram0_bss
[mapping:main]
archive: libmain.a
entries:
* (main_dram_config)

View File

@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <stdio.h>
#include <inttypes.h>
extern int _bss_start_low, _bss_start_high;
extern int _bss_end_low, _bss_end_high;
char buf1[100 * 1024];
char buf2[100 * 1024];
static void test_mem_write(char* buf, size_t size_bytes, int seed)
{
srand(seed);
for (size_t i = 0; i < size_bytes; ++i) {
buf[i] = (char) (rand() % 256);
}
}
static void test_mem_read(char* buf, size_t size_bytes, int seed)
{
size_t num_errors = 0;
srand(seed);
printf("Testing at %p ... ", buf);
for (size_t i = 0; i < size_bytes; ++i) {
if (buf[i] != (char) (rand() % 256)) {
++num_errors;
}
}
printf("%s!\n", num_errors == 0 ? "OK" : "ERROR");
}
void app_main(void)
{
if (! (((void *)&_bss_start_low <= (void *)buf2) && ((void *)buf2 < (void *)&_bss_end_low)))
printf("buf2 (%p) is expected to be placed in low sram (%p .. %p)\n", buf2, &_bss_start_low, &_bss_end_low);
else
printf("buf2 placed in low sram\n");
if (! ((void *)&_bss_start_high <= (void *)buf1 && (void *)buf1 < (void *)&_bss_end_high))
printf("buf1 (%p) is expected to be placed in high sram (%p .. %p)\n", buf1, &_bss_start_high, &_bss_end_high);
else
printf("buf1 placed in high sram\n");
test_mem_write(buf2, sizeof(buf1), 1);
test_mem_write(buf1, sizeof(buf1), 0);
test_mem_read(buf1, sizeof(buf1), 0);
test_mem_read(buf2, sizeof(buf2), 1);
test_mem_write(buf2, sizeof(buf1), 1);
test_mem_read(buf1, sizeof(buf1), 0);
test_mem_read(buf2, sizeof(buf2), 1);
}

View File

@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
TEST_APP_IN_FLASH = [pytest.param('app_in_flash', marks=pytest.mark.esp32p4)]
@pytest.mark.esp32p4
@pytest.mark.generic
@pytest.mark.parametrize('config', TEST_APP_IN_FLASH, indirect=True)
def test_ld_non_contiguous_memory(dut: Dut) -> None:
dut.expect_exact('buf2 placed in low sram')
dut.expect_exact('buf1 placed in high sram')
for _ in range(0, 4):
dut.expect(r'Testing at 0x[0-9a-f]+ ... OK!')

View File

@ -1,22 +0,0 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
#"Trim" the build. Include the minimal set of components, main, and anything it depends on.
set(COMPONENTS main)
project(ldalign_test)
idf_build_get_property(python PYTHON)
idf_build_get_property(elf EXECUTABLE)
set(check_alignment "${CMAKE_CURRENT_LIST_DIR}/check_alignment.py")
set(readelf "${_CMAKE_TOOLCHAIN_PREFIX}readelf")
add_custom_command(
TARGET ${elf}
POST_BUILD
COMMAND ${python} ${check_alignment} ${readelf} $<TARGET_FILE:${elf}>
)

View File

@ -1,2 +0,0 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |

View File

@ -1,7 +0,0 @@
Runs a build test to check alignment and position of `.flash.appdesc` and
`.flash.rodata` sections. Indeed, `.flash.appdesc` shall ALWAYS be aligned on
a 16-byte bounds, whereas `.flash.rodata` can have any alignment. In any case,
the end address of first one shall match the start address of the second one.
This will let both of them be merged when generating the final bin image.
The Python script that performs the checks, `check_alignment.py`, automatically
runs after the app is built.

View File

@ -1,53 +0,0 @@
#!/usr/bin/env python
#
# SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
#
import argparse
import re
import subprocess
from typing import Tuple
argparser = argparse.ArgumentParser()
argparser.add_argument('readelf')
argparser.add_argument('elf')
args = argparser.parse_args()
# Get the content of the readelf command
contents = subprocess.check_output([args.readelf, '-S', args.elf]).decode()
# Define a class for readelf parsing error
class ParsingError(Exception):
pass
# Look for the start address and size of any section
def find_partition_info(sectionname): # type: (str) -> Tuple[int, int, int]
match = re.search(sectionname + r'\s+PROGBITS\s+([a-f0-9]+) [a-f0-9]+ ([a-f0-9]+) \d+\s+[A-Z]+ 0 0 (\d+)',
contents)
if not match:
raise ParsingError('ELF header parsing error')
# Return the address of the section, the size and the alignment
address = match.group(1)
size = match.group(2)
alignment = match.group(3)
return (int(address, 16), int(size, 16), int(alignment, 10))
# Get address and size for .flash.appdesc section
app_address, app_size, app_align = find_partition_info('.flash.appdesc')
# Same goes for .flash.rodata section
rodata_address, _, rodata_align = find_partition_info('.flash.rodata')
# Assert than everything is as expected:
# appdesc is aligned on 16
# rodata is aligned on 64
# appdesc ends where rodata starts
assert app_align == 16, '.flash.appdesc section should have been aligned on 16!'
assert rodata_align == 64, '.flash.rodata section should have been aligned on 64!'
assert app_address + app_size == rodata_address, ".flash.appdesc's end address and .flash.rodata's begin start must have no gap in between!"

View File

@ -1,3 +0,0 @@
idf_component_register(SRCS "test_main.c"
INCLUDE_DIRS ".")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -1,16 +0,0 @@
#include <stdio.h>
const static uint32_t __attribute__ ((aligned (64))) testTab[] =
{
0xff445566, 0x44556677, 0x33221100,
0x88997755, 0x99887755, 0x88997755,
0x99546327, 0x7946fa9e, 0xa6b5f8ee,
0x12345678
};
void app_main(void)
{
/* Do something with the array, in order to avoid it being discarded. */
for (uint32_t i = 0; i < 10; i++)
printf ("%x\n", testTab[i]);
}

View File

@ -16,6 +16,10 @@ if(NOT CONFIG_SOC_RTC_MEM_SUPPORTED)
set(args "--no-rtc")
endif()
if(CONFIG_SOC_MEM_NON_CONTIGUOUS_SRAM)
set(args "--non-contiguous-sram")
endif()
add_custom_command(
TARGET ${elf}
POST_BUILD

View File

@ -1,22 +1,27 @@
#!/usr/bin/env python
#
# SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
#
# Check placements in this test app for main
# specified in main/linker.lf
import argparse
import subprocess
from pyparsing import LineEnd, LineStart, Literal, Optional, Word, alphanums, hexnums
from pyparsing import alphanums
from pyparsing import hexnums
from pyparsing import LineEnd
from pyparsing import LineStart
from pyparsing import Literal
from pyparsing import Optional
from pyparsing import Word
argparser = argparse.ArgumentParser()
argparser.add_argument('objdump')
argparser.add_argument('elf')
argparser.add_argument('--no-rtc', action='store_true')
argparser.add_argument('--non-contiguous-sram', action='store_true')
args = argparser.parse_args()
@ -57,6 +62,15 @@ assert sym1_start % 9 == 0, '_sym1_start is not aligned as specified in linker f
assert sym1_end % 12 == 0, '_sym1_end is not aligned as specified in linker fragment'
print('check placement pass: _sym1_start < func1 < __sym1_end and alignments checked')
func0 = check_location('func0', '.iram0.text')
if args.non_contiguous_sram:
assert func1 < func0, 'check placement fail: func1 comes after func0'
print('check placement pass: func1 < func0 checked')
else:
assert func1 > func0, 'check placement fail: func0 comes after func1'
print('check placement pass: func1 > func0 checked')
# src1:func2 (rtc) - explicit mapping for func2 using 'rtc' scheme
if not args.no_rtc:
check_location('func2', '.rtc.text')

View File

@ -5,5 +5,7 @@ entries:
src1 (default)
src1:func1 (noflash);
text->iram0_text KEEP() ALIGN(9) ALIGN(12, post) SURROUND(sym1)
src1:func0 (noflash);
text->iram0_text KEEP()
if SOC_RTC_MEM_SUPPORTED = y:
src1:func2 (rtc)

View File

@ -1,5 +1,10 @@
#include <stdio.h>
void func0(void)
{
printf("Hello from func0!\n");
}
void func1(void)
{
printf("Hello from func1!\n");