Skip to content

Commit 8eaae96

Browse files
committed
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
2 parents f46ad1f + 49a236d commit 8eaae96

File tree

5 files changed

+140
-20
lines changed

5 files changed

+140
-20
lines changed

components/bootloader_support/src/bootloader_flash.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*/
2424
static const char *TAG = "bootloader_mmap";
2525

26-
static spi_flash_mmap_memory_t map;
26+
static spi_flash_mmap_handle_t map;
2727

2828
const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
2929
{
@@ -36,7 +36,8 @@ const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
3636
size += (src_addr - src_page);
3737
esp_err_t err = spi_flash_mmap(src_page, size, SPI_FLASH_MMAP_DATA, &result, &map);
3838
if (err != ESP_OK) {
39-
result = NULL;
39+
ESP_LOGE(TAG, "spi_flash_mmap failed: 0x%x", err);
40+
return NULL;
4041
}
4142
return (void *)((intptr_t)result + (src_addr - src_page));
4243
}

components/bootloader_support/src/esp_image_format.c

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <esp_image_format.h>
2020
#include <esp_secure_boot.h>
2121
#include <esp_log.h>
22+
#include <esp_spi_flash.h>
2223
#include <bootloader_flash.h>
2324
#include <bootloader_random.h>
2425
#include <bootloader_sha.h>
@@ -33,6 +34,9 @@ static const char *TAG = "esp_image";
3334
/* Headroom to ensure between stack SP (at time of checking) and data loaded from flash */
3435
#define STACK_LOAD_HEADROOM 32768
3536

37+
/* Mmap source address mask */
38+
#define MMAP_ALIGNED_MASK 0x0000FFFF
39+
3640
#ifdef BOOTLOADER_BUILD
3741
/* 64 bits of random data to obfuscate loaded RAM with, until verification is complete
3842
(Means loaded code isn't executable until after the secure boot check.)
@@ -48,6 +52,9 @@ static bool should_map(uint32_t load_addr);
4852
/* Load or verify a segment */
4953
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);
5054

55+
/* split segment and verify if data_len is too long */
56+
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);
57+
5158
/* Verify the main image header */
5259
static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent);
5360

@@ -291,7 +298,36 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
291298
}
292299
}
293300
}
301+
#ifndef BOOTLOADER_BUILD
302+
uint32_t free_page_count = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
303+
ESP_LOGD(TAG, "free data page_count 0x%08x",free_page_count);
304+
uint32_t offset_page = 0;
305+
while (data_len >= free_page_count * SPI_FLASH_MMU_PAGE_SIZE) {
306+
offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0)?1:0;
307+
err = process_segment_data(load_addr, data_addr, (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE, do_load, sha_handle, checksum);
308+
if (err != ESP_OK) {
309+
return err;
310+
}
311+
data_addr += (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE;
312+
data_len -= (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE;
313+
}
314+
#endif
315+
err = process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum);
316+
if (err != ESP_OK) {
317+
return err;
318+
}
319+
return ESP_OK;
320+
321+
err:
322+
if (err == ESP_OK) {
323+
err = ESP_ERR_IMAGE_INVALID;
324+
}
325+
326+
return err;
327+
}
294328

329+
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)
330+
{
295331
const uint32_t *data = (const uint32_t *)bootloader_mmap(data_addr, data_len);
296332
if(!data) {
297333
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
332368
bootloader_munmap(data);
333369

334370
return ESP_OK;
335-
336-
err:
337-
if (err == ESP_OK) {
338-
err = ESP_ERR_IMAGE_INVALID;
339-
}
340-
return err;
341371
}
342372

343373
static esp_err_t verify_segment_header(int index, const esp_image_segment_header_t *segment, uint32_t segment_data_offs, bool silent)

components/spi_flash/flash_mmap.c

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,21 @@ static void IRAM_ATTR spi_flash_mmap_init()
100100
DPORT_STALL_OTHER_CPU_END();
101101
}
102102

103+
static void IRAM_ATTR get_mmu_region(spi_flash_mmap_memory_t memory, int* out_begin, int* out_size,uint32_t* region_addr)
104+
{
105+
if (memory == SPI_FLASH_MMAP_DATA) {
106+
// Vaddr0
107+
*out_begin = 0;
108+
*out_size = 64;
109+
*region_addr = VADDR0_START_ADDR;
110+
} else {
111+
// only part of VAddr1 is usable, so adjust for that
112+
*out_begin = PRO_IRAM0_FIRST_USABLE_PAGE;
113+
*out_size = 3 * 64 - *out_begin;
114+
*region_addr = VADDR1_FIRST_USABLE_ADDR;
115+
}
116+
}
117+
103118
esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_memory_t memory,
104119
const void** out_ptr, spi_flash_mmap_handle_t* out_handle)
105120
{
@@ -157,25 +172,17 @@ esp_err_t IRAM_ATTR spi_flash_mmap_pages(int *pages, size_t page_count, spi_flas
157172
int region_begin; // first page to check
158173
int region_size; // number of pages to check
159174
uint32_t region_addr; // base address of memory region
160-
if (memory == SPI_FLASH_MMAP_DATA) {
161-
// Vaddr0
162-
region_begin = 0;
163-
region_size = 64;
164-
region_addr = VADDR0_START_ADDR;
165-
} else {
166-
// only part of VAddr1 is usable, so adjust for that
167-
region_begin = PRO_IRAM0_FIRST_USABLE_PAGE;
168-
region_size = 3 * 64 - region_begin;
169-
region_addr = VADDR1_FIRST_USABLE_ADDR;
170-
}
175+
get_mmu_region(memory,&region_begin,&region_size,&region_addr);
171176
if (region_size < page_count) {
172177
return ESP_ERR_NO_MEM;
173178
}
174179
// The following part searches for a range of MMU entries which can be used.
175180
// Algorithm is essentially naïve strstr algorithm, except that unused MMU
176181
// entries are treated as wildcards.
177182
int start;
178-
int end = region_begin + region_size - page_count;
183+
// the " + 1" is a fix when loop the MMU table pages, because the last MMU page
184+
// is valid as well if it have not been used
185+
int end = region_begin + region_size - page_count + 1;
179186
for (start = region_begin; start < end; ++start) {
180187
int pageno = 0;
181188
int pos;
@@ -292,6 +299,24 @@ void spi_flash_mmap_dump()
292299
}
293300
}
294301

302+
uint32_t spi_flash_mmap_get_free_pages(spi_flash_mmap_memory_t memory)
303+
{
304+
spi_flash_mmap_init();
305+
int count = 0;
306+
int region_begin; // first page to check
307+
int region_size; // number of pages to check
308+
uint32_t region_addr; // base address of memory region
309+
get_mmu_region(memory,&region_begin,&region_size,&region_addr);
310+
DPORT_STALL_OTHER_CPU_START();
311+
for (int i = region_begin; i < region_begin + region_size; ++i) {
312+
if (s_mmap_page_refcnt[i] == 0 && DPORT_PRO_FLASH_MMU_TABLE[i] == INVALID_ENTRY_VAL) {
313+
count++;
314+
}
315+
}
316+
DPORT_STALL_OTHER_CPU_END();
317+
return count;
318+
}
319+
295320
/* 256-bit (up to 16MB of 64KB pages) bitset of all flash pages
296321
that have been written to since last cache flush.
297322

components/spi_flash/include/esp_spi_flash.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,21 @@ void spi_flash_munmap(spi_flash_mmap_handle_t handle);
236236
*/
237237
void spi_flash_mmap_dump();
238238

239+
/**
240+
* @brief get free pages number which can be mmap
241+
*
242+
* This function will return free page number of the mmu table which can mmap,
243+
* when you want to call spi_flash_mmap to mmap an ranger of flash data to Dcache or Icache
244+
* memmory region, maybe the size of MMU table will exceed,so if you are not sure the
245+
* size need mmap is ok, can call the interface and watch how many MMU table page can be
246+
* mmaped.
247+
*
248+
* @param memory memmory type of MMU table free page
249+
*
250+
* @return number of free pages which can be mmaped
251+
*/
252+
uint32_t spi_flash_mmap_get_free_pages(spi_flash_mmap_memory_t memory);
253+
239254

240255
#define SPI_FLASH_CACHE2PHYS_FAIL UINT32_MAX /*<! Result from spi_flash_cache2phys() if flash cache address is invalid */
241256

components/spi_flash/test/test_mmap.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,55 @@ TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]")
276276
handle1 = 0;
277277
}
278278

279+
TEST_CASE("flash_mmap can mmap after get enough free MMU pages", "[spi_flash]")
280+
{
281+
//this test case should make flash size >= 4MB, because max size of Dcache can mapped is 4MB
282+
setup_mmap_tests();
283+
284+
printf("Mapping %x (+%x)\n", start, end - start);
285+
const void *ptr1;
286+
ESP_ERROR_CHECK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) );
287+
printf("mmap_res: handle=%d ptr=%p\n", handle1, ptr1);
288+
289+
spi_flash_mmap_dump();
290+
291+
srand(0);
292+
const uint32_t *data = (const uint32_t *) ptr1;
293+
for (int block = 0; block < (end - start) / 0x10000; ++block) {
294+
printf("block %d\n", block);
295+
for (int sector = 0; sector < 16; ++sector) {
296+
printf("sector %d\n", sector);
297+
for (uint32_t word = 0; word < 1024; ++word) {
298+
TEST_ASSERT_EQUAL_HEX32(rand(), data[(block * 16 + sector) * 1024 + word]);
299+
}
300+
}
301+
}
302+
uint32_t free_pages = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
303+
if (spi_flash_get_chip_size() <= 0x200000) {
304+
free_pages -= 0x200000/0x10000;
305+
}
306+
307+
printf("Mapping %x (+%x)\n", 0, free_pages * SPI_FLASH_MMU_PAGE_SIZE);
308+
const void *ptr2;
309+
ESP_ERROR_CHECK( spi_flash_mmap(0, free_pages * SPI_FLASH_MMU_PAGE_SIZE, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) );
310+
printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2);
311+
312+
spi_flash_mmap_dump();
313+
314+
315+
printf("Unmapping handle1\n");
316+
spi_flash_munmap(handle1);
317+
handle1 = 0;
318+
spi_flash_mmap_dump();
319+
320+
printf("Unmapping handle2\n");
321+
spi_flash_munmap(handle2);
322+
handle2 = 0;
323+
spi_flash_mmap_dump();
324+
325+
TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA));
326+
}
327+
279328
TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash]")
280329
{
281330
uint8_t buf[64];

0 commit comments

Comments
 (0)