ota_image.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /*
  2. * Copyright (c) 2019 Actions Semiconductor Co., Ltd
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * @file
  8. * @brief OTA firmware image interface
  9. */
  10. #include <kernel.h>
  11. #include <string.h>
  12. #include <soc.h>
  13. #include <mem_manager.h>
  14. #include <ota_backend.h>
  15. #include <crc.h>
  16. #include <ota_storage.h>
  17. #include "ota_image.h"
  18. #include <os_common_api.h>
  19. #define OTA_FW_HDR_MAGIC 0x41544f41 //'AOTA'
  20. struct ota_fw_hdr {
  21. uint32_t magic;
  22. uint32_t header_checksum;
  23. uint16_t header_version;
  24. uint16_t header_size;
  25. uint16_t file_cnt;
  26. uint16_t flag;
  27. uint16_t dir_offset;
  28. uint16_t data_offset;
  29. uint32_t data_size;
  30. uint32_t data_checksum;
  31. uint8_t reserved[4];
  32. } __attribute__((packed));
  33. /* size 0x60 */
  34. struct ota_fw_ver {
  35. uint8_t version_name[32];
  36. uint8_t board_name[32];
  37. uint8_t hardware_ver[4];
  38. uint32_t version_code;
  39. uint8_t reserved[8];
  40. uint8_t build_time[16];
  41. } __attribute__((packed));
  42. struct ota_dir_entry {
  43. uint8_t filename[12];
  44. uint8_t reserved1[4];
  45. uint32_t offset;
  46. uint32_t length;
  47. uint8_t reserved2[4];
  48. uint32_t checksum;
  49. } __attribute__((packed));
  50. struct ota_fw_dir {
  51. struct ota_dir_entry entrys[16];
  52. };
  53. struct ota_fw_head {
  54. /* offset: 0x0 */
  55. struct ota_fw_hdr hdr;
  56. /* offset: 0x20 */
  57. uint8_t reserved1[32];
  58. /* offset: 0x40, new OTA firmware version */
  59. struct ota_fw_ver new_ver;
  60. /* offset: 0xa0, old ota firmware version
  61. * only used for ota patch firmware
  62. */
  63. struct ota_fw_ver old_ver;
  64. /* offset: 0x100 */
  65. uint8_t reserved2[256];
  66. /* offset: 0x200, OTA file dir entries */
  67. struct ota_fw_dir dir;
  68. } __attribute__((packed));
  69. struct ota_progress {
  70. #define OTA_PROGRESS_UP_LIMIT (99)
  71. uint32_t total_size;
  72. uint32_t cur_size;
  73. uint8_t cursor;
  74. uint8_t on;
  75. };
  76. struct ota_image {
  77. struct ota_backend *backend;
  78. struct ota_fw_hdr hdr;
  79. struct ota_fw_dir dir;
  80. struct ota_dir_entry *cur_dir;
  81. //struct ota_fw_head *fw_head;
  82. struct ota_progress progress;
  83. };
  84. /* 16MB */
  85. //#define OTA_IMAGE_MAX_LENGTH 0x3000000
  86. #define OTA_IMAGE_DATA_CHECK_BUF_SIZE 0x800
  87. static struct ota_dir_entry *ota_image_find_file(struct ota_image *img, const char *filename)
  88. {
  89. struct ota_dir_entry *dir;
  90. int i;
  91. SYS_LOG_INF("find file %s", filename);
  92. if (img->cur_dir && (0 == strncmp(img->cur_dir->filename, filename, 12))) {
  93. dir = img->cur_dir;
  94. } else {
  95. for (i = 0; i < img->hdr.file_cnt; i++) {
  96. dir = &img->dir.entrys[i];
  97. if (0 == strncmp(dir->filename, filename, 12)) {
  98. SYS_LOG_INF("found file %s at [%d]", filename, i);
  99. return dir;
  100. }
  101. }
  102. }
  103. return NULL;
  104. }
  105. int ota_image_get_file_length(struct ota_image *img, const char *filename)
  106. {
  107. struct ota_dir_entry *dir;
  108. if (filename == NULL) {
  109. SYS_LOG_INF("get image length 0x%x", img->hdr.data_size);
  110. return img->hdr.data_size;
  111. }
  112. dir = ota_image_find_file(img, filename);
  113. if (!dir) {
  114. SYS_LOG_ERR("cannot found file %s", filename);
  115. return -1;
  116. }
  117. return dir->length;
  118. }
  119. int ota_image_get_file_offset(struct ota_image *img, const char *filename)
  120. {
  121. struct ota_dir_entry *dir;
  122. if (filename == NULL) {
  123. SYS_LOG_INF("get image offset 0");
  124. return 0;
  125. }
  126. dir = ota_image_find_file(img, filename);
  127. if (!dir) {
  128. SYS_LOG_ERR("cannot found file %s", filename);
  129. return -1;
  130. }
  131. return dir->offset;
  132. }
  133. int ota_image_ioctl(struct ota_image *img, int cmd, unsigned int param)
  134. {
  135. SYS_LOG_DBG("cmd 0x%x param 0x%x", cmd, param);
  136. return ota_backend_ioctl(img->backend, cmd, param);
  137. }
  138. int ota_image_progress_on(struct ota_image *img, uint32_t total_size, uint32_t start_offset)
  139. {
  140. if (img && !img->progress.on) {
  141. img->progress.total_size = total_size;
  142. img->progress.cur_size = start_offset;
  143. img->progress.cursor = 100 * start_offset / total_size;
  144. img->progress.on = 1;
  145. SYS_LOG_INF("OTA image progress total size %d", total_size);
  146. SYS_LOG_INF("OTA upgrade progress ==> %d%%", img->progress.cursor);
  147. return 0;
  148. }
  149. return -1;
  150. }
  151. int ota_image_progress_reset(struct ota_image *img)
  152. {
  153. if (img) {
  154. img->progress.cur_size = 0;
  155. img->progress.cursor = 0;
  156. }
  157. return 0;
  158. }
  159. int ota_image_report_progress(struct ota_image *img, uint32_t pre_xfer_size, bool is_final)
  160. {
  161. struct ota_progress *progress = &img->progress;
  162. uint32_t grade_size;
  163. if (img && progress->on) {
  164. if (progress->total_size < pre_xfer_size) {
  165. SYS_LOG_ERR("error total size %d xfer_size %d",
  166. progress->total_size, pre_xfer_size);
  167. return -1;
  168. }
  169. if ((pre_xfer_size + progress->cur_size) > progress->total_size) {
  170. SYS_LOG_ERR("error xfer_size %d cur_size %d total_size %d",
  171. pre_xfer_size, progress->cur_size, progress->total_size);
  172. return -1;
  173. }
  174. progress->cur_size += pre_xfer_size;
  175. grade_size = progress->total_size / 100;
  176. grade_size *= (progress->cursor + 1);
  177. if (!is_final) {
  178. if (progress->cur_size > grade_size) {
  179. progress->cursor = 100 * progress->cur_size / progress->total_size;
  180. if (progress->cursor > OTA_PROGRESS_UP_LIMIT) {
  181. ota_image_ioctl(img, OTA_BACKEND_IOCTL_REPORT_PROCESS, OTA_PROGRESS_UP_LIMIT);
  182. SYS_LOG_INF("OTA upgrade progress ==> %d%%", OTA_PROGRESS_UP_LIMIT);
  183. } else {
  184. ota_image_ioctl(img, OTA_BACKEND_IOCTL_REPORT_PROCESS, progress->cursor);
  185. SYS_LOG_INF("OTA upgrade progress ==> %d%%", img->progress.cursor);
  186. }
  187. }
  188. } else {
  189. ota_image_ioctl(img, OTA_BACKEND_IOCTL_REPORT_PROCESS, 100);
  190. }
  191. }
  192. return 0;
  193. }
  194. int ota_image_read_prepare(struct ota_image *img, int offset, uint8_t *buf, int size)
  195. {
  196. int ret;
  197. SYS_LOG_DBG("offset 0x%x, buf %p, size %d", offset, buf, size);
  198. ret = ota_backend_read_prepare(img->backend, offset, buf, size);
  199. return ret;
  200. }
  201. int ota_image_read_complete(struct ota_image *img, int offset, uint8_t *buf, int size)
  202. {
  203. int ret;
  204. SYS_LOG_DBG("offset 0x%x, buf %p, size %d", offset, buf, size);
  205. ret = ota_backend_read_complete(img->backend, offset, buf, size);
  206. ota_image_report_progress(img, size, false);
  207. return ret;
  208. }
  209. int ota_image_read(struct ota_image *img, int offset, uint8_t *buf, int size)
  210. {
  211. int ret;
  212. SYS_LOG_DBG("offset 0x%x, buf %p, size %d", offset, buf, size);
  213. ret = ota_backend_read(img->backend, offset, buf, size);
  214. ota_image_report_progress(img, size, false);
  215. return ret;
  216. }
  217. int ota_image_check_file(struct ota_image *img, const char *filename, const uint8_t *buf, int size)
  218. {
  219. struct ota_dir_entry *dir;
  220. uint32_t crc;
  221. dir = ota_image_find_file(img, filename);
  222. if (!dir) {
  223. SYS_LOG_ERR("cannot found file %s", filename);
  224. return -1;
  225. }
  226. crc = utils_crc32(0, buf, size);
  227. if (crc != dir->checksum) {
  228. SYS_LOG_INF("file %s checksum error", filename);
  229. return -1;
  230. }
  231. SYS_LOG_INF("file %s checksum pass", filename);
  232. return 0;
  233. }
  234. #if 1
  235. static int ota_image_calc_crc(struct ota_image *img, uint32_t offset, int size)
  236. {
  237. char *buf;
  238. int err, rlen;
  239. uint32_t crc, addr;
  240. SYS_LOG_INF("caculate image crc offset 0x%x size 0x%x", offset, size);
  241. buf = mem_malloc(OTA_IMAGE_DATA_CHECK_BUF_SIZE);
  242. if (!img) {
  243. SYS_LOG_ERR("malloc failed");
  244. return 0;
  245. }
  246. addr = offset;
  247. rlen = OTA_IMAGE_DATA_CHECK_BUF_SIZE;
  248. crc = 0;
  249. while (size > 0) {
  250. if (size < rlen)
  251. rlen = size;
  252. err = ota_image_read(img, addr, buf, rlen);
  253. if (err) {
  254. SYS_LOG_INF("read image err, addr 0x%x, rlen 0x%x return %d",
  255. addr, rlen, err);
  256. crc = 0;
  257. goto exit;
  258. }
  259. crc = utils_crc32(crc, buf, rlen);
  260. size -= rlen;
  261. addr += rlen;
  262. }
  263. exit:
  264. mem_free(buf);
  265. return crc;
  266. }
  267. #endif
  268. static int ota_image_check_head_crc(struct ota_fw_head *fw_head)
  269. {
  270. uint32_t crc;
  271. /* skip magic & head crc self field */
  272. crc = utils_crc32(0, (const char *)fw_head + 8, sizeof(struct ota_fw_head) - 8);
  273. if (crc == -1 || crc != fw_head->hdr.header_checksum) {
  274. SYS_LOG_INF("image head crc error, calc crc 0x%x, head->crc 0x%x",
  275. crc, fw_head->hdr.header_checksum);
  276. return -1;
  277. }
  278. SYS_LOG_INF("image head check pass");
  279. return 0;
  280. }
  281. int ota_image_check_data(struct ota_image *img)
  282. {
  283. #if 1
  284. struct ota_fw_hdr *hdr = &img->hdr;
  285. uint32_t crc;
  286. crc = ota_image_calc_crc(img, hdr->data_offset, hdr->data_size - hdr->data_offset);
  287. if (crc == 0 || crc != hdr->data_checksum) {
  288. SYS_LOG_INF("image data crc error, calc crc 0x%x, head->data_checksum 0x%x",
  289. crc, hdr->data_checksum);
  290. return -1;
  291. }
  292. SYS_LOG_INF("image data check pass");
  293. #endif
  294. return 0;
  295. }
  296. int ota_image_check(struct ota_image *img, struct ota_fw_head *fw_head)
  297. {
  298. struct ota_fw_hdr *hdr = &fw_head->hdr;
  299. int err;
  300. SYS_LOG_INF("checking image");
  301. if (!img || !img->backend)
  302. return -EINVAL;
  303. if (hdr->magic != OTA_FW_HDR_MAGIC) {
  304. SYS_LOG_ERR("wrong magic 0x%x\n", hdr->magic);
  305. return -1;
  306. }
  307. if (hdr->header_size != sizeof(struct ota_fw_head)) {
  308. SYS_LOG_ERR("invalid header size %d", hdr->header_size);
  309. return -1;
  310. }
  311. // if (hdr->data_size > OTA_IMAGE_MAX_LENGTH) {
  312. // return -1;
  313. // }
  314. err = ota_image_check_head_crc(fw_head);
  315. if (err) {
  316. SYS_LOG_ERR("bad head crc");
  317. return -1;
  318. }
  319. #if 0
  320. /* only check data in recovery app to save time */
  321. err = ota_image_check_data(img);
  322. if (err) {
  323. SYS_LOG_ERR("bad data crc");
  324. return -1;
  325. }
  326. #endif
  327. SYS_LOG_INF("image check pass");
  328. return 0;
  329. }
  330. int ota_image_open(struct ota_image *img)
  331. {
  332. struct ota_fw_head *fw_head;
  333. int err;
  334. SYS_LOG_INF("open type %d", img->backend->type);
  335. err = ota_backend_open(img->backend);
  336. if (err) {
  337. SYS_LOG_INF("backend open: err %d", err);
  338. return err;
  339. }
  340. SYS_LOG_INF("read image header");
  341. fw_head = mem_malloc(sizeof(struct ota_fw_head));
  342. if (!fw_head) {
  343. SYS_LOG_ERR("malloc image header failed");
  344. return -ENOMEM;
  345. }
  346. /* read image header */
  347. err = ota_image_read(img, 0, (uint8_t *)fw_head, sizeof(struct ota_fw_head));
  348. if (err) {
  349. SYS_LOG_INF("read head err, return %d", err);
  350. goto exit;
  351. }
  352. SYS_LOG_INF("image header:");
  353. //print_buffer(fw_head, 1, sizeof(struct ota_fw_hdr), 16, 0);
  354. /* check image */
  355. err = ota_image_check(img, fw_head);
  356. if (err) {
  357. SYS_LOG_INF("check: err %d", err);
  358. goto exit;
  359. }
  360. /* read image header */
  361. memcpy(&img->hdr, &fw_head->hdr, sizeof(struct ota_fw_hdr));
  362. memcpy(&img->dir, &fw_head->dir, sizeof(struct ota_fw_dir));
  363. mem_free(fw_head);
  364. return 0;
  365. exit:
  366. mem_free(fw_head);
  367. ota_backend_close(img->backend);
  368. img->backend = NULL;
  369. return err;
  370. }
  371. int ota_image_close(struct ota_image *img)
  372. {
  373. int err = 0;
  374. SYS_LOG_INF("close");
  375. if (img->backend) {
  376. // delay 1s to close bt for sending remain data
  377. //if (img->backend->type == OTA_BACKEND_TYPE_BLUETOOTH) {
  378. // os_sleep(1000);
  379. //}
  380. err = ota_backend_close(img->backend);
  381. if (err) {
  382. SYS_LOG_INF("open: err %d", err);
  383. }
  384. //img->backend = NULL;
  385. }
  386. memset(&img->progress, 0, sizeof(struct ota_progress));
  387. return err;
  388. }
  389. int ota_image_bind(struct ota_image *img, struct ota_backend *backend)
  390. {
  391. SYS_LOG_INF("bind backend %d", backend->type);
  392. img->backend = backend;
  393. return 0;
  394. }
  395. int ota_image_unbind(struct ota_image *img, struct ota_backend *backend)
  396. {
  397. SYS_LOG_INF("unbind backend %d", backend->type);
  398. if (img->backend == backend) {
  399. img->backend = NULL;
  400. }
  401. return 0;
  402. }
  403. struct ota_backend *ota_image_get_backend(struct ota_image *img)
  404. {
  405. return img->backend;
  406. }
  407. uint32_t ota_image_get_checksum(struct ota_image *img)
  408. {
  409. return img->hdr.data_checksum;
  410. }
  411. #if defined(CONFIG_OTA_PRODUCT_SUPPORT) || defined(CONFIG_OTA_BLE_MASTER_SUPPORT)
  412. uint32_t ota_image_get_datasize(struct ota_image *img)
  413. {
  414. return img->hdr.data_size;
  415. }
  416. #endif
  417. static struct ota_image global_ota_image;
  418. struct ota_image *ota_image_init(void)
  419. {
  420. struct ota_image *img;
  421. SYS_LOG_INF("init");
  422. img = &global_ota_image;
  423. memset(img, 0x0, sizeof(struct ota_image));
  424. return img;
  425. }
  426. void ota_image_exit(struct ota_image *img)
  427. {
  428. SYS_LOG_INF("exit");
  429. if (img->backend && (img->backend->type == OTA_BACKEND_TYPE_CARD)) {
  430. ota_backend_exit(img->backend);
  431. }
  432. img->backend = NULL;
  433. }