mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 10:47:19 +02:00
feat(hw_support): move call_start_cpu0 into flash to save IRAM
This commit is contained in:
@ -22,6 +22,7 @@
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "soc/dport_reg.h"
|
||||
@ -258,6 +259,13 @@ void IRAM_ATTR call_start_cpu1(void)
|
||||
esp_rom_delay_us(100);
|
||||
}
|
||||
|
||||
/* SPI Flash driver initialization runs in the CORE stage of ESP SYSTEM INIT FN of core 0, which runs in parallel
|
||||
* with this function. During that, the scheduler (hence the ipc service) is not ready, while the flash driver needs
|
||||
* to disable the cache. s_resume_cores indicates the end of CORE stage.
|
||||
*
|
||||
* Other CPUs are not allowed to access the flash through the cache, i.e. run code which is not placed in IRAM or
|
||||
* print string which locates on flash, until the SECONDARY stage of ESP SYSTEM INIT FN.
|
||||
*/
|
||||
SYS_STARTUP_FN();
|
||||
}
|
||||
|
||||
@ -350,18 +358,8 @@ void IRAM_ATTR do_multicore_settings(void)
|
||||
#endif // !SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
#endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
|
||||
/*
|
||||
* We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
|
||||
* and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
|
||||
*/
|
||||
void IRAM_ATTR call_start_cpu0(void)
|
||||
FORCE_INLINE_ATTR IRAM_ATTR void init_cpu(void)
|
||||
{
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
soc_reset_reason_t __attribute__((unused)) rst_reas[SOC_CPU_CORES_NUM];
|
||||
#else
|
||||
soc_reset_reason_t __attribute__((unused)) rst_reas[1];
|
||||
#endif
|
||||
|
||||
#ifdef __riscv
|
||||
if (esp_cpu_dbgr_is_attached()) {
|
||||
/* Let debugger some time to detect that target started, halt it, enable ebreaks and resume.
|
||||
@ -404,13 +402,19 @@ void IRAM_ATTR call_start_cpu0(void)
|
||||
extern uint32_t esp_tee_service_call(int argc, ...);
|
||||
esprv_int_setup_mgmt_cb((void *)esp_tee_service_call);
|
||||
#endif
|
||||
}
|
||||
|
||||
//Keep this static, the compiler will check if rst_reas is initialized.
|
||||
FORCE_INLINE_ATTR IRAM_ATTR void get_reset_reason(soc_reset_reason_t *rst_reas)
|
||||
{
|
||||
rst_reas[0] = esp_rom_get_reset_reason(0);
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
rst_reas[1] = esp_rom_get_reset_reason(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
//Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this.
|
||||
FORCE_INLINE_ATTR IRAM_ATTR void init_bss(const soc_reset_reason_t *rst_reas)
|
||||
{
|
||||
#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));
|
||||
@ -434,49 +438,30 @@ void IRAM_ATTR call_start_cpu0(void)
|
||||
memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE && !SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE && !CONFIG_IDF_TARGET_ESP32H4 // TODO IDF-12289
|
||||
// It helps to fix missed cache settings for other cores. It happens when bootloader is unicore.
|
||||
do_multicore_settings();
|
||||
#endif
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
//cache hal ctx needs to be initialised
|
||||
cache_hal_init();
|
||||
#endif
|
||||
|
||||
// When the APP is loaded into ram for execution, some hardware initialization behaviors
|
||||
// in the bootloader are still necessary
|
||||
#if CONFIG_APP_BUILD_TYPE_RAM
|
||||
FORCE_INLINE_ATTR IRAM_ATTR void ram_app_init(void)
|
||||
{
|
||||
bootloader_init();
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
bootloader_flash_hardware_init();
|
||||
#endif //#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
}
|
||||
#endif //#if CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
#define RWDT_RESET RESET_REASON_CORE_RWDT
|
||||
#define MWDT_RESET RESET_REASON_CORE_MWDT
|
||||
#else
|
||||
#define RWDT_RESET RESET_REASON_CORE_RTC_WDT
|
||||
#define MWDT_RESET RESET_REASON_CORE_MWDT0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BOOTLOADER_WDT_ENABLE
|
||||
// from panic handler we can be reset by RWDT or TG0WDT
|
||||
if (rst_reas[0] == RWDT_RESET || rst_reas[0] == MWDT_RESET
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
|| rst_reas[1] == RWDT_RESET || rst_reas[1] == MWDT_RESET
|
||||
#endif
|
||||
) {
|
||||
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
|
||||
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||
wdt_hal_disable(&rtc_wdt_ctx);
|
||||
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
//Keep this static, the compiler will check output parameters are initialized.
|
||||
FORCE_INLINE_ATTR IRAM_ATTR void cache_init(void)
|
||||
{
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE && !SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE && !CONFIG_IDF_TARGET_ESP32H4 // TODO IDF-12289
|
||||
// It helps to fix missed cache settings for other cores. It happens when bootloader is unicore.
|
||||
do_multicore_settings();
|
||||
#endif
|
||||
|
||||
//cache hal ctx needs to be initialised
|
||||
cache_hal_init();
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
/* Configure the mode of instruction cache : cache size, cache associated ways, cache line size. */
|
||||
extern void esp_config_instruction_cache_mode(void);
|
||||
@ -509,41 +494,59 @@ void IRAM_ATTR call_start_cpu0(void)
|
||||
esp_config_l2_cache_mode();
|
||||
#endif
|
||||
|
||||
#if ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE
|
||||
#if CONFIG_APP_BUILD_TYPE_ELF_RAM
|
||||
// For RAM loadable ELF case, we don't need to reserve IROM/DROM as instructions and data
|
||||
// are all in internal RAM. If the RAM loadable ELF has any requirement to memory map the
|
||||
// external flash then it should use flash or partition mmap APIs.
|
||||
#if ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE
|
||||
uint32_t cache_mmu_irom_size = 0;
|
||||
__attribute__((unused)) uint32_t cache_mmu_drom_size = 0;
|
||||
#else // CONFIG_APP_BUILD_TYPE_ELF_RAM
|
||||
#if !CONFIG_APP_BUILD_TYPE_ELF_RAM
|
||||
uint32_t _instruction_size = (uint32_t)&_instruction_reserved_end - (uint32_t)&_instruction_reserved_start;
|
||||
uint32_t cache_mmu_irom_size = ((_instruction_size + SPI_FLASH_MMU_PAGE_SIZE - 1) / SPI_FLASH_MMU_PAGE_SIZE) * sizeof(uint32_t);
|
||||
|
||||
uint32_t _rodata_size = (uint32_t)&_rodata_reserved_end - (uint32_t)&_rodata_reserved_start;
|
||||
__attribute__((unused)) uint32_t cache_mmu_drom_size = ((_rodata_size + SPI_FLASH_MMU_PAGE_SIZE - 1) / SPI_FLASH_MMU_PAGE_SIZE) * sizeof(uint32_t);
|
||||
cache_mmu_irom_size = ((_instruction_size + SPI_FLASH_MMU_PAGE_SIZE - 1) / SPI_FLASH_MMU_PAGE_SIZE) * sizeof(uint32_t);
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_ELF_RAM
|
||||
|
||||
/* Configure the Cache MMU size for instruction and rodata in flash. */
|
||||
Cache_Set_IDROM_MMU_Size(cache_mmu_irom_size, CACHE_DROM_MMU_MAX_END - cache_mmu_irom_size);
|
||||
#endif // ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
|
||||
#if CONFIG_ESPTOOLPY_OCT_FLASH && !CONFIG_ESPTOOLPY_FLASH_MODE_AUTO_DETECT
|
||||
bool efuse_opflash_en = efuse_ll_get_flash_type();
|
||||
if (!efuse_opflash_en) {
|
||||
ESP_DRAM_LOGE(TAG, "Octal Flash option selected, but EFUSE not configured!");
|
||||
abort();
|
||||
// On chips with different virtual address space for flash and PSRAM, code in flash is not available before XIP is
|
||||
// initialized. Hence, these functions have to be in the IRAM.
|
||||
#if SOC_MMU_PER_EXT_MEM_TARGET
|
||||
#define MSPI_INIT_ATTR FORCE_INLINE_ATTR IRAM_ATTR
|
||||
#else
|
||||
#define MSPI_INIT_ATTR NOINLINE_ATTR static
|
||||
#endif
|
||||
|
||||
MSPI_INIT_ATTR void sys_rtc_init(const soc_reset_reason_t *rst_reas)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
#define RWDT_RESET RESET_REASON_CORE_RWDT
|
||||
#define MWDT_RESET RESET_REASON_CORE_MWDT
|
||||
#else
|
||||
#define RWDT_RESET RESET_REASON_CORE_RTC_WDT
|
||||
#define MWDT_RESET RESET_REASON_CORE_MWDT0
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BOOTLOADER_WDT_ENABLE
|
||||
// from panic handler we can be reset by RWDT or TG0WDT
|
||||
if (rst_reas[0] == RWDT_RESET || rst_reas[0] == MWDT_RESET
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
|| rst_reas[1] == RWDT_RESET || rst_reas[1] == MWDT_RESET
|
||||
#endif
|
||||
) {
|
||||
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
|
||||
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||
wdt_hal_disable(&rtc_wdt_ctx);
|
||||
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_mspi_pin_init();
|
||||
// For Octal flash, it's hard to implement a read_id function in OPI mode for all vendors.
|
||||
// So we have to read it here in SPI mode, before entering the OPI mode.
|
||||
bootloader_flash_update_id();
|
||||
|
||||
// Configure the power related stuff. After this the MSPI timing tuning can be done.
|
||||
esp_rtc_init();
|
||||
}
|
||||
|
||||
NOINLINE_ATTR IRAM_ATTR void flash_init_state(void)
|
||||
{
|
||||
/**
|
||||
* This function initialise the Flash chip to the user-defined settings.
|
||||
*
|
||||
@ -557,8 +560,27 @@ void IRAM_ATTR call_start_cpu0(void)
|
||||
// some state of flash is modified.
|
||||
mspi_timing_flash_tuning();
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_mmu_map_init();
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
MSPI_INIT_ATTR void mspi_init(void)
|
||||
{
|
||||
#if CONFIG_ESPTOOLPY_OCT_FLASH && !CONFIG_ESPTOOLPY_FLASH_MODE_AUTO_DETECT
|
||||
bool efuse_opflash_en = efuse_ll_get_flash_type();
|
||||
if (!efuse_opflash_en) {
|
||||
ESP_DRAM_LOGE(TAG, "Octal Flash option selected, but EFUSE not configured!");
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_mspi_pin_init();
|
||||
// For Octal flash, it's hard to implement a read_id function in OPI mode for all vendors.
|
||||
// So we have to read it here in SPI mode, before entering the OPI mode.
|
||||
bootloader_flash_update_id();
|
||||
|
||||
flash_init_state();
|
||||
|
||||
esp_mmu_map_init(); //required by image_process() and flash_mmap APIs
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_ELF_RAM
|
||||
#if CONFIG_SPIRAM_FLASH_LOAD_TO_PSRAM
|
||||
@ -585,15 +607,18 @@ void IRAM_ATTR call_start_cpu0(void)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
|
||||
//----------------------------------Separator-----------------------------//
|
||||
/**
|
||||
* @note
|
||||
* After this stage, you can access the flash through the cache, i.e. run code which is not placed in IRAM
|
||||
* or print string which locates on flash
|
||||
*/
|
||||
/*
|
||||
* Initialize other parts of the system, including other CPUs.
|
||||
* As CPU0 needs to disable the cache in system_early_init function, the other cores are not allowed to run with the
|
||||
* cache until the SYS_STARTUP_FN.
|
||||
*/
|
||||
NOINLINE_ATTR static void system_early_init(const soc_reset_reason_t *rst_reas)
|
||||
{
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
esp_mspi_pin_reserve();
|
||||
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
@ -647,8 +672,19 @@ void IRAM_ATTR call_start_cpu0(void)
|
||||
#endif //CONFIG_SPIRAM_MEMTEST
|
||||
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
|
||||
//TODO: IDF-5023, replace with MMU driver
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
uint32_t cache_mmu_irom_size = 0;
|
||||
uint32_t cache_mmu_drom_size = 0;
|
||||
#if !CONFIG_APP_BUILD_TYPE_ELF_RAM
|
||||
uint32_t _instruction_size = (uint32_t)&_instruction_reserved_end - (uint32_t)&_instruction_reserved_start;
|
||||
cache_mmu_irom_size = ((_instruction_size + SPI_FLASH_MMU_PAGE_SIZE - 1) / SPI_FLASH_MMU_PAGE_SIZE) * sizeof(uint32_t);
|
||||
|
||||
uint32_t _rodata_size = (uint32_t)&_rodata_reserved_end - (uint32_t)&_rodata_reserved_start;
|
||||
cache_mmu_drom_size = ((_rodata_size + SPI_FLASH_MMU_PAGE_SIZE - 1) / SPI_FLASH_MMU_PAGE_SIZE) * sizeof(uint32_t);
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_ELF_RAM
|
||||
|
||||
int s_instr_flash2spiram_off = 0;
|
||||
int s_rodata_flash2spiram_off = 0;
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
|
||||
@ -827,7 +863,6 @@ void IRAM_ATTR call_start_cpu0(void)
|
||||
s_cpu_inited[0] = true;
|
||||
|
||||
volatile bool cpus_inited = false;
|
||||
|
||||
while (!cpus_inited) {
|
||||
cpus_inited = true;
|
||||
for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
|
||||
@ -836,6 +871,67 @@ void IRAM_ATTR call_start_cpu0(void)
|
||||
esp_rom_delay_us(100);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
|
||||
* and the other CPU is in reset. We do have a stack, so we can do the initialization in C.
|
||||
*
|
||||
* CORE 0 CORE 1
|
||||
*
|
||||
* call_start_cpu0
|
||||
* │
|
||||
* ▼
|
||||
* cache & other core init
|
||||
* │
|
||||
* ▼
|
||||
* system_early_init────────────────►call_start_cpu1
|
||||
* │ │
|
||||
* ▼ ▼
|
||||
* ESP SYSTEM INIT FN:CORE core init...
|
||||
* (accesses to ext mem here) │
|
||||
* │ │
|
||||
* ▼ ▼
|
||||
* ESP SYSTEM INIT FN:SECONDARY ESP SYSTEM INIT FN
|
||||
*/
|
||||
void IRAM_ATTR call_start_cpu0(void)
|
||||
{
|
||||
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||
soc_reset_reason_t rst_reas[SOC_CPU_CORES_NUM] = { [0 ... SOC_CPU_CORES_NUM - 1] = RESET_REASON_CHIP_POWER_ON };
|
||||
#else
|
||||
soc_reset_reason_t rst_reas[1] = { RESET_REASON_CHIP_POWER_ON };
|
||||
#endif
|
||||
|
||||
init_cpu();
|
||||
get_reset_reason(rst_reas);
|
||||
// Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this.
|
||||
init_bss(rst_reas);
|
||||
|
||||
// When the APP is loaded into ram for execution, some hardware initialization steps used to be executed in the
|
||||
// bootloader are done here.
|
||||
#if CONFIG_APP_BUILD_TYPE_RAM
|
||||
ram_app_init();
|
||||
#endif //CONFIG_APP_BUILD_TYPE_RAM
|
||||
|
||||
// Initialize the cache.
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
cache_init();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
|
||||
sys_rtc_init(rst_reas);
|
||||
|
||||
// Frequency adjustment and other MSPI initialization stuff like PSRAM initialization.
|
||||
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
mspi_init();
|
||||
#endif // !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
||||
|
||||
/* ----------------------------------Separator-----------------------------
|
||||
* CPU0 can access external memory (cache) now. Please do not access external memory before this.
|
||||
*/
|
||||
|
||||
// Initialize other parts of the system, including other CPUs.
|
||||
// As CPU0 needs to disable the cache in system_early_init function and in the CORE stage of ESP SYSTEM INIT FN, the
|
||||
// other cores are not allowed to run with the cache until the SECONDARY stage of ESP SYSTEM INIT FN.
|
||||
system_early_init(rst_reas);
|
||||
SYS_STARTUP_FN();
|
||||
}
|
||||
|
@ -200,11 +200,17 @@ static void do_secondary_init(void)
|
||||
static void start_cpu0_default(void)
|
||||
{
|
||||
// Initialize core components and services.
|
||||
// Operations that needs the cache to be disabled have to be done here.
|
||||
do_core_init();
|
||||
|
||||
// Execute constructors.
|
||||
do_global_ctors();
|
||||
|
||||
/* ----------------------------------Separator-----------------------------
|
||||
* After this stage, other CPU start running with the cache, however the scheduler (and ipc service) is not available.
|
||||
* Don't touch the cache/MMU until the OS is up.
|
||||
*/
|
||||
|
||||
// Execute init functions of other components; blocks
|
||||
// until all cores finish (when !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE).
|
||||
do_secondary_init();
|
||||
|
Reference in New Issue
Block a user