From 093dd9810188e53141aacf06235151c328abeb81 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 17 Feb 2017 18:26:43 +1100 Subject: [PATCH] spi_flash: Add new phys2cache & cache2phys functions to query flash cache mappings --- components/spi_flash/flash_mmap.c | 82 +++++++++++++++++--- components/spi_flash/include/esp_spi_flash.h | 36 +++++++++ components/spi_flash/test/test_mmap.c | 69 ++++++++++++++++ docs/api/storage/spi_flash.rst | 3 + 4 files changed, 180 insertions(+), 10 deletions(-) diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index f8d2e3297d..64319a070b 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -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; +} diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index 060d598ec0..40720af38b 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -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 /* #include #include +#include #include #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)); +} diff --git a/docs/api/storage/spi_flash.rst b/docs/api/storage/spi_flash.rst index f941a3888b..4bf5e37a99 100644 --- a/docs/api/storage/spi_flash.rst +++ b/docs/api/storage/spi_flash.rst @@ -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