spi_flash: Add new phys2cache & cache2phys functions to query flash cache mappings

This commit is contained in:
Angus Gratton 2017-02-17 18:26:43 +11:00
parent 1f3a2e900c
commit 093dd98101
4 changed files with 180 additions and 10 deletions

View File

@ -74,16 +74,23 @@ static uint32_t s_mmap_last_handle = 0;
static void IRAM_ATTR spi_flash_mmap_init()
{
if (s_mmap_page_refcnt[0] != 0) {
return; /* mmap data already initialised */
}
for (int i = 0; i < REGIONS_COUNT * PAGES_PER_REGION; ++i) {
uint32_t entry_pro = DPORT_PRO_FLASH_MMU_TABLE[i];
uint32_t entry_app = DPORT_APP_FLASH_MMU_TABLE[i];
if (entry_pro != entry_app) {
// clean up entries used by boot loader
entry_pro = 0;
DPORT_PRO_FLASH_MMU_TABLE[i] = 0;
entry_pro = INVALID_ENTRY_VAL;
DPORT_PRO_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL;
}
if ((entry_pro & 0x100) == 0 && (i == 0 || i == PRO_IRAM0_FIRST_USABLE_PAGE || entry_pro != 0)) {
if ((entry_pro & INVALID_ENTRY_VAL) == 0 && (i == 0 || i == PRO_IRAM0_FIRST_USABLE_PAGE || entry_pro != 0)) {
s_mmap_page_refcnt[i] = 1;
} else {
DPORT_PRO_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL;
DPORT_APP_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL;
}
}
}
@ -108,9 +115,7 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_
did_flush = spi_flash_ensure_unmodified_region(src_addr, size);
if (s_mmap_page_refcnt[0] == 0) {
spi_flash_mmap_init();
}
spi_flash_mmap_init();
// figure out the memory region where we should look for pages
int region_begin; // first page to check
int region_size; // number of pages to check
@ -139,7 +144,7 @@ esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_
int pos;
for (pos = start; pos < start + page_count; ++pos, ++page) {
int table_val = (int) DPORT_PRO_FLASH_MMU_TABLE[pos];
uint8_t refcnt = s_mmap_page_refcnt[pos];
uint8_t refcnt = s_mmap_page_refcnt[pos];
if (refcnt != 0 && table_val != page) {
break;
}
@ -229,9 +234,7 @@ void IRAM_ATTR spi_flash_munmap(spi_flash_mmap_handle_t handle)
void spi_flash_mmap_dump()
{
if (s_mmap_page_refcnt[0] == 0) {
spi_flash_mmap_init();
}
spi_flash_mmap_init();
mmap_entry_t* it;
for (it = LIST_FIRST(&s_mmap_entries_head); it != NULL; it = LIST_NEXT(it, entries)) {
printf("handle=%d page=%d count=%d\n", it->handle, it->page, it->count);
@ -305,3 +308,62 @@ static inline IRAM_ATTR bool update_written_pages(size_t start_addr, size_t leng
}
return false;
}
uint32_t spi_flash_cache2phys(const void *cached)
{
intptr_t c = (intptr_t)cached;
size_t cache_page;
if (c >= VADDR1_START_ADDR && c < VADDR1_FIRST_USABLE_ADDR) {
/* IRAM address, doesn't map to flash */
return SPI_FLASH_CACHE2PHYS_FAIL;
}
else if (c < VADDR1_FIRST_USABLE_ADDR) {
/* expect cache is in DROM */
cache_page = (c - VADDR0_START_ADDR) / SPI_FLASH_MMU_PAGE_SIZE;
} else {
/* expect cache is in IROM */
cache_page = (c - VADDR1_START_ADDR) / SPI_FLASH_MMU_PAGE_SIZE + 64;
}
if (cache_page >= 256) {
/* cached address was not in IROM or DROM */
return SPI_FLASH_CACHE2PHYS_FAIL;
}
uint32_t phys_page = DPORT_PRO_FLASH_MMU_TABLE[cache_page];
if (phys_page == INVALID_ENTRY_VAL) {
/* page is not mapped */
return SPI_FLASH_CACHE2PHYS_FAIL;
}
uint32_t phys_offs = phys_page * SPI_FLASH_MMU_PAGE_SIZE;
return phys_offs | (c & (SPI_FLASH_MMU_PAGE_SIZE-1));
}
const void *spi_flash_phys2cache(uint32_t phys_offs, spi_flash_mmap_memory_t memory)
{
uint32_t phys_page = phys_offs / SPI_FLASH_MMU_PAGE_SIZE;
int start, end, page_delta;
intptr_t base;
if (memory == SPI_FLASH_MMAP_DATA) {
start = 0;
end = 64;
base = VADDR0_START_ADDR;
page_delta = 0;
} else {
start = PRO_IRAM0_FIRST_USABLE_PAGE;
end = 256;
base = VADDR1_START_ADDR;
page_delta = 64;
}
for (int i = start; i < end; i++) {
if (DPORT_PRO_FLASH_MMU_TABLE[i] == phys_page) {
i -= page_delta;
intptr_t cache_page = base + (SPI_FLASH_MMU_PAGE_SIZE * i);
return (const void *) (cache_page | (phys_offs & (SPI_FLASH_MMU_PAGE_SIZE-1)));
}
}
return NULL;
}

View File

@ -197,6 +197,42 @@ void spi_flash_munmap(spi_flash_mmap_handle_t handle);
*/
void spi_flash_mmap_dump();
#define SPI_FLASH_CACHE2PHYS_FAIL UINT32_MAX /*<! Result from spi_flash_cache2phys() if flash cache address is invalid */
/**
* @brief Given a memory address where flash is mapped, return the corresponding physical flash offset.
*
* Cache address does not have have been assigned via spi_flash_mmap(), any address in flash map space can be looked up.
*
* @param cached Pointer to flashed cached memory.
*
* @return
* - SPI_FLASH_CACHE2PHYS_FAIL If cache address is outside flash cache region, or the address is not mapped.
* - Otherwise, returns physical offset in flash
*/
size_t spi_flash_cache2phys(const void *cached);
/** @brief Given a physical offset in flash, return the address where it is mapped in the memory space.
*
* Physical address does not have to have been assigned via spi_flash_mmap(), any address in flash can be looked up.
*
* @note Only the first matching cache address is returned. If MMU flash cache table is configured so multiple entries
* point to the same physical address, there may be more than one cache address corresponding to that physical
* address. It is also possible for a single physical address to be mapped to both the IROM and DROM regions.
*
* @note This function doesn't impose any alignment constraints, but if memory argument is SPI_FLASH_MMAP_INST and
* phys_offs is not 4-byte aligned, then reading from the returned pointer will result in a crash.
*
* @param phys_offs Physical offset in flash memory to look up.
* @param memory Memory type to look up a flash cache address mapping for (IROM or DROM)
*
* @return
* - NULL if the physical address is invalid or not mapped to flash cache of the specified memory type.
* - Cached memory address (in IROM or DROM space) corresponding to phys_offs.
*/
const void *spi_flash_phys2cache(size_t phys_offs, spi_flash_mmap_memory_t memory);
/**
* @brief SPI flash critical section enter function.
*/

View File

@ -8,6 +8,7 @@
#include <unity.h>
#include <esp_spi_flash.h>
#include <esp_attr.h>
#include <esp_partition.h>
#include <esp_flash_encrypt.h>
#include "test_config.h"
@ -65,6 +66,11 @@ TEST_CASE("Can mmap into data address space", "[mmap]")
const void *ptr2;
ESP_ERROR_CHECK( spi_flash_mmap(start - 0x10000, 0x20000, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) );
printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2);
TEST_ASSERT_EQUAL_HEX32(start - 0x10000, spi_flash_cache2phys(ptr2));
TEST_ASSERT_EQUAL_PTR(ptr2, spi_flash_phys2cache(start - 0x10000, SPI_FLASH_MMAP_DATA));
TEST_ASSERT_EQUAL_PTR((intptr_t)ptr2 + 0x12000, spi_flash_phys2cache(start - 0x10000 + 0x12000, SPI_FLASH_MMAP_DATA));
spi_flash_mmap_dump();
printf("Mapping %x (+%x)\n", start, 0x10000);
@ -72,6 +78,11 @@ TEST_CASE("Can mmap into data address space", "[mmap]")
const void *ptr3;
ESP_ERROR_CHECK( spi_flash_mmap(start, 0x10000, SPI_FLASH_MMAP_DATA, &ptr3, &handle3) );
printf("mmap_res: handle=%d ptr=%p\n", handle3, ptr3);
TEST_ASSERT_EQUAL_HEX32(start, spi_flash_cache2phys(ptr3));
TEST_ASSERT_EQUAL_PTR(ptr3, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA));
TEST_ASSERT_EQUAL_PTR((intptr_t)ptr3 + 0x4444, spi_flash_phys2cache(start + 0x4444, SPI_FLASH_MMAP_DATA));
spi_flash_mmap_dump();
printf("Unmapping handle1\n");
@ -84,6 +95,8 @@ TEST_CASE("Can mmap into data address space", "[mmap]")
printf("Unmapping handle3\n");
spi_flash_munmap(handle3);
TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA));
}
TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]")
@ -131,3 +144,59 @@ TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]")
spi_flash_munmap(handle1);
}
TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash]")
{
uint8_t buf_a[32], buf_b[32];
/* esp_partition_find is in IROM */
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));
TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA));
/* Read the flash @ 'phys' and compare it to the data we get via cache */
memcpy(buf_a, esp_partition_find, sizeof(buf_a));
spi_flash_read(phys, buf_b, sizeof(buf_b));
TEST_ASSERT_EQUAL_HEX8_ARRAY(buf_a, buf_b, sizeof(buf_b));
/* spi_flash_mmap is in IRAM */
printf("%p\n", spi_flash_mmap);
TEST_ASSERT_EQUAL_HEX32(SPI_FLASH_CACHE2PHYS_FAIL,
spi_flash_cache2phys(spi_flash_mmap));
/* 'start' should be in DROM */
phys = spi_flash_cache2phys(&start);
TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys);
TEST_ASSERT_EQUAL_PTR(&start,
spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA));
TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST));
/* Read the flash @ 'phys' and compare it to the data we get via cache */
memcpy(buf_a, &start, sizeof(start));
spi_flash_read(phys, buf_b, sizeof(start));
TEST_ASSERT_EQUAL_HEX8_ARRAY(buf_a, buf_b, sizeof(start));
}
TEST_CASE("mmap consistent with phys2cache/cache2phys", "[spi_flash]")
{
spi_flash_mmap_handle_t handle = 0;
const void *ptr = NULL;
const size_t test_size = 2 * SPI_FLASH_MMU_PAGE_SIZE;
TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr));
ESP_ERROR_CHECK( spi_flash_mmap(TEST_REGION_START, test_size, SPI_FLASH_MMAP_DATA, &ptr, &handle) );
TEST_ASSERT_NOT_NULL(ptr);
TEST_ASSERT_NOT_EQUAL(0, handle);
TEST_ASSERT_EQUAL_HEX(TEST_REGION_START, spi_flash_cache2phys(ptr));
TEST_ASSERT_EQUAL_HEX(TEST_REGION_START + 1024, spi_flash_cache2phys((void *)((intptr_t)ptr + 1024)));
TEST_ASSERT_EQUAL_HEX(TEST_REGION_START + 3000, spi_flash_cache2phys((void *)((intptr_t)ptr + 3000)));
/* this pointer lands in a different MMU table entry */
TEST_ASSERT_EQUAL_HEX(TEST_REGION_START + test_size - 4, spi_flash_cache2phys((void *)((intptr_t)ptr + test_size - 4)));
spi_flash_munmap(handle);
TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr));
}

View File

@ -26,6 +26,7 @@ Macros
.. doxygendefine:: SPI_FLASH_SEC_SIZE
.. doxygendefine:: SPI_FLASH_MMU_PAGE_SIZE
.. doxygendefine:: ESP_PARTITION_SUBTYPE_OTA
.. doxygendefine:: SPI_FLASH_CACHE2PHYS_FAIL
Type Definitions
^^^^^^^^^^^^^^^^
@ -59,6 +60,8 @@ Functions
.. doxygenfunction:: spi_flash_mmap
.. doxygenfunction:: spi_flash_munmap
.. doxygenfunction:: spi_flash_mmap_dump
.. doxygenfunction:: spi_flash_cache2phys
.. doxygenfunction:: spi_flash_phys2cache
.. doxygenfunction:: esp_partition_find
.. doxygenfunction:: esp_partition_find_first
.. doxygenfunction:: esp_partition_get