From 824c8e05932bac81ac76080917da4267e66b999d Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Mon, 12 Feb 2024 09:51:25 +0400 Subject: [PATCH] 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 --- .../esp_bootloader_desc.c | 8 +- components/esp_system/CMakeLists.txt | 4 + components/esp_system/ld/esp32/sections.ld.in | 4 + .../esp_system/ld/esp32c2/sections.ld.in | 27 ++-- .../esp_system/ld/esp32c3/sections.ld.in | 27 ++-- .../esp_system/ld/esp32c5/sections.ld.in | 30 ++-- components/esp_system/ld/esp32c6/memory.ld.in | 30 +--- .../esp_system/ld/esp32c6/sections.ld.in | 60 +++----- components/esp_system/ld/esp32h2/memory.ld.in | 30 +--- .../esp_system/ld/esp32h2/sections.ld.in | 60 +++----- components/esp_system/ld/esp32p4/memory.ld.in | 42 +++--- .../esp_system/ld/esp32p4/sections.ld.in | 137 ++++++++++-------- .../esp_system/ld/esp32s2/sections.ld.in | 3 + .../esp_system/ld/esp32s3/sections.ld.in | 3 + components/esp_system/ld/ld.cmake | 72 +++++---- components/esp_system/ld/ld.common | 19 ++- components/esp_system/port/cpu_start.c | 10 ++ .../FreeRTOS-Kernel-SMP/portable/riscv/port.c | 41 ++---- .../FreeRTOS-Kernel/portable/riscv/port.c | 39 +---- components/heap/port/esp32p4/memory_layout.c | 7 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32p4/include/soc/soc_caps.h | 4 +- .../api-guides/linker-script-generation.rst | 49 +++++-- .../api-guides/linker-script-generation.rst | 49 +++++-- tools/ci/check_copyright_ignore.txt | 1 - tools/ldgen/ldgen.py | 9 +- tools/ldgen/ldgen/generation.py | 40 +++-- tools/ldgen/ldgen/linker_script.py | 43 ++++-- tools/ldgen/ldgen/output_commands.py | 12 +- tools/ldgen/test/test_generation.py | 61 ++++---- tools/test_apps/.build-test-rules.yml | 4 + .../ld_non_contiguous_memory/CMakeLists.txt | 4 + .../ld_non_contiguous_memory/README.md | 2 + .../main/CMakeLists.txt | 2 + .../ld_non_contiguous_memory/main/linker.lf | 13 ++ .../main/test_app_main.c | 55 +++++++ .../pytest_ld_non_contiguous_memory.py | 17 +++ .../build_system/ldalign_test/CMakeLists.txt | 22 --- .../build_system/ldalign_test/README.md | 2 - .../build_system/ldalign_test/README.txt | 7 - .../ldalign_test/check_alignment.py | 53 ------- .../ldalign_test/main/CMakeLists.txt | 3 - .../ldalign_test/main/test_main.c | 16 -- .../build_system/ldgen_test/CMakeLists.txt | 4 + .../ldgen_test/check_placements.py | 22 ++- .../build_system/ldgen_test/main/linker.lf | 2 + .../build_system/ldgen_test/main/src1.c | 5 + 47 files changed, 604 insertions(+), 554 deletions(-) create mode 100644 tools/test_apps/build_system/ld_non_contiguous_memory/CMakeLists.txt create mode 100644 tools/test_apps/build_system/ld_non_contiguous_memory/README.md create mode 100644 tools/test_apps/build_system/ld_non_contiguous_memory/main/CMakeLists.txt create mode 100644 tools/test_apps/build_system/ld_non_contiguous_memory/main/linker.lf create mode 100644 tools/test_apps/build_system/ld_non_contiguous_memory/main/test_app_main.c create mode 100644 tools/test_apps/build_system/ld_non_contiguous_memory/pytest_ld_non_contiguous_memory.py delete mode 100644 tools/test_apps/build_system/ldalign_test/CMakeLists.txt delete mode 100644 tools/test_apps/build_system/ldalign_test/README.md delete mode 100644 tools/test_apps/build_system/ldalign_test/README.txt delete mode 100644 tools/test_apps/build_system/ldalign_test/check_alignment.py delete mode 100644 tools/test_apps/build_system/ldalign_test/main/CMakeLists.txt delete mode 100644 tools/test_apps/build_system/ldalign_test/main/test_main.c diff --git a/components/esp_bootloader_format/esp_bootloader_desc.c b/components/esp_bootloader_format/esp_bootloader_desc.c index 545cc41143..fdcc2049ba 100644 --- a/components/esp_bootloader_format/esp_bootloader_desc.c +++ b/components/esp_bootloader_format/esp_bootloader_desc.c @@ -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, diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index a3276ad2c2..94e723a1b6 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -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() diff --git a/components/esp_system/ld/esp32/sections.ld.in b/components/esp_system/ld/esp32/sections.ld.in index 3f4da1a6e2..b4fc9ea0e2 100644 --- a/components/esp_system/ld/esp32/sections.ld.in +++ b/components/esp_system/ld/esp32/sections.ld.in @@ -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) { diff --git a/components/esp_system/ld/esp32c2/sections.ld.in b/components/esp_system/ld/esp32c2/sections.ld.in index f42334f87b..8e5feaeb17 100644 --- a/components/esp_system/ld/esp32c2/sections.ld.in +++ b/components/esp_system/ld/esp32c2/sections.ld.in @@ -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. */ diff --git a/components/esp_system/ld/esp32c3/sections.ld.in b/components/esp_system/ld/esp32c3/sections.ld.in index 70e1e08377..1c1a48af61 100644 --- a/components/esp_system/ld/esp32c3/sections.ld.in +++ b/components/esp_system/ld/esp32c3/sections.ld.in @@ -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. */ diff --git a/components/esp_system/ld/esp32c5/sections.ld.in b/components/esp_system/ld/esp32c5/sections.ld.in index e777129842..fcb2f4755b 100644 --- a/components/esp_system/ld/esp32c5/sections.ld.in +++ b/components/esp_system/ld/esp32c5/sections.ld.in @@ -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. */ diff --git a/components/esp_system/ld/esp32c6/memory.ld.in b/components/esp_system/ld/esp32c6/memory.ld.in index a286d87d31..389113a128 100644 --- a/components/esp_system/ld/esp32c6/memory.ld.in +++ b/components/esp_system/ld/esp32c6/memory.ld.in @@ -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 /** diff --git a/components/esp_system/ld/esp32c6/sections.ld.in b/components/esp_system/ld/esp32c6/sections.ld.in index db73f9021d..8c55675fbf 100644 --- a/components/esp_system/ld/esp32c6/sections.ld.in +++ b/components/esp_system/ld/esp32c6/sections.ld.in @@ -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.") diff --git a/components/esp_system/ld/esp32h2/memory.ld.in b/components/esp_system/ld/esp32h2/memory.ld.in index b7f69707ff..a4591890dd 100644 --- a/components/esp_system/ld/esp32h2/memory.ld.in +++ b/components/esp_system/ld/esp32h2/memory.ld.in @@ -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 /** diff --git a/components/esp_system/ld/esp32h2/sections.ld.in b/components/esp_system/ld/esp32h2/sections.ld.in index de2f7eeb04..b353bac612 100644 --- a/components/esp_system/ld/esp32h2/sections.ld.in +++ b/components/esp_system/ld/esp32h2/sections.ld.in @@ -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.") diff --git a/components/esp_system/ld/esp32p4/memory.ld.in b/components/esp_system/ld/esp32p4/memory.ld.in index 47a2bb34c3..8d2910c164 100644 --- a/components/esp_system/ld/esp32p4/memory.ld.in +++ b/components/esp_system/ld/esp32p4/memory.ld.in @@ -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 diff --git a/components/esp_system/ld/esp32p4/sections.ld.in b/components/esp_system/ld/esp32p4/sections.ld.in index d029244f23..ff10f4e550 100644 --- a/components/esp_system/ld/esp32p4/sections.ld.in +++ b/components/esp_system/ld/esp32p4/sections.ld.in @@ -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.") diff --git a/components/esp_system/ld/esp32s2/sections.ld.in b/components/esp_system/ld/esp32s2/sections.ld.in index 681e686c85..119f29eb46 100644 --- a/components/esp_system/ld/esp32s2/sections.ld.in +++ b/components/esp_system/ld/esp32s2/sections.ld.in @@ -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) { diff --git a/components/esp_system/ld/esp32s3/sections.ld.in b/components/esp_system/ld/esp32s3/sections.ld.in index 850305ee69..5e86deb7ae 100644 --- a/components/esp_system/ld/esp32s3/sections.ld.in +++ b/components/esp_system/ld/esp32s3/sections.ld.in @@ -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) { diff --git a/components/esp_system/ld/ld.cmake b/components/esp_system/ld/ld.cmake index 5e80268da7..aa8c1b8121 100644 --- a/components/esp_system/ld/ld.cmake +++ b/components/esp_system/ld/ld.cmake @@ -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) diff --git a/components/esp_system/ld/ld.common b/components/esp_system/ld/ld.common index 867adc6f0a..f5ec5ff726 100644 --- a/components/esp_system/ld/ld.common +++ b/components/esp_system/ld/ld.common @@ -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.)) diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index aef3bd3633..2cca0dae66 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -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 diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c index e6fe3258b4..5af4c851f5 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c @@ -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; } diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index bcb2855c00..1003d56617 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -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; } diff --git a/components/heap/port/esp32p4/memory_layout.c b/components/heap/port/esp32p4/memory_layout.c index dc5afa7496..127f61da45 100644 --- a/components/heap/port/esp32p4/memory_layout.c +++ b/components/heap/port/esp32p4/memory_layout.c @@ -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); diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index b2ede9b4d6..44613dcf84 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -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 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 93274a13f8..f971bdd9a1 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -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 */ diff --git a/docs/en/api-guides/linker-script-generation.rst b/docs/en/api-guides/linker-script-generation.rst index 92964f8b2b..72075b1652 100644 --- a/docs/en/api-guides/linker-script-generation.rst +++ b/docs/en/api-guides/linker-script-generation.rst @@ -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: diff --git a/docs/zh_CN/api-guides/linker-script-generation.rst b/docs/zh_CN/api-guides/linker-script-generation.rst index 5877ac8fcd..f037498db0 100644 --- a/docs/zh_CN/api-guides/linker-script-generation.rst +++ b/docs/zh_CN/api-guides/linker-script-generation.rst @@ -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 假设链接器脚本生成器收集到了以下片段定义: diff --git a/tools/ci/check_copyright_ignore.txt b/tools/ci/check_copyright_ignore.txt index b4645eeed4..d58426465b 100644 --- a/tools/ci/check_copyright_ignore.txt +++ b/tools/ci/check_copyright_ignore.txt @@ -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 diff --git a/tools/ldgen/ldgen.py b/tools/ldgen/ldgen.py index 5f19b7b553..41a854e258 100755 --- a/tools/ldgen/ldgen.py +++ b/tools/ldgen/ldgen.py @@ -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) diff --git a/tools/ldgen/ldgen/generation.py b/tools/ldgen/ldgen/generation.py index a2743e7424..c3697c86fd 100644 --- a/tools/ldgen/ldgen/generation.py +++ b/tools/ldgen/ldgen/generation.py @@ -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 diff --git a/tools/ldgen/ldgen/linker_script.py b/tools/ldgen/ldgen/linker_script.py index 59405e2fc9..c57188f418 100644 --- a/tools/ldgen/ldgen/linker_script.py +++ b/tools/ldgen/ldgen/linker_script.py @@ -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 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) diff --git a/tools/ldgen/ldgen/output_commands.py b/tools/ldgen/ldgen/output_commands.py index ae8e2b7027..e7d32dd64e 100644 --- a/tools/ldgen/ldgen/output_commands.py +++ b/tools/ldgen/ldgen/output_commands.py @@ -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 = '( )' diff --git a/tools/ldgen/test/test_generation.py b/tools/ldgen/test/test_generation.py index 742a7e3032..3b4061a732 100755 --- a/tools/ldgen/test/test_generation.py +++ b/tools/ldgen/test/test_generation.py @@ -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__': diff --git a/tools/test_apps/.build-test-rules.yml b/tools/test_apps/.build-test-rules.yml index 12f15f9dce..a4347ccae5 100644 --- a/tools/test_apps/.build-test-rules.yml +++ b/tools/test_apps/.build-test-rules.yml @@ -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" diff --git a/tools/test_apps/build_system/ld_non_contiguous_memory/CMakeLists.txt b/tools/test_apps/build_system/ld_non_contiguous_memory/CMakeLists.txt new file mode 100644 index 0000000000..0ce29970dd --- /dev/null +++ b/tools/test_apps/build_system/ld_non_contiguous_memory/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test_non_contiguous_regions) diff --git a/tools/test_apps/build_system/ld_non_contiguous_memory/README.md b/tools/test_apps/build_system/ld_non_contiguous_memory/README.md new file mode 100644 index 0000000000..909282018f --- /dev/null +++ b/tools/test_apps/build_system/ld_non_contiguous_memory/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | diff --git a/tools/test_apps/build_system/ld_non_contiguous_memory/main/CMakeLists.txt b/tools/test_apps/build_system/ld_non_contiguous_memory/main/CMakeLists.txt new file mode 100644 index 0000000000..8c36f76153 --- /dev/null +++ b/tools/test_apps/build_system/ld_non_contiguous_memory/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "test_app_main.c" + LDFRAGMENTS "linker.lf") diff --git a/tools/test_apps/build_system/ld_non_contiguous_memory/main/linker.lf b/tools/test_apps/build_system/ld_non_contiguous_memory/main/linker.lf new file mode 100644 index 0000000000..916f738bb2 --- /dev/null +++ b/tools/test_apps/build_system/ld_non_contiguous_memory/main/linker.lf @@ -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) diff --git a/tools/test_apps/build_system/ld_non_contiguous_memory/main/test_app_main.c b/tools/test_apps/build_system/ld_non_contiguous_memory/main/test_app_main.c new file mode 100644 index 0000000000..c71d2bef94 --- /dev/null +++ b/tools/test_apps/build_system/ld_non_contiguous_memory/main/test_app_main.c @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: CC0-1.0 + */ + +#include +#include + +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); +} diff --git a/tools/test_apps/build_system/ld_non_contiguous_memory/pytest_ld_non_contiguous_memory.py b/tools/test_apps/build_system/ld_non_contiguous_memory/pytest_ld_non_contiguous_memory.py new file mode 100644 index 0000000000..3bb473f033 --- /dev/null +++ b/tools/test_apps/build_system/ld_non_contiguous_memory/pytest_ld_non_contiguous_memory.py @@ -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!') diff --git a/tools/test_apps/build_system/ldalign_test/CMakeLists.txt b/tools/test_apps/build_system/ldalign_test/CMakeLists.txt deleted file mode 100644 index 4a269001e1..0000000000 --- a/tools/test_apps/build_system/ldalign_test/CMakeLists.txt +++ /dev/null @@ -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} $ -) diff --git a/tools/test_apps/build_system/ldalign_test/README.md b/tools/test_apps/build_system/ldalign_test/README.md deleted file mode 100644 index bf47d80ec6..0000000000 --- a/tools/test_apps/build_system/ldalign_test/README.md +++ /dev/null @@ -1,2 +0,0 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/tools/test_apps/build_system/ldalign_test/README.txt b/tools/test_apps/build_system/ldalign_test/README.txt deleted file mode 100644 index a6299c7fad..0000000000 --- a/tools/test_apps/build_system/ldalign_test/README.txt +++ /dev/null @@ -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. diff --git a/tools/test_apps/build_system/ldalign_test/check_alignment.py b/tools/test_apps/build_system/ldalign_test/check_alignment.py deleted file mode 100644 index a5cc4c60d0..0000000000 --- a/tools/test_apps/build_system/ldalign_test/check_alignment.py +++ /dev/null @@ -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!" diff --git a/tools/test_apps/build_system/ldalign_test/main/CMakeLists.txt b/tools/test_apps/build_system/ldalign_test/main/CMakeLists.txt deleted file mode 100644 index e7ddb446f8..0000000000 --- a/tools/test_apps/build_system/ldalign_test/main/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -idf_component_register(SRCS "test_main.c" - INCLUDE_DIRS ".") -target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/tools/test_apps/build_system/ldalign_test/main/test_main.c b/tools/test_apps/build_system/ldalign_test/main/test_main.c deleted file mode 100644 index 160197ba59..0000000000 --- a/tools/test_apps/build_system/ldalign_test/main/test_main.c +++ /dev/null @@ -1,16 +0,0 @@ -#include - -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]); -} diff --git a/tools/test_apps/build_system/ldgen_test/CMakeLists.txt b/tools/test_apps/build_system/ldgen_test/CMakeLists.txt index 0cc92d4b72..928b59de43 100644 --- a/tools/test_apps/build_system/ldgen_test/CMakeLists.txt +++ b/tools/test_apps/build_system/ldgen_test/CMakeLists.txt @@ -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 diff --git a/tools/test_apps/build_system/ldgen_test/check_placements.py b/tools/test_apps/build_system/ldgen_test/check_placements.py index e2dcd93c84..174793e2eb 100644 --- a/tools/test_apps/build_system/ldgen_test/check_placements.py +++ b/tools/test_apps/build_system/ldgen_test/check_placements.py @@ -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') diff --git a/tools/test_apps/build_system/ldgen_test/main/linker.lf b/tools/test_apps/build_system/ldgen_test/main/linker.lf index 63150db29d..17f0490949 100644 --- a/tools/test_apps/build_system/ldgen_test/main/linker.lf +++ b/tools/test_apps/build_system/ldgen_test/main/linker.lf @@ -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) diff --git a/tools/test_apps/build_system/ldgen_test/main/src1.c b/tools/test_apps/build_system/ldgen_test/main/src1.c index c8be4906da..775f53834c 100644 --- a/tools/test_apps/build_system/ldgen_test/main/src1.c +++ b/tools/test_apps/build_system/ldgen_test/main/src1.c @@ -1,5 +1,10 @@ #include +void func0(void) +{ + printf("Hello from func0!\n"); +} + void func1(void) { printf("Hello from func1!\n");