@@ -151,21 +151,40 @@ static inline bool is_uf2_block (UF2_Block const *bl)
151
151
(bl -> payloadSize == 256 ) && !(bl -> targetAddr & 0xff );
152
152
}
153
153
154
+ // used when upgrading application
154
155
static inline bool in_app_space (uint32_t addr )
155
156
{
156
157
return USER_FLASH_START <= addr && addr < USER_FLASH_END ;
157
158
}
158
159
160
+ // used when upgrading bootloader
159
161
static inline bool in_bootloader_space (uint32_t addr )
160
162
{
161
- return CFG_UF2_BOOTLOADER_ADDR_START <= addr && addr < CFG_UF2_BOOTLOADER_ADDR_END ;
163
+ return BOOTLOADER_LOWEST_ADDR <= addr && addr < BOOTLOADER_ADDR_END ;
162
164
}
163
165
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
164
179
static inline bool in_uicr_space (uint32_t addr )
165
180
{
166
181
return addr == 0x10001000 ;
167
182
}
168
183
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
+
169
188
//--------------------------------------------------------------------+
170
189
//
171
190
//--------------------------------------------------------------------+
@@ -284,14 +303,7 @@ void read_block(uint32_t block_no, uint8_t *data) {
284
303
*------------------------------------------------------------------*/
285
304
286
305
/**
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.
295
307
* @return number of bytes processed, only 3 following values
296
308
* -1 : if not an uf2 block
297
309
* 512 : write is successful
@@ -308,18 +320,7 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
308
320
case CFG_UF2_FAMILY_ID :
309
321
/* Upgrading Application
310
322
*
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.
323
324
*
324
325
* ------------- -------------
325
326
* | | | |
@@ -338,34 +339,36 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
338
339
if ( in_app_space (bl -> targetAddr ) )
339
340
{
340
341
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
-
348
342
flash_nrf5x_write (bl -> targetAddr , bl -> data , bl -> payloadSize , true);
349
343
}else if ( bl -> targetAddr < USER_FLASH_START )
350
344
{
351
- // do nothing if writing to MBR
345
+ // do nothing if writing to MBR, occurs when SD hex is included
352
346
// keep going as successful write
353
- state -> has_mbr = true ;
347
+ PRINTF ( "skip writing to MBR\r\n" ) ;
354
348
}else
355
349
{
356
350
return -1 ;
357
351
}
358
352
break ;
359
353
360
354
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.
362
364
*
363
365
* 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.
366
369
*
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
369
372
*
370
373
* ------------- ------------- -------------
371
374
* | | | | + | New |
@@ -374,41 +377,68 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
374
377
* | | | New | + | |
375
378
* | | | Bootloader | + | |
376
379
* | | | ++++++++ | | |
377
- * | Application | ---> | | | |
380
+ * | | ---> | | | |
381
+ * | | | | | |
382
+ * | Application | | Application | | Application |
383
+ * | | | | | |
378
384
* | | | | | |
379
- * | | | ++++++++ | | ++++++++ |
380
- * | | | New | | New |
381
- * | | | SoftDevice | | SoftDevice |
382
385
* USER_FLASH_START--|-------------| |-------------| |-------------|
383
386
* | MBR | | MBR | | MBR |
384
387
* ------------- ------------- -------------
385
388
*/
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
+
386
397
if ( in_uicr_space (bl -> targetAddr ) )
387
398
{
388
399
/* 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
390
401
* - 0x10001018 MBR Params: mostly fixed
391
402
*
392
- * WARNING: incorrect value of these UCIR will break device
403
+ * WARNING: incorrect value of these UCIR will brick device
393
404
*/
405
+ uint32_t ucir_boot_addr ;
406
+ uint32_t ucir_mbr_param ;
394
407
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
+ }
401
433
}
402
- else if ( in_app_space (bl -> targetAddr ) )
434
+ else if ( in_bootloader_space (bl -> targetAddr ) && ( bl -> targetAddr >= BOOTLOADER_LOWEST_ADDR ) )
403
435
{
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);
409
438
}
410
439
else
411
440
{
441
+ state -> aborted = true;
412
442
return -1 ;
413
443
}
414
444
break ;
@@ -446,6 +476,12 @@ int write_block (uint32_t block_no, uint8_t *data, WriteState *state)
446
476
if ( state -> numWritten >= state -> numBlocks )
447
477
{
448
478
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
+ }
449
485
}
450
486
}
451
487
}
0 commit comments