parabak.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. /*
  2. * Copyright (c) 2026, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2026-03-09 user first version
  9. */
  10. #define DBG_TAG "BAK"
  11. #define DBG_LVL DBG_LOG
  12. #include <rtdbg.h>
  13. #include <rthw.h>
  14. #include <fal.h>
  15. #include <string.h>
  16. #include <easyflash.h>
  17. #include "parabak.h"
  18. #include "ecode.h"
  19. #include "main.h"
  20. /* 引入需要备份的外部结构体 */
  21. #include "ym310_protecl.h" // 提供 sys_info, dev_info, limit 的定义
  22. /* 外部时间变量 */
  23. extern struct rtc_time time_now;
  24. /*=============================================================================
  25. * 常量定义
  26. *============================================================================*/
  27. #define PARABAK_MAGIC 0x50415241 /* "PARA" */
  28. #define PARABAK_VERSION 1
  29. #define PARABAK_PART_SIZE 8192 /* 8KB */
  30. #define HEADER_SECTOR_OFFSET 0 /* 头部扇区偏移 0 */
  31. #define DATA_SECTOR_OFFSET 4096 /* 数据扇区偏移 4096 */
  32. #define SECTOR_SIZE 4096
  33. /*=============================================================================
  34. * 备份项表(内置,静态)
  35. *============================================================================*/
  36. static const parabak_item_t parabak_items[PARABAK_ID_MAX] = {
  37. {PARABAK_ID_SYS_INFO, &sys_info, sizeof(SYS_INFO), "para_sys", EF_SYS_INFO},
  38. {PARABAK_ID_DEV_INFO, &dev_info, sizeof(DEV_INFO), "para_dev", EF_DEV_INFO},
  39. {PARABAK_ID_LIMIT, &limit, sizeof(LIMIT), "para_lim", EF_LIMIT},
  40. };
  41. /*=============================================================================
  42. * 静态变量(互斥锁、初始化标志)
  43. *============================================================================*/
  44. static rt_mutex_t parabak_lock = RT_NULL; /* 保护数据操作的互斥锁 */
  45. static rt_mutex_t init_mutex = RT_NULL; /* 保护初始化的互斥锁 */
  46. static rt_bool_t initialized = RT_FALSE; /* 是否已初始化 */
  47. /*=============================================================================
  48. * CRC32 计算(标准算法)
  49. *============================================================================*/
  50. static uint32_t crc32_update(uint32_t crc, uint8_t data)
  51. {
  52. crc ^= data;
  53. for (int i = 0; i < 8; i++)
  54. {
  55. if (crc & 1)
  56. crc = (crc >> 1) ^ 0xEDB88320;
  57. else
  58. crc >>= 1;
  59. }
  60. return crc;
  61. }
  62. static uint32_t calc_crc32(const uint8_t *data, uint32_t len)
  63. {
  64. uint32_t crc = 0xFFFFFFFF;
  65. for (uint32_t i = 0; i < len; i++)
  66. crc = crc32_update(crc, data[i]);
  67. return crc ^ 0xFFFFFFFF;
  68. }
  69. /*=============================================================================
  70. * 时间戳转换(rtc_time -> parabak_tm)
  71. *============================================================================*/
  72. static void rtc_to_parabak_tm(const struct rtc_time *src, struct parabak_tm *dst)
  73. {
  74. dst->tm_year = src->year - 2000;
  75. dst->tm_mon = src->month;
  76. dst->tm_mday = src->date;
  77. dst->tm_hour = src->hour;
  78. dst->tm_min = src->minute;
  79. dst->tm_sec = src->second;
  80. }
  81. static void get_timestamp(struct parabak_tm *ts)
  82. {
  83. rtc_to_parabak_tm(&time_now, ts);
  84. }
  85. /*=============================================================================
  86. * 分区操作辅助函数
  87. *============================================================================*/
  88. static const struct fal_partition *get_partition_by_id(parabak_id_t id)
  89. {
  90. if (id >= PARABAK_ID_MAX)
  91. return RT_NULL;
  92. const char *part_name = parabak_items[id].partition_name;
  93. return fal_partition_find(part_name);
  94. }
  95. static int erase_sector(const struct fal_partition *part, uint32_t offset)
  96. {
  97. if (fal_partition_erase(part, offset, SECTOR_SIZE) < 0)
  98. {
  99. LOG_E("erase sector at 0x%x failed", offset);
  100. return -RT_ERROR;
  101. }
  102. return RT_EOK;
  103. }
  104. static int write_header(const struct fal_partition *part, const parabak_header_t *hdr)
  105. {
  106. if (erase_sector(part, HEADER_SECTOR_OFFSET) != RT_EOK)
  107. return -RT_ERROR;
  108. if (fal_partition_write(part, HEADER_SECTOR_OFFSET, (uint8_t *)hdr, sizeof(parabak_header_t)) < 0)
  109. {
  110. LOG_E("write header failed");
  111. return -RT_ERROR;
  112. }
  113. return RT_EOK;
  114. }
  115. static int read_header(const struct fal_partition *part, parabak_header_t *hdr)
  116. {
  117. if (fal_partition_read(part, HEADER_SECTOR_OFFSET, (uint8_t *)hdr, sizeof(parabak_header_t)) < 0)
  118. {
  119. LOG_E("read header failed");
  120. return -RT_ERROR;
  121. }
  122. return RT_EOK;
  123. }
  124. static int write_data(const struct fal_partition *part, const uint8_t *data, uint32_t len)
  125. {
  126. if (len > SECTOR_SIZE)
  127. {
  128. LOG_E("data too large for sector");
  129. return -RT_ERROR;
  130. }
  131. if (erase_sector(part, DATA_SECTOR_OFFSET) != RT_EOK)
  132. return -RT_ERROR;
  133. if (fal_partition_write(part, DATA_SECTOR_OFFSET, data, len) < 0)
  134. {
  135. LOG_E("write data failed");
  136. return -RT_ERROR;
  137. }
  138. return RT_EOK;
  139. }
  140. static int read_data(const struct fal_partition *part, uint8_t *buf, uint32_t len)
  141. {
  142. if (len > SECTOR_SIZE)
  143. return -RT_ERROR;
  144. if (fal_partition_read(part, DATA_SECTOR_OFFSET, buf, len) < 0)
  145. {
  146. LOG_E("read data failed");
  147. return -RT_ERROR;
  148. }
  149. return RT_EOK;
  150. }
  151. /*=============================================================================
  152. * 内部初始化核心函数(仅执行一次)
  153. *============================================================================*/
  154. static int parabak_init_core(void)
  155. {
  156. parabak_lock = rt_mutex_create("parabak", RT_IPC_FLAG_FIFO);
  157. if (parabak_lock == RT_NULL)
  158. {
  159. LOG_E("create data mutex failed");
  160. return -RT_ERROR;
  161. }
  162. LOG_I("parabak core initialized");
  163. return RT_EOK;
  164. }
  165. /* 确保模块已初始化(线程安全,只执行一次) */
  166. static int ensure_initialized(void)
  167. {
  168. if (initialized)
  169. return RT_EOK;
  170. if (init_mutex == RT_NULL)
  171. {
  172. init_mutex = rt_mutex_create("parabak_init", RT_IPC_FLAG_FIFO);
  173. if (init_mutex == RT_NULL)
  174. {
  175. LOG_E("create init mutex failed");
  176. return -RT_ERROR;
  177. }
  178. }
  179. rt_mutex_take(init_mutex, RT_WAITING_FOREVER);
  180. if (!initialized)
  181. {
  182. int ret = parabak_init_core();
  183. if (ret == RT_EOK)
  184. initialized = RT_TRUE;
  185. else
  186. LOG_E("parabak_init_core failed");
  187. }
  188. rt_mutex_release(init_mutex);
  189. return initialized ? RT_EOK : -RT_ERROR;
  190. }
  191. /*=============================================================================
  192. * 公共 API(全部自动调用 ensure_initialized)
  193. *============================================================================*/
  194. int parabak_backup(parabak_id_t id)
  195. {
  196. const parabak_item_t *item;
  197. const struct fal_partition *part;
  198. parabak_header_t hdr;
  199. uint32_t crc;
  200. int ret;
  201. if (ensure_initialized() != RT_EOK)
  202. {
  203. LOG_E("parabak not initialized");
  204. return -RT_ERROR;
  205. }
  206. if (id >= PARABAK_ID_MAX)
  207. return -RT_ERROR;
  208. item = &parabak_items[id];
  209. part = get_partition_by_id(id);
  210. if (part == RT_NULL)
  211. {
  212. LOG_E("partition not found for id %d", id);
  213. return -RT_ERROR;
  214. }
  215. rt_mutex_take(parabak_lock, RT_WAITING_FOREVER);
  216. crc = calc_crc32((uint8_t *)item->data_ptr, item->data_size);
  217. hdr.magic = PARABAK_MAGIC;
  218. hdr.version = PARABAK_VERSION;
  219. hdr.data_len = item->data_size;
  220. hdr.data_crc = crc;
  221. get_timestamp(&hdr.time_stamp);
  222. hdr.state = 1; /* 已备份 */
  223. memset(hdr.reserved, 0, sizeof(hdr.reserved));
  224. if (write_header(part, &hdr) != RT_EOK)
  225. {
  226. LOG_E("backup: write header failed");
  227. ret = -RT_ERROR;
  228. goto out;
  229. }
  230. if (write_data(part, (uint8_t *)item->data_ptr, item->data_size) != RT_EOK)
  231. {
  232. LOG_E("backup: write data failed");
  233. ret = -RT_ERROR;
  234. goto out;
  235. }
  236. LOG_I("✅ Backup id %d (%s) SUCC, CRC=0x%08X, TIME=%02d/%02d/%02d %02d:%02d:%02d",
  237. id, item->partition_name, crc,
  238. hdr.time_stamp.tm_year, hdr.time_stamp.tm_mon, hdr.time_stamp.tm_mday,
  239. hdr.time_stamp.tm_hour, hdr.time_stamp.tm_min, hdr.time_stamp.tm_sec);
  240. Recode_e_code(e_bak_backup, id, "执行备份分区");
  241. ret = RT_EOK;
  242. out:
  243. rt_mutex_release(parabak_lock);
  244. return ret;
  245. }
  246. int parabak_self_check(parabak_id_t id, parabak_header_t *hdr)
  247. {
  248. const struct fal_partition *part;
  249. parabak_header_t tmp_hdr;
  250. uint8_t *data_buf = RT_NULL;
  251. uint32_t crc;
  252. int ret = -1;
  253. if (ensure_initialized() != RT_EOK)
  254. {
  255. LOG_E("parabak not initialized");
  256. return -1;
  257. }
  258. if (id >= PARABAK_ID_MAX)
  259. return -1;
  260. part = get_partition_by_id(id);
  261. if (part == RT_NULL)
  262. return -1;
  263. rt_mutex_take(parabak_lock, RT_WAITING_FOREVER);
  264. if (read_header(part, &tmp_hdr) != RT_EOK)
  265. {
  266. LOG_E("self_check: read header failed");
  267. goto out;
  268. }
  269. if (hdr)
  270. *hdr = tmp_hdr;
  271. if (tmp_hdr.magic != PARABAK_MAGIC || tmp_hdr.version != PARABAK_VERSION)
  272. {
  273. LOG_D("self_check: invalid magic/version");
  274. ret = 0;
  275. goto out;
  276. }
  277. if (tmp_hdr.data_len == 0 || tmp_hdr.data_len > SECTOR_SIZE)
  278. {
  279. LOG_W("self_check: invalid data len %d", tmp_hdr.data_len);
  280. ret = 0;
  281. goto out;
  282. }
  283. data_buf = rt_malloc(tmp_hdr.data_len);
  284. if (data_buf == RT_NULL)
  285. {
  286. LOG_E("self_check: out of memory");
  287. goto out;
  288. }
  289. if (read_data(part, data_buf, tmp_hdr.data_len) != RT_EOK)
  290. {
  291. LOG_E("self_check: read data failed");
  292. goto out;
  293. }
  294. crc = calc_crc32(data_buf, tmp_hdr.data_len);
  295. if (crc != tmp_hdr.data_crc)
  296. {
  297. LOG_W("self_check: CRC mismatch (stored=0x%08x, calc=0x%08x)", tmp_hdr.data_crc, crc);
  298. ret = 0;
  299. }
  300. else
  301. {
  302. ret = tmp_hdr.state;
  303. }
  304. out:
  305. if (data_buf)
  306. rt_free(data_buf);
  307. rt_mutex_release(parabak_lock);
  308. return ret;
  309. }
  310. int parabak_verify(parabak_id_t id)
  311. {
  312. const parabak_item_t *item;
  313. parabak_header_t hdr;
  314. int state;
  315. if (ensure_initialized() != RT_EOK)
  316. {
  317. LOG_E("parabak not initialized");
  318. return -RT_ERROR;
  319. }
  320. if (id >= PARABAK_ID_MAX)
  321. return -RT_ERROR;
  322. item = &parabak_items[id];
  323. state = parabak_self_check(id, &hdr);
  324. if (state < 0)
  325. return -RT_ERROR;
  326. if (state == 0)
  327. {
  328. LOG_W("verify id %d: no valid backup", id);
  329. return -RT_ERROR;
  330. }
  331. uint32_t mem_crc = calc_crc32((uint8_t *)item->data_ptr, item->data_size);
  332. if (mem_crc != hdr.data_crc)
  333. {
  334. LOG_W("verify id %d: mem CRC mismatch (mem=0x%08x, backup=0x%08x)", id, mem_crc, hdr.data_crc);
  335. return -RT_ERROR;
  336. }
  337. LOG_I("✅ Verify OK: id=%d, %s=%d, CRC=0x%08X, TIME=%02d/%02d/%02d %02d:%02d:%02d",
  338. id, item->partition_name, hdr.state, hdr.data_crc,
  339. hdr.time_stamp.tm_year, hdr.time_stamp.tm_mon, hdr.time_stamp.tm_mday,
  340. hdr.time_stamp.tm_hour, hdr.time_stamp.tm_min, hdr.time_stamp.tm_sec);
  341. return RT_EOK;
  342. }
  343. int parabak_restore(parabak_id_t id)
  344. {
  345. const parabak_item_t *item;
  346. parabak_header_t hdr;
  347. uint8_t *data_buf;
  348. int state;
  349. int ret = -RT_ERROR;
  350. if (ensure_initialized() != RT_EOK)
  351. {
  352. LOG_E("parabak not initialized");
  353. return -RT_ERROR;
  354. }
  355. if (id >= PARABAK_ID_MAX)
  356. return -RT_ERROR;
  357. item = &parabak_items[id];
  358. state = parabak_self_check(id, &hdr);
  359. if (state < 0)
  360. {
  361. LOG_E("restore id %d: self check failed", id);
  362. return -RT_ERROR;
  363. }
  364. if (state == 0)
  365. {
  366. LOG_W("restore id %d: no valid backup", id);
  367. return -RT_ERROR;
  368. }
  369. if (state == 2)
  370. {
  371. LOG_I("restore id %d: already restored once, skip", id);
  372. return RT_EOK;
  373. }
  374. data_buf = rt_malloc(hdr.data_len);
  375. if (data_buf == RT_NULL)
  376. {
  377. LOG_E("restore id %d: out of memory", id);
  378. return -RT_ERROR;
  379. }
  380. rt_mutex_take(parabak_lock, RT_WAITING_FOREVER);
  381. if (read_data(get_partition_by_id(id), data_buf, hdr.data_len) != RT_EOK)
  382. {
  383. LOG_E("restore id %d: read data failed", id);
  384. goto out;
  385. }
  386. uint32_t crc = calc_crc32(data_buf, hdr.data_len);
  387. if (crc != hdr.data_crc)
  388. {
  389. LOG_E("restore id %d: CRC mismatch after read", id);
  390. goto out;
  391. }
  392. /* 1. 恢复到内存 */
  393. rt_memcpy(item->data_ptr, data_buf, hdr.data_len);
  394. /* 2. 写入 EasyFlash (env) */
  395. int env_ret = ef_set_env_blob(item->env_key, item->data_ptr, item->data_size);
  396. if (env_ret != EF_NO_ERR)
  397. {
  398. LOG_E("restore id %d: write to env failed, ret=%d", id, env_ret);
  399. goto out; // 失败则退出,不更新头部状态
  400. }
  401. LOG_I("restore id %d: env updated", id);
  402. /* 3. 更新头部状态为已还原 (2) */
  403. hdr.state = 2;
  404. if (write_header(get_partition_by_id(id), &hdr) != RT_EOK)
  405. {
  406. LOG_W("restore id %d: update header state failed", id);
  407. // 即使头部更新失败,env已写入,内存已恢复,仍算成功,但状态未变下次可能再次还原
  408. }
  409. LOG_I("restore id %d: memory and env restored", id);
  410. Recode_e_code(e_bak_restore, id, "执行还原分区");
  411. ret = RT_EOK;
  412. out:
  413. rt_mutex_release(parabak_lock);
  414. rt_free(data_buf);
  415. return ret;
  416. }
  417. int parabak_get_header(parabak_id_t id, parabak_header_t *hdr)
  418. {
  419. const struct fal_partition *part;
  420. if (ensure_initialized() != RT_EOK)
  421. {
  422. LOG_E("parabak not initialized");
  423. return -RT_ERROR;
  424. }
  425. if (id >= PARABAK_ID_MAX || hdr == RT_NULL)
  426. return -RT_ERROR;
  427. part = get_partition_by_id(id);
  428. if (part == RT_NULL)
  429. return -RT_ERROR;
  430. rt_mutex_take(parabak_lock, RT_WAITING_FOREVER);
  431. int ret = read_header(part, hdr);
  432. rt_mutex_release(parabak_lock);
  433. return ret;
  434. }
  435. /*=============================================================================
  436. * 自动校验功能(新增自动备份)
  437. *============================================================================*/
  438. int parabak_auto_check(void)
  439. {
  440. int restored_id = -1;
  441. parabak_id_t id;
  442. int state;
  443. if (ensure_initialized() != RT_EOK)
  444. {
  445. LOG_E("auto_check: parabak not initialized");
  446. return -1;
  447. }
  448. for (id = 0; id < PARABAK_ID_MAX; id++)
  449. {
  450. parabak_header_t hdr;
  451. state = parabak_self_check(id, &hdr);
  452. if (state < 0)
  453. {
  454. LOG_E("auto_check: self check failed for id %d", id);
  455. return -1;
  456. }
  457. if (state == 0)
  458. {
  459. // 未备份,执行一次备份
  460. LOG_I("auto_check: no backup for id %d, performing initial backup", id);
  461. if (parabak_backup(id) != RT_EOK)
  462. {
  463. LOG_W("auto_check: initial backup failed for id %d", id);
  464. // 继续处理其他项
  465. }
  466. }
  467. else if (state == 1)
  468. { // 已备份状态
  469. if (parabak_verify(id) != RT_EOK)
  470. {
  471. LOG_W("auto_check: verify failed for id %d, try restore", id);
  472. if (parabak_restore(id) == RT_EOK)
  473. {
  474. if (restored_id == -1)
  475. {
  476. restored_id = id; // 记录第一个被还原的ID
  477. }
  478. }
  479. else
  480. {
  481. LOG_E("auto_check: restore failed for id %d", id);
  482. return -1;
  483. }
  484. }
  485. }
  486. else if (state == 2)
  487. {
  488. // 已还原状态,检查当前内存是否与备份一致
  489. if (parabak_verify(id) == RT_EOK)
  490. {
  491. // 一致,说明系统稳定,将备份区状态置为已备份
  492. LOG_I("auto_check: id %d already restored and consistent, set state to backup", id);
  493. const struct fal_partition *part = get_partition_by_id(id);
  494. if (part != RT_NULL)
  495. {
  496. rt_mutex_take(parabak_lock, RT_WAITING_FOREVER);
  497. parabak_header_t hdr_mod;
  498. if (read_header(part, &hdr_mod) == RT_EOK && hdr_mod.state == 2)
  499. {
  500. hdr_mod.state = 1;
  501. if (write_header(part, &hdr_mod) == RT_EOK)
  502. {
  503. LOG_I("auto_check: id %d state changed from 2 to 1", id);
  504. }
  505. else
  506. {
  507. LOG_W("auto_check: id %d state change failed", id);
  508. }
  509. }
  510. rt_mutex_release(parabak_lock);
  511. }
  512. }
  513. }
  514. }
  515. if (restored_id >= 0)
  516. {
  517. LOG_I("auto_check: some partitions restored, first id=%d", restored_id);
  518. return restored_id;
  519. }
  520. LOG_I("auto_check: all partitions OK");
  521. return 0;
  522. }
  523. /**
  524. * @brief 测试指令
  525. *
  526. */
  527. /* 擦除所有备份分区(仅测试用) */
  528. static void parabak_erase_all(int argc, char **argv)
  529. {
  530. parabak_id_t id;
  531. int count = 0;
  532. int ret;
  533. if (ensure_initialized() != RT_EOK)
  534. {
  535. LOG_E("parabak not initialized");
  536. return;
  537. }
  538. LOG_W("!!! Erasing all backup partitions !!!");
  539. for (id = 0; id < PARABAK_ID_MAX; id++)
  540. {
  541. const struct fal_partition *part = get_partition_by_id(id);
  542. if (part == RT_NULL)
  543. {
  544. LOG_E("partition not found for id %d", id);
  545. continue;
  546. }
  547. rt_mutex_take(parabak_lock, RT_WAITING_FOREVER);
  548. ret = fal_partition_erase(part, 0, PARABAK_PART_SIZE);
  549. rt_mutex_release(parabak_lock);
  550. if (ret < 0)
  551. {
  552. LOG_E("erase partition %s failed", part->name);
  553. }
  554. else
  555. {
  556. LOG_I("erased partition %s", part->name);
  557. count++;
  558. }
  559. }
  560. LOG_I("Erased %d partitions", count);
  561. }
  562. MSH_CMD_EXPORT(parabak_erase_all, Erase all backup partitions (for test only));