@@ -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
154155static 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
159161static 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
164179static 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 }
0 commit comments