fal_partition.c 14 KB

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