nrf_bootloader.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. /**
  2. * Copyright (c) 2016 - 2020, 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_bootloader.h"
  41. #include "compiler_abstraction.h"
  42. #include "nrf.h"
  43. #include "boards.h"
  44. #include "sdk_config.h"
  45. #include "nrf_power.h"
  46. #include "nrf_delay.h"
  47. #include "nrf_log.h"
  48. #include "nrf_log_ctrl.h"
  49. #include "nrf_dfu.h"
  50. #include "nrf_error.h"
  51. #include "nrf_dfu_settings.h"
  52. #include "nrf_dfu_utils.h"
  53. #include "nrf_bootloader_wdt.h"
  54. #include "nrf_bootloader_info.h"
  55. #include "nrf_bootloader_app_start.h"
  56. #include "nrf_bootloader_fw_activation.h"
  57. #include "nrf_bootloader_dfu_timers.h"
  58. #include "app_scheduler.h"
  59. #include "nrf_dfu_validation.h"
  60. static nrf_dfu_observer_t m_user_observer; //<! Observer callback set by the user.
  61. static volatile bool m_flash_write_done;
  62. #define SCHED_QUEUE_SIZE 32 /**< Maximum number of events in the scheduler queue. */
  63. #define SCHED_EVENT_DATA_SIZE NRF_DFU_SCHED_EVENT_DATA_SIZE /**< Maximum app_scheduler event size. */
  64. #if !(defined(NRF_BL_DFU_ENTER_METHOD_BUTTON) && \
  65. defined(NRF_BL_DFU_ENTER_METHOD_PINRESET) && \
  66. defined(NRF_BL_DFU_ENTER_METHOD_GPREGRET) && \
  67. defined(NRF_BL_DFU_ENTER_METHOD_BUTTONLESS)&& \
  68. defined(NRF_BL_RESET_DELAY_MS) && \
  69. defined(NRF_BL_DEBUG_PORT_DISABLE))
  70. #error Configuration file is missing flags. Update sdk_config.h.
  71. #endif
  72. STATIC_ASSERT((NRF_BL_DFU_INACTIVITY_TIMEOUT_MS >= 100) || (NRF_BL_DFU_INACTIVITY_TIMEOUT_MS == 0),
  73. "NRF_BL_DFU_INACTIVITY_TIMEOUT_MS must be 100 ms or more, or 0 to indicate that it is disabled.");
  74. #if defined(NRF_LOG_BACKEND_FLASH_START_PAGE)
  75. STATIC_ASSERT(NRF_LOG_BACKEND_FLASH_START_PAGE != 0,
  76. "If nrf_log flash backend is used it cannot use space after code because it would collide with settings page.");
  77. #endif
  78. /**@brief Weak implemenation of nrf_dfu_init
  79. *
  80. * @note This function will be overridden if nrf_dfu.c is
  81. * compiled and linked with the project
  82. */
  83. #if (__LINT__ != 1)
  84. __WEAK uint32_t nrf_dfu_init(nrf_dfu_observer_t observer)
  85. {
  86. NRF_LOG_DEBUG("in weak nrf_dfu_init");
  87. return NRF_SUCCESS;
  88. }
  89. #endif
  90. /**@brief Weak implementation of nrf_dfu_init
  91. *
  92. * @note This function must be overridden in application if
  93. * user-specific initialization is needed.
  94. */
  95. __WEAK uint32_t nrf_dfu_init_user(void)
  96. {
  97. NRF_LOG_DEBUG("in weak nrf_dfu_init_user");
  98. return NRF_SUCCESS;
  99. }
  100. static void flash_write_callback(void * p_context)
  101. {
  102. UNUSED_PARAMETER(p_context);
  103. m_flash_write_done = true;
  104. }
  105. static void do_reset(void * p_context)
  106. {
  107. UNUSED_PARAMETER(p_context);
  108. NRF_LOG_FINAL_FLUSH();
  109. nrf_delay_ms(NRF_BL_RESET_DELAY_MS);
  110. NVIC_SystemReset();
  111. }
  112. static void bootloader_reset(bool do_backup)
  113. {
  114. NRF_LOG_DEBUG("Resetting bootloader.");
  115. if (do_backup)
  116. {
  117. m_flash_write_done = false;
  118. nrf_dfu_settings_backup(do_reset);
  119. }
  120. else
  121. {
  122. do_reset(NULL);
  123. }
  124. }
  125. static void inactivity_timeout(void)
  126. {
  127. NRF_LOG_INFO("Inactivity timeout.");
  128. bootloader_reset(true);
  129. }
  130. /**@brief Function for handling DFU events.
  131. */
  132. static void dfu_observer(nrf_dfu_evt_type_t evt_type)
  133. {
  134. switch (evt_type)
  135. {
  136. case NRF_DFU_EVT_DFU_STARTED:
  137. case NRF_DFU_EVT_OBJECT_RECEIVED:
  138. nrf_bootloader_dfu_inactivity_timer_restart(
  139. NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS),
  140. inactivity_timeout);
  141. break;
  142. case NRF_DFU_EVT_DFU_COMPLETED:
  143. case NRF_DFU_EVT_DFU_ABORTED:
  144. bootloader_reset(true);
  145. break;
  146. case NRF_DFU_EVT_TRANSPORT_DEACTIVATED:
  147. // Reset the internal state of the DFU settings to the last stored state.
  148. nrf_dfu_settings_reinit();
  149. break;
  150. default:
  151. break;
  152. }
  153. if (m_user_observer)
  154. {
  155. m_user_observer(evt_type);
  156. }
  157. }
  158. /**@brief Function for initializing the event scheduler.
  159. */
  160. static void scheduler_init(void)
  161. {
  162. APP_SCHED_INIT(SCHED_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
  163. }
  164. /**@brief Suspend the CPU until an interrupt occurs.
  165. */
  166. static void wait_for_event(void)
  167. {
  168. #if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
  169. (void)sd_app_evt_wait();
  170. #else
  171. // Wait for an event.
  172. __WFE();
  173. // Clear the internal event register.
  174. __SEV();
  175. __WFE();
  176. #endif
  177. }
  178. /**@brief Continually sleep and process tasks whenever woken.
  179. */
  180. static void loop_forever(void)
  181. {
  182. while (true)
  183. {
  184. //feed the watchdog if enabled.
  185. nrf_bootloader_wdt_feed();
  186. app_sched_execute();
  187. if (!NRF_LOG_PROCESS())
  188. {
  189. wait_for_event();
  190. }
  191. }
  192. }
  193. #if NRF_BL_DFU_ENTER_METHOD_BUTTON
  194. #ifndef BUTTON_PULL
  195. #error NRF_BL_DFU_ENTER_METHOD_BUTTON is enabled but not buttons seem to be available on the board.
  196. #endif
  197. /**@brief Function for initializing button used to enter DFU mode.
  198. */
  199. static void dfu_enter_button_init(void)
  200. {
  201. nrf_gpio_cfg_sense_input(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN,
  202. BUTTON_PULL,
  203. NRF_GPIO_PIN_SENSE_LOW);
  204. }
  205. #endif
  206. static bool crc_on_valid_app_required(void)
  207. {
  208. bool ret = true;
  209. if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_SYSTEMOFF_RESET &&
  210. (nrf_power_resetreas_get() & NRF_POWER_RESETREAS_OFF_MASK))
  211. {
  212. nrf_power_resetreas_clear(NRF_POWER_RESETREAS_OFF_MASK);
  213. ret = false;
  214. }
  215. else if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_GPREGRET2 &&
  216. ((nrf_power_gpregret2_get() & BOOTLOADER_DFU_GPREGRET2_MASK) == BOOTLOADER_DFU_GPREGRET2)
  217. && (nrf_power_gpregret2_get() & BOOTLOADER_DFU_SKIP_CRC_BIT_MASK))
  218. {
  219. nrf_power_gpregret2_set(nrf_power_gpregret2_get() & ~BOOTLOADER_DFU_SKIP_CRC);
  220. ret = false;
  221. }
  222. else
  223. {
  224. }
  225. return ret;
  226. }
  227. static bool boot_validate(boot_validation_t const * p_validation, uint32_t data_addr, uint32_t data_len, bool do_crc)
  228. {
  229. if (!do_crc && (p_validation->type == VALIDATE_CRC))
  230. {
  231. return true;
  232. }
  233. return nrf_dfu_validation_boot_validate(p_validation, data_addr, data_len);
  234. }
  235. /** @brief Function for checking if the main application is valid.
  236. *
  237. * @details This function checks if there is a valid application
  238. * located at Bank 0.
  239. *
  240. * @param[in] do_crc Perform CRC check on application. Only CRC checks
  241. can be skipped. For other boot validation types,
  242. this parameter is ignored.
  243. *
  244. * @retval true If a valid application has been detected.
  245. * @retval false If there is no valid application.
  246. */
  247. static bool app_is_valid(bool do_crc)
  248. {
  249. if (s_dfu_settings.bank_0.bank_code != NRF_DFU_BANK_VALID_APP)
  250. {
  251. NRF_LOG_INFO("Boot validation failed. No valid app to boot.");
  252. return false;
  253. }
  254. else if (NRF_BL_APP_SIGNATURE_CHECK_REQUIRED &&
  255. (s_dfu_settings.boot_validation_app.type != VALIDATE_ECDSA_P256_SHA256))
  256. {
  257. NRF_LOG_WARNING("Boot validation failed. The boot validation of the app must be a signature check.");
  258. return false;
  259. }
  260. else if (SD_PRESENT && !boot_validate(&s_dfu_settings.boot_validation_softdevice, MBR_SIZE, s_dfu_settings.sd_size, do_crc))
  261. {
  262. NRF_LOG_WARNING("Boot validation failed. SoftDevice is present but invalid.");
  263. return false;
  264. }
  265. else if (!boot_validate(&s_dfu_settings.boot_validation_app, nrf_dfu_bank0_start_addr(), s_dfu_settings.bank_0.image_size, do_crc))
  266. {
  267. NRF_LOG_WARNING("Boot validation failed. App is invalid.");
  268. return false;
  269. }
  270. // The bootloader itself is not checked, since a self-check of this kind gives little to no benefit
  271. // compared to the cost incurred on each bootup.
  272. NRF_LOG_DEBUG("App is valid");
  273. return true;
  274. }
  275. /**@brief Function for clearing all DFU enter flags that
  276. * preserve state during reset.
  277. *
  278. * @details This is used to make sure that each of these flags
  279. * is checked only once after reset.
  280. */
  281. static void dfu_enter_flags_clear(void)
  282. {
  283. if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
  284. (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk))
  285. {
  286. // Clear RESETPIN flag.
  287. NRF_POWER->RESETREAS |= POWER_RESETREAS_RESETPIN_Msk;
  288. }
  289. if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
  290. ((nrf_power_gpregret_get() & BOOTLOADER_DFU_GPREGRET_MASK) == BOOTLOADER_DFU_GPREGRET)
  291. && (nrf_power_gpregret_get() & BOOTLOADER_DFU_START_BIT_MASK))
  292. {
  293. // Clear DFU mark in GPREGRET register.
  294. nrf_power_gpregret_set(nrf_power_gpregret_get() & ~BOOTLOADER_DFU_START);
  295. }
  296. if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS &&
  297. (s_dfu_settings.enter_buttonless_dfu == 1))
  298. {
  299. // Clear DFU flag in flash settings.
  300. s_dfu_settings.enter_buttonless_dfu = 0;
  301. APP_ERROR_CHECK(nrf_dfu_settings_write(NULL));
  302. }
  303. }
  304. /**@brief Function for checking whether to enter DFU mode or not.
  305. */
  306. static bool dfu_enter_check(void)
  307. {
  308. if (!app_is_valid(crc_on_valid_app_required()))
  309. {
  310. NRF_LOG_DEBUG("DFU mode because app is not valid.");
  311. return true;
  312. }
  313. if (NRF_BL_DFU_ENTER_METHOD_BUTTON &&
  314. (nrf_gpio_pin_read(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN) == 0))
  315. {
  316. NRF_LOG_DEBUG("DFU mode requested via button.");
  317. return true;
  318. }
  319. if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
  320. (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk))
  321. {
  322. NRF_LOG_DEBUG("DFU mode requested via pin-reset.");
  323. return true;
  324. }
  325. if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
  326. (nrf_power_gpregret_get() & BOOTLOADER_DFU_START))
  327. {
  328. NRF_LOG_DEBUG("DFU mode requested via GPREGRET.");
  329. return true;
  330. }
  331. if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS &&
  332. (s_dfu_settings.enter_buttonless_dfu == 1))
  333. {
  334. NRF_LOG_DEBUG("DFU mode requested via bootloader settings.");
  335. return true;
  336. }
  337. return false;
  338. }
  339. #if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
  340. static void postvalidate(void)
  341. {
  342. NRF_LOG_INFO("Postvalidating update after reset.");
  343. nrf_dfu_validation_init();
  344. if (nrf_dfu_validation_init_cmd_present())
  345. {
  346. uint32_t firmware_start_addr;
  347. uint32_t firmware_size;
  348. // Execute a previously received init packed. Subsequent executes will have no effect.
  349. if (nrf_dfu_validation_init_cmd_execute(&firmware_start_addr, &firmware_size) == NRF_DFU_RES_CODE_SUCCESS)
  350. {
  351. if (nrf_dfu_validation_prevalidate() == NRF_DFU_RES_CODE_SUCCESS)
  352. {
  353. if (nrf_dfu_validation_activation_prepare(firmware_start_addr, firmware_size) == NRF_DFU_RES_CODE_SUCCESS)
  354. {
  355. NRF_LOG_INFO("Postvalidation successful.");
  356. }
  357. }
  358. }
  359. }
  360. s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_0;
  361. UNUSED_RETURN_VALUE(nrf_dfu_settings_write_and_backup(flash_write_callback));
  362. }
  363. #endif
  364. ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer)
  365. {
  366. NRF_LOG_DEBUG("In nrf_bootloader_init");
  367. ret_code_t ret_val;
  368. nrf_bootloader_fw_activation_result_t activation_result;
  369. uint32_t initial_timeout;
  370. bool dfu_enter = false;
  371. m_user_observer = observer;
  372. if (NRF_BL_DEBUG_PORT_DISABLE)
  373. {
  374. nrf_bootloader_debug_port_disable();
  375. }
  376. #if NRF_BL_DFU_ENTER_METHOD_BUTTON
  377. dfu_enter_button_init();
  378. #endif
  379. ret_val = nrf_dfu_settings_init(false);
  380. if (ret_val != NRF_SUCCESS)
  381. {
  382. return NRF_ERROR_INTERNAL;
  383. }
  384. #if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
  385. // Postvalidate if DFU has signaled that update is ready.
  386. if (s_dfu_settings.bank_current == NRF_DFU_CURRENT_BANK_1)
  387. {
  388. postvalidate();
  389. }
  390. #endif
  391. // Check if an update needs to be activated and activate it.
  392. activation_result = nrf_bootloader_fw_activate();
  393. switch (activation_result)
  394. {
  395. case ACTIVATION_NONE:
  396. initial_timeout = NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS);
  397. dfu_enter = dfu_enter_check();
  398. break;
  399. case ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE:
  400. initial_timeout = NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_CONTINUATION_TIMEOUT_MS);
  401. dfu_enter = true;
  402. break;
  403. case ACTIVATION_SUCCESS:
  404. bootloader_reset(true);
  405. NRF_LOG_ERROR("Unreachable");
  406. return NRF_ERROR_INTERNAL; // Should not reach this.
  407. case ACTIVATION_ERROR:
  408. default:
  409. return NRF_ERROR_INTERNAL;
  410. }
  411. if (dfu_enter)
  412. {
  413. nrf_bootloader_wdt_init();
  414. scheduler_init();
  415. dfu_enter_flags_clear();
  416. // Call user-defined init function if implemented
  417. ret_val = nrf_dfu_init_user();
  418. if (ret_val != NRF_SUCCESS)
  419. {
  420. return NRF_ERROR_INTERNAL;
  421. }
  422. nrf_bootloader_dfu_inactivity_timer_restart(initial_timeout, inactivity_timeout);
  423. ret_val = nrf_dfu_init(dfu_observer);
  424. if (ret_val != NRF_SUCCESS)
  425. {
  426. return NRF_ERROR_INTERNAL;
  427. }
  428. NRF_LOG_DEBUG("Enter main loop");
  429. loop_forever(); // This function will never return.
  430. NRF_LOG_ERROR("Unreachable");
  431. }
  432. else
  433. {
  434. // Erase additional data like peer data or advertisement name
  435. ret_val = nrf_dfu_settings_additional_erase();
  436. if (ret_val != NRF_SUCCESS)
  437. {
  438. return NRF_ERROR_INTERNAL;
  439. }
  440. m_flash_write_done = false;
  441. nrf_dfu_settings_backup(flash_write_callback);
  442. ASSERT(m_flash_write_done);
  443. nrf_bootloader_app_start();
  444. NRF_LOG_ERROR("Unreachable");
  445. }
  446. // Should not be reached.
  447. return NRF_ERROR_INTERNAL;
  448. }