mirror of
https://github.com/espressif/esp-idf.git
synced 2025-11-02 16:11:41 +01:00
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:
@@ -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"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(test_non_contiguous_regions)
|
||||
@@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32-P4 |
|
||||
| ----------------- | -------- |
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "test_app_main.c"
|
||||
LDFRAGMENTS "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)
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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!')
|
||||
@@ -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}>
|
||||
)
|
||||
@@ -1,2 +0,0 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
@@ -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.
|
||||
@@ -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!"
|
||||
@@ -1,3 +0,0 @@
|
||||
idf_component_register(SRCS "test_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
@@ -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]);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void func0(void)
|
||||
{
|
||||
printf("Hello from func0!\n");
|
||||
}
|
||||
|
||||
void func1(void)
|
||||
{
|
||||
printf("Hello from func1!\n");
|
||||
|
||||
Reference in New Issue
Block a user