dfu_dual_bank.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
  2. *
  3. * The information contained herein is property of Nordic Semiconductor ASA.
  4. * Terms and conditions of usage are described in detail in NORDIC
  5. * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
  6. *
  7. * Licensees are granted free, non-transferable use of the information. NO
  8. * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
  9. * the file.
  10. *
  11. */
  12. #include <stddef.h>
  13. #include "dfu.h"
  14. #include <dfu_types.h>
  15. #include "dfu_bank_internal.h"
  16. #include "nrf.h"
  17. #include "nrf_sdm.h"
  18. #include "app_error.h"
  19. #include "app_timer.h"
  20. #include "bootloader.h"
  21. #include "bootloader_types.h"
  22. #include "pstorage.h"
  23. #include "nrf_mbr.h"
  24. #include "dfu_init.h"
  25. #include "sdk_common.h"
  26. static dfu_state_t m_dfu_state; /**< Current DFU state. */
  27. static uint32_t m_image_size; /**< Size of the image that will be transmitted. */
  28. static dfu_start_packet_t m_start_packet; /**< Start packet received for this update procedure. Contains update mode and image sizes information to be used for image transfer. */
  29. static uint8_t m_init_packet[128]; /**< Init packet, can hold CRC, Hash, Signed Hash and similar, for image validation, integrety check and authorization checking. */
  30. static uint8_t m_init_packet_length; /**< Length of init packet received. */
  31. static uint16_t m_image_crc; /**< Calculated CRC of the image received. */
  32. APP_TIMER_DEF(m_dfu_timer_id); /**< Application timer id. */
  33. static bool m_dfu_timed_out = false; /**< Boolean flag value for tracking DFU timer timeout state. */
  34. static pstorage_handle_t m_storage_handle_swap; /**< Pstorage handle for the swap area (bank 1). Bank used when updating an application or bootloader without SoftDevice. */
  35. static pstorage_handle_t m_storage_handle_app; /**< Pstorage handle for the application area (bank 0). Bank used when updating a SoftDevice w/wo bootloader. Handle also used when swapping received application from bank 1 to bank 0. */
  36. static pstorage_handle_t * mp_storage_handle_active; /**< Pointer to the pstorage handle for the active bank for receiving of data packets. */
  37. static dfu_callback_t m_data_pkt_cb; /**< Callback from DFU Bank module for notification of asynchronous operation such as flash prepare. */
  38. static dfu_bank_func_t m_functions; /**< Structure holding operations for the selected update process. */
  39. /**@brief Function for handling callbacks from pstorage module.
  40. *
  41. * @details Handles pstorage results for clear and storage operation. For detailed description of
  42. * the parameters provided with the callback, please refer to \ref pstorage_ntf_cb_t.
  43. */
  44. static void pstorage_callback_handler(pstorage_handle_t * p_handle,
  45. uint8_t op_code,
  46. uint32_t result,
  47. uint8_t * p_data,
  48. uint32_t data_len)
  49. {
  50. switch (op_code)
  51. {
  52. case PSTORAGE_STORE_OP_CODE:
  53. if ((m_dfu_state == DFU_STATE_RX_DATA_PKT) && (m_data_pkt_cb != NULL))
  54. {
  55. m_data_pkt_cb(DATA_PACKET, result, p_data);
  56. }
  57. break;
  58. case PSTORAGE_CLEAR_OP_CODE:
  59. if (m_dfu_state == DFU_STATE_PREPARING)
  60. {
  61. m_functions.cleared();
  62. m_dfu_state = DFU_STATE_RDY;
  63. if (m_data_pkt_cb != NULL)
  64. {
  65. m_data_pkt_cb(START_PACKET, result, p_data);
  66. }
  67. }
  68. break;
  69. default:
  70. break;
  71. }
  72. APP_ERROR_CHECK(result);
  73. }
  74. /**@brief Function for handling the DFU timeout.
  75. *
  76. * @param[in] p_context The timeout context.
  77. */
  78. static void dfu_timeout_handler(void * p_context)
  79. {
  80. UNUSED_PARAMETER(p_context);
  81. dfu_update_status_t update_status;
  82. m_dfu_timed_out = true;
  83. update_status.status_code = DFU_TIMEOUT;
  84. bootloader_dfu_update_process(update_status);
  85. }
  86. /**@brief Function for restarting the DFU Timer.
  87. *
  88. * @details This function will stop and restart the DFU timer. This function will be called by the
  89. * functions handling any DFU packet received from the peer that is transferring a firmware
  90. * image.
  91. */
  92. static uint32_t dfu_timer_restart(void)
  93. {
  94. if (m_dfu_timed_out)
  95. {
  96. // The DFU timer had already timed out.
  97. return NRF_ERROR_INVALID_STATE;
  98. }
  99. uint32_t err_code = app_timer_stop(m_dfu_timer_id);
  100. APP_ERROR_CHECK(err_code);
  101. err_code = app_timer_start(m_dfu_timer_id, DFU_TIMEOUT_INTERVAL, NULL);
  102. APP_ERROR_CHECK(err_code);
  103. return err_code;
  104. }
  105. /**@brief Function for preparing of flash before receiving SoftDevice image.
  106. *
  107. * @details This function will erase current application area to ensure sufficient amount of
  108. * storage for the SoftDevice image. Upon erase complete a callback will be done.
  109. * See \ref dfu_bank_prepare_t for further details.
  110. */
  111. static void dfu_prepare_func_app_erase(uint32_t image_size)
  112. {
  113. uint32_t err_code;
  114. mp_storage_handle_active = &m_storage_handle_app;
  115. // Doing a SoftDevice update thus current application must be cleared to ensure enough space
  116. // for new SoftDevice.
  117. m_dfu_state = DFU_STATE_PREPARING;
  118. err_code = pstorage_clear(&m_storage_handle_app, m_image_size);
  119. APP_ERROR_CHECK(err_code);
  120. }
  121. /**@brief Function for preparing swap before receiving application or bootloader image.
  122. *
  123. * @details This function will erase current swap area to ensure flash is ready for storage of the
  124. * Application or Bootloader image. Upon erase complete a callback will be done.
  125. * See \ref dfu_bank_prepare_t for further details.
  126. */
  127. static void dfu_prepare_func_swap_erase(uint32_t image_size)
  128. {
  129. uint32_t err_code;
  130. mp_storage_handle_active = &m_storage_handle_swap;
  131. m_dfu_state = DFU_STATE_PREPARING;
  132. err_code = pstorage_clear(&m_storage_handle_swap, DFU_IMAGE_MAX_SIZE_BANKED);
  133. APP_ERROR_CHECK(err_code);
  134. }
  135. /**@brief Function for handling behaviour when clear operation has completed.
  136. */
  137. static void dfu_cleared_func_swap(void)
  138. {
  139. // Do nothing.
  140. }
  141. /**@brief Function for handling behaviour when clear operation has completed.
  142. */
  143. static void dfu_cleared_func_app(void)
  144. {
  145. dfu_update_status_t update_status = {DFU_BANK_0_ERASED, };
  146. bootloader_dfu_update_process(update_status);
  147. }
  148. /**@brief Function for calculating storage offset for receiving SoftDevice image.
  149. *
  150. * @details When a new SoftDevice is received it will be temporary stored in flash before moved to
  151. * address 0x0. In order to succesfully validate transfer and relocation it is important
  152. * that temporary image and final installed image does not ovwerlap hence an offset must
  153. * be calculated in case new image is larger than currently installed SoftDevice.
  154. */
  155. uint32_t offset_calculate(uint32_t sd_image_size)
  156. {
  157. uint32_t offset = 0;
  158. if (m_start_packet.sd_image_size > DFU_BANK_0_REGION_START)
  159. {
  160. uint32_t page_mask = (CODE_PAGE_SIZE - 1);
  161. uint32_t diff = m_start_packet.sd_image_size - DFU_BANK_0_REGION_START;
  162. offset = diff & ~page_mask;
  163. // Align offset to next page if image size is not page sized.
  164. if ((diff & page_mask) > 0)
  165. {
  166. offset += CODE_PAGE_SIZE;
  167. }
  168. }
  169. return offset;
  170. }
  171. /**@brief Function for activating received SoftDevice image.
  172. *
  173. * @note This function will not move the SoftDevice image.
  174. * The bootloader settings will be marked as SoftDevice update complete and the swapping of
  175. * current SoftDevice will occur after system reset.
  176. *
  177. * @return NRF_SUCCESS on success.
  178. */
  179. static uint32_t dfu_activate_sd(void)
  180. {
  181. dfu_update_status_t update_status;
  182. update_status.status_code = DFU_UPDATE_SD_COMPLETE;
  183. update_status.app_crc = m_image_crc;
  184. update_status.sd_image_start = DFU_BANK_0_REGION_START;
  185. update_status.sd_size = m_start_packet.sd_image_size;
  186. update_status.bl_size = m_start_packet.bl_image_size;
  187. update_status.app_size = m_start_packet.app_image_size;
  188. bootloader_dfu_update_process(update_status);
  189. return NRF_SUCCESS;
  190. }
  191. /**@brief Function for activating received Application image.
  192. *
  193. * @details This function will move the received application image fram swap (bank 1) to
  194. * application area (bank 0).
  195. *
  196. * @return NRF_SUCCESS on success. Error code otherwise.
  197. */
  198. static uint32_t dfu_activate_app(void)
  199. {
  200. uint32_t err_code;
  201. // Erase BANK 0.
  202. err_code = pstorage_clear(&m_storage_handle_app, m_start_packet.app_image_size);
  203. APP_ERROR_CHECK(err_code);
  204. err_code = pstorage_store(&m_storage_handle_app,
  205. (uint8_t *)m_storage_handle_swap.block_id,
  206. m_start_packet.app_image_size,
  207. 0);
  208. if (err_code == NRF_SUCCESS)
  209. {
  210. dfu_update_status_t update_status;
  211. memset(&update_status, 0, sizeof(dfu_update_status_t ));
  212. update_status.status_code = DFU_UPDATE_APP_COMPLETE;
  213. update_status.app_crc = m_image_crc;
  214. update_status.app_size = m_start_packet.app_image_size;
  215. bootloader_dfu_update_process(update_status);
  216. }
  217. return err_code;
  218. }
  219. /**@brief Function for activating received Bootloader image.
  220. *
  221. * @note This function will not move the bootloader image.
  222. * The bootloader settings will be marked as Bootloader update complete and the swapping of
  223. * current bootloader will occur after system reset.
  224. *
  225. * @return NRF_SUCCESS on success.
  226. */
  227. static uint32_t dfu_activate_bl(void)
  228. {
  229. dfu_update_status_t update_status;
  230. update_status.status_code = DFU_UPDATE_BOOT_COMPLETE;
  231. update_status.app_crc = m_image_crc;
  232. update_status.sd_size = m_start_packet.sd_image_size;
  233. update_status.bl_size = m_start_packet.bl_image_size;
  234. update_status.app_size = m_start_packet.app_image_size;
  235. bootloader_dfu_update_process(update_status);
  236. return NRF_SUCCESS;
  237. }
  238. uint32_t dfu_init(void)
  239. {
  240. uint32_t err_code;
  241. pstorage_module_param_t storage_module_param = {.cb = pstorage_callback_handler};
  242. m_init_packet_length = 0;
  243. m_image_crc = 0;
  244. err_code = pstorage_register(&storage_module_param, &m_storage_handle_app);
  245. if (err_code != NRF_SUCCESS)
  246. {
  247. m_dfu_state = DFU_STATE_INIT_ERROR;
  248. return err_code;
  249. }
  250. m_storage_handle_app.block_id = DFU_BANK_0_REGION_START;
  251. m_storage_handle_swap = m_storage_handle_app;
  252. m_storage_handle_swap.block_id = DFU_BANK_1_REGION_START;
  253. // Create the timer to monitor the activity by the peer doing the firmware update.
  254. err_code = app_timer_create(&m_dfu_timer_id,
  255. APP_TIMER_MODE_SINGLE_SHOT,
  256. dfu_timeout_handler);
  257. APP_ERROR_CHECK(err_code);
  258. // Start the DFU timer.
  259. err_code = app_timer_start(m_dfu_timer_id, DFU_TIMEOUT_INTERVAL, NULL);
  260. APP_ERROR_CHECK(err_code);
  261. m_data_received = 0;
  262. m_dfu_state = DFU_STATE_IDLE;
  263. return NRF_SUCCESS;
  264. }
  265. void dfu_register_callback(dfu_callback_t callback_handler)
  266. {
  267. m_data_pkt_cb = callback_handler;
  268. }
  269. uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet)
  270. {
  271. uint32_t err_code;
  272. m_start_packet = *(p_packet->params.start_packet);
  273. // Check that the requested update procedure is supported.
  274. // Currently the following combinations are allowed:
  275. // - Application
  276. // - SoftDevice
  277. // - Bootloader
  278. // - SoftDevice with Bootloader
  279. if (IS_UPDATING_APP(m_start_packet) &&
  280. (IS_UPDATING_SD(m_start_packet) || IS_UPDATING_BL(m_start_packet)))
  281. {
  282. // App update is only supported independently.
  283. return NRF_ERROR_NOT_SUPPORTED;
  284. }
  285. if (!(IS_WORD_SIZED(m_start_packet.sd_image_size) &&
  286. IS_WORD_SIZED(m_start_packet.bl_image_size) &&
  287. IS_WORD_SIZED(m_start_packet.app_image_size)))
  288. {
  289. // Image_sizes are not a multiple of 4 (word size).
  290. return NRF_ERROR_NOT_SUPPORTED;
  291. }
  292. m_image_size = m_start_packet.sd_image_size + m_start_packet.bl_image_size +
  293. m_start_packet.app_image_size;
  294. if (m_start_packet.bl_image_size > DFU_BL_IMAGE_MAX_SIZE)
  295. {
  296. return NRF_ERROR_DATA_SIZE;
  297. }
  298. if (IS_UPDATING_SD(m_start_packet))
  299. {
  300. if (m_image_size > (DFU_IMAGE_MAX_SIZE_FULL))
  301. {
  302. return NRF_ERROR_DATA_SIZE;
  303. }
  304. m_functions.prepare = dfu_prepare_func_app_erase;
  305. m_functions.cleared = dfu_cleared_func_app;
  306. m_functions.activate = dfu_activate_sd;
  307. }
  308. else
  309. {
  310. if (m_image_size > DFU_IMAGE_MAX_SIZE_BANKED)
  311. {
  312. return NRF_ERROR_DATA_SIZE;
  313. }
  314. m_functions.prepare = dfu_prepare_func_swap_erase;
  315. m_functions.cleared = dfu_cleared_func_swap;
  316. if (IS_UPDATING_BL(m_start_packet))
  317. {
  318. m_functions.activate = dfu_activate_bl;
  319. }
  320. else
  321. {
  322. m_functions.activate = dfu_activate_app;
  323. }
  324. }
  325. switch (m_dfu_state)
  326. {
  327. case DFU_STATE_IDLE:
  328. // Valid peer activity detected. Hence restart the DFU timer.
  329. err_code = dfu_timer_restart();
  330. VERIFY_SUCCESS(err_code);
  331. m_functions.prepare(m_image_size);
  332. break;
  333. default:
  334. err_code = NRF_ERROR_INVALID_STATE;
  335. break;
  336. }
  337. return err_code;
  338. }
  339. uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet)
  340. {
  341. uint32_t data_length;
  342. uint32_t err_code;
  343. uint32_t * p_data;
  344. VERIFY_PARAM_NOT_NULL(p_packet);
  345. // Check pointer alignment.
  346. if (!is_word_aligned(p_packet->params.data_packet.p_data_packet))
  347. {
  348. // The p_data_packet is not word aligned address.
  349. return NRF_ERROR_INVALID_ADDR;
  350. }
  351. switch (m_dfu_state)
  352. {
  353. case DFU_STATE_RDY:
  354. case DFU_STATE_RX_INIT_PKT:
  355. return NRF_ERROR_INVALID_STATE;
  356. case DFU_STATE_RX_DATA_PKT:
  357. data_length = p_packet->params.data_packet.packet_length * sizeof(uint32_t);
  358. if ((m_data_received + data_length) > m_image_size)
  359. {
  360. // The caller is trying to write more bytes into the flash than the size provided to
  361. // the dfu_image_size_set function. This is treated as a serious error condition and
  362. // an unrecoverable one. Hence point the variable mp_app_write_address to the top of
  363. // the flash area. This will ensure that all future application data packet writes
  364. // will be blocked because of the above check.
  365. m_data_received = 0xFFFFFFFF;
  366. return NRF_ERROR_DATA_SIZE;
  367. }
  368. // Valid peer activity detected. Hence restart the DFU timer.
  369. err_code = dfu_timer_restart();
  370. VERIFY_SUCCESS(err_code);
  371. p_data = (uint32_t *)p_packet->params.data_packet.p_data_packet;
  372. err_code = pstorage_store(mp_storage_handle_active,
  373. (uint8_t *)p_data,
  374. data_length,
  375. m_data_received);
  376. VERIFY_SUCCESS(err_code);
  377. m_data_received += data_length;
  378. if (m_data_received != m_image_size)
  379. {
  380. // The entire image is not received yet. More data is expected.
  381. err_code = NRF_ERROR_INVALID_LENGTH;
  382. }
  383. else
  384. {
  385. // The entire image has been received. Return NRF_SUCCESS.
  386. err_code = NRF_SUCCESS;
  387. }
  388. break;
  389. default:
  390. err_code = NRF_ERROR_INVALID_STATE;
  391. break;
  392. }
  393. return err_code;
  394. }
  395. uint32_t dfu_init_pkt_complete(void)
  396. {
  397. uint32_t err_code = NRF_ERROR_INVALID_STATE;
  398. // DFU initialization has been done and a start packet has been received.
  399. if (IMAGE_WRITE_IN_PROGRESS())
  400. {
  401. // Image write is already in progress. Cannot handle an init packet now.
  402. return NRF_ERROR_INVALID_STATE;
  403. }
  404. if (m_dfu_state == DFU_STATE_RX_INIT_PKT)
  405. {
  406. err_code = dfu_init_prevalidate(m_init_packet, m_init_packet_length);
  407. if (err_code == NRF_SUCCESS)
  408. {
  409. m_dfu_state = DFU_STATE_RX_DATA_PKT;
  410. }
  411. else
  412. {
  413. m_init_packet_length = 0;
  414. }
  415. }
  416. return err_code;
  417. }
  418. uint32_t dfu_init_pkt_handle(dfu_update_packet_t * p_packet)
  419. {
  420. uint32_t err_code = NRF_SUCCESS;
  421. uint32_t length;
  422. switch (m_dfu_state)
  423. {
  424. case DFU_STATE_RDY:
  425. m_dfu_state = DFU_STATE_RX_INIT_PKT;
  426. // When receiving init packet in state ready just update and fall through this case.
  427. case DFU_STATE_RX_INIT_PKT:
  428. // DFU initialization has been done and a start packet has been received.
  429. if (IMAGE_WRITE_IN_PROGRESS())
  430. {
  431. // Image write is already in progress. Cannot handle an init packet now.
  432. return NRF_ERROR_INVALID_STATE;
  433. }
  434. // Valid peer activity detected. Hence restart the DFU timer.
  435. err_code = dfu_timer_restart();
  436. VERIFY_SUCCESS(err_code);
  437. length = p_packet->params.data_packet.packet_length * sizeof(uint32_t);
  438. if ((m_init_packet_length + length) > sizeof(m_init_packet))
  439. {
  440. return NRF_ERROR_INVALID_LENGTH;
  441. }
  442. memcpy(&m_init_packet[m_init_packet_length],
  443. &p_packet->params.data_packet.p_data_packet[0],
  444. length);
  445. m_init_packet_length += length;
  446. break;
  447. default:
  448. // Either the start packet was not received or dfu_init function was not called before.
  449. err_code = NRF_ERROR_INVALID_STATE;
  450. break;
  451. }
  452. return err_code;
  453. }
  454. uint32_t dfu_image_validate()
  455. {
  456. uint32_t err_code;
  457. switch (m_dfu_state)
  458. {
  459. case DFU_STATE_RX_DATA_PKT:
  460. // Check if the application image write has finished.
  461. if (m_data_received != m_image_size)
  462. {
  463. // Image not yet fully transfered by the peer or the peer has attempted to write
  464. // too much data. Hence the validation should fail.
  465. err_code = NRF_ERROR_INVALID_STATE;
  466. }
  467. else
  468. {
  469. m_dfu_state = DFU_STATE_VALIDATE;
  470. // Valid peer activity detected. Hence restart the DFU timer.
  471. err_code = dfu_timer_restart();
  472. if (err_code == NRF_SUCCESS)
  473. {
  474. err_code = dfu_init_postvalidate((uint8_t *)mp_storage_handle_active->block_id,
  475. m_image_size);
  476. VERIFY_SUCCESS(err_code);
  477. m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE;
  478. }
  479. }
  480. break;
  481. default:
  482. err_code = NRF_ERROR_INVALID_STATE;
  483. break;
  484. }
  485. return err_code;
  486. }
  487. uint32_t dfu_image_activate()
  488. {
  489. uint32_t err_code;
  490. switch (m_dfu_state)
  491. {
  492. case DFU_STATE_WAIT_4_ACTIVATE:
  493. // Stop the DFU Timer because the peer activity need not be monitored any longer.
  494. err_code = app_timer_stop(m_dfu_timer_id);
  495. APP_ERROR_CHECK(err_code);
  496. err_code = m_functions.activate();
  497. break;
  498. default:
  499. err_code = NRF_ERROR_INVALID_STATE;
  500. break;
  501. }
  502. return err_code;
  503. }
  504. void dfu_reset(void)
  505. {
  506. dfu_update_status_t update_status;
  507. update_status.status_code = DFU_RESET;
  508. bootloader_dfu_update_process(update_status);
  509. }
  510. static uint32_t dfu_compare_block(uint32_t * ptr1, uint32_t * ptr2, uint32_t len)
  511. {
  512. sd_mbr_command_t sd_mbr_cmd;
  513. sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE;
  514. sd_mbr_cmd.params.compare.ptr1 = ptr1;
  515. sd_mbr_cmd.params.compare.ptr2 = ptr2;
  516. sd_mbr_cmd.params.compare.len = len / sizeof(uint32_t);
  517. return sd_mbr_command(&sd_mbr_cmd);
  518. }
  519. static uint32_t dfu_copy_sd(uint32_t * src, uint32_t * dst, uint32_t len)
  520. {
  521. sd_mbr_command_t sd_mbr_cmd;
  522. sd_mbr_cmd.command = SD_MBR_COMMAND_COPY_SD;
  523. sd_mbr_cmd.params.copy_sd.src = src;
  524. sd_mbr_cmd.params.copy_sd.dst = dst;
  525. sd_mbr_cmd.params.copy_sd.len = len / sizeof(uint32_t);
  526. return sd_mbr_command(&sd_mbr_cmd);
  527. }
  528. static uint32_t dfu_sd_img_block_swap(uint32_t * src,
  529. uint32_t * dst,
  530. uint32_t len,
  531. uint32_t block_size)
  532. {
  533. // It is neccesarry to swap the new SoftDevice in 3 rounds to ensure correct copy of data
  534. // and verifucation of data in case power reset occurs during write to flash.
  535. // To ensure the robustness of swapping the images are compared backwards till start of
  536. // image swap. If the back is identical everything is swapped.
  537. uint32_t err_code = dfu_compare_block(src, dst, len);
  538. if (err_code == NRF_SUCCESS)
  539. {
  540. return err_code;
  541. }
  542. if ((uint32_t)dst > SOFTDEVICE_REGION_START)
  543. {
  544. err_code = dfu_sd_img_block_swap((uint32_t *)((uint32_t)src - block_size),
  545. (uint32_t *)((uint32_t)dst - block_size),
  546. block_size,
  547. block_size);
  548. VERIFY_SUCCESS(err_code);
  549. }
  550. err_code = dfu_copy_sd(src, dst, len);
  551. VERIFY_SUCCESS(err_code);
  552. return dfu_compare_block(src, dst, len);
  553. }
  554. uint32_t dfu_sd_image_swap(void)
  555. {
  556. bootloader_settings_t boot_settings;
  557. bootloader_settings_get(&boot_settings);
  558. if (boot_settings.sd_image_size == 0)
  559. {
  560. return NRF_SUCCESS;
  561. }
  562. if ((SOFTDEVICE_REGION_START + boot_settings.sd_image_size) > boot_settings.sd_image_start)
  563. {
  564. uint32_t err_code;
  565. uint32_t sd_start = SOFTDEVICE_REGION_START;
  566. uint32_t block_size = (boot_settings.sd_image_start - sd_start) / 2;
  567. uint32_t image_end = boot_settings.sd_image_start + boot_settings.sd_image_size;
  568. uint32_t img_block_start = boot_settings.sd_image_start + 2 * block_size;
  569. uint32_t sd_block_start = sd_start + 2 * block_size;
  570. if (SD_SIZE_GET(MBR_SIZE) < boot_settings.sd_image_size)
  571. {
  572. // This will clear a page thus ensuring the old image is invalidated before swapping.
  573. err_code = dfu_copy_sd((uint32_t *)(sd_start + block_size),
  574. (uint32_t *)(sd_start + block_size),
  575. sizeof(uint32_t));
  576. VERIFY_SUCCESS(err_code);
  577. err_code = dfu_copy_sd((uint32_t *)sd_start, (uint32_t *)sd_start, sizeof(uint32_t));
  578. VERIFY_SUCCESS(err_code);
  579. }
  580. return dfu_sd_img_block_swap((uint32_t *)img_block_start,
  581. (uint32_t *)sd_block_start,
  582. image_end - img_block_start,
  583. block_size);
  584. }
  585. else
  586. {
  587. if (boot_settings.sd_image_size != 0)
  588. {
  589. return dfu_copy_sd((uint32_t *)boot_settings.sd_image_start,
  590. (uint32_t *)SOFTDEVICE_REGION_START,
  591. boot_settings.sd_image_size);
  592. }
  593. }
  594. return NRF_SUCCESS;
  595. }
  596. uint32_t dfu_bl_image_swap(void)
  597. {
  598. bootloader_settings_t bootloader_settings;
  599. sd_mbr_command_t sd_mbr_cmd;
  600. bootloader_settings_get(&bootloader_settings);
  601. if (bootloader_settings.bl_image_size != 0)
  602. {
  603. uint32_t bl_image_start = (bootloader_settings.sd_image_size == 0) ?
  604. DFU_BANK_1_REGION_START :
  605. bootloader_settings.sd_image_start +
  606. bootloader_settings.sd_image_size;
  607. sd_mbr_cmd.command = SD_MBR_COMMAND_COPY_BL;
  608. sd_mbr_cmd.params.copy_bl.bl_src = (uint32_t *)(bl_image_start);
  609. sd_mbr_cmd.params.copy_bl.bl_len = bootloader_settings.bl_image_size / sizeof(uint32_t);
  610. return sd_mbr_command(&sd_mbr_cmd);
  611. }
  612. return NRF_SUCCESS;
  613. }
  614. uint32_t dfu_bl_image_validate(void)
  615. {
  616. bootloader_settings_t bootloader_settings;
  617. sd_mbr_command_t sd_mbr_cmd;
  618. bootloader_settings_get(&bootloader_settings);
  619. if (bootloader_settings.bl_image_size != 0)
  620. {
  621. uint32_t bl_image_start = (bootloader_settings.sd_image_size == 0) ?
  622. DFU_BANK_1_REGION_START :
  623. bootloader_settings.sd_image_start +
  624. bootloader_settings.sd_image_size;
  625. sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE;
  626. sd_mbr_cmd.params.compare.ptr1 = (uint32_t *)BOOTLOADER_REGION_START;
  627. sd_mbr_cmd.params.compare.ptr2 = (uint32_t *)(bl_image_start);
  628. sd_mbr_cmd.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t);
  629. return sd_mbr_command(&sd_mbr_cmd);
  630. }
  631. return NRF_SUCCESS;
  632. }
  633. uint32_t dfu_sd_image_validate(void)
  634. {
  635. bootloader_settings_t bootloader_settings;
  636. sd_mbr_command_t sd_mbr_cmd;
  637. bootloader_settings_get(&bootloader_settings);
  638. if (bootloader_settings.sd_image_size == 0)
  639. {
  640. return NRF_SUCCESS;
  641. }
  642. if ((SOFTDEVICE_REGION_START + bootloader_settings.sd_image_size) > bootloader_settings.sd_image_start)
  643. {
  644. uint32_t sd_start = SOFTDEVICE_REGION_START;
  645. uint32_t block_size = (bootloader_settings.sd_image_start - sd_start) / 2;
  646. uint32_t image_end = bootloader_settings.sd_image_start +
  647. bootloader_settings.sd_image_size;
  648. uint32_t img_block_start = bootloader_settings.sd_image_start + 2 * block_size;
  649. uint32_t sd_block_start = sd_start + 2 * block_size;
  650. if (SD_SIZE_GET(MBR_SIZE) < bootloader_settings.sd_image_size)
  651. {
  652. return NRF_ERROR_NULL;
  653. }
  654. return dfu_sd_img_block_swap((uint32_t *)img_block_start,
  655. (uint32_t *)sd_block_start,
  656. image_end - img_block_start,
  657. block_size);
  658. }
  659. sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE;
  660. sd_mbr_cmd.params.compare.ptr1 = (uint32_t *)SOFTDEVICE_REGION_START;
  661. sd_mbr_cmd.params.compare.ptr2 = (uint32_t *)bootloader_settings.sd_image_start;
  662. sd_mbr_cmd.params.compare.len = bootloader_settings.sd_image_size / sizeof(uint32_t);
  663. return sd_mbr_command(&sd_mbr_cmd);
  664. }