fixed the bootloader start address for simplicity and prevent bricking device

This commit is contained in:
hathach committed 2020-05-12 01:28:21 +07:00
1 parent afeb645a87
commit 27882cdce6
4 files changed
+75 -104

No files matched your search

+14 -28
View File
@@ -191,44 +191,30 @@ void tud_msc_write10_complete_cb(uint8_t lun)
dfu_update_status_t update_status;
memset(&update_status, 0, sizeof(dfu_update_status_t ));
if ( _wr_state.boot_addr_ucir )
if ( _wr_state.update_bootloader )
{
// update bootloader
// update bootloader always end with reset
update_status.status_code = DFU_RESET;
if ( 0 == memcmp((uint8_t*) _wr_state.boot_stored_addr, (uint8_t*) BOOTLOADER_ADDR_START, _wr_state.boot_size) )
{
// skip if there is no bootloader change
}else
{
PRINTF("Coyping bootloader to 0x%08lX from 0x%08lX with size = 0x%lX\r\n",
_wr_state.boot_addr_ucir, _wr_state.boot_stored_addr, _wr_state.boot_size);
// Location of current stored new bootloader
uint32_t * new_bootloader = (uint32_t *) BOOTLOADER_ADDR_NEW_RECIEVED;
// erase an change UCIR bootloader
// if ( )
PRINT_HEX(new_bootloader);
// skip if there is no bootloader change
if ( memcmp(new_bootloader, (uint8_t*) BOOTLOADER_ADDR_START, DFU_BL_IMAGE_MAX_SIZE) )
{
PRINTF("Coyping new bootloader\r\n");
sd_mbr_command_t command =
{
.command = SD_MBR_COMMAND_COPY_BL,
.params.copy_bl.bl_src = (uint32_t*) _wr_state.boot_stored_addr,
.params.copy_bl.bl_len = _wr_state.boot_size/4 // size in words
.params.copy_bl.bl_src = new_bootloader,
.params.copy_bl.bl_len = DFU_BL_IMAGE_MAX_SIZE/4 // size in words
};
if ( NRF_SUCCESS != sd_mbr_command(&command) )
{
PRINTF("Failed to execute SD_MBR_COMMAND_COPY_BL, we are about to bricked\r\n");
}else
{
PRINTF("SD_MBR_COMMAND_COPY_BL successfully\r\n");
}
NRFX_DELAY_MS(10);
// update_status.status_code = DFU_UPDATE_BOOT_COMPLETE;
// update_status.bl_size = _wr_state.boot_size;
//
// // Reuse the DFU combined SD + Bootloader with SD Size = 0
// update_status.sd_image_start = _wr_state.boot_stored_addr;
// update_status.sd_size = 0;
// on success, COPY_BL won't return but run the new bootloader right away.
sd_mbr_command(&command);
}
PRINTF("bootloader update complete\r\n");
+50 -65
View File
@@ -160,19 +160,7 @@ static inline bool in_app_space (uint32_t addr)
// used when upgrading bootloader
static inline bool in_bootloader_space (uint32_t addr)
{
return BOOTLOADER_LOWEST_ADDR <= addr && addr < BOOTLOADER_ADDR_END;
}
static inline uint32_t get_new_bootloader_size(uint32_t numblocks)
{
// -1 for UCIR block
uint32_t new_size = (numblocks-1)*256;
// round up to 4K
uint32_t mod4k = new_size & 0xFFFUL;
if ( mod4k ) new_size += 4096 - mod4k;
return new_size;
return BOOTLOADER_ADDR_START <= addr && addr < BOOTLOADER_ADDR_END;
}
// used when upgrading bootloader
@@ -324,13 +312,13 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
*
* ------------- -------------
* | | | |
* | Bootloader | | Bootloader |
* | Bootloader | | Bootloader |
* BOOTLOADER_ADDR_START--|-------------| |-------------|
* | App Data | | App Data |
* USER_FLASH_END ---|-------------| |-------------|
* | | | |
* | | | |
* | Application | ---> | New |
* | | | Application |
* | | | |
* | | | New |
* | Application | ----> | Application |
* | | | |
* USER_FLASH_START--|-------------| |-------------|
* | MBR | | MBR |
@@ -354,19 +342,17 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
case CFG_UF2_BOOTLOADER_ID:
/* Upgrading Bootloader
*
* Along with bootloader code, UCIR (at 0x1000100) is also included containing
* - For simplicity, the Bootloader Start Address is fixed for now.
*
* - Since SoftDevice is not part of Bootloader, it MUST NOT be included as part of uf2 file.
*
* - To prevent corruption/disconnection while transferring we don't directly write over Bootloader.
* Instead it is written to highest possible address in Application region. Once everything is received
* and verified, it is safely activated using MBR COPY BL command.
*
* - Along with bootloader code, UCIR (at 0x1000100) is also included containing
* 0x10001014 (bootloader address), and 0x10001018 (MBR Params address).
*
* Since SoftDevice is not part of Bootloader, it must not be included as part of uf2 file.
* To prevent generating uf2 from incorrect bin/hex. Bootloader imposes a hard code limit size
* of 64 KB (end address is fixed at MBR Params). If uf2 contains any address lower than this
* (except UCIR) the update is aborted.
*
* To prevent corruption/disconnection while transferring we don't directly write over
* Bootloader. Instead it is written to highest possible address in Application
* region. Once everything is received and verified, it is safely activated using
* MBR COPY BL command.
*
* Note: part of the existing application can be affected when updating bootloader.
* TODO May be worth to have some kind crc/application integrity checking
*
@@ -374,11 +360,11 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
* | | | | + | New |
* | Bootloader | | Bootloader | + | Bootloader |
* BOOTLOADER_ADDR_START--|-------------| |-------------| + |-------------|
* | | | New | + | |
* | | | Bootloader | + | |
* | | | ++++++++ | | |
* | | ---> | | | |
* | | | | | |
* | App Data | | App Data | + | App Data |
* USER_FLASH_END --|-------------| | ---------- | + |------------ |
* | | | New |+ | |
* | | ---> | Bootloader | | |
* | | | ++++++ | | |
* | Application | | Application | | Application |
* | | | | | |
* | | | | | |
@@ -388,54 +374,53 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
*/
PRINTF("addr = 0x%08lX, block = %ld (%ld of %ld)\r\n", bl->targetAddr, bl->blockNo, state->numWritten, bl->numBlocks);
uint32_t const new_boot_size = get_new_bootloader_size(bl->numBlocks);
// Offset write the new bootloader address.
// The offset is the current bootloader size or the new size whichever is larger
uint32_t const offset_addr = max32(new_boot_size, BOOTLOADER_ADDR_END-BOOTLOADER_ADDR_START);
state->update_bootloader = true;
if ( in_uicr_space(bl->targetAddr) )
{
/* UCIR contains bootloader & MBR address as follow:
* - 0x10001014 bootloader address: only change if bootloader size changes
* - 0x10001014 bootloader address
* - 0x10001018 MBR Params: mostly fixed
*
* WARNING: incorrect value of these UCIR will brick device
* Since the bootloader start address is fixed, we only use this for verification
*/
uint32_t ucir_boot_addr;
uint32_t ucir_mbr_param;
uint32_t uicr_boot_addr;
uint32_t uicr_mbr_param;
memcpy(&ucir_boot_addr, bl->data + 0x14, 4);
memcpy(&ucir_mbr_param, bl->data + 0x18, 4);
PRINT_HEX(ucir_boot_addr);
PRINT_HEX(ucir_mbr_param);
PRINT_HEX(new_boot_size);
memcpy(&uicr_boot_addr, bl->data + 0x14, 4);
memcpy(&uicr_mbr_param, bl->data + 0x18, 4);
// Check MBR params is fixed and prohibited to change and
// Bootloader address against its new size
if ( (ucir_mbr_param != BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS) ||
(ucir_boot_addr != BOOTLOADER_ADDR_END - new_boot_size) )
if ( (uicr_boot_addr != BOOTLOADER_ADDR_START) ||
(uicr_mbr_param != BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS) )
{
PRINTF("Incorrect UCIR value");
PRINTF("Incorrect UICR value");
PRINT_HEX(uicr_boot_addr);
PRINT_HEX(uicr_mbr_param);
state->aborted = true;
return -1;
}else
{
// Good to go, save the boot address
state->boot_addr_ucir = ucir_boot_addr;
state->boot_size = new_boot_size;
state->boot_stored_addr = BOOTLOADER_ADDR_END - (new_boot_size + offset_addr);
PRINT_HEX(state->boot_stored_addr);
}
state->has_uicr = true;
}
else if ( in_bootloader_space(bl->targetAddr) && (bl->targetAddr >= BOOTLOADER_LOWEST_ADDR) )
else if ( in_bootloader_space(bl->targetAddr) )
{
// PRINT_HEX(offset_addr);
// Offset to write the new bootloader address (skipping the App Data)
uint32_t const offset_addr = BOOTLOADER_ADDR_END-USER_FLASH_END;
flash_nrf5x_write(bl->targetAddr-offset_addr, bl->data, bl->payloadSize, true);
}
#if 0 // don't allow bundle SoftDevice to prevent confusion
else if ( in_app_space(bl->targetAddr) )
{
// Should be Softdevice
flash_nrf5x_write(bl->targetAddr, bl->data, bl->payloadSize, true);
}
else if ( bl->targetAddr < USER_FLASH_START )
{
PRINTF("skip writing to MBR\r\n");
}
#endif
else
{
state->aborted = true;
@@ -478,7 +463,7 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
flash_nrf5x_flush(true);
// Failed if update bootloader without UCIR value
if ( (bl->familyID == CFG_UF2_BOOTLOADER_ID) && !state->boot_addr_ucir )
if ( state->update_bootloader && !state->has_uicr )
{
state->aborted = true;
}
+2 -3
View File
@@ -54,9 +54,8 @@ typedef struct {
uint32_t numWritten;
bool aborted; // aborting update and reset
uint32_t boot_addr_ucir; // if ucir bootloader address value
uint32_t boot_size; // new bootloader size
uint32_t boot_stored_addr; // temporary base address storing new bootloader
bool update_bootloader; // if updating bootloader (else app)
bool has_uicr; // if containing uicr data
uint8_t writtenMask[MAX_BLOCKS / 8 + 1];
} WriteState;
+9 -8
View File
@@ -11,13 +11,14 @@
#define USER_FLASH_START MBR_SIZE // skip MBR included in SD hex
#define USER_FLASH_END 0xAD000
// Current Bootloader start address
#define BOOTLOADER_ADDR_START BOOTLOADER_REGION_START
// Due to SD_MBR_COMMAND_COPY_BL, bootloader start address cannot
// be changed with DFU, and only done with a debugger
// Bootloader end address which is always fixed
#define BOOTLOADER_ADDR_END BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS
// Bootloader start address
#define BOOTLOADER_ADDR_START BOOTLOADER_REGION_START
// 64 KB is hard coded limit size for bootloader when updating.
// This is used as sanity check to make sure user doesn't make mistake
// converting wrong bin/hex into uf2 file for bootloader.
#define BOOTLOADER_LOWEST_ADDR (BOOTLOADER_ADDR_END - 64*1024)
// Bootloader end address
#define BOOTLOADER_ADDR_END BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS
// Address where new bootloader is written before activation (skip application data)
#define BOOTLOADER_ADDR_NEW_RECIEVED (USER_FLASH_END-DFU_BL_IMAGE_MAX_SIZE)