forked from espressif/esp-idf
memory: port SPIRAM noinit segment support to master
This commit is contained in:
committed by
Armando (Dou Yiwen)
parent
a542f1b67d
commit
ad8e1a395c
@@ -3,89 +3,10 @@ if(NOT "${target}" STREQUAL "esp32")
|
|||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
idf_build_get_property(sdkconfig_header SDKCONFIG_HEADER)
|
if(NOT BOOTLOADER_BUILD)
|
||||||
|
# [refactor-todo] propagate these requirements for compatibility
|
||||||
if(BOOTLOADER_BUILD)
|
# remove in the future
|
||||||
# For bootloader, all we need from esp32 is headers
|
set(legacy_reqs driver efuse soc)
|
||||||
idf_component_register(INCLUDE_DIRS include REQUIRES xtensa)
|
|
||||||
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.peripherals.ld")
|
|
||||||
else()
|
|
||||||
# Regular app build
|
|
||||||
set(srcs
|
|
||||||
"cache_sram_mmu.c"
|
|
||||||
"dport_access.c"
|
|
||||||
"esp_himem.c"
|
|
||||||
"spiram.c"
|
|
||||||
"spiram_psram.c")
|
|
||||||
|
|
||||||
set(include_dirs "include")
|
|
||||||
|
|
||||||
set(requires driver efuse soc xtensa) #unfortunately rom/uart uses SOC registers directly
|
|
||||||
|
|
||||||
# app_update is added here because cpu_start.c uses esp_ota_get_app_description() function.
|
|
||||||
# esp_timer is added here because cpu_start.c uses esp_timer
|
|
||||||
set(priv_requires app_trace app_update bootloader_support esp_system log mbedtls nvs_flash pthread
|
|
||||||
spi_flash vfs espcoredump esp_common perfmon esp_timer esp_ipc esp_pm)
|
|
||||||
|
|
||||||
idf_component_register(SRCS "${srcs}"
|
|
||||||
INCLUDE_DIRS "${include_dirs}"
|
|
||||||
REQUIRES "${requires}"
|
|
||||||
PRIV_REQUIRES "${priv_requires}"
|
|
||||||
REQUIRED_IDF_TARGETS esp32)
|
|
||||||
|
|
||||||
target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld")
|
|
||||||
|
|
||||||
if(CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY)
|
|
||||||
# This has to be linked before esp32.project.ld
|
|
||||||
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.extram.noinit.ld")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# 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}/ld/esp32.project.ld.in"
|
|
||||||
PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/esp32.project.ld")
|
|
||||||
|
|
||||||
target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32.peripherals.ld")
|
|
||||||
target_link_libraries(${COMPONENT_LIB} PUBLIC gcc)
|
|
||||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u call_user_start_cpu0")
|
|
||||||
|
|
||||||
idf_build_get_property(config_dir CONFIG_DIR)
|
|
||||||
# Preprocess esp32.ld linker script to include configuration, becomes esp32_out.ld
|
|
||||||
set(LD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/ld)
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT esp32_out.ld
|
|
||||||
COMMAND "${CMAKE_C_COMPILER}" -C -P -x c -E -o esp32_out.ld -I ${config_dir} ${LD_DIR}/esp32.ld
|
|
||||||
MAIN_DEPENDENCY ${LD_DIR}/esp32.ld
|
|
||||||
DEPENDS ${sdkconfig_header}
|
|
||||||
COMMENT "Generating linker script..."
|
|
||||||
VERBATIM)
|
|
||||||
|
|
||||||
add_custom_target(esp32_linker_script DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld)
|
|
||||||
add_dependencies(${COMPONENT_LIB} esp32_linker_script)
|
|
||||||
|
|
||||||
if(CONFIG_SPIRAM_CACHE_WORKAROUND)
|
|
||||||
# Note: Adding as a PUBLIC compile option here causes this option to propagate to all
|
|
||||||
# components that depend on esp32.
|
|
||||||
#
|
|
||||||
# To handle some corner cases, the same flag is set in project_include.cmake
|
|
||||||
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue)
|
|
||||||
# also, make sure we link with this option so correct toolchain libs are pulled in
|
|
||||||
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-issue)
|
|
||||||
# set strategy selected
|
|
||||||
# note that we don't need to set link options as the library linked is independent of this
|
|
||||||
if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST)
|
|
||||||
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=dupldst)
|
|
||||||
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=dupldst)
|
|
||||||
endif()
|
|
||||||
if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW)
|
|
||||||
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=memw)
|
|
||||||
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=memw)
|
|
||||||
endif()
|
|
||||||
if(CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS)
|
|
||||||
target_compile_options(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=nops)
|
|
||||||
target_link_libraries(${COMPONENT_LIB} PUBLIC -mfix-esp32-psram-cache-strategy=nops)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
idf_component_register(INCLUDE_DIRS include
|
idf_component_register(INCLUDE_DIRS include
|
||||||
|
@@ -1,39 +1,3 @@
|
|||||||
#
|
#
|
||||||
# Component Makefile
|
# Component Makefile
|
||||||
#
|
#
|
||||||
|
|
||||||
COMPONENT_SRCDIRS := .
|
|
||||||
|
|
||||||
ifdef CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY
|
|
||||||
# This linker script must come before esp32.project.ld
|
|
||||||
LINKER_SCRIPTS += esp32.extram.noinit.ld
|
|
||||||
endif
|
|
||||||
|
|
||||||
#Linker scripts used to link the final application.
|
|
||||||
#Warning: These linker scripts are only used when the normal app is compiled; the bootloader
|
|
||||||
#specifies its own scripts.
|
|
||||||
LINKER_SCRIPTS += $(COMPONENT_BUILD_DIR)/esp32.project.ld esp32.peripherals.ld
|
|
||||||
|
|
||||||
#ld_include_panic_highint_hdl is added as an undefined symbol because otherwise the
|
|
||||||
#linker will ignore panic_highint_hdl.S as it has no other files depending on any
|
|
||||||
#symbols in it.
|
|
||||||
COMPONENT_ADD_LDFLAGS += -L $(COMPONENT_PATH)/ld \
|
|
||||||
-T esp32_out.ld \
|
|
||||||
-u ld_include_panic_highint_hdl \
|
|
||||||
$(addprefix -T ,$(LINKER_SCRIPTS)) \
|
|
||||||
|
|
||||||
# final linking of project ELF depends on all binary libraries, and
|
|
||||||
# all linker scripts (except esp32_out.ld, as this is code generated here.)
|
|
||||||
COMPONENT_ADD_LINKER_DEPS := $(addprefix ld/, $(filter-out $(COMPONENT_BUILD_DIR)/esp32.project.ld, $(LINKER_SCRIPTS))) \
|
|
||||||
$(COMPONENT_BUILD_DIR)/esp32.project.ld
|
|
||||||
|
|
||||||
# Preprocess esp32.ld linker script into esp32_out.ld
|
|
||||||
#
|
|
||||||
# The library doesn't really depend on esp32_out.ld, but it
|
|
||||||
# saves us from having to add the target to a Makefile.projbuild
|
|
||||||
$(COMPONENT_LIBRARY): esp32_out.ld
|
|
||||||
|
|
||||||
esp32_out.ld: $(COMPONENT_PATH)/ld/esp32.ld ../include/sdkconfig.h
|
|
||||||
$(CC) -I ../include -C -P -x c -E $< -o $@
|
|
||||||
|
|
||||||
COMPONENT_EXTRA_CLEAN := esp32_out.ld $(COMPONENT_BUILD_DIR)/esp32.project.ld
|
|
||||||
|
@@ -72,14 +72,6 @@ extern "C" {
|
|||||||
#define EXT_RAM_ATTR
|
#define EXT_RAM_ATTR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY
|
|
||||||
// Forces data into external memory noinit section to avoid initialization after restart.
|
|
||||||
#define EXT_RAM_NOINIT_ATTR _SECTION_ATTR_IMPL(".ext_ram.noinit", __COUNTER__)
|
|
||||||
#else
|
|
||||||
// Place in internal noinit section
|
|
||||||
#define EXT_RAM_NOINIT_ATTR __NOINIT_ATTR
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst"
|
// Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst"
|
||||||
// Any variable marked with this attribute will keep its value
|
// Any variable marked with this attribute will keep its value
|
||||||
// during a deep sleep / wake cycle.
|
// during a deep sleep / wake cycle.
|
||||||
@@ -97,6 +89,14 @@ extern "C" {
|
|||||||
// Forces data into noinit section to avoid initialization after restart.
|
// Forces data into noinit section to avoid initialization after restart.
|
||||||
#define __NOINIT_ATTR _SECTION_ATTR_IMPL(".noinit", __COUNTER__)
|
#define __NOINIT_ATTR _SECTION_ATTR_IMPL(".noinit", __COUNTER__)
|
||||||
|
|
||||||
|
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
|
||||||
|
// Forces data into external memory noinit section to avoid initialization after restart.
|
||||||
|
#define EXT_RAM_NOINIT_ATTR _SECTION_ATTR_IMPL(".ext_ram.noinit", __COUNTER__)
|
||||||
|
#else
|
||||||
|
// Place in internal noinit section
|
||||||
|
#define EXT_RAM_NOINIT_ATTR __NOINIT_ATTR
|
||||||
|
#endif
|
||||||
|
|
||||||
// Forces data into RTC slow memory of .noinit section.
|
// Forces data into RTC slow memory of .noinit section.
|
||||||
// Any variable marked with this attribute will keep its value
|
// Any variable marked with this attribute will keep its value
|
||||||
// after restart or during a deep sleep / wake cycle.
|
// after restart or during a deep sleep / wake cycle.
|
||||||
|
@@ -102,10 +102,12 @@ config SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
|
|||||||
|
|
||||||
Note that the variables placed in SPIRAM using EXT_RAM_ATTR will be zero initialized.
|
Note that the variables placed in SPIRAM using EXT_RAM_ATTR will be zero initialized.
|
||||||
|
|
||||||
config SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY
|
config SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
|
||||||
bool "Enable placement of noinit segments in external memory"
|
bool "Allow .noinit segment placed in external memory"
|
||||||
default n
|
default n
|
||||||
depends on SPIRAM
|
depends on SPIRAM && IDF_TARGET_ESP32
|
||||||
help
|
help
|
||||||
If enabled, noinit variables can be placed in PSRAM using EXT_RAM_NOINIT_ATTR.
|
If enabled, noinit variables can be placed in PSRAM using EXT_RAM_NOINIT_ATTR.
|
||||||
If disabled, EXT_RAM_NOINIT_ATTR will act like __NOINIT_ATTR.
|
|
||||||
|
Note the values placed into this section will not be initialized at startup and should keep its value
|
||||||
|
after software restart.
|
||||||
|
@@ -59,7 +59,7 @@ void esp_spiram_init_cache(void);
|
|||||||
*
|
*
|
||||||
* @return true on success, false on failed memory test
|
* @return true on success, false on failed memory test
|
||||||
*/
|
*/
|
||||||
bool esp_spiram_test(const void* keepout_addr_low, const void* keepout_addr_high);
|
bool esp_spiram_test(void);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -55,7 +55,7 @@ static const char* TAG = "spiram";
|
|||||||
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
|
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
|
||||||
extern uint8_t _ext_ram_bss_start, _ext_ram_bss_end;
|
extern uint8_t _ext_ram_bss_start, _ext_ram_bss_end;
|
||||||
#endif
|
#endif
|
||||||
#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY
|
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
|
||||||
extern uint8_t _ext_ram_noinit_start, _ext_ram_noinit_end;
|
extern uint8_t _ext_ram_noinit_start, _ext_ram_noinit_end;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -83,25 +83,32 @@ static size_t spiram_size_usable_for_malloc(void)
|
|||||||
true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been
|
true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been
|
||||||
initialized (in a two-core system) or after the heap allocator has taken ownership of the memory.
|
initialized (in a two-core system) or after the heap allocator has taken ownership of the memory.
|
||||||
*/
|
*/
|
||||||
bool esp_spiram_test(const void* keepout_addr_low, const void* keepout_addr_high)
|
bool esp_spiram_test(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
|
||||||
|
const void *keepout_addr_low = (const void*)&_ext_ram_noinit_start;
|
||||||
|
const void *keepout_addr_high = (const void*)&_ext_ram_noinit_end;
|
||||||
|
#else
|
||||||
|
const void *keepout_addr_low = 0;
|
||||||
|
const void *keepout_addr_high = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
volatile int *spiram=(volatile int*)SOC_EXTRAM_DATA_LOW;
|
volatile int *spiram=(volatile int*)SOC_EXTRAM_DATA_LOW;
|
||||||
size_t p;
|
size_t p;
|
||||||
size_t s=spiram_size_usable_for_malloc();
|
size_t s=spiram_size_usable_for_malloc();
|
||||||
int errct=0;
|
int errct=0;
|
||||||
int initial_err=-1;
|
int initial_err=-1;
|
||||||
for (p=0; p<(s/sizeof(int)); p+=8) {
|
for (p=0; p<(s/sizeof(int)); p+=8) {
|
||||||
if ((keepout_addr_low <= (const void*)&spiram[p]) && ((const void*)&spiram[p] < keepout_addr_high)) {
|
const void *addr = (const void *)&spiram[p];
|
||||||
continue;
|
if ((keepout_addr_low <= addr) && (addr < keepout_addr_high)) {
|
||||||
} else if ((keepout_addr_low < (const void*)&spiram[p+1]) && ((const void*)&spiram[p+1] <= keepout_addr_high)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
spiram[p]=p^0xAAAAAAAA;
|
spiram[p]=p^0xAAAAAAAA;
|
||||||
}
|
}
|
||||||
for (p=0; p<(s/sizeof(int)); p+=8) {
|
for (p=0; p<(s/sizeof(int)); p+=8) {
|
||||||
if ((keepout_addr_low <= (const void*)&spiram[p]) && ((const void*)&spiram[p] < keepout_addr_high)) {
|
const void *addr = (const void *)&spiram[p];
|
||||||
continue;
|
if ((keepout_addr_low <= addr) && (addr < keepout_addr_high)) {
|
||||||
} else if ((keepout_addr_low < (const void*)&spiram[p+1]) && ((const void*)&spiram[p+1] <= keepout_addr_high)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (spiram[p]!=(p^0xAAAAAAAA)) {
|
if (spiram[p]!=(p^0xAAAAAAAA)) {
|
||||||
@@ -192,7 +199,7 @@ esp_err_t esp_spiram_add_to_heapalloc(void)
|
|||||||
mallocable_ram_start = (intptr_t)&_ext_ram_bss_end;
|
mallocable_ram_start = (intptr_t)&_ext_ram_bss_end;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY
|
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
|
||||||
if (mallocable_ram_start < (intptr_t)&_ext_ram_noinit_end) {
|
if (mallocable_ram_start < (intptr_t)&_ext_ram_noinit_end) {
|
||||||
mallocable_ram_start = (intptr_t)&_ext_ram_noinit_end;
|
mallocable_ram_start = (intptr_t)&_ext_ram_noinit_end;
|
||||||
}
|
}
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
/* This section is only included if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY
|
|
||||||
is set, to link some NOINIT sections in PSRAM */
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
/* external memory bss, from any global variable with EXT_RAM_NOINIT_ATTR attribute*/
|
|
||||||
.ext_ram.noinit (NOLOAD) :
|
|
||||||
{
|
|
||||||
_ext_ram_noinit_start = ABSOLUTE(.);
|
|
||||||
*(.ext_ram.noinit*)
|
|
||||||
. = ALIGN(4);
|
|
||||||
_ext_ram_noinit_end = ABSOLUTE(.);
|
|
||||||
} > extern_ram_seg
|
|
||||||
}
|
|
@@ -197,6 +197,18 @@ SECTIONS
|
|||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
} > dram0_0_seg
|
} > dram0_0_seg
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This section holds data that won't be initialised when startup.
|
||||||
|
* This section locates in External RAM region.
|
||||||
|
*/
|
||||||
|
.ext_ram.noinit (NOLOAD) :
|
||||||
|
{
|
||||||
|
_ext_ram_noinit_start = ABSOLUTE(.);
|
||||||
|
*(.ext_ram.noinit*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ext_ram_noinit_end = ABSOLUTE(.);
|
||||||
|
} > extern_ram_seg
|
||||||
|
|
||||||
/*This section holds data that should not be initialized at power up.
|
/*This section holds data that should not be initialized at power up.
|
||||||
The section located in Internal SRAM memory region. The macro _NOINIT
|
The section located in Internal SRAM memory region. The macro _NOINIT
|
||||||
can be used as attribute to place data into this section.
|
can be used as attribute to place data into this section.
|
||||||
|
@@ -129,10 +129,6 @@ static const char *TAG = "cpu_start";
|
|||||||
extern int _ext_ram_bss_start;
|
extern int _ext_ram_bss_start;
|
||||||
extern int _ext_ram_bss_end;
|
extern int _ext_ram_bss_end;
|
||||||
#endif
|
#endif
|
||||||
#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY
|
|
||||||
extern int _ext_ram_noinit_start;
|
|
||||||
extern int _ext_ram_noinit_end;
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
|
#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
|
||||||
extern int _iram_bss_start;
|
extern int _iram_bss_start;
|
||||||
extern int _iram_bss_end;
|
extern int _iram_bss_end;
|
||||||
@@ -423,11 +419,7 @@ void IRAM_ATTR call_start_cpu0(void)
|
|||||||
|
|
||||||
#if CONFIG_SPIRAM_MEMTEST
|
#if CONFIG_SPIRAM_MEMTEST
|
||||||
if (g_spiram_ok) {
|
if (g_spiram_ok) {
|
||||||
#if CONFIG_SPIRAM_ALLOW_NOINIT_EXTERNAL_MEMORY
|
bool ext_ram_ok = esp_spiram_test();
|
||||||
bool ext_ram_ok = esp_spiram_test(&_ext_ram_noinit_start, &_ext_ram_noinit_end);
|
|
||||||
#else
|
|
||||||
bool ext_ram_ok = esp_spiram_test(0, 0);
|
|
||||||
#endif
|
|
||||||
if (!ext_ram_ok) {
|
if (!ext_ram_ok) {
|
||||||
ESP_EARLY_LOGE(TAG, "External RAM failed memory test!");
|
ESP_EARLY_LOGE(TAG, "External RAM failed memory test!");
|
||||||
abort();
|
abort();
|
||||||
|
Reference in New Issue
Block a user