fal_partition.c 14 KB

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