From d6e3943233e10467e87dae234788df12012b02db Mon Sep 17 00:00:00 2001 From: Jiang Jiang Jian Date: Fri, 30 Mar 2018 19:32:35 +0800 Subject: [PATCH] Merge branch 'bugfix/flash_mapp' into 'master' spi_flash: add api to get valid mmu table pages number See merge request idf/esp-idf!2070 (cherry picked from commit 8eaae96658ca382096b801e9991eeaeca5937824) 75550315 add api get valid mmu table pages number fa687743 spi_flash: 49a236da fix CI failed when flash chip size if 2MBytes --- .../bootloader_support/src/bootloader_flash.c | 5 +- .../bootloader_support/src/esp_image_format.c | 42 +++++++++++++--- components/spi_flash/flash_mmap.c | 49 ++++++++++++++----- components/spi_flash/include/esp_spi_flash.h | 15 ++++++ components/spi_flash/test/test_mmap.c | 49 +++++++++++++++++++ 5 files changed, 140 insertions(+), 20 deletions(-) diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index 9a82590393..a7a6f6e616 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -23,7 +23,7 @@ */ static const char *TAG = "bootloader_mmap"; -static spi_flash_mmap_memory_t map; +static spi_flash_mmap_handle_t map; const void *bootloader_mmap(uint32_t src_addr, uint32_t size) { @@ -36,7 +36,8 @@ const void *bootloader_mmap(uint32_t src_addr, uint32_t size) size += (src_addr - src_page); esp_err_t err = spi_flash_mmap(src_page, size, SPI_FLASH_MMAP_DATA, &result, &map); if (err != ESP_OK) { - result = NULL; + ESP_LOGE(TAG, "spi_flash_mmap failed: 0x%x", err); + return NULL; } return (void *)((intptr_t)result + (src_addr - src_page)); } diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index f053a20692..c65020595b 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,9 @@ static const char *TAG = "esp_image"; /* Headroom to ensure between stack SP (at time of checking) and data loaded from flash */ #define STACK_LOAD_HEADROOM 32768 +/* Mmap source address mask */ +#define MMAP_ALIGNED_MASK 0x0000FFFF + #ifdef BOOTLOADER_BUILD /* 64 bits of random data to obfuscate loaded RAM with, until verification is complete (Means loaded code isn't executable until after the secure boot check.) @@ -48,6 +52,9 @@ static bool should_map(uint32_t load_addr); /* Load or verify a segment */ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segment_header_t *header, bool silent, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum); +/* split segment and verify if data_len is too long */ +static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, uint32_t data_len, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum); + /* Verify the main image header */ static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent); @@ -291,7 +298,36 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme } } } +#ifndef BOOTLOADER_BUILD + uint32_t free_page_count = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA); + ESP_LOGD(TAG, "free data page_count 0x%08x",free_page_count); + uint32_t offset_page = 0; + while (data_len >= free_page_count * SPI_FLASH_MMU_PAGE_SIZE) { + offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0)?1:0; + err = process_segment_data(load_addr, data_addr, (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE, do_load, sha_handle, checksum); + if (err != ESP_OK) { + return err; + } + data_addr += (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE; + data_len -= (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE; + } +#endif + err = process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum); + if (err != ESP_OK) { + return err; + } + return ESP_OK; +err: + if (err == ESP_OK) { + err = ESP_ERR_IMAGE_INVALID; + } + + return err; +} + +static esp_err_t process_segment_data(intptr_t load_addr, uint32_t data_addr, uint32_t data_len, bool do_load, bootloader_sha256_handle_t sha_handle, uint32_t *checksum) +{ const uint32_t *data = (const uint32_t *)bootloader_mmap(data_addr, data_len); if(!data) { ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", @@ -332,12 +368,6 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme bootloader_munmap(data); return ESP_OK; - - err: - if (err == ESP_OK) { - err = ESP_ERR_IMAGE_INVALID; - } - return err; } static esp_err_t verify_segment_header(int index, const esp_image_segment_header_t *segment, uint32_t segment_data_offs, bool silent) diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index d6b884d33c..91e213d4d8 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -100,6 +100,21 @@ static void IRAM_ATTR spi_flash_mmap_init() DPORT_STALL_OTHER_CPU_END(); } +static void IRAM_ATTR get_mmu_region(spi_flash_mmap_memory_t memory, int* out_begin, int* out_size,uint32_t* region_addr) +{ + if (memory == SPI_FLASH_MMAP_DATA) { + // Vaddr0 + *out_begin = 0; + *out_size = 64; + *region_addr = VADDR0_START_ADDR; + } else { + // only part of VAddr1 is usable, so adjust for that + *out_begin = PRO_IRAM0_FIRST_USABLE_PAGE; + *out_size = 3 * 64 - *out_begin; + *region_addr = VADDR1_FIRST_USABLE_ADDR; + } +} + esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_memory_t memory, const void** out_ptr, spi_flash_mmap_handle_t* out_handle) { @@ -157,17 +172,7 @@ esp_err_t IRAM_ATTR spi_flash_mmap_pages(int *pages, size_t page_count, spi_flas int region_begin; // first page to check int region_size; // number of pages to check uint32_t region_addr; // base address of memory region - if (memory == SPI_FLASH_MMAP_DATA) { - // Vaddr0 - region_begin = 0; - region_size = 64; - region_addr = VADDR0_START_ADDR; - } else { - // only part of VAddr1 is usable, so adjust for that - region_begin = PRO_IRAM0_FIRST_USABLE_PAGE; - region_size = 3 * 64 - region_begin; - region_addr = VADDR1_FIRST_USABLE_ADDR; - } + get_mmu_region(memory,®ion_begin,®ion_size,®ion_addr); if (region_size < page_count) { return ESP_ERR_NO_MEM; } @@ -175,7 +180,9 @@ esp_err_t IRAM_ATTR spi_flash_mmap_pages(int *pages, size_t page_count, spi_flas // Algorithm is essentially naïve strstr algorithm, except that unused MMU // entries are treated as wildcards. int start; - int end = region_begin + region_size - page_count; + // the " + 1" is a fix when loop the MMU table pages, because the last MMU page + // is valid as well if it have not been used + int end = region_begin + region_size - page_count + 1; for (start = region_begin; start < end; ++start) { int pageno = 0; int pos; @@ -292,6 +299,24 @@ void spi_flash_mmap_dump() } } +uint32_t spi_flash_mmap_get_free_pages(spi_flash_mmap_memory_t memory) +{ + spi_flash_mmap_init(); + int count = 0; + int region_begin; // first page to check + int region_size; // number of pages to check + uint32_t region_addr; // base address of memory region + get_mmu_region(memory,®ion_begin,®ion_size,®ion_addr); + DPORT_STALL_OTHER_CPU_START(); + for (int i = region_begin; i < region_begin + region_size; ++i) { + if (s_mmap_page_refcnt[i] == 0 && DPORT_PRO_FLASH_MMU_TABLE[i] == INVALID_ENTRY_VAL) { + count++; + } + } + DPORT_STALL_OTHER_CPU_END(); + return count; +} + /* 256-bit (up to 16MB of 64KB pages) bitset of all flash pages that have been written to since last cache flush. diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index 8dee9d341e..beb881713a 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -220,6 +220,21 @@ void spi_flash_munmap(spi_flash_mmap_handle_t handle); */ void spi_flash_mmap_dump(); +/** + * @brief get free pages number which can be mmap + * + * This function will return free page number of the mmu table which can mmap, + * when you want to call spi_flash_mmap to mmap an ranger of flash data to Dcache or Icache + * memmory region, maybe the size of MMU table will exceed,so if you are not sure the + * size need mmap is ok, can call the interface and watch how many MMU table page can be + * mmaped. + * + * @param memory memmory type of MMU table free page + * + * @return number of free pages which can be mmaped + */ +uint32_t spi_flash_mmap_get_free_pages(spi_flash_mmap_memory_t memory); + #define SPI_FLASH_CACHE2PHYS_FAIL UINT32_MAX /*= 4MB, because max size of Dcache can mapped is 4MB + setup_mmap_tests(); + + printf("Mapping %x (+%x)\n", start, end - start); + const void *ptr1; + ESP_ERROR_CHECK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); + printf("mmap_res: handle=%d ptr=%p\n", handle1, ptr1); + + spi_flash_mmap_dump(); + + srand(0); + const uint32_t *data = (const uint32_t *) ptr1; + for (int block = 0; block < (end - start) / 0x10000; ++block) { + printf("block %d\n", block); + for (int sector = 0; sector < 16; ++sector) { + printf("sector %d\n", sector); + for (uint32_t word = 0; word < 1024; ++word) { + TEST_ASSERT_EQUAL_HEX32(rand(), data[(block * 16 + sector) * 1024 + word]); + } + } + } + uint32_t free_pages = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA); + if (spi_flash_get_chip_size() <= 0x200000) { + free_pages -= 0x200000/0x10000; + } + + printf("Mapping %x (+%x)\n", 0, free_pages * SPI_FLASH_MMU_PAGE_SIZE); + const void *ptr2; + ESP_ERROR_CHECK( spi_flash_mmap(0, free_pages * SPI_FLASH_MMU_PAGE_SIZE, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) ); + printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2); + + spi_flash_mmap_dump(); + + + printf("Unmapping handle1\n"); + spi_flash_munmap(handle1); + handle1 = 0; + spi_flash_mmap_dump(); + + printf("Unmapping handle2\n"); + spi_flash_munmap(handle2); + handle2 = 0; + spi_flash_mmap_dump(); + + TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA)); +} + TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash]") { uint8_t buf[64];