| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
- *
- * The information contained herein is property of Nordic Semiconductor ASA.
- * Terms and conditions of usage are described in detail in NORDIC
- * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
- *
- * Licensees are granted free, non-transferable use of the information. NO
- * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
- * the file.
- *
- */
- #include "bootloader.h"
- #include <string.h>
- #include "bootloader_types.h"
- #include "bootloader_util.h"
- #include "dfu.h"
- #include "dfu_transport.h"
- #include "nrf.h"
- #include "app_error.h"
- #include "nrf_sdm.h"
- #include "nrf_soc.h"
- #include "nordic_common.h"
- #include "pstorage.h"
- #include "app_scheduler.h"
- #include "nrf_delay.h"
- #include "debug_pin.h"
- #define IRQ_ENABLED 0x01 /**< Field identifying if an interrupt is enabled. */
- #define MAX_NUMBER_INTERRUPTS 32 /**< Maximum number of interrupts available. */
- /*
- * bootloader_settings space is subdivided into 8 128byte sized blocks to properly use pstorage data abstraction scheme
- * with the intent to use the last block located, specifically at 0x3FF80, for ant_boot_settings matters.
- */
- #define BOOTLOADER_SETTINGS_FLASH_BLOCK_SIZE 128
- #define BOOTLOADER_SETTINGS_FLASH_BLOCK_COUNT 8 /* Total of 1024 */
- typedef enum
- {
- BOOTLOADER_UPDATING,
- BOOTLOADER_SETTINGS_SAVING,
- BOOTLOADER_COMPLETE,
- BOOTLOADER_TIMEOUT,
- BOOTLOADER_RESET,
- } bootloader_status_t;
- static pstorage_handle_t m_bootsettings_handle; /**< Pstorage handle to use for registration and identifying the bootloader module on subsequent calls to the pstorage module for load and store of bootloader setting in flash. */
- static bootloader_status_t m_update_status; /**< Current update status for the bootloader module to ensure correct behaviour when updating settings and when update completes. */
- static uint8_t m_delay_applied = false;/**< Delay has been applied before the initial access to flash > */
- /* NOTE: Temporary use of this page until the bootloader_settings slotting is implemented */
- #define BOOT_SETTINGS_PEND_ADDRESS (BOOTLOADER_MBR_RETAINING_PAGE_ADDRESS)
- #define BOOT_SETTINGS_PEND_VALUE 0xFFFFFFFE
- uint8_t m_boot_settings_pend[CODE_PAGE_SIZE] __attribute__((at(BOOT_SETTINGS_PEND_ADDRESS))) __attribute__((used));
- uint32_t blocking_flash_page_erase(uint32_t page_number)
- {
- uint32_t err_code;
- do{
- err_code = sd_flash_page_erase(page_number);
- } while(err_code == NRF_ERROR_BUSY);
- return err_code;
- }
- uint32_t blocking_flash_word_write(uint32_t * const p_dst, uint32_t data)
- {
- uint32_t err_code;
- do{
- err_code = sd_flash_write(p_dst, &data, 1);
- } while(err_code == NRF_ERROR_BUSY);
- return err_code;
- }
- static void pstorage_callback_handler(pstorage_handle_t * handle, uint8_t op_code, uint32_t result, uint8_t * p_data, uint32_t data_len)
- {
- // If we are in BOOTLOADER_SETTINGS_SAVING state and we receive an PSTORAGE_STORE_OP_CODE
- // response then settings has been saved and update has completed.
- if ((m_update_status == BOOTLOADER_SETTINGS_SAVING) && (op_code == PSTORAGE_STORE_OP_CODE) && (handle->block_id == BOOTLOADER_SETTINGS_ADDRESS)) //
- {
- m_update_status = BOOTLOADER_COMPLETE;
- /*Clears bootloader_settings critical flag*/
- if (*((uint32_t *)BOOT_SETTINGS_PEND_ADDRESS) == BOOT_SETTINGS_PEND_VALUE)
- {
- uint32_t err_code = blocking_flash_page_erase(BOOT_SETTINGS_PEND_ADDRESS/CODE_PAGE_SIZE);
- APP_ERROR_CHECK(err_code);
- }
- }
- APP_ERROR_CHECK(result);
- }
- /**@brief Function for waiting for events.
- *
- * @details This function will place the chip in low power mode while waiting for events from
- * the S110 SoftDevice or other peripherals. When interrupted by an event, it will call the
- * @ref app_sched_execute function to process the received event. This function will return
- * when the final state of the firmware update is reached OR when a tear down is in
- * progress.
- */
- static void wait_for_events(void)
- {
- for (;;)
- {
- // Wait in low power state for any events.
- uint32_t err_code = sd_app_evt_wait();
- APP_ERROR_CHECK(err_code);
- // Event received. Process it from the scheduler.
- app_sched_execute();
- if ((m_update_status == BOOTLOADER_COMPLETE) ||
- (m_update_status == BOOTLOADER_TIMEOUT) ||
- (m_update_status == BOOTLOADER_RESET))
- {
- // When update has completed or a timeout/reset occured we will return.
- return;
- }
- }
- }
- bool bootloader_app_is_valid(uint32_t app_addr)
- {
- const bootloader_settings_t * p_bootloader_settings;
- // Critical flag was not cleared.
- if (*((uint32_t *)BOOT_SETTINGS_PEND_ADDRESS) == BOOT_SETTINGS_PEND_VALUE)
- {
- return false;
- }
- // There exists an application in CODE region 1.
- if (*((uint32_t *) app_addr) == EMPTY_FLASH_MASK)
- {
- return false;
- }
- bootloader_util_settings_get(&p_bootloader_settings);
- // The application in CODE region 1 was not flagged as invalid.
- if (p_bootloader_settings->valid_app == BOOTLOADER_SETTINGS_INVALID_APPLICATION)
- {
- return false;
- }
- return true;
- }
- static void bootloader_settings_save(bootloader_settings_t * p_settings)
- {
- //TODO. This is temporary
- static uint8_t ant_boot_settings[BOOTLOADER_SETTINGS_FLASH_BLOCK_SIZE];
- static pstorage_handle_t ant_boot_settings_handle;
- /* Backing up ant_boot_settings. */
- ant_boot_settings_handle.module_id = m_bootsettings_handle.module_id;
- ant_boot_settings_handle.block_id = m_bootsettings_handle.block_id + (BOOTLOADER_SETTINGS_FLASH_BLOCK_SIZE * (BOOTLOADER_SETTINGS_FLASH_BLOCK_COUNT - 1));
- memcpy(ant_boot_settings, (uint8_t*)ant_boot_settings_handle.block_id, BOOTLOADER_SETTINGS_FLASH_BLOCK_SIZE);
- /* NOTE: Must erase the whole module to prevent pstorage block erasing which uses swap space*/
- uint32_t err_code = pstorage_clear(&m_bootsettings_handle,
- BOOTLOADER_SETTINGS_FLASH_BLOCK_SIZE * BOOTLOADER_SETTINGS_FLASH_BLOCK_COUNT);
- APP_ERROR_CHECK(err_code);
- /* Write back ant_boot_settings */
- err_code = pstorage_store(&ant_boot_settings_handle,
- ant_boot_settings,
- BOOTLOADER_SETTINGS_FLASH_BLOCK_SIZE,
- 0);
- APP_ERROR_CHECK(err_code);
- err_code = pstorage_store(&m_bootsettings_handle,
- (uint8_t *)p_settings,
- sizeof(bootloader_settings_t),
- 0);
- APP_ERROR_CHECK(err_code);
- }
- void bootloader_dfu_update_process(dfu_update_status_t update_status)
- {
- static bootloader_settings_t settings;
- const bootloader_settings_t * p_bootloader_settings;
- uint32_t err_code;
- bootloader_util_settings_get(&p_bootloader_settings); /* Extract current values of the bootloader_settings*/
- memcpy(&settings, p_bootloader_settings, sizeof(bootloader_settings_t)); /* Copy over to local bootloader_settings*/
- if (update_status.status_code == DFU_UPDATE_NEW_IMAGES)
- {
- if (update_status.sd_image_size != NEW_IMAGE_SIZE_EMPTY)
- {
- settings.sd_image.st.size = update_status.sd_image_size;
- settings.sd_image.st.bank = update_status.bank_used;
- }
- else
- {
- settings.sd_image.st.size = NEW_IMAGE_SIZE_EMPTY;
- }
- if (update_status.bl_image_size != NEW_IMAGE_SIZE_EMPTY)
- {
- settings.bl_image.st.size = update_status.bl_image_size;
- settings.bl_image.st.bank = update_status.bank_used;
- }
- else
- {
- settings.bl_image.st.size = NEW_IMAGE_SIZE_EMPTY;
- }
- if (update_status.ap_image_size != NEW_IMAGE_SIZE_EMPTY)
- {
- settings.ap_image.st.size = update_status.ap_image_size;
- settings.ap_image.st.bank = update_status.bank_used;
- }
- else
- {
- settings.ap_image.st.size = NEW_IMAGE_SIZE_EMPTY;
- }
- settings.src_image_address = update_status.src_image_address;
- m_update_status = BOOTLOADER_SETTINGS_SAVING;
- /*Clears bootloader_settings critical flag - in case it was used by MBR*/
- if (*((uint32_t *)BOOT_SETTINGS_PEND_ADDRESS) != 0xFFFFFFFF)
- {
- err_code = blocking_flash_page_erase(BOOT_SETTINGS_PEND_ADDRESS/CODE_PAGE_SIZE);
- APP_ERROR_CHECK(err_code);
- }
- // TEMPORARY: This serves as a critical flag for the bootloader_settings updating.
- err_code = blocking_flash_word_write((uint32_t *)BOOT_SETTINGS_PEND_ADDRESS,
- BOOT_SETTINGS_PEND_VALUE);
- APP_ERROR_CHECK(err_code);
- bootloader_settings_save(&settings);
- }
- else if (update_status.status_code == DFU_UPDATE_AP_SWAPPED)
- {
- settings.ap_image.st.bank = NEW_IMAGE_BANK_DONE;
- settings.ap_image.st.size = p_bootloader_settings->ap_image.st.size;
- settings.valid_app = BOOTLOADER_SETTINGS_VALID_APPLICATION;
- m_update_status = BOOTLOADER_SETTINGS_SAVING;
- /*Clears bootloader_settings critical flag - in case it was used by MBR*/
- if (*((uint32_t *)BOOT_SETTINGS_PEND_ADDRESS) != 0xFFFFFFFF)
- {
- err_code = blocking_flash_page_erase(BOOT_SETTINGS_PEND_ADDRESS/CODE_PAGE_SIZE);
- APP_ERROR_CHECK(err_code);
- }
- // TEMPORARY: This serves as a critical flag for the bootloader_settings updating.
- err_code = blocking_flash_word_write((uint32_t *)BOOT_SETTINGS_PEND_ADDRESS,
- BOOT_SETTINGS_PEND_VALUE);
- APP_ERROR_CHECK(err_code);
- bootloader_settings_save(&settings);
- }
- else if (update_status.status_code == DFU_UPDATE_AP_INVALIDATED)
- {
- if (p_bootloader_settings->valid_app != BOOTLOADER_SETTINGS_INVALID_APPLICATION)
- {
- settings.valid_app = BOOTLOADER_SETTINGS_INVALID_APPLICATION;
- m_update_status = BOOTLOADER_UPDATING;
- bootloader_settings_save(&settings);
- }
- }
- else if (update_status.status_code == DFU_TIMEOUT)
- {
- // Timeout has occurred. Close the connection with the DFU Controller.
- // dfu_transport_close();
- m_update_status = BOOTLOADER_TIMEOUT;
- }
- else if (update_status.status_code == DFU_RESET)
- {
- // Timeout has occurred. Close the connection with the DFU Controller.
- // dfu_transport_close();
- m_update_status = BOOTLOADER_RESET;
- }
- else
- {
- // No implementation needed.
- }
- }
- uint32_t bootloader_init(void)
- {
- uint32_t err_code;
- pstorage_module_param_t storage_params;
- storage_params.cb = pstorage_callback_handler;
- storage_params.block_size = BOOTLOADER_SETTINGS_FLASH_BLOCK_SIZE;
- storage_params.block_count = BOOTLOADER_SETTINGS_FLASH_BLOCK_COUNT;
- err_code = pstorage_init();
- if (err_code != NRF_SUCCESS)
- {
- return err_code;
- }
- err_code = pstorage_register(&storage_params, &m_bootsettings_handle);
- m_delay_applied = false;
- return err_code;
- }
- uint32_t bootloader_dfu_start(void)
- {
- uint32_t err_code = NRF_SUCCESS;
- err_code = dfu_init();
- if (err_code != NRF_SUCCESS)
- {
- return err_code;
- }
- err_code = dfu_transport_update_start();
- wait_for_events();
- err_code = dfu_transport_close();
- return err_code;
- }
- /**@brief Function for disabling all interrupts before jumping from bootloader to application.
- */
- static void interrupts_disable(void)
- {
- uint32_t interrupt_setting_mask;
- uint8_t irq;
- // We start the loop from first interrupt, i.e. interrupt 0.
- irq = 0;
- // Fetch the current interrupt settings.
- interrupt_setting_mask = NVIC->ISER[0];
- for (; irq < MAX_NUMBER_INTERRUPTS; irq++)
- {
- if (interrupt_setting_mask & (IRQ_ENABLED << irq))
- {
- // The interrupt was enabled, and hence disable it.
- NVIC_DisableIRQ((IRQn_Type) irq);
- }
- }
- }
- // Ensure that flash operations are not executed within the first 100 ms seconds to allow
- // a debugger to be attached
- static void debugger_delay (void)
- {
- if (m_delay_applied == false)
- {
- m_delay_applied = true;
- nrf_delay_ms(100);
- }
- }
- void bootloader_app_start(uint32_t app_addr)
- {
- // If the applications CRC has been checked and passed, the magic number will be written and we
- // can start the application safely.
- uint32_t err_code = sd_softdevice_disable();
- APP_ERROR_CHECK(err_code);
- interrupts_disable();
- #if defined (S210_V3_STACK)
- err_code = sd_softdevice_forward_to_application();
- #else
- err_code = sd_softdevice_vector_table_base_set(CODE_REGION_1_START);
- #endif
- APP_ERROR_CHECK(err_code);
- bootloader_util_app_start(CODE_REGION_1_START);
- }
- #if !defined (S210_V3_STACK)
- uint32_t temp_value;
- uint32_t bootloader_dfu_sd_update_continue()
- {
- uint32_t err_code = NRF_SUCCESS;
- const bootloader_settings_t * p_bootloader_settings;
- bootloader_util_settings_get(&p_bootloader_settings);
- /* Ignore update attempts on invalid src_image_address */
- if( (p_bootloader_settings->src_image_address == SRC_IMAGE_ADDRESS_EMPTY) ||
- (p_bootloader_settings->src_image_address == SRC_IMAGE_ADDRESS_INVALID))
- {
- return NRF_SUCCESS;
- }
- if( (p_bootloader_settings->sd_image.st.bank == NEW_IMAGE_BANK_0) ||
- (p_bootloader_settings->sd_image.st.bank == NEW_IMAGE_BANK_1))
- {
- debugger_delay();
- err_code = dfu_sd_image_swap();
- if (dfu_sd_image_validate() == NRF_SUCCESS)
- {
- /* This is a manual write to flash, non-softdevice managed */
- uint32_t address = (uint32_t)p_bootloader_settings + BOOTLOADER_SETTINGS_SD_IMAGE_SIZE_ADR_OFFSET;
- temp_value = p_bootloader_settings->sd_image.all & 0x3FFFFFFF; // clears image bank bits.
- err_code = blocking_flash_word_write((uint32_t *)address, temp_value);
- //TODO need to catch verification error
- }
- }
- return err_code;
- }
- uint32_t bootloader_dfu_bl_update_continue(void)
- {
- uint32_t err_code = NRF_SUCCESS;
- const bootloader_settings_t * p_bootloader_settings;
- bootloader_util_settings_get(&p_bootloader_settings);
- /* Ignore update attempts on invalid src_image_address */
- if( (p_bootloader_settings->src_image_address == SRC_IMAGE_ADDRESS_EMPTY) ||
- (p_bootloader_settings->src_image_address == SRC_IMAGE_ADDRESS_INVALID))
- {
- return NRF_SUCCESS;
- }
- if( (p_bootloader_settings->bl_image.st.bank == NEW_IMAGE_BANK_0) ||
- (p_bootloader_settings->bl_image.st.bank == NEW_IMAGE_BANK_1))
- {
- debugger_delay();
- if (dfu_bl_image_validate() != NRF_SUCCESS)
- {
- err_code = dfu_bl_image_swap(); // reset is built in to the mbr bootloader swap
- }
- else
- {
- /* This is a manual write to flash, non-softdevice managed */
- uint32_t address = (uint32_t)p_bootloader_settings + BOOTLOADER_SETTINGS_BL_IMAGE_SIZE_ADR_OFFSET;
- uint32_t value = p_bootloader_settings->bl_image.all & 0x3FFFFFFF; // clears image bank bits.
- err_code = blocking_flash_word_write((uint32_t *)address, value);
- //TODO need to catch verification error
- }
- }
- return err_code;
- }
- #endif // !S210_V3_STACK
- uint32_t bootloader_dfu_ap_update_continue(void)
- {
- uint32_t err_code = NRF_SUCCESS;
- const bootloader_settings_t * p_bootloader_settings;
- bootloader_util_settings_get(&p_bootloader_settings);
- /* Ignore update attempts on invalid src_image_address */
- if( (p_bootloader_settings->src_image_address == SRC_IMAGE_ADDRESS_EMPTY) ||
- (p_bootloader_settings->src_image_address == SRC_IMAGE_ADDRESS_INVALID))
- {
- return NRF_SUCCESS;
- }
- if( (p_bootloader_settings->ap_image.st.bank == NEW_IMAGE_BANK_0) ||
- (p_bootloader_settings->ap_image.st.bank == NEW_IMAGE_BANK_1))
- {
- /* If updating application only, we can start the copy right now*/
- if ((p_bootloader_settings->sd_image.st.size == NEW_IMAGE_SIZE_EMPTY) &&
- (p_bootloader_settings->bl_image.st.size == NEW_IMAGE_SIZE_EMPTY))
- {
- err_code = dfu_ap_image_swap();
- dfu_update_status_t update_status = {DFU_UPDATE_AP_SWAPPED, };
- bootloader_dfu_update_process(update_status);
- wait_for_events();
- }
- }
- return err_code;
- }
|