mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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 commit8eaae96658
)75550315
add api get valid mmu table pages numberfa687743
spi_flash:49a236da
fix CI failed when flash chip size if 2MBytes
This commit is contained in:
parent
d881fcd380
commit
d6e3943233
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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,®ion_begin,®ion_size,®ion_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,®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
|
/* 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.
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
|
@ -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];
|
||||||
|
Loading…
Reference in New Issue
Block a user