mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
spi_flash: Add new phys2cache & cache2phys functions to query flash cache mappings
This commit is contained in:
parent
1f3a2e900c
commit
093dd98101
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user