test_mmap.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <freertos/FreeRTOS.h>
  5. #include <freertos/task.h>
  6. #include <freertos/semphr.h>
  7. #include <unity.h>
  8. #include <esp_spi_flash.h>
  9. #include <esp_attr.h>
  10. #include <esp_partition.h>
  11. #include <esp_flash_encrypt.h>
  12. #include "test_utils.h"
  13. static uint32_t buffer[1024];
  14. /* read-only region used for mmap tests, intialised in setup_mmap_tests() */
  15. static uint32_t start;
  16. static uint32_t end;
  17. static spi_flash_mmap_handle_t handle1, handle2, handle3;
  18. static void setup_mmap_tests()
  19. {
  20. if (start == 0) {
  21. const esp_partition_t *part = get_test_data_partition();
  22. start = part->address;
  23. end = part->address + part->size;
  24. printf("Test data partition @ 0x%x - 0x%x\n", start, end);
  25. }
  26. TEST_ASSERT(end > start);
  27. TEST_ASSERT(end - start >= 512*1024);
  28. /* clean up any mmap handles left over from failed tests */
  29. if (handle1) {
  30. spi_flash_munmap(handle1);
  31. handle1 = 0;
  32. }
  33. if (handle2) {
  34. spi_flash_munmap(handle2);
  35. handle2 = 0;
  36. }
  37. if (handle3) {
  38. spi_flash_munmap(handle3);
  39. handle3 = 0;
  40. }
  41. /* prepare flash contents */
  42. srand(0);
  43. for (int block = start / 0x10000; block < end / 0x10000; ++block) {
  44. for (int sector = 0; sector < 16; ++sector) {
  45. uint32_t abs_sector = (block * 16) + sector;
  46. uint32_t sector_offs = abs_sector * SPI_FLASH_SEC_SIZE;
  47. bool sector_needs_write = false;
  48. ESP_ERROR_CHECK( spi_flash_read(sector_offs, buffer, sizeof(buffer)) );
  49. for (uint32_t word = 0; word < 1024; ++word) {
  50. uint32_t val = rand();
  51. if (block == start / 0x10000 && sector == 0 && word == 0) {
  52. printf("setup_mmap_tests(): first prepped word: 0x%08x (flash holds 0x%08x)\n", val, buffer[word]);
  53. }
  54. if (buffer[word] != val) {
  55. buffer[word] = val;
  56. sector_needs_write = true;
  57. }
  58. }
  59. /* Only rewrite the sector if it has changed */
  60. if (sector_needs_write) {
  61. printf("setup_mmap_tests(): Prepping sector %d\n", abs_sector);
  62. ESP_ERROR_CHECK( spi_flash_erase_sector((uint16_t) abs_sector) );
  63. ESP_ERROR_CHECK( spi_flash_write(sector_offs, (const uint8_t *) buffer, sizeof(buffer)) );
  64. }
  65. }
  66. }
  67. }
  68. TEST_CASE("Can mmap into data address space", "[spi_flash]")
  69. {
  70. setup_mmap_tests();
  71. printf("Mapping %x (+%x)\n", start, end - start);
  72. const void *ptr1;
  73. ESP_ERROR_CHECK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) );
  74. printf("mmap_res: handle=%d ptr=%p\n", handle1, ptr1);
  75. spi_flash_mmap_dump();
  76. srand(0);
  77. const uint32_t *data = (const uint32_t *) ptr1;
  78. for (int block = 0; block < (end - start) / 0x10000; ++block) {
  79. printf("block %d\n", block);
  80. for (int sector = 0; sector < 16; ++sector) {
  81. printf("sector %d\n", sector);
  82. for (uint32_t word = 0; word < 1024; ++word) {
  83. TEST_ASSERT_EQUAL_HEX32(rand(), data[(block * 16 + sector) * 1024 + word]);
  84. }
  85. }
  86. }
  87. printf("Mapping %x (+%x)\n", start - 0x10000, 0x20000);
  88. const void *ptr2;
  89. ESP_ERROR_CHECK( spi_flash_mmap(start - 0x10000, 0x20000, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) );
  90. printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2);
  91. TEST_ASSERT_EQUAL_HEX32(start - 0x10000, spi_flash_cache2phys(ptr2));
  92. TEST_ASSERT_EQUAL_PTR(ptr2, spi_flash_phys2cache(start - 0x10000, SPI_FLASH_MMAP_DATA));
  93. spi_flash_mmap_dump();
  94. printf("Mapping %x (+%x)\n", start, 0x10000);
  95. const void *ptr3;
  96. ESP_ERROR_CHECK( spi_flash_mmap(start, 0x10000, SPI_FLASH_MMAP_DATA, &ptr3, &handle3) );
  97. printf("mmap_res: handle=%d ptr=%p\n", handle3, ptr3);
  98. TEST_ASSERT_EQUAL_HEX32(start, spi_flash_cache2phys(ptr3));
  99. TEST_ASSERT_EQUAL_PTR(ptr3, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA));
  100. TEST_ASSERT_EQUAL_PTR((intptr_t)ptr3 + 0x4444, spi_flash_phys2cache(start + 0x4444, SPI_FLASH_MMAP_DATA));
  101. spi_flash_mmap_dump();
  102. printf("Unmapping handle1\n");
  103. spi_flash_munmap(handle1);
  104. handle1 = 0;
  105. spi_flash_mmap_dump();
  106. printf("Unmapping handle2\n");
  107. spi_flash_munmap(handle2);
  108. handle2 = 0;
  109. spi_flash_mmap_dump();
  110. printf("Unmapping handle3\n");
  111. spi_flash_munmap(handle3);
  112. handle3 = 0;
  113. TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA));
  114. }
  115. TEST_CASE("Can mmap into instruction address space", "[mmap]")
  116. {
  117. setup_mmap_tests();
  118. printf("Mapping %x (+%x)\n", start, end - start);
  119. spi_flash_mmap_handle_t handle1;
  120. const void *ptr1;
  121. ESP_ERROR_CHECK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_INST, &ptr1, &handle1) );
  122. printf("mmap_res: handle=%d ptr=%p\n", handle1, ptr1);
  123. spi_flash_mmap_dump();
  124. srand(0);
  125. const uint32_t *data = (const uint32_t *) ptr1;
  126. for (int block = 0; block < (end - start) / 0x10000; ++block) {
  127. for (int sector = 0; sector < 16; ++sector) {
  128. for (uint32_t word = 0; word < 1024; ++word) {
  129. TEST_ASSERT_EQUAL_UINT32(rand(), data[(block * 16 + sector) * 1024 + word]);
  130. }
  131. }
  132. }
  133. printf("Mapping %x (+%x)\n", start - 0x10000, 0x20000);
  134. spi_flash_mmap_handle_t handle2;
  135. const void *ptr2;
  136. ESP_ERROR_CHECK( spi_flash_mmap(start - 0x10000, 0x20000, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) );
  137. printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2);
  138. spi_flash_mmap_dump();
  139. printf("Mapping %x (+%x)\n", start, 0x10000);
  140. spi_flash_mmap_handle_t handle3;
  141. const void *ptr3;
  142. ESP_ERROR_CHECK( spi_flash_mmap(start, 0x10000, SPI_FLASH_MMAP_DATA, &ptr3, &handle3) );
  143. printf("mmap_res: handle=%d ptr=%p\n", handle3, ptr3);
  144. spi_flash_mmap_dump();
  145. printf("Unmapping handle1\n");
  146. spi_flash_munmap(handle1);
  147. spi_flash_mmap_dump();
  148. printf("Unmapping handle2\n");
  149. spi_flash_munmap(handle2);
  150. spi_flash_mmap_dump();
  151. printf("Unmapping handle3\n");
  152. spi_flash_munmap(handle3);
  153. }
  154. TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash]")
  155. {
  156. const void *ptr1;
  157. const size_t test_size = 128;
  158. setup_mmap_tests();
  159. if (esp_flash_encryption_enabled()) {
  160. TEST_IGNORE_MESSAGE("flash encryption enabled, spi_flash_write_encrypted() test won't pass as-is");
  161. }
  162. ESP_ERROR_CHECK( spi_flash_erase_sector(start / SPI_FLASH_SEC_SIZE) );
  163. /* map erased test region to ptr1 */
  164. ESP_ERROR_CHECK( spi_flash_mmap(start, test_size, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) );
  165. printf("mmap_res ptr1: handle=%d ptr=%p\n", handle1, ptr1);
  166. /* verify it's all 0xFF */
  167. for (int i = 0; i < test_size; i++) {
  168. TEST_ASSERT_EQUAL_HEX(0xFF, ((uint8_t *)ptr1)[i]);
  169. }
  170. /* unmap the erased region */
  171. spi_flash_munmap(handle1);
  172. handle1 = 0;
  173. /* write flash region to 0xEE */
  174. uint8_t buf[test_size];
  175. memset(buf, 0xEE, test_size);
  176. ESP_ERROR_CHECK( spi_flash_write(start, buf, test_size) );
  177. /* re-map the test region at ptr1.
  178. this is a fresh mmap call so should trigger a cache flush,
  179. ensuring we see the updated flash.
  180. */
  181. ESP_ERROR_CHECK( spi_flash_mmap(start, test_size, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) );
  182. printf("mmap_res ptr1 #2: handle=%d ptr=%p\n", handle1, ptr1);
  183. /* assert that ptr1 now maps to the new values on flash,
  184. ie contents of buf array.
  185. */
  186. TEST_ASSERT_EQUAL_HEX8_ARRAY(buf, ptr1, test_size);
  187. spi_flash_munmap(handle1);
  188. handle1 = 0;
  189. }
  190. TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash]")
  191. {
  192. uint8_t buf[64];
  193. static const uint8_t constant_data[] = { 1, 2, 3, 7, 11, 16, 3, 88 };
  194. /* esp_partition_find is in IROM */
  195. uint32_t phys = spi_flash_cache2phys(esp_partition_find);
  196. TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys);
  197. TEST_ASSERT_EQUAL_PTR(esp_partition_find, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST));
  198. TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA));
  199. /* Read the flash @ 'phys' and compare it to the data we get via regular cache access */
  200. spi_flash_read(phys, buf, sizeof(buf));
  201. TEST_ASSERT_EQUAL_HEX32_ARRAY((void *)esp_partition_find, buf, sizeof(buf)/sizeof(uint32_t));
  202. /* spi_flash_mmap is in IRAM */
  203. printf("%p\n", spi_flash_mmap);
  204. TEST_ASSERT_EQUAL_HEX32(SPI_FLASH_CACHE2PHYS_FAIL,
  205. spi_flash_cache2phys(spi_flash_mmap));
  206. /* 'constant_data' should be in DROM */
  207. phys = spi_flash_cache2phys(&constant_data);
  208. TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys);
  209. TEST_ASSERT_EQUAL_PTR(&constant_data,
  210. spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA));
  211. TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST));
  212. /* Read the flash @ 'phys' and compare it to the data we get via normal cache access */
  213. spi_flash_read(phys, buf, sizeof(constant_data));
  214. TEST_ASSERT_EQUAL_HEX8_ARRAY(constant_data, buf, sizeof(constant_data));
  215. }
  216. TEST_CASE("mmap consistent with phys2cache/cache2phys", "[spi_flash]")
  217. {
  218. const void *ptr = NULL;
  219. const size_t test_size = 2 * SPI_FLASH_MMU_PAGE_SIZE;
  220. setup_mmap_tests();
  221. TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr));
  222. ESP_ERROR_CHECK( spi_flash_mmap(start, test_size, SPI_FLASH_MMAP_DATA, &ptr, &handle1) );
  223. TEST_ASSERT_NOT_NULL(ptr);
  224. TEST_ASSERT_NOT_EQUAL(0, handle1);
  225. TEST_ASSERT_EQUAL_HEX(start, spi_flash_cache2phys(ptr));
  226. TEST_ASSERT_EQUAL_HEX(start + 1024, spi_flash_cache2phys((void *)((intptr_t)ptr + 1024)));
  227. TEST_ASSERT_EQUAL_HEX(start + 3000, spi_flash_cache2phys((void *)((intptr_t)ptr + 3000)));
  228. /* this pointer lands in a different MMU table entry */
  229. TEST_ASSERT_EQUAL_HEX(start + test_size - 4, spi_flash_cache2phys((void *)((intptr_t)ptr + test_size - 4)));
  230. spi_flash_munmap(handle1);
  231. handle1 = 0;
  232. TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr));
  233. }
  234. TEST_CASE("munmap followed by mmap flushes cache", "[spi_flash]")
  235. {
  236. setup_mmap_tests();
  237. const esp_partition_t *p = get_test_data_partition();
  238. const uint32_t* data;
  239. spi_flash_mmap_handle_t handle;
  240. TEST_ESP_OK( esp_partition_mmap(p, 0, SPI_FLASH_MMU_PAGE_SIZE,
  241. SPI_FLASH_MMAP_DATA, (const void **) &data, &handle) );
  242. uint32_t buf[16];
  243. memcpy(buf, data, sizeof(buf));
  244. spi_flash_munmap(handle);
  245. TEST_ESP_OK( esp_partition_mmap(p, SPI_FLASH_MMU_PAGE_SIZE, SPI_FLASH_MMU_PAGE_SIZE,
  246. SPI_FLASH_MMAP_DATA, (const void **) &data, &handle) );
  247. TEST_ASSERT_NOT_EQUAL(0, memcmp(buf, data, sizeof(buf)));
  248. }