Merge branch 'bugfix/fix_mem_map_issue_v5.0' into 'release/v5.0'

flash_mmap: fix range issue (v5.0)

See merge request espressif/esp-idf!24529
This commit is contained in:
Jiang Jiang Jian 2023-08-26 10:28:44 +08:00
commit a78ad034f5
29 changed files with 325 additions and 4 deletions

View File

@ -45,6 +45,10 @@ if(CONFIG_ESP_ROM_HAS_CACHE_WRITEBACK_BUG)
list(APPEND sources "patches/esp_rom_cache_writeback_esp32s3.S")
endif()
if(CONFIG_ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE)
list(APPEND sources "patches/esp_rom_mmap.c")
endif()
idf_component_register(SRCS ${sources}
INCLUDE_DIRS ${include_dirs}
PRIV_REQUIRES ${private_required_comp}

View File

@ -42,3 +42,7 @@ config ESP_ROM_HAS_HEAP_TLSF
config ESP_ROM_TLSF_CHECK_PATCH
bool
default y
config ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE
bool
default y

View File

@ -16,3 +16,4 @@
#define ESP_ROM_HAS_HAL_SYSTIMER (1) // ROM has the implementation of Systimer HAL driver
#define ESP_ROM_HAS_HEAP_TLSF (1) // ROM has the implementation of the tlsf and multi-heap library
#define ESP_ROM_TLSF_CHECK_PATCH (1) // ROM does not contain the patch of tlsf_check()
#define ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE (1) // ROM needs to set cache MMU size according to instruction and rodata for flash mmap

View File

@ -46,3 +46,7 @@ config ESP_ROM_NEEDS_SWSETUP_WORKAROUND
config ESP_ROM_HAS_ETS_PRINTF_BUG
bool
default y
config ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE
bool
default y

View File

@ -17,3 +17,4 @@
#define ESP_ROM_GET_CLK_FREQ (1) // Get clk frequency with rom function `ets_get_cpu_frequency`
#define ESP_ROM_NEEDS_SWSETUP_WORKAROUND (1) // ROM uses 32-bit time_t. A workaround is required to prevent printf functions from crashing
#define ESP_ROM_HAS_ETS_PRINTF_BUG (1) // ROM has ets_printf bug when disable the ROM log either by eFuse or RTC storage register
#define ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE (1) // ROM needs to set cache MMU size according to instruction and rodata for flash mmap

View File

@ -42,3 +42,7 @@ config ESP_ROM_GET_CLK_FREQ
config ESP_ROM_HAS_ETS_PRINTF_BUG
bool
default y
config ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE
bool
default y

View File

@ -16,3 +16,4 @@
#define ESP_ROM_HAS_ERASE_0_REGION_BUG (1) // ROM has esp_flash_erase_region(size=0) bug
#define ESP_ROM_GET_CLK_FREQ (1) // Get clk frequency with rom function `ets_get_cpu_frequency`
#define ESP_ROM_HAS_ETS_PRINTF_BUG (1) // ROM has ets_printf bug when disable the ROM log either by eFuse or RTC storage register
#define ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE (1) // ROM needs to set cache MMU size according to instruction and rodata for flash mmap

View File

@ -66,3 +66,7 @@ config ESP_ROM_HAS_CACHE_SUSPEND_WAITI_BUG
config ESP_ROM_HAS_CACHE_WRITEBACK_BUG
bool
default y
config ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE
bool
default y

View File

@ -22,3 +22,4 @@
#define ESP_ROM_HAS_FLASH_COUNT_PAGES_BUG (1) // ROM api Cache_Count_Flash_Pages will return unexpected value
#define ESP_ROM_HAS_CACHE_SUSPEND_WAITI_BUG (1) // ROM api Cache_Suspend_I/DCache and Cache_Freeze_I/DCache_Enable does not waiti
#define ESP_ROM_HAS_CACHE_WRITEBACK_BUG (1) // ROM api Cache_WriteBack_Addr access cacheline being writen back may cause cache hit with wrong value.
#define ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE (1) // ROM needs to set cache MMU size according to instruction and rodata for flash mmap

View File

@ -11,3 +11,5 @@ entries:
esp_rom_tlsf (noflash)
if SOC_SYSTIMER_SUPPORTED = y:
esp_rom_systimer (noflash)
if ESP_ROM_NEEDS_SET_CACHE_MMU_SIZE = y:
esp_rom_mmap (noflash)

View File

@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "sdkconfig.h"
#include "soc/ext_mem_defs.h"
uint32_t Cache_Get_IROM_MMU_End(void)
{
#if CONFIG_IDF_TARGET_ESP32S3
return 0x800;
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
return 0x200;
#elif CONFIG_IDF_TARGET_ESP32C2
return 0x100;
#else
assert(false);
#endif
}
uint32_t Cache_Get_DROM_MMU_End(void)
{
#if CONFIG_IDF_TARGET_ESP32S3
return 0x800;
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
return 0x200;
#elif CONFIG_IDF_TARGET_ESP32C2
return 0x100;
#else
assert(false);
#endif
}

View File

@ -51,7 +51,7 @@ extern "C" {
#define CACHE_IROM_MMU_END Cache_Get_IROM_MMU_End()
#define CACHE_IROM_MMU_SIZE (CACHE_IROM_MMU_END - CACHE_IROM_MMU_START)
#define CACHE_DROM_MMU_START CACHE_IROM_MMU_END
#define CACHE_DROM_MMU_START 0
#define CACHE_DROM_MMU_END Cache_Get_DROM_MMU_End()
#define CACHE_DROM_MMU_SIZE (CACHE_DROM_MMU_END - CACHE_DROM_MMU_START)

View File

@ -49,7 +49,7 @@ extern "C" {
#define CACHE_IROM_MMU_END Cache_Get_IROM_MMU_End()
#define CACHE_IROM_MMU_SIZE (CACHE_IROM_MMU_END - CACHE_IROM_MMU_START)
#define CACHE_DROM_MMU_START CACHE_IROM_MMU_END
#define CACHE_DROM_MMU_START 0
#define CACHE_DROM_MMU_END Cache_Get_DROM_MMU_End()
#define CACHE_DROM_MMU_SIZE (CACHE_DROM_MMU_END - CACHE_DROM_MMU_START)

View File

@ -49,7 +49,7 @@ extern "C" {
#define CACHE_IROM_MMU_END Cache_Get_IROM_MMU_End()
#define CACHE_IROM_MMU_SIZE (CACHE_IROM_MMU_END - CACHE_IROM_MMU_START)
#define CACHE_DROM_MMU_START CACHE_IROM_MMU_END
#define CACHE_DROM_MMU_START 0
#define CACHE_DROM_MMU_END Cache_Get_DROM_MMU_End()
#define CACHE_DROM_MMU_SIZE (CACHE_DROM_MMU_END - CACHE_DROM_MMU_START)

View File

@ -22,6 +22,7 @@ extern "C" {
#define SOC_MMU_DROM0_PAGES_END (PRO_CACHE_IBUS2_MMU_END / sizeof(uint32_t))
#define SOC_MMU_ADDR_MASK MMU_VALID_VAL_MASK
#define SOC_MMU_PAGE_IN_FLASH(page) ((page) | MMU_ACCESS_FLASH)
#define SOC_MMU_PAGE_IN_PSRAM(page) ((page) | MMU_ACCESS_SPIRAM)
#define SOC_MMU_VADDR1_START_ADDR SOC_IROM_MASK_LOW
#define SOC_MMU_PRO_IRAM0_FIRST_USABLE_PAGE ((SOC_MMU_VADDR1_FIRST_USABLE_ADDR - SOC_MMU_VADDR1_START_ADDR) / SPI_FLASH_MMU_PAGE_SIZE + SOC_MMU_IROM0_PAGES_START)
#define SOC_MMU_VADDR0_START_ADDR SOC_DROM_LOW

View File

@ -48,7 +48,7 @@ extern "C" {
#define CACHE_IROM_MMU_END Cache_Get_IROM_MMU_End()
#define CACHE_IROM_MMU_SIZE (CACHE_IROM_MMU_END - CACHE_IROM_MMU_START)
#define CACHE_DROM_MMU_START CACHE_IROM_MMU_END
#define CACHE_DROM_MMU_START 0
#define CACHE_DROM_MMU_END Cache_Get_DROM_MMU_End()
#define CACHE_DROM_MMU_SIZE (CACHE_DROM_MMU_END - CACHE_DROM_MMU_START)

View File

@ -22,6 +22,7 @@ extern "C" {
#define SOC_MMU_DROM0_PAGES_END (CACHE_DROM_MMU_END / sizeof(uint32_t))
#define SOC_MMU_ADDR_MASK MMU_VALID_VAL_MASK
#define SOC_MMU_PAGE_IN_FLASH(page) ((page) | MMU_ACCESS_FLASH)
#define SOC_MMU_PAGE_IN_PSRAM(page) ((page) | MMU_ACCESS_SPIRAM)
#define SOC_MMU_VADDR1_START_ADDR IRAM0_CACHE_ADDRESS_LOW
#define SOC_MMU_PRO_IRAM0_FIRST_USABLE_PAGE SOC_MMU_IROM0_PAGES_START
#define SOC_MMU_VADDR0_START_ADDR (SOC_DROM_LOW + (SOC_MMU_DROM0_PAGES_START * SPI_FLASH_MMU_PAGE_SIZE))

View File

@ -198,6 +198,13 @@ esp_err_t IRAM_ATTR spi_flash_mmap_pages(const int *pages, size_t page_count, sp
for (pos = start; pos < start + page_count; ++pos, ++pageno) {
int table_val = (int) mmu_ll_read_entry(MMU_TABLE_CORE0, pos);
uint8_t refcnt = s_mmap_page_refcnt[pos];
#if !CONFIG_IDF_TARGET_ESP32 && SOC_SPIRAM_SUPPORTED
if (table_val == SOC_MMU_PAGE_IN_PSRAM(pages[pageno])) {
break;
}
#endif //#if !CONFIG_IDF_TARGET_ESP32
if (refcnt != 0 && table_val != SOC_MMU_PAGE_IN_FLASH(pages[pageno])) {
break;
}
@ -219,6 +226,12 @@ esp_err_t IRAM_ATTR spi_flash_mmap_pages(const int *pages, size_t page_count, sp
#if !CONFIG_FREERTOS_UNICORE && CONFIG_IDF_TARGET_ESP32
uint32_t entry_app = mmu_ll_read_entry(MMU_TABLE_CORE1, i);
#endif
if (s_mmap_page_refcnt[i] == 0) {
assert(mmu_ll_get_entry_is_invalid(MMU_TABLE_CORE0, i));
#if !CONFIG_FREERTOS_UNICORE && CONFIG_IDF_TARGET_ESP32
assert(mmu_ll_get_entry_is_invalid(MMU_TABLE_CORE1, i));
#endif
}
assert(s_mmap_page_refcnt[i] == 0 ||
(entry_pro == SOC_MMU_PAGE_IN_FLASH(pages[pageno])
#if !CONFIG_FREERTOS_UNICORE && CONFIG_IDF_TARGET_ESP32

View File

@ -378,7 +378,9 @@ TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash][mmap]")
uint32_t phys = spi_flash_cache2phys(esp_partition_find);
TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys);
TEST_ASSERT_EQUAL_PTR(esp_partition_find, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST));
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA));
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
/* Read the flash @ 'phys' and compare it to the data we get via regular cache access */
spi_flash_read_maybe_encrypted(phys, buf, sizeof(buf));
@ -394,7 +396,9 @@ TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash][mmap]")
TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys);
TEST_ASSERT_EQUAL_PTR(&constant_data,
spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA));
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST));
#endif
/* Read the flash @ 'phys' and compare it to the data we get via normal cache access */
spi_flash_read_maybe_encrypted(phys, buf, sizeof(constant_data));

View File

@ -0,0 +1,6 @@
# 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)
project(test_flash_mmap)

View File

@ -0,0 +1,7 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |
This project tests if Flash and PSRAM can work under different configurations.
To add new configuration, create one more sdkconfig.ci.NAME file in this directory.
If you need to test for anything other than flash and psram, create another test project.

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "test_flash_mmap.c"
INCLUDE_DIRS "."
PRIV_REQUIRES unity spi_flash esp_partition)

View File

@ -0,0 +1,162 @@
/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include <sys/queue.h>
#include "sdkconfig.h"
#include "unity.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_check.h"
#include "esp_attr.h"
#include "esp_flash.h"
#include "esp_partition.h"
#include "spi_flash_mmap.h"
const static char *TAG = "MMAP_TEST";
#define TEST_BLOCK_SIZE CONFIG_MMU_PAGE_SIZE
typedef struct test_block_info_ {
uint32_t vaddr;
spi_flash_mmap_handle_t handle;
LIST_ENTRY(test_block_info_) entries;
} test_block_info_t;
static LIST_HEAD(test_block_list_head_, test_block_info_) test_block_head;
static DRAM_ATTR uint8_t sector_buf[TEST_BLOCK_SIZE];
static const esp_partition_t *s_get_partition(void)
{
//Find the "storage1" partition defined in `partitions.csv`
const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage1");
if (!result) {
ESP_LOGE(TAG, "Can't find the partition, please define it correctly in `partitions.csv`");
abort();
}
return result;
}
static void s_fill_random_data(uint8_t *buffer, size_t size, int random_seed)
{
srand(random_seed);
for (int i = 0 ; i < size; i++) {
buffer[i] = rand() % 0xff;
}
}
static bool s_test_mmap_data_by_random(uint8_t *mblock_ptr, size_t size, int random_seed)
{
srand(random_seed);
uint8_t *test_ptr = mblock_ptr;
for (int i = 0; i < size; i++) {
uint8_t test_data = rand() % 0xff;
if(test_data != test_ptr[i]) {
printf("i: %d\n", i);
printf("test_data: %d\n", test_data);
printf("test_ptr[%d]: %d\n", i, test_ptr[i]);
printf("sector_buf[%d]: %d\n", i, sector_buf[i]);
ESP_EARLY_LOGE(TAG, "FAIL!!!!!!");
return false;
}
}
return true;
}
static void s_print_free_pages(void)
{
uint32_t free_i_pages = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_INST);
uint32_t free_d_pages = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
printf("free_i_pages: 0d%"PRId32"\n", free_i_pages);
printf("free_d_pages: 0d%"PRId32"\n", free_d_pages);
}
void app_main(void)
{
//Get the partition used for SPI1 erase operation
const esp_partition_t *part = s_get_partition();
ESP_LOGI(TAG, "found partition '%s' at offset 0x%"PRIx32" with size 0x%"PRIx32, part->label, part->address, part->size);
//Erase whole region
TEST_ESP_OK(esp_flash_erase_region(part->flash_chip, part->address, part->size));
ESP_LOGI(TAG, "TEST_BLOCK_SIZE: 0x%x", TEST_BLOCK_SIZE);
s_print_free_pages();
uint32_t offset = 0;
int test_seed = 299;
while (1) {
s_fill_random_data(sector_buf, sizeof(sector_buf), test_seed);
ESP_LOGI(TAG, "rand seed: %d, write flash addr: %p...", test_seed, (void *)(part->address + offset));
TEST_ESP_OK(esp_flash_write(part->flash_chip, sector_buf, (part->address + offset), sizeof(sector_buf)));
test_seed++;
offset += TEST_BLOCK_SIZE;
if (offset == part->size) {
break;
}
}
esp_err_t ret = ESP_FAIL;
int count = 0;
LIST_INIT(&test_block_head);
offset = 0;
test_seed = 299;
while (1) {
test_block_info_t *block_info = heap_caps_calloc(1, sizeof(test_block_info_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
TEST_ASSERT(block_info && "no mem");
spi_flash_mmap_handle_t handle;
const void *ptr = NULL;
ret = spi_flash_mmap(part->address + offset, TEST_BLOCK_SIZE, SPI_FLASH_MMAP_DATA, &ptr, &handle);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "ptr is %p", ptr);
s_fill_random_data(sector_buf, sizeof(sector_buf), test_seed);
bool success = s_test_mmap_data_by_random((uint8_t *)ptr, sizeof(sector_buf), test_seed);
TEST_ASSERT(success);
} else if (ret == ESP_ERR_NOT_FOUND) {
free(block_info);
break;
} else {
ESP_LOGE(TAG, "ret: 0x%x", ret);
TEST_ASSERT(false);
}
block_info->vaddr = (uint32_t)ptr;
block_info->handle = handle;
LIST_INSERT_HEAD(&test_block_head, block_info, entries);
count++;
test_seed++;
offset += TEST_BLOCK_SIZE;
if (offset == part->size) {
break;
}
}
ESP_LOGI(TAG, "no more free block / free flash size, finish test, test block size: 0x%x, count: 0d%d", TEST_BLOCK_SIZE, count);
s_print_free_pages();
test_block_info_t *block_to_free = LIST_FIRST(&test_block_head);
test_block_info_t *temp = NULL;
while (block_to_free) {
temp = block_to_free;
spi_flash_munmap(block_to_free->handle);
block_to_free = LIST_NEXT(block_to_free, entries);
free(temp);
}
s_print_free_pages();
printf("flash mmap test success\n");
}

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage1, data, fat, , 896K,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage1, data, fat, , 896K,

View File

@ -0,0 +1,40 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import os
import pathlib
import pytest
from pytest_embedded import Dut
# For F4R8 board (Quad Flash and Octal PSRAM)
MSPI_F4R8_configs = [p.name.replace('sdkconfig.ci.', '') for p in pathlib.Path(os.path.dirname(__file__)).glob('sdkconfig.ci.f4r8*')]
@pytest.mark.esp32s3
@pytest.mark.MSPI_F4R8
@pytest.mark.parametrize('config', MSPI_F4R8_configs, indirect=True)
def test_mmap_flash4_psram8(dut: Dut) -> None:
dut.expect_exact('flash mmap test success', timeout=300)
@pytest.mark.esp32
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.parametrize('config', [
'psram',
], indirect=True)
def test_mmap_psram(dut: Dut) -> None:
dut.expect_exact('flash mmap test success', timeout=300)
@pytest.mark.esp32
@pytest.mark.esp32s2
@pytest.mark.esp32c2
@pytest.mark.esp32c3
@pytest.mark.esp32s3
@pytest.mark.parametrize('config', [
'release',
], indirect=True)
def test_mmap(dut: Dut) -> None:
dut.expect_exact('flash mmap test success', timeout=300)

View File

@ -0,0 +1,7 @@
# F4R8, Flash 80M SDR, PSRAM 80M DDR
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y

View File

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

View File

@ -0,0 +1,3 @@
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@ -0,0 +1,5 @@
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"