dfu_file.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #include "dfu_file.h"
  2. #include <furi_hal.h>
  3. #include <toolbox/crc32_calc.h>
  4. #define VALID_WHOLE_FILE_CRC 0xFFFFFFFF
  5. #define DFU_SUFFIX_VERSION 0x011A
  6. #define DFU_SIGNATURE "DfuSe"
  7. bool dfu_file_validate_crc(File* dfuf, const DfuPageTaskProgressCb progress_cb, void* context) {
  8. uint32_t file_crc = crc32_calc_file(dfuf, progress_cb, context);
  9. /* Last 4 bytes of DFU file = CRC of previous file contents, inverted
  10. * If we calculate whole file CRC32, incl. embedded CRC,
  11. * that should give us 0xFFFFFFFF
  12. */
  13. return file_crc == VALID_WHOLE_FILE_CRC;
  14. }
  15. uint8_t dfu_file_validate_headers(File* dfuf, const DfuValidationParams* reference_params) {
  16. furi_assert(reference_params);
  17. DfuPrefix dfu_prefix = {0};
  18. DfuSuffix dfu_suffix = {0};
  19. uint16_t bytes_read = 0;
  20. if(!storage_file_is_open(dfuf) || !storage_file_seek(dfuf, 0, true)) {
  21. return 0;
  22. }
  23. const uint32_t dfu_suffix_offset = storage_file_size(dfuf) - sizeof(DfuSuffix);
  24. bytes_read = storage_file_read(dfuf, &dfu_prefix, sizeof(DfuPrefix));
  25. if(bytes_read != sizeof(DfuPrefix)) {
  26. return 0;
  27. }
  28. if(memcmp(dfu_prefix.szSignature, DFU_SIGNATURE, sizeof(dfu_prefix.szSignature))) {
  29. return 0;
  30. }
  31. if((dfu_prefix.bVersion != 1) || (dfu_prefix.DFUImageSize != dfu_suffix_offset)) {
  32. return 0;
  33. }
  34. if(!storage_file_seek(dfuf, dfu_suffix_offset, true)) {
  35. return 0;
  36. }
  37. bytes_read = storage_file_read(dfuf, &dfu_suffix, sizeof(DfuSuffix));
  38. if(bytes_read != sizeof(DfuSuffix)) {
  39. return 0;
  40. }
  41. if((dfu_suffix.bLength != sizeof(DfuSuffix)) || (dfu_suffix.bcdDFU != DFU_SUFFIX_VERSION)) {
  42. return 0;
  43. }
  44. /* TODO: check DfuSignature?.. */
  45. if((dfu_suffix.idVendor != reference_params->vendor) ||
  46. (dfu_suffix.idProduct != reference_params->product) ||
  47. (dfu_suffix.bcdDevice != reference_params->device)) {
  48. return 0;
  49. }
  50. return dfu_prefix.bTargets;
  51. }
  52. /* Assumes file is open, valid and read pointer is set at the start of image data
  53. */
  54. static DfuUpdateBlockResult dfu_file_perform_task_for_update_pages(
  55. const DfuUpdateTask* task,
  56. File* dfuf,
  57. const ImageElementHeader* header) {
  58. furi_assert(task);
  59. furi_assert(header);
  60. task->progress_cb(0, task->context);
  61. const size_t FLASH_PAGE_SIZE = furi_hal_flash_get_page_size();
  62. const size_t FLASH_PAGE_ALIGNMENT_MASK = FLASH_PAGE_SIZE - 1;
  63. if((header->dwElementAddress & FLASH_PAGE_ALIGNMENT_MASK) != 0) {
  64. /* start address is not aligned by page boundary -- we don't support that. Yet. */
  65. return UpdateBlockResult_Failed;
  66. }
  67. if(task->address_cb && (!task->address_cb(header->dwElementAddress) ||
  68. !task->address_cb(header->dwElementAddress + header->dwElementSize))) {
  69. storage_file_seek(dfuf, header->dwElementSize, false);
  70. task->progress_cb(100, task->context);
  71. return UpdateBlockResult_Skipped;
  72. }
  73. uint8_t* fw_block = malloc(FLASH_PAGE_SIZE);
  74. uint16_t bytes_read = 0;
  75. uint32_t element_offs = 0;
  76. while(element_offs < header->dwElementSize) {
  77. uint32_t n_bytes_to_read = FLASH_PAGE_SIZE;
  78. if((element_offs + n_bytes_to_read) > header->dwElementSize) {
  79. n_bytes_to_read = header->dwElementSize - element_offs;
  80. }
  81. bytes_read = storage_file_read(dfuf, fw_block, n_bytes_to_read);
  82. if(bytes_read == 0) {
  83. break;
  84. }
  85. int16_t i_page = furi_hal_flash_get_page_number(header->dwElementAddress + element_offs);
  86. if(i_page < 0) {
  87. break;
  88. }
  89. if(!task->task_cb(i_page, fw_block, bytes_read)) {
  90. break;
  91. }
  92. element_offs += bytes_read;
  93. task->progress_cb(element_offs * 100 / header->dwElementSize, task->context);
  94. }
  95. free(fw_block);
  96. return (element_offs == header->dwElementSize) ? UpdateBlockResult_OK :
  97. UpdateBlockResult_Failed;
  98. }
  99. bool dfu_file_process_targets(const DfuUpdateTask* task, File* dfuf, const uint8_t n_targets) {
  100. TargetPrefix target_prefix = {0};
  101. ImageElementHeader image_element = {0};
  102. uint16_t bytes_read = 0;
  103. if(!storage_file_seek(dfuf, sizeof(DfuPrefix), true)) {
  104. return UpdateBlockResult_Failed;
  105. };
  106. for(uint8_t i_target = 0; i_target < n_targets; ++i_target) {
  107. bytes_read = storage_file_read(dfuf, &target_prefix, sizeof(TargetPrefix));
  108. if(bytes_read != sizeof(TargetPrefix)) {
  109. return UpdateBlockResult_Failed;
  110. }
  111. /* TODO: look into TargetPrefix and validate/filter?.. */
  112. for(uint32_t i_element = 0; i_element < target_prefix.dwNbElements; ++i_element) {
  113. bytes_read = storage_file_read(dfuf, &image_element, sizeof(ImageElementHeader));
  114. if(bytes_read != sizeof(ImageElementHeader)) {
  115. return UpdateBlockResult_Failed;
  116. }
  117. if(dfu_file_perform_task_for_update_pages(task, dfuf, &image_element) ==
  118. UpdateBlockResult_Failed) {
  119. return false;
  120. }
  121. }
  122. }
  123. return true;
  124. }