Merge branch 'fix/mmu_multicore_app_bl' into 'master'

fix(MMU): fixed mmap deadlock when using multicore app with unicore bootloader

Closes IDFGH-10359

See merge request espressif/esp-idf!32745
This commit is contained in:
Michael (XIAO Xufeng) 2024-08-16 11:49:32 +08:00
commit 742a4838d6
6 changed files with 99 additions and 7 deletions

View File

@ -330,6 +330,17 @@ static void start_other_core(void)
}
#if !SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#if CONFIG_IDF_TARGET_ESP32
static void restore_app_mmu_from_pro_mmu(void)
{
const int mmu_reg_num = 2048;
volatile uint32_t* from = (uint32_t*)DR_REG_FLASH_MMU_TABLE_PRO;
volatile uint32_t* to = (uint32_t*)DR_REG_FLASH_MMU_TABLE_APP;
for (int i = 0; i < mmu_reg_num; i++) {
*(to++) = *(from++);
}
}
#endif
// This function is needed to make the multicore app runnable on a unicore bootloader (built with FREERTOS UNICORE).
// It does some cache settings for other CPUs.
void IRAM_ATTR do_multicore_settings(void)
@ -341,9 +352,11 @@ void IRAM_ATTR do_multicore_settings(void)
Cache_Read_Disable(1);
Cache_Flush(1);
DPORT_REG_SET_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
mmu_init(1);
DPORT_REG_CLR_BIT(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MMU_IA_CLR);
// We do not enable cache for CPU1 now because it will be done later in start_other_core().
}
restore_app_mmu_from_pro_mmu();
#endif
cache_bus_mask_t cache_bus_mask_core0 = cache_ll_l1_get_enabled_bus(0);

View File

@ -1 +1,2 @@
idf_component_register(SRCS "main.c")
idf_component_register(SRCS "main.c"
PRIV_REQUIRES nvs_flash esp_psram)

View File

@ -5,8 +5,70 @@
*/
#include <stdio.h>
#include <inttypes.h>
#include "nvs_flash.h"
#include "nvs.h"
void app_main(void)
{
printf("App is running\n");
// One difference of multicore bootloader is whether it resets all the MMU. If not, it may cause the nvs fail to
// call mmap. Test code copied from examples/storage/nvs_rw_value.
// Initialize NVS
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated and needs to be erased
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK( err );
// Open
printf("Opening Non-Volatile Storage (NVS) handle... ");
nvs_handle_t my_handle;
err = nvs_open("storage", NVS_READWRITE, &my_handle);
if (err != ESP_OK) {
printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
} else {
printf("Done\n");
// Read
printf("Reading restart counter from NVS ... ");
int32_t restart_counter = 0; // value will default to 0, if not set yet in NVS
err = nvs_get_i32(my_handle, "restart_counter", &restart_counter);
switch (err) {
case ESP_OK:
printf("Done\n");
printf("Restart counter = %" PRIu32 "\n", restart_counter);
break;
case ESP_ERR_NVS_NOT_FOUND:
printf("The value is not initialized yet!\n");
break;
default :
printf("Error (%s) reading!\n", esp_err_to_name(err));
}
// Write
printf("Updating restart counter in NVS ... ");
restart_counter++;
err = nvs_set_i32(my_handle, "restart_counter", restart_counter);
printf((err != ESP_OK) ? "Failed!\n" : "Done\n");
// Commit written value.
// After setting any values, nvs_commit() must be called to ensure changes are written
// to flash storage. Implementations may write to storage at other times,
// but this is not guaranteed.
printf("Committing updates in NVS ... ");
err = nvs_commit(my_handle);
printf((err != ESP_OK) ? "Failed!\n" : "Done\n");
// Close
nvs_close(my_handle);
}
printf("NVS test done\n");
}

View File

@ -1,6 +1,7 @@
# SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import os
import re
import pytest
from artifacts_handler import ArtifactType
@ -12,13 +13,16 @@ from pytest_embedded import Dut
@pytest.mark.esp32s3
@pytest.mark.esp32p4
@pytest.mark.generic
@pytest.mark.parametrize('config', ['multicore'], indirect=True)
def test_multicore_app_and_unicore_bootloader(dut: Dut, app_downloader) -> None: # type: ignore
@pytest.mark.parametrize('config', ['multicore', 'multicore_psram'], indirect=True)
def test_multicore_app_and_unicore_bootloader(dut: Dut, app_downloader, config) -> None: # type: ignore
dut.expect('Multicore bootloader')
dut.expect('Multicore app')
dut.expect('App is running')
path_to_unicore_build = os.path.join(dut.app.app_path, f'build_{dut.target}_unicore')
assert 'multicore' in config
app_config = config.replace('multicore', 'unicore')
path_to_unicore_build = os.path.join(dut.app.app_path, f'build_{dut.target}_{app_config}')
if app_downloader:
app_downloader.download_app(
os.path.relpath(path_to_unicore_build, IDF_PATH), ArtifactType.BUILD_DIR_WITHOUT_MAP_AND_ELF_FILES
@ -27,20 +31,26 @@ def test_multicore_app_and_unicore_bootloader(dut: Dut, app_downloader) -> None:
dut.serial.bootloader_flash(path_to_unicore_build)
dut.expect('Unicore bootloader')
dut.expect('Multicore app')
if 'psram' in config:
dut.expect(re.compile(r'Adding pool of \d+K of PSRAM memory to heap allocator'))
dut.expect('App is running')
dut.expect('NVS test done\n')
@pytest.mark.esp32
@pytest.mark.esp32s3
@pytest.mark.esp32p4
@pytest.mark.generic
@pytest.mark.parametrize('config', ['unicore'], indirect=True)
def test_unicore_app_and_multicore_bootloader(dut: Dut, app_downloader) -> None: # type: ignore
@pytest.mark.parametrize('config', ['unicore', 'unicore_psram'], indirect=True)
def test_unicore_app_and_multicore_bootloader(dut: Dut, app_downloader, config) -> None: # type: ignore
dut.expect('Unicore bootloader')
dut.expect('Unicore app')
dut.expect('App is running')
path_to_multicore_build = os.path.join(dut.app.app_path, f'build_{dut.target}_multicore')
assert 'unicore' in config
app_config = config.replace('unicore', 'multicore')
path_to_multicore_build = os.path.join(dut.app.app_path, f'build_{dut.target}_{app_config}')
if app_downloader:
app_downloader.download_app(
os.path.relpath(path_to_multicore_build, IDF_PATH), ArtifactType.BUILD_DIR_WITHOUT_MAP_AND_ELF_FILES
@ -49,4 +59,7 @@ def test_unicore_app_and_multicore_bootloader(dut: Dut, app_downloader) -> None:
dut.serial.bootloader_flash(path_to_multicore_build)
dut.expect('Multicore bootloader')
dut.expect('Unicore app')
if 'psram' in config:
dut.expect(re.compile(r'Adding pool of \d+K of PSRAM memory to heap allocator'))
dut.expect('App is running')
dut.expect('NVS test done\n')

View File

@ -0,0 +1 @@
CONFIG_SPIRAM=y

View File

@ -0,0 +1,2 @@
CONFIG_FREERTOS_UNICORE=y
CONFIG_SPIRAM=y