partition_linux.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdlib.h>
  7. #include <assert.h>
  8. #include <string.h>
  9. #include <sys/mman.h>
  10. #include <sys/stat.h>
  11. #include <unistd.h>
  12. #include <limits.h>
  13. #include <errno.h>
  14. #include "sdkconfig.h"
  15. #include "esp_partition.h"
  16. #include "esp_flash_partitions.h"
  17. #include "esp_private/partition_linux.h"
  18. #include "esp_log.h"
  19. static const char *TAG = "linux_spiflash";
  20. static void *s_spiflash_mem_file_buf = NULL;
  21. static uint32_t s_spiflash_mem_file_size = 0x400000; //4MB fixed
  22. const char *esp_partition_type_to_str(const uint32_t type)
  23. {
  24. switch (type) {
  25. case PART_TYPE_APP: return "app";
  26. case PART_TYPE_DATA: return "data";
  27. default: return "unknown";
  28. }
  29. }
  30. const char *esp_partition_subtype_to_str(const uint32_t type, const uint32_t subtype)
  31. {
  32. switch (type) {
  33. case PART_TYPE_APP:
  34. switch (subtype) {
  35. case PART_SUBTYPE_FACTORY: return "factory";
  36. case PART_SUBTYPE_OTA_FLAG: return "ota_flag";
  37. case PART_SUBTYPE_OTA_MASK: return "ota_mask";
  38. case PART_SUBTYPE_TEST: return "test";
  39. default: return "unknown";
  40. }
  41. case PART_TYPE_DATA:
  42. switch (subtype) {
  43. case PART_SUBTYPE_DATA_OTA: return "data_ota";
  44. case PART_SUBTYPE_DATA_RF: return "data_rf";
  45. case PART_SUBTYPE_DATA_WIFI: return "data_wifi";
  46. case PART_SUBTYPE_DATA_NVS_KEYS: return "nvs_keys";
  47. case PART_SUBTYPE_DATA_EFUSE_EM: return "efuse_em";
  48. default: return "unknown";
  49. }
  50. default: return "unknown";
  51. }
  52. }
  53. esp_err_t esp_partition_file_mmap(const uint8_t **part_desc_addr_start)
  54. {
  55. //create temporary file to hold complete SPIFLASH size
  56. char temp_spiflash_mem_file_name[PATH_MAX] = {"/tmp/idf-partition-XXXXXX"};
  57. int spiflash_mem_file_fd = mkstemp(temp_spiflash_mem_file_name);
  58. if (spiflash_mem_file_fd == -1) {
  59. ESP_LOGE(TAG, "Failed to create SPI FLASH emulation file %s: %s", temp_spiflash_mem_file_name, strerror(errno));
  60. return ESP_ERR_NOT_FINISHED;
  61. }
  62. if (ftruncate(spiflash_mem_file_fd, s_spiflash_mem_file_size) != 0) {
  63. ESP_LOGE(TAG, "Failed to set size of SPI FLASH memory emulation file %s: %s", temp_spiflash_mem_file_name, strerror(errno));
  64. return ESP_ERR_INVALID_SIZE;
  65. }
  66. ESP_LOGV(TAG, "SPIFLASH memory emulation file created: %s (size: %d B)", temp_spiflash_mem_file_name, s_spiflash_mem_file_size);
  67. //create memory-mapping for the partitions holder file
  68. if ((s_spiflash_mem_file_buf = mmap(NULL, s_spiflash_mem_file_size, PROT_READ | PROT_WRITE, MAP_SHARED, spiflash_mem_file_fd, 0)) == MAP_FAILED) {
  69. ESP_LOGE(TAG, "Failed to mmap() SPI FLASH memory emulation file: %s", strerror(errno));
  70. return ESP_ERR_NO_MEM;
  71. }
  72. //initialize whole range with bit-1 (NOR FLASH default)
  73. memset(s_spiflash_mem_file_buf, 0xFF, s_spiflash_mem_file_size);
  74. //upload partition table to the mmap file at real offset as in SPIFLASH
  75. const char *partition_table_file_name = "build/partition_table/partition-table.bin";
  76. FILE *f_partition_table = fopen(partition_table_file_name, "r+");
  77. if (f_partition_table == NULL) {
  78. ESP_LOGE(TAG, "Failed to open partition table file %s: %s", partition_table_file_name, strerror(errno));
  79. return ESP_ERR_NOT_FOUND;
  80. }
  81. if (fseek(f_partition_table, 0L, SEEK_END) != 0) {
  82. ESP_LOGE(TAG, "Failed to seek in partition table file %s: %s", partition_table_file_name, strerror(errno));
  83. return ESP_ERR_INVALID_SIZE;
  84. }
  85. int partition_table_file_size = ftell(f_partition_table);
  86. ESP_LOGV(TAG, "Using partition table file %s (size: %d B):", partition_table_file_name, partition_table_file_size);
  87. uint8_t *part_table_in_spiflash = s_spiflash_mem_file_buf + ESP_PARTITION_TABLE_OFFSET;
  88. //copy partition table from the file to emulated SPIFLASH memory space
  89. if (fseek(f_partition_table, 0L, SEEK_SET) != 0) {
  90. ESP_LOGE(TAG, "Failed to seek in partition table file %s: %s", partition_table_file_name, strerror(errno));
  91. return ESP_ERR_INVALID_SIZE;
  92. }
  93. size_t res = fread(part_table_in_spiflash, 1, partition_table_file_size, f_partition_table);
  94. fclose(f_partition_table);
  95. if (res != partition_table_file_size) {
  96. ESP_LOGE(TAG, "Failed to read partition table file %s", partition_table_file_name);
  97. return ESP_ERR_INVALID_STATE;
  98. }
  99. #ifdef CONFIG_LOG_DEFAULT_LEVEL_VERBOSE
  100. uint8_t *part_ptr = part_table_in_spiflash;
  101. uint8_t *part_end_ptr = part_table_in_spiflash + partition_table_file_size;
  102. ESP_LOGV(TAG, "");
  103. ESP_LOGV(TAG, "Partition table sucessfully imported, partitions found:");
  104. while (part_ptr < part_end_ptr) {
  105. esp_partition_info_t *p_part_item = (esp_partition_info_t *)part_ptr;
  106. if (p_part_item->magic != ESP_PARTITION_MAGIC ) {
  107. break;
  108. }
  109. ESP_LOGV(TAG, " --------------");
  110. ESP_LOGV(TAG, " label: %s", p_part_item->label);
  111. ESP_LOGV(TAG, " type: %s", esp_partition_type_to_str(p_part_item->type));
  112. ESP_LOGV(TAG, " subtype: %s", esp_partition_subtype_to_str(p_part_item->type, p_part_item->subtype));
  113. ESP_LOGV(TAG, " offset: 0x%08X", p_part_item->pos.offset);
  114. ESP_LOGV(TAG, " size: %d", p_part_item->pos.size);
  115. ESP_LOGV(TAG, " flags: %d", p_part_item->flags);
  116. part_ptr += sizeof(esp_partition_info_t);
  117. }
  118. ESP_LOGV(TAG, "");
  119. #endif
  120. //return mmapped file starting address
  121. *part_desc_addr_start = s_spiflash_mem_file_buf;
  122. return ESP_OK;
  123. }
  124. esp_err_t esp_partition_file_munmap()
  125. {
  126. if (s_spiflash_mem_file_buf == NULL) {
  127. return ESP_ERR_NO_MEM;
  128. }
  129. if (s_spiflash_mem_file_size == 0) {
  130. return ESP_ERR_INVALID_SIZE;
  131. }
  132. if (munmap(s_spiflash_mem_file_buf, s_spiflash_mem_file_size) != 0) {
  133. ESP_LOGE(TAG, "Failed to munmap() SPI FLASH memory emulation file: %s", strerror(errno));
  134. return ESP_ERR_INVALID_RESPONSE;
  135. }
  136. s_spiflash_mem_file_buf = NULL;
  137. return ESP_OK;
  138. }
  139. esp_err_t esp_partition_write(const esp_partition_t *partition, size_t dst_offset, const void *src, size_t size)
  140. {
  141. assert(partition != NULL);
  142. if (partition->encrypted) {
  143. return ESP_ERR_NOT_SUPPORTED;
  144. }
  145. if (dst_offset > partition->size) {
  146. return ESP_ERR_INVALID_ARG;
  147. }
  148. if (dst_offset + size > partition->size) {
  149. return ESP_ERR_INVALID_SIZE;
  150. }
  151. uint8_t *write_buf = malloc(size);
  152. if (write_buf == NULL) {
  153. return ESP_ERR_NO_MEM;
  154. }
  155. void *dst_addr = s_spiflash_mem_file_buf + partition->address + dst_offset;
  156. ESP_LOGV(TAG, "esp_partition_write(): partition=%s dst_offset=%zu src=%p size=%zu (real dst address: %p)", partition->label, dst_offset, src, size, dst_addr);
  157. //read the contents first, AND with the write buffer (to emulate real NOR FLASH behavior)
  158. memcpy(write_buf, dst_addr, size);
  159. for (size_t x = 0; x < size; x++) {
  160. write_buf[x] &= ((uint8_t *)src)[x];
  161. }
  162. memcpy(dst_addr, write_buf, size);
  163. free(write_buf);
  164. return ESP_OK;
  165. }
  166. esp_err_t esp_partition_read(const esp_partition_t *partition, size_t src_offset, void *dst, size_t size)
  167. {
  168. assert(partition != NULL);
  169. if (partition->encrypted) {
  170. return ESP_ERR_NOT_SUPPORTED;
  171. }
  172. if (src_offset > partition->size) {
  173. return ESP_ERR_INVALID_ARG;
  174. }
  175. if (src_offset + size > partition->size) {
  176. return ESP_ERR_INVALID_SIZE;
  177. }
  178. void *src_addr = s_spiflash_mem_file_buf + partition->address + src_offset;
  179. ESP_LOGV(TAG, "esp_partition_read(): partition=%s src_offset=%zu dst=%p size=%zu (real src address: %p)", partition->label, src_offset, dst, size, src_addr);
  180. memcpy(dst, src_addr, size);
  181. return ESP_OK;
  182. }
  183. esp_err_t esp_partition_read_raw(const esp_partition_t *partition, size_t src_offset, void *dst, size_t size)
  184. {
  185. ESP_LOGV(TAG, "esp_partition_read_raw(): calling esp_partition_read()");
  186. return esp_partition_read(partition, src_offset, dst, size);
  187. }
  188. esp_err_t esp_partition_write_raw(const esp_partition_t *partition, size_t dst_offset, const void *src, size_t size)
  189. {
  190. ESP_LOGV(TAG, "esp_partition_write_raw(): calling esp_partition_write()");
  191. return esp_partition_write(partition, dst_offset, src, size);
  192. }
  193. esp_err_t esp_partition_erase_range(const esp_partition_t *partition, size_t offset, size_t size)
  194. {
  195. assert(partition != NULL);
  196. if (offset > partition->size || offset % SPI_FLASH_SEC_SIZE != 0) {
  197. return ESP_ERR_INVALID_ARG;
  198. }
  199. if (offset + size > partition->size || size % SPI_FLASH_SEC_SIZE != 0) {
  200. return ESP_ERR_INVALID_SIZE;
  201. }
  202. void *target_addr = s_spiflash_mem_file_buf + partition->address + offset;
  203. ESP_LOGV(TAG, "esp_partition_erase_range(): partition=%s offset=%zu size=%zu (real target address: %p)", partition->label, offset, size, target_addr);
  204. //set all bits to 1 (NOR FLASH default)
  205. memset(target_addr, 0xFF, size);
  206. return ESP_OK;
  207. }