test_mmap.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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 esp_err_t spi_flash_read_maybe_encrypted(size_t src_addr, void *des_addr, size_t size)
  19. {
  20. if (!esp_flash_encryption_enabled()) {
  21. return spi_flash_read(src_addr, des_addr, size);
  22. } else {
  23. return spi_flash_read_encrypted(src_addr, des_addr, size);
  24. }
  25. }
  26. static esp_err_t spi_flash_write_maybe_encrypted(size_t des_addr, const void *src_addr, size_t size)
  27. {
  28. if (!esp_flash_encryption_enabled()) {
  29. return spi_flash_write(des_addr, src_addr, size);
  30. } else {
  31. return spi_flash_write_encrypted(des_addr, src_addr, size);
  32. }
  33. }
  34. static void setup_mmap_tests(void)
  35. {
  36. if (start == 0) {
  37. const esp_partition_t *part = get_test_data_partition();
  38. start = part->address;
  39. end = part->address + part->size;
  40. printf("Test data partition @ 0x%x - 0x%x\n", start, end);
  41. }
  42. TEST_ASSERT(end > start);
  43. TEST_ASSERT(end - start >= 512*1024);
  44. /* clean up any mmap handles left over from failed tests */
  45. if (handle1) {
  46. spi_flash_munmap(handle1);
  47. handle1 = 0;
  48. }
  49. if (handle2) {
  50. spi_flash_munmap(handle2);
  51. handle2 = 0;
  52. }
  53. if (handle3) {
  54. spi_flash_munmap(handle3);
  55. handle3 = 0;
  56. }
  57. /* prepare flash contents */
  58. srand(0);
  59. for (int block = start / 0x10000; block < end / 0x10000; ++block) {
  60. for (int sector = 0; sector < 16; ++sector) {
  61. uint32_t abs_sector = (block * 16) + sector;
  62. uint32_t sector_offs = abs_sector * SPI_FLASH_SEC_SIZE;
  63. bool sector_needs_write = false;
  64. ESP_ERROR_CHECK( spi_flash_read_maybe_encrypted(sector_offs, buffer, sizeof(buffer)) );
  65. for (uint32_t word = 0; word < 1024; ++word) {
  66. uint32_t val = rand();
  67. if (block == start / 0x10000 && sector == 0 && word == 0) {
  68. printf("setup_mmap_tests(): first prepped word: 0x%08x (flash holds 0x%08x)\n", val, buffer[word]);
  69. }
  70. if (buffer[word] != val) {
  71. buffer[word] = val;
  72. sector_needs_write = true;
  73. }
  74. }
  75. /* Only rewrite the sector if it has changed */
  76. if (sector_needs_write) {
  77. ESP_ERROR_CHECK( spi_flash_erase_sector((uint16_t) abs_sector) );
  78. ESP_ERROR_CHECK( spi_flash_write_maybe_encrypted(sector_offs, (const uint8_t *) buffer, sizeof(buffer)) );
  79. }
  80. }
  81. }
  82. }
  83. TEST_CASE("Can mmap into data address space", "[spi_flash][mmap]")
  84. {
  85. setup_mmap_tests();
  86. printf("Mapping %x (+%x)\n", start, end - start);
  87. const void *ptr1;
  88. ESP_ERROR_CHECK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) );
  89. printf("mmap_res: handle=%d ptr=%p\n", handle1, ptr1);
  90. spi_flash_mmap_dump();
  91. srand(0);
  92. const uint32_t *data = (const uint32_t *) ptr1;
  93. for (int block = 0; block < (end - start) / 0x10000; ++block) {
  94. printf("block %d\n", block);
  95. for (int sector = 0; sector < 16; ++sector) {
  96. printf("sector %d\n", sector);
  97. for (uint32_t word = 0; word < 1024; ++word) {
  98. TEST_ASSERT_EQUAL_HEX32(rand(), data[(block * 16 + sector) * 1024 + word]);
  99. }
  100. }
  101. }
  102. printf("Mapping %x (+%x)\n", start - 0x10000, 0x20000);
  103. const void *ptr2;
  104. ESP_ERROR_CHECK( spi_flash_mmap(start - 0x10000, 0x20000, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) );
  105. printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2);
  106. TEST_ASSERT_EQUAL_HEX32(start - 0x10000, spi_flash_cache2phys(ptr2));
  107. TEST_ASSERT_EQUAL_PTR(ptr2, spi_flash_phys2cache(start - 0x10000, SPI_FLASH_MMAP_DATA));
  108. spi_flash_mmap_dump();
  109. printf("Mapping %x (+%x)\n", start, 0x10000);
  110. const void *ptr3;
  111. ESP_ERROR_CHECK( spi_flash_mmap(start, 0x10000, SPI_FLASH_MMAP_DATA, &ptr3, &handle3) );
  112. printf("mmap_res: handle=%d ptr=%p\n", handle3, ptr3);
  113. TEST_ASSERT_EQUAL_HEX32(start, spi_flash_cache2phys(ptr3));
  114. TEST_ASSERT_EQUAL_PTR(ptr3, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA));
  115. TEST_ASSERT_EQUAL_PTR((intptr_t)ptr3 + 0x4444, spi_flash_phys2cache(start + 0x4444, SPI_FLASH_MMAP_DATA));
  116. spi_flash_mmap_dump();
  117. printf("Unmapping handle1\n");
  118. spi_flash_munmap(handle1);
  119. handle1 = 0;
  120. spi_flash_mmap_dump();
  121. printf("Unmapping handle2\n");
  122. spi_flash_munmap(handle2);
  123. handle2 = 0;
  124. spi_flash_mmap_dump();
  125. printf("Unmapping handle3\n");
  126. spi_flash_munmap(handle3);
  127. handle3 = 0;
  128. TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA));
  129. }
  130. TEST_CASE("Can mmap into instruction address space", "[spi_flash][mmap]")
  131. {
  132. setup_mmap_tests();
  133. printf("Mapping %x (+%x)\n", start, end - start);
  134. spi_flash_mmap_handle_t handle1;
  135. const void *ptr1;
  136. ESP_ERROR_CHECK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_INST, &ptr1, &handle1) );
  137. printf("mmap_res: handle=%d ptr=%p\n", handle1, ptr1);
  138. spi_flash_mmap_dump();
  139. srand(0);
  140. const uint32_t *data = (const uint32_t *) ptr1;
  141. for (int block = 0; block < (end - start) / 0x10000; ++block) {
  142. for (int sector = 0; sector < 16; ++sector) {
  143. for (uint32_t word = 0; word < 1024; ++word) {
  144. TEST_ASSERT_EQUAL_UINT32(rand(), data[(block * 16 + sector) * 1024 + word]);
  145. }
  146. }
  147. }
  148. printf("Mapping %x (+%x)\n", start - 0x10000, 0x20000);
  149. spi_flash_mmap_handle_t handle2;
  150. const void *ptr2;
  151. ESP_ERROR_CHECK( spi_flash_mmap(start - 0x10000, 0x20000, SPI_FLASH_MMAP_INST, &ptr2, &handle2) );
  152. printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2);
  153. TEST_ASSERT_EQUAL_HEX32(start - 0x10000, spi_flash_cache2phys(ptr2));
  154. TEST_ASSERT_EQUAL_PTR(ptr2, spi_flash_phys2cache(start - 0x10000, SPI_FLASH_MMAP_INST));
  155. spi_flash_mmap_dump();
  156. printf("Mapping %x (+%x)\n", start, 0x10000);
  157. spi_flash_mmap_handle_t handle3;
  158. const void *ptr3;
  159. ESP_ERROR_CHECK( spi_flash_mmap(start, 0x10000, SPI_FLASH_MMAP_INST, &ptr3, &handle3) );
  160. printf("mmap_res: handle=%d ptr=%p\n", handle3, ptr3);
  161. TEST_ASSERT_EQUAL_HEX32(start, spi_flash_cache2phys(ptr3));
  162. TEST_ASSERT_EQUAL_PTR(ptr3, spi_flash_phys2cache(start, SPI_FLASH_MMAP_INST));
  163. spi_flash_mmap_dump();
  164. printf("Unmapping handle1\n");
  165. spi_flash_munmap(handle1);
  166. spi_flash_mmap_dump();
  167. printf("Unmapping handle2\n");
  168. spi_flash_munmap(handle2);
  169. spi_flash_mmap_dump();
  170. printf("Unmapping handle3\n");
  171. spi_flash_munmap(handle3);
  172. }
  173. TEST_CASE("Can mmap unordered pages into contiguous memory", "[spi_flash][mmap]")
  174. {
  175. int nopages;
  176. int *pages;
  177. int startpage;
  178. setup_mmap_tests();
  179. nopages=(end-start)/SPI_FLASH_MMU_PAGE_SIZE;
  180. pages=alloca(sizeof(int)*nopages);
  181. startpage=start/SPI_FLASH_MMU_PAGE_SIZE;
  182. //make inverse mapping: virt 0 -> page (nopages-1), virt 1 -> page (nopages-2), ...
  183. for (int i=0; i<nopages; i++) {
  184. pages[i]=startpage+(nopages-1)-i;
  185. printf("Offset %x page %d\n", i*0x10000, pages[i]);
  186. }
  187. printf("Attempting mapping of unordered pages to contiguous memory area\n");
  188. spi_flash_mmap_handle_t handle1;
  189. const void *ptr1;
  190. ESP_ERROR_CHECK( spi_flash_mmap_pages(pages, nopages, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) );
  191. printf("mmap_res: handle=%d ptr=%p\n", handle1, ptr1);
  192. spi_flash_mmap_dump();
  193. srand(0);
  194. const uint32_t *data = (const uint32_t *) ptr1;
  195. for (int block = 0; block < nopages; ++block) {
  196. for (int sector = 0; sector < 16; ++sector) {
  197. for (uint32_t word = 0; word < 1024; ++word) {
  198. TEST_ASSERT_EQUAL_UINT32(rand(), data[(((nopages-1)-block) * 16 + sector) * 1024 + word]);
  199. }
  200. }
  201. }
  202. printf("Unmapping handle1\n");
  203. spi_flash_munmap(handle1);
  204. spi_flash_mmap_dump();
  205. }
  206. TEST_CASE("flash_mmap invalidates just-written data", "[spi_flash][mmap]")
  207. {
  208. const void *ptr1;
  209. const size_t test_size = 128;
  210. setup_mmap_tests();
  211. if (esp_flash_encryption_enabled()) {
  212. TEST_IGNORE_MESSAGE("flash encryption enabled, spi_flash_write_encrypted() test won't pass as-is");
  213. }
  214. ESP_ERROR_CHECK( spi_flash_erase_sector(start / SPI_FLASH_SEC_SIZE) );
  215. /* map erased test region to ptr1 */
  216. ESP_ERROR_CHECK( spi_flash_mmap(start, test_size, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) );
  217. printf("mmap_res ptr1: handle=%d ptr=%p\n", handle1, ptr1);
  218. /* verify it's all 0xFF */
  219. for (int i = 0; i < test_size; i++) {
  220. TEST_ASSERT_EQUAL_HEX(0xFF, ((uint8_t *)ptr1)[i]);
  221. }
  222. /* unmap the erased region */
  223. spi_flash_munmap(handle1);
  224. handle1 = 0;
  225. /* write flash region to 0xEE */
  226. uint8_t buf[test_size];
  227. memset(buf, 0xEE, test_size);
  228. ESP_ERROR_CHECK( spi_flash_write(start, buf, test_size) );
  229. /* re-map the test region at ptr1.
  230. this is a fresh mmap call so should trigger a cache flush,
  231. ensuring we see the updated flash.
  232. */
  233. ESP_ERROR_CHECK( spi_flash_mmap(start, test_size, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) );
  234. printf("mmap_res ptr1 #2: handle=%d ptr=%p\n", handle1, ptr1);
  235. /* assert that ptr1 now maps to the new values on flash,
  236. ie contents of buf array.
  237. */
  238. TEST_ASSERT_EQUAL_HEX8_ARRAY(buf, ptr1, test_size);
  239. spi_flash_munmap(handle1);
  240. handle1 = 0;
  241. }
  242. TEST_CASE("flash_mmap can mmap after get enough free MMU pages", "[spi_flash][mmap]")
  243. {
  244. //this test case should make flash size >= 4MB, because max size of Dcache can mapped is 4MB
  245. setup_mmap_tests();
  246. printf("Mapping %x (+%x)\n", start, end - start);
  247. const void *ptr1;
  248. ESP_ERROR_CHECK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) );
  249. printf("mmap_res: handle=%d ptr=%p\n", handle1, ptr1);
  250. spi_flash_mmap_dump();
  251. srand(0);
  252. const uint32_t *data = (const uint32_t *) ptr1;
  253. for (int block = 0; block < (end - start) / 0x10000; ++block) {
  254. printf("block %d\n", block);
  255. for (int sector = 0; sector < 16; ++sector) {
  256. printf("sector %d\n", sector);
  257. for (uint32_t word = 0; word < 1024; ++word) {
  258. TEST_ASSERT_EQUAL_HEX32(rand(), data[(block * 16 + sector) * 1024 + word]);
  259. }
  260. }
  261. }
  262. uint32_t free_pages = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA);
  263. uint32_t flash_pages = spi_flash_get_chip_size() / SPI_FLASH_MMU_PAGE_SIZE;
  264. free_pages = (free_pages > flash_pages) ? flash_pages : free_pages;
  265. printf("Mapping %x (+%x)\n", 0, free_pages * SPI_FLASH_MMU_PAGE_SIZE);
  266. const void *ptr2;
  267. ESP_ERROR_CHECK( spi_flash_mmap(0, free_pages * SPI_FLASH_MMU_PAGE_SIZE, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) );
  268. printf("mmap_res: handle=%d ptr=%p\n", handle2, ptr2);
  269. spi_flash_mmap_dump();
  270. printf("Unmapping handle1\n");
  271. spi_flash_munmap(handle1);
  272. handle1 = 0;
  273. spi_flash_mmap_dump();
  274. printf("Unmapping handle2\n");
  275. spi_flash_munmap(handle2);
  276. handle2 = 0;
  277. spi_flash_mmap_dump();
  278. TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA));
  279. }
  280. TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash][mmap]")
  281. {
  282. uint8_t buf[64];
  283. static const uint8_t constant_data[] = { 1, 2, 3, 7, 11, 16, 3, 88 };
  284. /* esp_partition_find is in IROM */
  285. uint32_t phys = spi_flash_cache2phys(esp_partition_find);
  286. TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys);
  287. TEST_ASSERT_EQUAL_PTR(esp_partition_find, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST));
  288. TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA));
  289. /* Read the flash @ 'phys' and compare it to the data we get via regular cache access */
  290. spi_flash_read_maybe_encrypted(phys, buf, sizeof(buf));
  291. TEST_ASSERT_EQUAL_HEX32_ARRAY((void *)esp_partition_find, buf, sizeof(buf)/sizeof(uint32_t));
  292. /* spi_flash_mmap is in IRAM */
  293. printf("%p\n", spi_flash_mmap);
  294. TEST_ASSERT_EQUAL_HEX32(SPI_FLASH_CACHE2PHYS_FAIL,
  295. spi_flash_cache2phys(spi_flash_mmap));
  296. /* 'constant_data' should be in DROM */
  297. phys = spi_flash_cache2phys(&constant_data);
  298. TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys);
  299. TEST_ASSERT_EQUAL_PTR(&constant_data,
  300. spi_flash_phys2cache(phys, SPI_FLASH_MMAP_DATA));
  301. TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(phys, SPI_FLASH_MMAP_INST));
  302. /* Read the flash @ 'phys' and compare it to the data we get via normal cache access */
  303. spi_flash_read_maybe_encrypted(phys, buf, sizeof(constant_data));
  304. TEST_ASSERT_EQUAL_HEX8_ARRAY(constant_data, buf, sizeof(constant_data));
  305. }
  306. TEST_CASE("mmap consistent with phys2cache/cache2phys", "[spi_flash][mmap]")
  307. {
  308. const void *ptr = NULL;
  309. const size_t test_size = 2 * SPI_FLASH_MMU_PAGE_SIZE;
  310. setup_mmap_tests();
  311. TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr));
  312. ESP_ERROR_CHECK( spi_flash_mmap(start, test_size, SPI_FLASH_MMAP_DATA, &ptr, &handle1) );
  313. TEST_ASSERT_NOT_NULL(ptr);
  314. TEST_ASSERT_NOT_EQUAL(0, handle1);
  315. TEST_ASSERT_EQUAL_HEX(start, spi_flash_cache2phys(ptr));
  316. TEST_ASSERT_EQUAL_HEX(start + 1024, spi_flash_cache2phys((void *)((intptr_t)ptr + 1024)));
  317. TEST_ASSERT_EQUAL_HEX(start + 3000, spi_flash_cache2phys((void *)((intptr_t)ptr + 3000)));
  318. /* this pointer lands in a different MMU table entry */
  319. TEST_ASSERT_EQUAL_HEX(start + test_size - 4, spi_flash_cache2phys((void *)((intptr_t)ptr + test_size - 4)));
  320. spi_flash_munmap(handle1);
  321. handle1 = 0;
  322. TEST_ASSERT_EQUAL_HEX(SPI_FLASH_CACHE2PHYS_FAIL, spi_flash_cache2phys(ptr));
  323. }
  324. TEST_CASE("munmap followed by mmap flushes cache", "[spi_flash][mmap]")
  325. {
  326. setup_mmap_tests();
  327. const esp_partition_t *p = get_test_data_partition();
  328. const uint32_t* data;
  329. spi_flash_mmap_handle_t handle;
  330. TEST_ESP_OK( esp_partition_mmap(p, 0, SPI_FLASH_MMU_PAGE_SIZE,
  331. SPI_FLASH_MMAP_DATA, (const void **) &data, &handle) );
  332. uint32_t buf[16];
  333. memcpy(buf, data, sizeof(buf));
  334. spi_flash_munmap(handle);
  335. TEST_ESP_OK( esp_partition_mmap(p, SPI_FLASH_MMU_PAGE_SIZE, SPI_FLASH_MMU_PAGE_SIZE,
  336. SPI_FLASH_MMAP_DATA, (const void **) &data, &handle) );
  337. TEST_ASSERT_NOT_EQUAL(0, memcmp(buf, data, sizeof(buf)));
  338. }
  339. TEST_CASE("no stale data read post mmap and write partition", "[spi_flash][mmap]")
  340. {
  341. /* Buffer size is set to 32 to allow encrypted flash writes */
  342. const char buf[32] = "Test buffer data for partition";
  343. char read_data[sizeof(buf)];
  344. setup_mmap_tests();
  345. const esp_partition_t *p = get_test_data_partition();
  346. const uint32_t* data;
  347. spi_flash_mmap_handle_t handle;
  348. TEST_ESP_OK(esp_partition_mmap(p, 0, SPI_FLASH_MMU_PAGE_SIZE,
  349. SPI_FLASH_MMAP_DATA, (const void **) &data, &handle) );
  350. memcpy(read_data, data, sizeof(read_data));
  351. TEST_ESP_OK(esp_partition_erase_range(p, 0, SPI_FLASH_MMU_PAGE_SIZE));
  352. /* not using esp_partition_write here, since the partition in not marked as "encrypted"
  353. in the partition table */
  354. TEST_ESP_OK(spi_flash_write_maybe_encrypted(p->address + 0, buf, sizeof(buf)));
  355. /* This should retrigger actual flash content read */
  356. memcpy(read_data, data, sizeof(read_data));
  357. spi_flash_munmap(handle);
  358. TEST_ASSERT_EQUAL(0, memcmp(buf, read_data, sizeof(buf)));
  359. }