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 8eaae96658)

75550315 add api get valid mmu table pages number
fa687743 spi_flash:
49a236da fix CI failed when flash chip size if 2MBytes
This commit is contained in:
Jiang Jiang Jian 2018-03-30 19:32:35 +08:00 committed by bot
parent d881fcd380
commit d6e3943233
5 changed files with 140 additions and 20 deletions

View File

@ -23,7 +23,7 @@
*/ */
static const char *TAG = "bootloader_mmap"; 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) 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); size += (src_addr - src_page);
esp_err_t err = spi_flash_mmap(src_page, size, SPI_FLASH_MMAP_DATA, &result, &map); esp_err_t err = spi_flash_mmap(src_page, size, SPI_FLASH_MMAP_DATA, &result, &map);
if (err != ESP_OK) { 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)); return (void *)((intptr_t)result + (src_addr - src_page));
} }

View File

@ -19,6 +19,7 @@
#include <esp_image_format.h> #include <esp_image_format.h>
#include <esp_secure_boot.h> #include <esp_secure_boot.h>
#include <esp_log.h> #include <esp_log.h>
#include <esp_spi_flash.h>
#include <bootloader_flash.h> #include <bootloader_flash.h>
#include <bootloader_random.h> #include <bootloader_random.h>
#include <bootloader_sha.h> #include <bootloader_sha.h>
@ -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 */ /* Headroom to ensure between stack SP (at time of checking) and data loaded from flash */
#define STACK_LOAD_HEADROOM 32768 #define STACK_LOAD_HEADROOM 32768
/* Mmap source address mask */
#define MMAP_ALIGNED_MASK 0x0000FFFF
#ifdef BOOTLOADER_BUILD #ifdef BOOTLOADER_BUILD
/* 64 bits of random data to obfuscate loaded RAM with, until verification is complete /* 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.) (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 */ /* 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); 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 */ /* Verify the main image header */
static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent); 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); const uint32_t *data = (const uint32_t *)bootloader_mmap(data_addr, data_len);
if(!data) { if(!data) {
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", 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); bootloader_munmap(data);
return ESP_OK; 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) static esp_err_t verify_segment_header(int index, const esp_image_segment_header_t *segment, uint32_t segment_data_offs, bool silent)

View File

@ -100,6 +100,21 @@ static void IRAM_ATTR spi_flash_mmap_init()
DPORT_STALL_OTHER_CPU_END(); 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, 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) 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_begin; // first page to check
int region_size; // number of pages to check int region_size; // number of pages to check
uint32_t region_addr; // base address of memory region uint32_t region_addr; // base address of memory region
if (memory == SPI_FLASH_MMAP_DATA) { get_mmu_region(memory,&region_begin,&region_size,&region_addr);
// 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;
}
if (region_size < page_count) { if (region_size < page_count) {
return ESP_ERR_NO_MEM; 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 // Algorithm is essentially naïve strstr algorithm, except that unused MMU
// entries are treated as wildcards. // entries are treated as wildcards.
int start; 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) { for (start = region_begin; start < end; ++start) {
int pageno = 0; int pageno = 0;
int pos; 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,&region_begin,&region_size,&region_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 /* 256-bit (up to 16MB of 64KB pages) bitset of all flash pages
that have been written to since last cache flush. that have been written to since last cache flush.

View File

@ -220,6 +220,21 @@ void spi_flash_munmap(spi_flash_mmap_handle_t handle);
*/ */
void spi_flash_mmap_dump(); 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 /*<! Result from spi_flash_cache2phys() if flash cache address is invalid */ #define SPI_FLASH_CACHE2PHYS_FAIL UINT32_MAX /*<! Result from spi_flash_cache2phys() if flash cache address is invalid */

View File

@ -276,6 +276,55 @@ TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]")
handle1 = 0; handle1 = 0;
} }
TEST_CASE("flash_mmap can mmap after get enough free MMU pages", "[spi_flash]")
{
//this test case should make flash size >= 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]") TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash]")
{ {
uint8_t buf[64]; uint8_t buf[64];