fal_partition.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. * File : fal_partition.c
  3. * This file is part of FAL (Flash Abstraction Layer) package
  4. * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. * 2018-05-17 armink the first version
  23. */
  24. #include <fal.h>
  25. #include <string.h>
  26. #include <stdlib.h>
  27. /* partition magic word */
  28. #define FAL_PART_MAGIC_WORD 0x45503130
  29. #define FAL_PART_MAGIC_WORD_H 0x4550L
  30. #define FAL_PART_MAGIC_WORD_L 0x3130L
  31. #define FAL_PART_MAGIC_WROD 0x45503130
  32. /**
  33. * FAL partition table config has defined on 'fal_cfg.h'.
  34. * When this option is disable, it will auto find the partition table on a specified location in flash partition.
  35. */
  36. #ifdef FAL_PART_HAS_TABLE_CFG
  37. /* check partition table definition */
  38. #if !defined(FAL_PART_TABLE)
  39. #error "You must defined FAL_PART_TABLE on 'fal_cfg.h'"
  40. #endif
  41. #ifdef __CC_ARM /* ARM Compiler */
  42. #define SECTION(x) __attribute__((section(x)))
  43. #define USED __attribute__((used))
  44. #elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */
  45. #define SECTION(x) @ x
  46. #define USED __root
  47. #elif defined (__GNUC__) /* GNU GCC Compiler */
  48. #define SECTION(x) __attribute__((section(x)))
  49. #define USED __attribute__((used))
  50. #else
  51. #error not supported tool chain
  52. #endif /* __CC_ARM */
  53. USED static const struct fal_partition partition_table_def[] SECTION("FalPartTable") = FAL_PART_TABLE;
  54. static const struct fal_partition *partition_table = NULL;
  55. #else /* FAL_PART_HAS_TABLE_CFG */
  56. #if !defined(FAL_PART_TABLE_FLASH_DEV_NAME)
  57. #error "You must defined FAL_PART_TABLE_FLASH_DEV_NAME on 'fal_cfg.h'"
  58. #endif
  59. /* check partition table end offset address definition */
  60. #if !defined(FAL_PART_TABLE_END_OFFSET)
  61. #error "You must defined FAL_PART_TABLE_END_OFFSET on 'fal_cfg.h'"
  62. #endif
  63. static struct fal_partition *partition_table = NULL;
  64. #endif /* FAL_PART_HAS_TABLE_CFG */
  65. static uint8_t init_ok = 0;
  66. static size_t partition_table_len = 0;
  67. /**
  68. * print the partition table
  69. */
  70. void fal_show_part_table(void)
  71. {
  72. char *item1 = "name", *item2 = "flash_dev";
  73. size_t i, part_name_max = strlen(item1), flash_dev_name_max = strlen(item2);
  74. const struct fal_partition *part;
  75. if (partition_table_len)
  76. {
  77. for (i = 0; i < partition_table_len; i++)
  78. {
  79. part = &partition_table[i];
  80. if (strlen(part->name) > part_name_max)
  81. {
  82. part_name_max = strlen(part->name);
  83. }
  84. if (strlen(part->flash_name) > flash_dev_name_max)
  85. {
  86. flash_dev_name_max = strlen(part->flash_name);
  87. }
  88. }
  89. }
  90. log_i("==================== FAL partition table ====================");
  91. log_i("| %-*.*s | %-*.*s | offset | length |", part_name_max, FAL_DEV_NAME_MAX, item1, flash_dev_name_max,
  92. FAL_DEV_NAME_MAX, item2);
  93. log_i("-------------------------------------------------------------");
  94. for (i = 0; i < partition_table_len; i++)
  95. {
  96. #ifdef FAL_PART_HAS_TABLE_CFG
  97. part = &partition_table[i];
  98. #else
  99. part = &partition_table[partition_table_len - i - 1];
  100. #endif
  101. log_i("| %-*.*s | %-*.*s | 0x%08lx | 0x%08x |", part_name_max, FAL_DEV_NAME_MAX, part->name, flash_dev_name_max,
  102. FAL_DEV_NAME_MAX, part->flash_name, part->offset, part->len);
  103. }
  104. log_i("=============================================================");
  105. }
  106. /**
  107. * Initialize all flash partition on FAL partition table
  108. *
  109. * @return partitions total number
  110. */
  111. int fal_partition_init(void)
  112. {
  113. size_t i;
  114. const struct fal_flash_dev *flash_dev = NULL;
  115. if (init_ok)
  116. {
  117. return partition_table_len;
  118. }
  119. #ifdef FAL_PART_HAS_TABLE_CFG
  120. partition_table = &partition_table_def[0];
  121. partition_table_len = sizeof(partition_table_def) / sizeof(partition_table_def[0]);
  122. #else
  123. /* load partition table from the end address FAL_PART_TABLE_END_OFFSET, error return 0 */
  124. long part_table_offset = FAL_PART_TABLE_END_OFFSET;
  125. size_t table_num = 0, table_item_size = 0;
  126. uint8_t part_table_find_ok = 0;
  127. uint32_t read_magic_word;
  128. fal_partition_t new_part = NULL;
  129. flash_dev = fal_flash_device_find(FAL_PART_TABLE_FLASH_DEV_NAME);
  130. if (flash_dev == NULL)
  131. {
  132. log_e("Initialize failed! Flash device (%s) NOT found.", FAL_PART_TABLE_FLASH_DEV_NAME);
  133. goto _exit;
  134. }
  135. /* check partition table offset address */
  136. if (part_table_offset < 0 || part_table_offset >= (long) flash_dev->len)
  137. {
  138. log_e("Setting partition table end offset address(%ld) out of flash bound(<%d).", part_table_offset, flash_dev->len);
  139. goto _exit;
  140. }
  141. table_item_size = sizeof(struct fal_partition);
  142. new_part = (fal_partition_t)FAL_MALLOC(table_item_size);
  143. if (new_part == NULL)
  144. {
  145. log_e("Initialize failed! No memory for table buffer.");
  146. goto _exit;
  147. }
  148. /* find partition table location */
  149. {
  150. uint8_t read_buf[64];
  151. part_table_offset -= sizeof(read_buf);
  152. while (part_table_offset >= 0)
  153. {
  154. if (flash_dev->ops.read(part_table_offset, read_buf, sizeof(read_buf)) > 0)
  155. {
  156. /* find magic word in read buf */
  157. for (i = 0; i < sizeof(read_buf) - sizeof(read_magic_word) + 1; i++)
  158. {
  159. read_magic_word = read_buf[0 + i] + (read_buf[1 + i] << 8) + (read_buf[2 + i] << 16) + (read_buf[3 + i] << 24);
  160. if (read_magic_word == ((FAL_PART_MAGIC_WORD_H << 16) + FAL_PART_MAGIC_WORD_L))
  161. {
  162. part_table_find_ok = 1;
  163. part_table_offset += i;
  164. log_d("Find the partition table on '%s' offset @0x%08lx.", FAL_PART_TABLE_FLASH_DEV_NAME,
  165. part_table_offset);
  166. break;
  167. }
  168. }
  169. }
  170. else
  171. {
  172. /* read failed */
  173. break;
  174. }
  175. if (part_table_find_ok)
  176. {
  177. break;
  178. }
  179. else
  180. {
  181. /* calculate next read buf position */
  182. if (part_table_offset >= (long)sizeof(read_buf))
  183. {
  184. part_table_offset -= sizeof(read_buf);
  185. part_table_offset += (sizeof(read_magic_word) - 1);
  186. }
  187. else if (part_table_offset != 0)
  188. {
  189. part_table_offset = 0;
  190. }
  191. else
  192. {
  193. /* find failed */
  194. break;
  195. }
  196. }
  197. }
  198. }
  199. /* load partition table */
  200. while (part_table_find_ok)
  201. {
  202. memset(new_part, 0x00, table_num);
  203. if (flash_dev->ops.read(part_table_offset - table_item_size * (table_num), (uint8_t *) new_part,
  204. table_item_size) < 0)
  205. {
  206. log_e("Initialize failed! Flash device (%s) read error!", flash_dev->name);
  207. table_num = 0;
  208. break;
  209. }
  210. if (new_part->magic_word != ((FAL_PART_MAGIC_WORD_H << 16) + FAL_PART_MAGIC_WORD_L))
  211. {
  212. break;
  213. }
  214. partition_table = (fal_partition_t) FAL_REALLOC(partition_table, table_item_size * (table_num + 1));
  215. if (partition_table == NULL)
  216. {
  217. log_e("Initialize failed! No memory for partition table");
  218. table_num = 0;
  219. break;
  220. }
  221. memcpy(partition_table + table_num, new_part, table_item_size);
  222. table_num++;
  223. };
  224. if (table_num == 0)
  225. {
  226. log_e("Partition table NOT found on flash: %s (len: %d) from offset: 0x%08x.", FAL_PART_TABLE_FLASH_DEV_NAME,
  227. FAL_DEV_NAME_MAX, FAL_PART_TABLE_END_OFFSET);
  228. goto _exit;
  229. }
  230. else
  231. {
  232. partition_table_len = table_num;
  233. }
  234. #endif /* FAL_PART_HAS_TABLE_CFG */
  235. /* check the partition table device exists */
  236. for (i = 0; i < partition_table_len; i++)
  237. {
  238. flash_dev = fal_flash_device_find(partition_table[i].flash_name);
  239. if (flash_dev == NULL)
  240. {
  241. log_d("Warning: Do NOT found the flash device(%s).", partition_table[i].flash_name);
  242. continue;
  243. }
  244. if (partition_table[i].offset >= (long)flash_dev->len)
  245. {
  246. log_e("Initialize failed! Partition(%s) offset address(%ld) out of flash bound(<%d).",
  247. partition_table[i].name, partition_table[i].offset, flash_dev->len);
  248. partition_table_len = 0;
  249. goto _exit;
  250. }
  251. }
  252. init_ok = 1;
  253. _exit:
  254. #if FAL_DEBUG
  255. fal_show_part_table();
  256. #endif
  257. #ifndef FAL_PART_HAS_TABLE_CFG
  258. if (new_part)
  259. {
  260. FAL_FREE(new_part);
  261. }
  262. #endif /* !FAL_PART_HAS_TABLE_CFG */
  263. return partition_table_len;
  264. }
  265. /**
  266. * find the partition by name
  267. *
  268. * @param name partition name
  269. *
  270. * @return != NULL: partition
  271. * NULL: not found
  272. */
  273. const struct fal_partition *fal_partition_find(const char *name)
  274. {
  275. assert(init_ok);
  276. size_t i;
  277. for (i = 0; i < partition_table_len; i++)
  278. {
  279. if (!strcmp(name, partition_table[i].name))
  280. {
  281. return &partition_table[i];
  282. }
  283. }
  284. return NULL;
  285. }
  286. /**
  287. * get the partition table
  288. *
  289. * @param len return the partition table length
  290. *
  291. * @return partition table
  292. */
  293. const struct fal_partition *fal_get_partition_table(size_t *len)
  294. {
  295. assert(init_ok);
  296. assert(len);
  297. *len = partition_table_len;
  298. return partition_table;
  299. }
  300. /**
  301. * set partition table temporarily
  302. * This setting will modify the partition table temporarily, the setting will be lost after restart.
  303. *
  304. * @param table partition table
  305. * @param len partition table length
  306. */
  307. void fal_set_partition_table_temp(struct fal_partition *table, size_t len)
  308. {
  309. assert(init_ok);
  310. assert(table);
  311. partition_table_len = len;
  312. partition_table = table;
  313. }
  314. /**
  315. * read data from partition
  316. *
  317. * @param part partition
  318. * @param addr relative address for partition
  319. * @param buf read buffer
  320. * @param size read size
  321. *
  322. * @return >= 0: successful read data size
  323. * -1: error
  324. */
  325. int fal_partition_read(const struct fal_partition *part, uint32_t addr, uint8_t *buf, size_t size)
  326. {
  327. int ret = 0;
  328. const struct fal_flash_dev *flash_dev = NULL;
  329. assert(part);
  330. assert(buf);
  331. if (addr + size > part->len)
  332. {
  333. log_e("Partition read error! Partition address out of bound.");
  334. return -1;
  335. }
  336. flash_dev = fal_flash_device_find(part->flash_name);
  337. if (flash_dev == NULL)
  338. {
  339. log_e("Partition read error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
  340. return -1;
  341. }
  342. ret = flash_dev->ops.read(part->offset + addr, buf, size);
  343. if (ret < 0)
  344. {
  345. log_e("Partition read error! Flash device(%s) read error!", part->flash_name);
  346. }
  347. return ret;
  348. }
  349. /**
  350. * write data to partition
  351. *
  352. * @param part partition
  353. * @param addr relative address for partition
  354. * @param buf write buffer
  355. * @param size write size
  356. *
  357. * @return >= 0: successful write data size
  358. * -1: error
  359. */
  360. int fal_partition_write(const struct fal_partition *part, uint32_t addr, const uint8_t *buf, size_t size)
  361. {
  362. int ret = 0;
  363. const struct fal_flash_dev *flash_dev = NULL;
  364. assert(part);
  365. assert(buf);
  366. if (addr + size > part->len)
  367. {
  368. log_e("Partition write error! Partition address out of bound.");
  369. return -1;
  370. }
  371. flash_dev = fal_flash_device_find(part->flash_name);
  372. if (flash_dev == NULL)
  373. {
  374. log_e("Partition write error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
  375. return -1;
  376. }
  377. ret = flash_dev->ops.write(part->offset + addr, buf, size);
  378. if (ret < 0)
  379. {
  380. log_e("Partition write error! Flash device(%s) write error!", part->flash_name);
  381. }
  382. return ret;
  383. }
  384. /**
  385. * erase partition data
  386. *
  387. * @param part partition
  388. * @param addr relative address for partition
  389. * @param size erase size
  390. *
  391. * @return >= 0: successful erased data size
  392. * -1: error
  393. */
  394. int fal_partition_erase(const struct fal_partition *part, uint32_t addr, size_t size)
  395. {
  396. int ret = 0;
  397. const struct fal_flash_dev *flash_dev = NULL;
  398. assert(part);
  399. if (addr + size > part->len)
  400. {
  401. log_e("Partition erase error! Partition address out of bound.");
  402. return -1;
  403. }
  404. flash_dev = fal_flash_device_find(part->flash_name);
  405. if (flash_dev == NULL)
  406. {
  407. log_e("Partition erase error! Don't found flash device(%s) of the partition(%s).", part->flash_name, part->name);
  408. return -1;
  409. }
  410. ret = flash_dev->ops.erase(part->offset + addr, size);
  411. if (ret < 0)
  412. {
  413. log_e("Partition erase error! Flash device(%s) erase error!", part->flash_name);
  414. }
  415. return ret;
  416. }
  417. /**
  418. * erase partition all data
  419. *
  420. * @param part partition
  421. *
  422. * @return >= 0: successful erased data size
  423. * -1: error
  424. */
  425. int fal_partition_erase_all(const struct fal_partition *part)
  426. {
  427. return fal_partition_erase(part, 0, part->len);
  428. }