Skip to content

Commit 46adc42

Browse files
committed
try to allow new bootloader with different size than current one
however, due to the design of MBR, the SD_MBR_COMMAND_COPY_BL prioritize its internal flash location MBR_BOOTLOADER_ADDR, we won't be able to change bootloader starting address to increase its size
1 parent 08c0f27 commit 46adc42

File tree

6 files changed

+173
-72
lines changed

6 files changed

+173
-72
lines changed

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,11 @@ Module.symvers
5151
Mkfile.old
5252
dkms.conf
5353

54-
src/segger/Output
55-
_build-*/
54+
segger/Output
55+
_build/
5656
bin/
5757
*.emSession
5858
*.jlink
59+
.idea/
5960

6061
TAGS

src/main.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,10 @@ void softdev_mbr_init(void)
153153
//--------------------------------------------------------------------+
154154
int main(void)
155155
{
156-
// Populate Boot Address and MBR Param if not already
157-
// Happens if flashing SD hex that overwrite current MBR
156+
// Populate Boot Address and MBR Param into MBR if not already
158157
// MBR_BOOTLOADER_ADDR/MBR_PARAM_PAGE_ADDR are used if available, else UICR registers are used
159-
bootloader_mbr_addrs_populate();
158+
// Note: skip it for now since this will prevent us to change the size of bootloader
159+
bootloader_mbr_addrs_populate();
160160

161161
// SD is already Initialized in case of BOOTLOADER_DFU_OTA_MAGIC
162162
bool sd_inited = (NRF_POWER->GPREGRET == DFU_MAGIC_OTA_APPJUM);

src/usb/msc_uf2.c

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,21 @@ void tud_msc_write10_complete_cb(uint8_t lun)
162162
{
163163
static bool first_write = true;
164164

165-
if ( _wr_state.numBlocks )
165+
// abort the DFU, uf2 block failed integrity check
166+
if ( _wr_state.aborted )
167+
{
168+
// aborted and reset
169+
PRINTF("Aborted\r\n");
170+
171+
dfu_update_status_t update_status;
172+
memset(&update_status, 0, sizeof(dfu_update_status_t ));
173+
update_status.status_code = DFU_RESET;
174+
175+
bootloader_dfu_update_process(update_status);
176+
177+
led_state(STATE_WRITING_FINISHED);
178+
}
179+
else if ( _wr_state.numBlocks )
166180
{
167181
// Start LED writing pattern with first write
168182
if (first_write)
@@ -177,13 +191,53 @@ void tud_msc_write10_complete_cb(uint8_t lun)
177191
dfu_update_status_t update_status;
178192
memset(&update_status, 0, sizeof(dfu_update_status_t ));
179193

180-
if ( _wr_state.update_bootloader )
194+
if ( _wr_state.boot_addr_ucir )
181195
{
182196
// update bootloader
197+
update_status.status_code = DFU_RESET;
198+
199+
if ( 0 == memcmp((uint8_t*) _wr_state.boot_stored_addr, (uint8_t*) BOOTLOADER_ADDR_START, _wr_state.boot_size) )
200+
{
201+
// skip if there is no bootloader change
202+
}else
203+
{
204+
PRINTF("Coyping bootloader to 0x%08lX from 0x%08lX with size = 0x%lX\r\n",
205+
_wr_state.boot_addr_ucir, _wr_state.boot_stored_addr, _wr_state.boot_size);
206+
207+
// erase an change UCIR bootloader
208+
// if ( )
209+
210+
sd_mbr_command_t command =
211+
{
212+
.command = SD_MBR_COMMAND_COPY_BL,
213+
.params.copy_bl.bl_src = (uint32_t*) _wr_state.boot_stored_addr,
214+
.params.copy_bl.bl_len = _wr_state.boot_size/4 // size in words
215+
};
216+
217+
if ( NRF_SUCCESS != sd_mbr_command(&command) )
218+
{
219+
PRINTF("Failed to execute SD_MBR_COMMAND_COPY_BL, we are about to bricked\r\n");
220+
}else
221+
{
222+
PRINTF("SD_MBR_COMMAND_COPY_BL successfully\r\n");
223+
}
224+
225+
NRFX_DELAY_MS(10);
226+
// update_status.status_code = DFU_UPDATE_BOOT_COMPLETE;
227+
// update_status.bl_size = _wr_state.boot_size;
228+
//
229+
// // Reuse the DFU combined SD + Bootloader with SD Size = 0
230+
// update_status.sd_image_start = _wr_state.boot_stored_addr;
231+
// update_status.sd_size = 0;
232+
}
233+
234+
PRINTF("bootloader update complete\r\n");
183235
}else
184236
{
185237
// update App
186238
update_status.status_code = DFU_UPDATE_APP_COMPLETE;
239+
240+
PRINTF("Application update complete\r\n");
187241
}
188242

189243
bootloader_dfu_update_process(update_status);

src/usb/uf2/ghostfat.c

Lines changed: 89 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -151,21 +151,40 @@ static inline bool is_uf2_block (UF2_Block const *bl)
151151
(bl->payloadSize == 256) && !(bl->targetAddr & 0xff);
152152
}
153153

154+
// used when upgrading application
154155
static inline bool in_app_space (uint32_t addr)
155156
{
156157
return USER_FLASH_START <= addr && addr < USER_FLASH_END;
157158
}
158159

160+
// used when upgrading bootloader
159161
static inline bool in_bootloader_space (uint32_t addr)
160162
{
161-
return CFG_UF2_BOOTLOADER_ADDR_START <= addr && addr < CFG_UF2_BOOTLOADER_ADDR_END;
163+
return BOOTLOADER_LOWEST_ADDR <= addr && addr < BOOTLOADER_ADDR_END;
162164
}
163165

166+
static inline uint32_t get_new_bootloader_size(uint32_t numblocks)
167+
{
168+
// -1 for UCIR block
169+
uint32_t new_size = (numblocks-1)*256;
170+
171+
// round up to 4K
172+
uint32_t mod4k = new_size & 0xFFFUL;
173+
if ( mod4k ) new_size += 4096 - mod4k;
174+
175+
return new_size;
176+
}
177+
178+
// used when upgrading bootloader
164179
static inline bool in_uicr_space(uint32_t addr)
165180
{
166181
return addr == 0x10001000;
167182
}
168183

184+
//static inline get_new_bootloader_base(uint32_t )
185+
186+
static inline uint32_t max32 (uint32_t x, uint32_t y) { return (x > y) ? x : y; }
187+
169188
//--------------------------------------------------------------------+
170189
//
171190
//--------------------------------------------------------------------+
@@ -284,14 +303,7 @@ void read_block(uint32_t block_no, uint8_t *data) {
284303
*------------------------------------------------------------------*/
285304

286305
/**
287-
* Write an uf2 block wrapped by 512 sector. Writing behavior is different when upgrading:
288-
* - Application
289-
* - current App is erased and flash with new firmware with same starting address
290-
*
291-
* - SoftDevice + Bootloader
292-
* - Current App is erased, contents of SD + bootloader is written to App starting address
293-
* - Trigger the SD + Bootloader migration
294-
*
306+
* Write an uf2 block wrapped by 512 sector.
295307
* @return number of bytes processed, only 3 following values
296308
* -1 : if not an uf2 block
297309
* 512 : write is successful
@@ -308,18 +320,7 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
308320
case CFG_UF2_FAMILY_ID:
309321
/* Upgrading Application
310322
*
311-
* Although SoftDevice is considered as part of application and the flashing is the same with/without it.
312-
* There are still 4 cases with slight differences in finishing procedure:
313-
* 1. Application with SoftDevice:
314-
* - starting address 0x0000
315-
* - since MBR is included in SD Hex file (then uf2 file), we must skip it
316-
* 2. Application only
317-
* a. For running with existing SoftDevice on the flash:
318-
* - starting address is right after SD e.g 0x26000
319-
* b. For running without SoftDevice e.g using other stack such as nimble or zephyr.
320-
* - starting address is right after MBR 0x1000
321-
* 3. SoftDevice only, should user somehow only flash with SD only. Bootloader mark app as invalid and wiil
322-
* back on bootloader mode after reset.
323+
* SoftDevice is considered as part of application and can be (or not) included in uf2.
323324
*
324325
* ------------- -------------
325326
* | | | |
@@ -338,34 +339,36 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
338339
if ( in_app_space(bl->targetAddr) )
339340
{
340341
PRINTF("Write addr = 0x%08lX, block = %ld (%ld of %ld)\r\n", bl->targetAddr, bl->blockNo, state->numWritten, bl->numBlocks);
341-
342-
// writing to SD Info struct is used as SD detector
343-
if (bl->targetAddr == (SOFTDEVICE_INFO_STRUCT_ADDRESS & 0xFFFFFF00) )
344-
{
345-
state->has_sd = true;
346-
}
347-
348342
flash_nrf5x_write(bl->targetAddr, bl->data, bl->payloadSize, true);
349343
}else if ( bl->targetAddr < USER_FLASH_START )
350344
{
351-
// do nothing if writing to MBR
345+
// do nothing if writing to MBR, occurs when SD hex is included
352346
// keep going as successful write
353-
state->has_mbr = true;
347+
PRINTF("skip writing to MBR\r\n");
354348
}else
355349
{
356350
return -1;
357351
}
358352
break;
359353

360354
case CFG_UF2_BOOTLOADER_ID:
361-
/* Upgrading Bootloader (with/without SoftDevice)
355+
/* Upgrading Bootloader
356+
*
357+
* Along with bootloader code, UCIR (at 0x1000100) is also included containing
358+
* 0x10001014 (bootloader address), and 0x10001018 (MBR Params address).
359+
*
360+
* Since SoftDevice is not part of Bootloader, it must not be included as part of uf2 file.
361+
* To prevent generating uf2 from incorrect bin/hex. Bootloader imposes a hard code limit size
362+
* of 64 KB (end address is fixed at MBR Params). If uf2 contains any address lower than this
363+
* (except UCIR) the update is aborted.
362364
*
363365
* To prevent corruption/disconnection while transferring we don't directly write over
364-
* Bootloader. Instead Bootloader is written to Application region.
365-
* Once everything is received and verified. It is written to its respective address
366+
* Bootloader. Instead it is written to highest possible address in Application
367+
* region. Once everything is received and verified, it is safely activated using
368+
* MBR COPY BL command.
366369
*
367-
* Note: to simplify the upgrade process, we ASSUME, Bootloader size is fixed and
368-
* is the same as the old bootloader
370+
* Note: part of the existing application can be affected when updating bootloader.
371+
* TODO May be worth to have some kind crc/application integrity checking
369372
*
370373
* ------------- ------------- -------------
371374
* | | | | + | New |
@@ -374,41 +377,68 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
374377
* | | | New | + | |
375378
* | | | Bootloader | + | |
376379
* | | | ++++++++ | | |
377-
* | Application | ---> | | | |
380+
* | | ---> | | | |
381+
* | | | | | |
382+
* | Application | | Application | | Application |
383+
* | | | | | |
378384
* | | | | | |
379-
* | | | ++++++++ | | ++++++++ |
380-
* | | | New | | New |
381-
* | | | SoftDevice | | SoftDevice |
382385
* USER_FLASH_START--|-------------| |-------------| |-------------|
383386
* | MBR | | MBR | | MBR |
384387
* ------------- ------------- -------------
385388
*/
389+
PRINTF("addr = 0x%08lX, block = %ld (%ld of %ld)\r\n", bl->targetAddr, bl->blockNo, state->numWritten, bl->numBlocks);
390+
391+
uint32_t const new_boot_size = get_new_bootloader_size(bl->numBlocks);
392+
393+
// Offset write the new bootloader address.
394+
// The offset is the current bootloader size or the new size whichever is larger
395+
uint32_t const offset_addr = max32(new_boot_size, BOOTLOADER_ADDR_END-BOOTLOADER_ADDR_START);
396+
386397
if ( in_uicr_space(bl->targetAddr) )
387398
{
388399
/* UCIR contains bootloader & MBR address as follow:
389-
* - 0x10001014 bootloader address: only change of bootloader size changes
400+
* - 0x10001014 bootloader address: only change if bootloader size changes
390401
* - 0x10001018 MBR Params: mostly fixed
391402
*
392-
* WARNING: incorrect value of these UCIR will break device
403+
* WARNING: incorrect value of these UCIR will brick device
393404
*/
405+
uint32_t ucir_boot_addr;
406+
uint32_t ucir_mbr_param;
394407

395-
// Nothing to do since bootloader size is fixed
396-
return 512;
397-
}
398-
else if ( in_bootloader_space(bl->targetAddr) )
399-
{
400-
// Right above the old SoftDevice
408+
memcpy(&ucir_boot_addr, bl->data + 0x14, 4);
409+
memcpy(&ucir_mbr_param, bl->data + 0x18, 4);
410+
411+
PRINT_HEX(ucir_boot_addr);
412+
PRINT_HEX(ucir_mbr_param);
413+
414+
PRINT_HEX(new_boot_size);
415+
416+
// Check MBR params is fixed and prohibited to change and
417+
// Bootloader address against its new size
418+
if ( (ucir_mbr_param != BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS) ||
419+
(ucir_boot_addr != BOOTLOADER_ADDR_END - new_boot_size) )
420+
{
421+
PRINTF("Incorrect UCIR value");
422+
state->aborted = true;
423+
return -1;
424+
}else
425+
{
426+
// Good to go, save the boot address
427+
state->boot_addr_ucir = ucir_boot_addr;
428+
state->boot_size = new_boot_size;
429+
state->boot_stored_addr = BOOTLOADER_ADDR_END - (new_boot_size + offset_addr);
430+
431+
PRINT_HEX(state->boot_stored_addr);
432+
}
401433
}
402-
else if ( in_app_space(bl->targetAddr) )
434+
else if ( in_bootloader_space(bl->targetAddr) && (bl->targetAddr >= BOOTLOADER_LOWEST_ADDR) )
403435
{
404-
// Right below the old Bootloader
405-
//wr_addr = USER_FLASH_START + bl->targetAddr;
406-
// writing to SD Info struct is used as SD detector
407-
// if (bl->targetAddr == SOFTDEVICE_INFO_STRUCT_ADDRESS) state->has_sd = true;
408-
436+
// PRINT_HEX(offset_addr);
437+
flash_nrf5x_write(bl->targetAddr-offset_addr, bl->data, bl->payloadSize, true);
409438
}
410439
else
411440
{
441+
state->aborted = true;
412442
return -1;
413443
}
414444
break;
@@ -446,6 +476,12 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
446476
if ( state->numWritten >= state->numBlocks )
447477
{
448478
flash_nrf5x_flush(true);
479+
480+
// Failed if update bootloader without UCIR value
481+
if ( (bl->familyID == CFG_UF2_BOOTLOADER_ID) && !state->boot_addr_ucir )
482+
{
483+
state->aborted = true;
484+
}
449485
}
450486
}
451487
}

src/usb/uf2/uf2.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,12 @@ SOFTWARE.
5252
typedef struct {
5353
uint32_t numBlocks;
5454
uint32_t numWritten;
55-
bool has_sd; // if uf2 includes SD
56-
bool has_mbr; // if uf2 includes MBR
57-
bool update_bootloader; // if updating bootloader
55+
56+
bool aborted; // aborting update and reset
57+
uint32_t boot_addr_ucir; // if ucir bootloader address value
58+
uint32_t boot_size; // new bootloader size
59+
uint32_t boot_stored_addr; // temporary base address storing new bootloader
60+
5861
uint8_t writtenMask[MAX_BLOCKS / 8 + 1];
5962
} WriteState;
6063

src/usb/uf2/uf2cfg.h

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
#include "boards.h"
22
#include "dfu_types.h"
33

4-
#define CFG_UF2_FAMILY_ID 0xADA52840
5-
#define CFG_UF2_BOOTLOADER_ID ((USB_DESC_VID << 16) | USB_DESC_UF2_PID)
4+
#define CFG_UF2_FAMILY_ID 0xADA52840
5+
#define CFG_UF2_BOOTLOADER_ID ((USB_DESC_VID << 16) | USB_DESC_UF2_PID)
66

7-
#define CFG_UF2_NUM_BLOCKS 8000 // at least 4,1 MB for FAT16
8-
#define CFG_UF2_FLASH_SIZE (1024*1024) // 1 MB
7+
#define CFG_UF2_NUM_BLOCKS 8000 // at least 4,1 MB for FAT16
8+
#define CFG_UF2_FLASH_SIZE (1024*1024) // 1 MB
99

1010
// Application Address Space
11-
#define USER_FLASH_START MBR_SIZE // skip MBR included in SD hex
12-
#define USER_FLASH_END 0xAD000
11+
#define USER_FLASH_START MBR_SIZE // skip MBR included in SD hex
12+
#define USER_FLASH_END 0xAD000
1313

14-
// Bootloader Address Space
15-
#define CFG_UF2_BOOTLOADER_ADDR_START BOOTLOADER_REGION_START
16-
#define CFG_UF2_BOOTLOADER_ADDR_END BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS
14+
// Current Bootloader start address
15+
#define BOOTLOADER_ADDR_START BOOTLOADER_REGION_START
16+
17+
// Bootloader end address which is always fixed
18+
#define BOOTLOADER_ADDR_END BOOTLOADER_MBR_PARAMS_PAGE_ADDRESS
19+
20+
// 64 KB is hard coded limit size for bootloader when updating.
21+
// This is used as sanity check to make sure user doesn't make mistake
22+
// converting wrong bin/hex into uf2 file for bootloader.
23+
#define BOOTLOADER_LOWEST_ADDR (BOOTLOADER_ADDR_END - 64*1024)

0 commit comments

Comments
 (0)