nrf_dfu_utils.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /**
  2. * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. #include "nrf_dfu_utils.h"
  41. #include "nrf_dfu_settings.h"
  42. #include "nrf_bootloader_info.h"
  43. #include "crc32.h"
  44. #include "nrf_log.h"
  45. void nrf_dfu_bank_invalidate(nrf_dfu_bank_t * const p_bank)
  46. {
  47. // Set the bank-code to invalid, and reset size/CRC
  48. memset(p_bank, 0, sizeof(nrf_dfu_bank_t));
  49. // Reset write pointer after completed operation
  50. s_dfu_settings.write_offset = 0;
  51. }
  52. #ifndef BLE_STACK_SUPPORT_REQD
  53. void nrf_dfu_softdevice_invalidate(void)
  54. {
  55. static const uint32_t all_zero = 0UL;
  56. if (SD_PRESENT)
  57. {
  58. ret_code_t err_code = nrf_dfu_flash_store(SD_MAGIC_NUMBER_ABS_OFFSET_GET(MBR_SIZE), &all_zero, 4, NULL);
  59. if (err_code != NRF_SUCCESS)
  60. {
  61. NRF_LOG_ERROR("Could not invalidate SoftDevice.")
  62. }
  63. else
  64. {
  65. // If there is an app it must be invalidated since its start address can no longer be resolved.
  66. if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP)
  67. {
  68. s_dfu_settings.bank_0.bank_code = NRF_DFU_BANK_INVALID;
  69. }
  70. // Since the start of bank 0 has now implicitly been moved to the start
  71. // of the invalidated SoftDevice, its image size must be increased by the
  72. // same amount so the start of bank 1 will be correctly calculated.
  73. s_dfu_settings.bank_0.image_size += SD_SIZE_GET(MBR_SIZE) - MBR_SIZE;
  74. }
  75. }
  76. }
  77. #endif
  78. uint32_t nrf_dfu_bank0_start_addr(void)
  79. {
  80. if (SD_PRESENT)
  81. {
  82. return ALIGN_TO_PAGE(SD_SIZE_GET(MBR_SIZE));
  83. }
  84. else
  85. {
  86. return MBR_SIZE;
  87. }
  88. }
  89. uint32_t nrf_dfu_bank1_start_addr(void)
  90. {
  91. uint32_t bank0_addr = nrf_dfu_bank0_start_addr();
  92. return ALIGN_TO_PAGE(bank0_addr + s_dfu_settings.bank_0.image_size);
  93. }
  94. uint32_t nrf_dfu_app_start_address(void)
  95. {
  96. return nrf_dfu_bank0_start_addr();
  97. }
  98. uint32_t nrf_dfu_softdevice_start_address(void)
  99. {
  100. return MBR_SIZE;
  101. }
  102. bool nrf_dfu_app_is_valid(bool do_crc)
  103. {
  104. NRF_LOG_DEBUG("Enter nrf_dfu_app_is_valid");
  105. if (s_dfu_settings.bank_0.bank_code != NRF_DFU_BANK_VALID_APP)
  106. {
  107. // Bank 0 has no valid app. Nothing to boot
  108. NRF_LOG_DEBUG("No valid app to boot.");
  109. return false;
  110. }
  111. // If CRC == 0, the CRC check is skipped.
  112. if (do_crc && (s_dfu_settings.bank_0.image_crc != 0))
  113. {
  114. uint32_t crc = crc32_compute((uint8_t*) nrf_dfu_app_start_address(),
  115. s_dfu_settings.bank_0.image_size,
  116. NULL);
  117. if (crc != s_dfu_settings.bank_0.image_crc)
  118. {
  119. // CRC does not match with what is stored.
  120. NRF_LOG_DEBUG("CRC check of app failed. Return %d", NRF_DFU_DEBUG);
  121. return NRF_DFU_DEBUG;
  122. }
  123. }
  124. NRF_LOG_DEBUG("Return true. App was valid");
  125. return true;
  126. }
  127. uint32_t nrf_dfu_cache_prepare(const uint32_t required_size, bool single_bank, bool keep_app, bool keep_softdevice)
  128. {
  129. ret_code_t err_code;
  130. bool cache_too_small;
  131. enum
  132. {
  133. INITIAL_DELETE_APP = 0,
  134. APP_DELETED_DELETE_SOFTDEVICE = 1,
  135. SOFTDEVICE_DELETED = 2
  136. } pass;
  137. NRF_LOG_DEBUG("Enter nrf_dfu_cache_prepare()");
  138. NRF_LOG_DEBUG("required_size: 0x%x.", required_size);
  139. NRF_LOG_DEBUG("single_bank: %s.", single_bank ? "true" : "false");
  140. NRF_LOG_DEBUG("keep_app: %s.", keep_app ? "true" : "false");
  141. NRF_LOG_DEBUG("keep_softdevice: %s.", keep_softdevice ? "true" : "false");
  142. NRF_LOG_DEBUG("SD_PRESENT: %s.", SD_PRESENT ? "true" : "false");
  143. NRF_LOG_DEBUG("Bank contents:");
  144. NRF_LOG_DEBUG("Bank 0 code: 0x%02x: Size: 0x%x", s_dfu_settings.bank_0.bank_code, s_dfu_settings.bank_0.image_size);
  145. NRF_LOG_DEBUG("Bank 1 code: 0x%02x: Size: 0x%x", s_dfu_settings.bank_1.bank_code, s_dfu_settings.bank_1.image_size);
  146. // Pass 0 deletes the app if necessary or requested, and if so, proceeds to pass 1.
  147. // Pass 1 deletes the SoftDevice if necessary or requested, and if so, proceeds to pass 2.
  148. // Pass 2 does a last size check.
  149. for (pass = INITIAL_DELETE_APP; pass <= SOFTDEVICE_DELETED; pass++)
  150. {
  151. uint32_t cache_address;
  152. const uint32_t bootloader_start_addr = BOOTLOADER_START_ADDR; // Assign to a variable to prevent warning in Keil 4.
  153. bool keep_firmware = true;
  154. bool delete_more;
  155. switch (pass)
  156. {
  157. case INITIAL_DELETE_APP:
  158. cache_address = nrf_dfu_bank1_start_addr();
  159. // If there is no app, keep_app should be assumed false, so we can free up more space.
  160. keep_firmware = keep_app && (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP);
  161. break;
  162. case APP_DELETED_DELETE_SOFTDEVICE:
  163. cache_address = nrf_dfu_bank0_start_addr();
  164. // If there is no SoftDevice, keep_SoftDevice should be assumed true, because there is
  165. // no point to continuing since the SoftDevice is the last firmware that can be deleted.
  166. keep_firmware = keep_softdevice || !SD_PRESENT;
  167. break;
  168. case SOFTDEVICE_DELETED:
  169. cache_address = nrf_dfu_softdevice_start_address();
  170. break;
  171. default:
  172. ASSERT(false);
  173. cache_address = 0;
  174. break;
  175. }
  176. ASSERT(cache_address <= DFU_REGION_END(bootloader_start_addr));
  177. cache_too_small = required_size > (DFU_REGION_END(bootloader_start_addr) - cache_address);
  178. delete_more = cache_too_small || single_bank; // Delete app or SoftDevice only if we need more room, or if single bank is requested.
  179. NRF_LOG_DEBUG("pass: %d.", pass);
  180. NRF_LOG_DEBUG("cache_address: 0x%x.", cache_address);
  181. NRF_LOG_DEBUG("cache_too_small: %s.", cache_too_small ? "true" : "false");
  182. NRF_LOG_DEBUG("keep_firmware: %s.", keep_firmware ? "true" : "false");
  183. NRF_LOG_DEBUG("delete_more: %s.", delete_more ? "true" : "false");
  184. if (!delete_more || keep_firmware || (pass >= SOFTDEVICE_DELETED))
  185. {
  186. // Stop, done.
  187. break;
  188. }
  189. }
  190. if (cache_too_small)
  191. {
  192. NRF_LOG_WARNING("Aborting. Cannot fit new firmware on device");
  193. err_code = NRF_ERROR_NO_MEM;
  194. }
  195. else
  196. {
  197. // Room was found. Make the necessary preparations for receiving update.
  198. #ifndef BLE_STACK_SUPPORT_REQD
  199. if (pass >= SOFTDEVICE_DELETED)
  200. {
  201. NRF_LOG_DEBUG("Invalidating SoftDevice.");
  202. nrf_dfu_softdevice_invalidate();
  203. }
  204. #endif
  205. if (pass >= APP_DELETED_DELETE_SOFTDEVICE)
  206. {
  207. NRF_LOG_DEBUG("Invalidating app.");
  208. nrf_dfu_bank_invalidate(&s_dfu_settings.bank_0);
  209. }
  210. s_dfu_settings.bank_layout = NRF_DFU_BANK_LAYOUT_DUAL;
  211. s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_1;
  212. // Prepare bank for new image.
  213. nrf_dfu_bank_invalidate(&s_dfu_settings.bank_1);
  214. // Store the Firmware size in the bank for continuations
  215. s_dfu_settings.bank_1.image_size = required_size;
  216. err_code = NRF_SUCCESS;
  217. }
  218. return err_code;
  219. }