Skip to content

Commit 0d2873a

Browse files
authored
Feature/separate header from app (ARMmbed#98)
FEATURE * Do not assume active header contiguous with app Modify the README * Info re hdr loc & storage choices * Add info re RoT * and link to docs re firmware stoarge API porting * restore build badge and clean up IOTUC-70
1 parent af62fa4 commit 0d2873a

File tree

3 files changed

+119
-60
lines changed

3 files changed

+119
-60
lines changed

README.md

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# mbed-bootloader
2+
3+
[![Build Status](https://jenkins-internal.mbed.com/buildStatus/icon?job=ARMmbed/mbed-bootloader-internal/master)](https://jenkins-internal.mbed.com/job/ARMmbed/job/mbed-bootloader-internal/job/master/)
24

35
Generic bootloader to be used in conjunction with [mbed-cloud-client](https://github.com/ARMmbed/mbed-cloud-client).
46

@@ -7,7 +9,7 @@ Generic bootloader to be used in conjunction with [mbed-cloud-client](https://gi
79
1. Install `mbed-cli` https://github.com/ARMmbed/mbed-cli
810
1. Run `mbed deploy` to pull in dependencies
911
1. Compile by running `mbed compile -t GCC_ARM -m (K64F|NUCLEO_F429ZI|UBLOX_EVK_ODIN_W2) --profile=tiny.json`
10-
1. Use this [script](https://github.com/ARMmbed/mbed-cloud-client-example/blob/master/tools/combine_bootloader_with_app.py) to combine the bootloader with application `python tools/combine_bootloader_with_app.py -a {application.bin} -b {bootloader.bin} --app-offset {firmware_metadata_header_address+firmware_metadata_header_size} --header-offset {firmware_metadata_header_address} -o {combined.bin}`.
12+
1. Use this [script](https://github.com/ARMmbed/mbed-cloud-client-example/blob/master/tools/combine_bootloader_with_app.py) to combine the bootloader with application `python tools/combine_bootloader_with_app.py -a {application.bin} -b {bootloader.bin} --app-offset {application-start-address} --header-offset {firmware_metadata_header_address} -o {combined.bin}`.
1113
1. Flash `{combined.bin}` to device by drag and drop.
1214

1315
## Metadata Header
@@ -18,19 +20,37 @@ The firmware metadata header structure can be found [here](https://github.com/AR
1820

1921
## Configurations
2022

21-
User **must** set in `mbed_app.json`:
23+
NOTE: All these configurations must be set the same in the mbed cloud client when compiling the corresponding application for successful update operation.
24+
25+
### Active Application and Header
26+
2227
1. `update-client.application-details`, Address at which the metadata header of the active firmware is written. **Must align to flash erase boundary**
2328
1. `application-start-address`, Address at which The application starts **Must align to vector table size boundary and flash write page boundary**. It is assumed the region between `update-client.application-details` and `application-start-address` contains only the header. MUST be the same as "target.mbed_app_start" in the application.
29+
30+
If the `application-start-address` is set less than one erase sector after the `update-client.application-details`, the two regions will be erased together. Otherwise the two regions will be erased separately in which case `application-start-address` must also align to **flash erase boundary**.
31+
32+
### Firmware Candidate Storage
33+
34+
1. `MBED_CLOUD_CLIENT_UPDATE_STORAGE`, This need to be set in the "macros" section of `mbed_app.json`. Choices are ARM_UCP_FLASHIAP_BLOCKDEVICE and ARM_UCP_FLASHIAP. This determines whether the firmware is stored on a blockdevice or internal flash. If blockdevice is used `ARM_UC_USE_PAL_BLOCKDEVICE=1` must also be set.
2435
1. `update-client.storage-address`, The address in sd block device or internal flash where the firmware candidates are stored. **Must align to flash erase boundary**
2536
1. `update-client.storage-size`, total size on the block device or internal flash reserved for firmware storage. It will be rounded up to align with flash erase sector size automatically.
2637
1. `update-client.storage-locations`, The number of slots in the firmware storage.
2738
1. `update-client.storage-page`, The write page size of the underlying storage.
2839

29-
If you are using SOTP to provide the RoT, you must set the following:
30-
- "sotp-section-1-address", "sotp-section-1-size", "sotp-section-2-address", "sotp-section-2-size"
31-
The addresses **Must align to flash erase boundary**. The sizes must be full sector sized and at least 1k large.
40+
NOTE: See the [mbed cloud client documentation](https://cloud.mbed.com/docs/current/porting/update-k64f-port.html) for more information about storage options avaiable and porting to new platforms.
41+
42+
### Device Secret Key
43+
44+
The bootloader uses device secret key to authenticate anything that is stored on external storage. The update client must be able to obtain the same key as the bootlaoder. The key is derived from a device root of trust using the algorithm [here](https://github.com/ARMmbed/mbed-cloud-client/blob/master/update-client-hub/modules/common/source/arm_uc_crypto.c#L401).
45+
46+
You may choose to use SOTP to generate and store device RoT. During first boot the mbed cloud client will generate a random number from an available entropy source and storge it in SOTP on internal flash. On subsequent boots, the RoT will be read from SOTP. To enable SOTP RoT, you must set the following:
47+
1. Macro `PAL_USE_INTERNAL_FLASH=1` and `PAL_INT_FLASH_NUM_SECTIONS=2` to indicate that 2 sectors are used for SOTP.
48+
1. Macro `ARM_UC_USE_SOTP=1` to tell bootloader to retrive RoT from SOTP.
49+
1. "sotp-section-1-address", "sotp-section-1-size", "sotp-section-2-address", "sotp-section-2-size". The addresses **Must align to flash erase boundary**. The sizes must be full sector sized and at least 1k large.
50+
51+
Alternatively you can choose to use a custom device specific RoT by implementing the function `mbed_cloud_client_get_rot_128bit`. An example can be found [here](https://github.com/ARMmbed/mbed-bootloader-internal/blob/master/source/example_insecure_rot.c#L40).
3252

33-
All these configurations must be set the same in the mbed cloud client when compiling the corresponding application for successful update operation.
53+
### MISC
3454

3555
User **may** set in `mbed_app.json`:
3656
1. `MAX_COPY_RETRIES`, The number of retries after a failed copy attempt.

source/active_application.cpp

Lines changed: 93 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -180,58 +180,107 @@ int checkActiveApplication(arm_uc_firmware_details_t* details)
180180
return result;
181181
}
182182

183+
int eraseSectorBySector(uint32_t addr, uint32_t size)
184+
{
185+
tr_debug("Erasing from 0x%08" PRIX32 " to 0x%08" PRIX32,
186+
(uint32_t) addr, (uint32_t) addr + size);
187+
188+
int result = -1;
189+
uint32_t erase_address = addr;
190+
191+
/* Erase flash to make place for new application. Erasing sector by sector as some
192+
platforms have varible sector sizes and mbed-os cannot deal with erasing multiple
193+
sectors successfully in that case. https://github.com/ARMmbed/mbed-os/issues/6077 */
194+
while (erase_address < (addr + size))
195+
{
196+
uint32_t sector_size = flash.get_sector_size(erase_address);
197+
result = flash.erase(erase_address,
198+
sector_size);
199+
if (result != 0)
200+
{
201+
tr_debug("Erasing from 0x%08" PRIX32 " to 0x%08" PRIX32 " failed with retval %i",
202+
erase_address, erase_address + sector_size, result);
203+
break;
204+
}
205+
else
206+
{
207+
erase_address += sector_size;
208+
}
209+
}
210+
211+
return result;
212+
}
213+
214+
uint32_t getSectorAlignedSize(uint32_t addr, uint32_t size)
215+
{
216+
tr_debug("getSectorAlignedSize at 0x%08" PRIX32 " of size 0x%08" PRIX32,
217+
(uint32_t) addr, (uint32_t) size);
218+
219+
/* Find the exact end sector boundary. Some platforms have different sector
220+
sizes from sector to sector. Hence we count the sizes 1 sector at a time here */
221+
uint32_t erase_address = addr;
222+
while (erase_address < (addr + size))
223+
{
224+
erase_address += flash.get_sector_size(erase_address);
225+
}
226+
227+
return erase_address - addr;
228+
}
229+
183230
/**
184231
* Wipe the ACTIVE firmware region in the flash
185232
*/
186233
bool eraseActiveFirmware(uint32_t firmwareSize)
187234
{
188235
tr_debug("eraseActiveFirmware");
189236

190-
/* Find the exact end sector boundary. Some platforms have different sector
191-
sizes from sector to sector. Hence we count the sizes 1 sector at a time here */
192-
uint32_t erase_address = FIRMWARE_METADATA_HEADER_ADDRESS;
193-
uint32_t size_needed = FIRMWARE_METADATA_HEADER_SIZE + firmwareSize;
194-
while (erase_address < (FIRMWARE_METADATA_HEADER_ADDRESS + size_needed))
237+
uint32_t fw_metadata_hdr_size = getSectorAlignedSize(FIRMWARE_METADATA_HEADER_ADDRESS,
238+
ARM_UC_INTERNAL_HEADER_SIZE_V2);
239+
uint32_t size_needed = 0;
240+
uint32_t erase_start_addr = 0;
241+
int result = 0;
242+
243+
if (((FIRMWARE_METADATA_HEADER_ADDRESS + fw_metadata_hdr_size) < \
244+
(MBED_CONF_APP_APPLICATION_START_ADDRESS)) || \
245+
(FIRMWARE_METADATA_HEADER_ADDRESS > MBED_CONF_APP_APPLICATION_START_ADDRESS))
195246
{
196-
erase_address += flash.get_sector_size(erase_address);
247+
/* header separate from app */
248+
tr_debug("Erasing header separately from active application");
249+
250+
/* erase header section first */
251+
result = eraseSectorBySector(FIRMWARE_METADATA_HEADER_ADDRESS, fw_metadata_hdr_size);
252+
253+
/* setup erase of the application region */
254+
size_needed = firmwareSize;
255+
erase_start_addr = MBED_CONF_APP_APPLICATION_START_ADDRESS;
256+
}
257+
else /* header contiguous with app */
258+
{
259+
/* setup erase of the header + application region */
260+
size_needed = fw_metadata_hdr_size + firmwareSize;
261+
erase_start_addr = FIRMWARE_METADATA_HEADER_ADDRESS;
197262
}
198263

199-
/* check that the erase will not exceed MBED_CONF_APP_MAX_APPLICATION_SIZE */
200-
int result = -1;
201-
if (erase_address < (MBED_CONF_APP_MAX_APPLICATION_SIZE + \
202-
MBED_CONF_APP_APPLICATION_START_ADDRESS))
264+
if (result == 0)
203265
{
204-
tr_debug("Erasing from 0x%08" PRIX32 " to 0x%08" PRIX32,
205-
(uint32_t) FIRMWARE_METADATA_HEADER_ADDRESS,
206-
(uint32_t) erase_address);
207-
208-
/* Erase flash to make place for new application. Erasing sector by sector as some
209-
platforms have varible sector sizes and mbed-os cannot deal with erasing multiple
210-
sectors successfully in that case. https://github.com/ARMmbed/mbed-os/issues/6077 */
211-
erase_address = FIRMWARE_METADATA_HEADER_ADDRESS;
212-
while (erase_address < (FIRMWARE_METADATA_HEADER_ADDRESS + size_needed))
266+
uint32_t erase_end_addr = erase_start_addr + \
267+
getSectorAlignedSize(erase_start_addr,
268+
size_needed);
269+
uint32_t max_end_addr = MBED_CONF_APP_MAX_APPLICATION_SIZE + \
270+
MBED_CONF_APP_APPLICATION_START_ADDRESS;
271+
/* check that the erase will not exceed MBED_CONF_APP_MAX_APPLICATION_SIZE */
272+
if (erase_end_addr <= max_end_addr)
213273
{
214-
uint32_t sector_size = flash.get_sector_size(erase_address);
215-
result = flash.erase(erase_address,
216-
sector_size);
217-
if (result != 0)
218-
{
219-
tr_debug("Erasing from 0x%08" PRIX32 " to 0x%08" PRIX32 " failed with retval %i",
220-
erase_address, erase_address + sector_size, result);
221-
break;
222-
}
223-
else
224-
{
225-
erase_address += sector_size;
226-
}
274+
result = eraseSectorBySector(erase_start_addr, size_needed);
275+
}
276+
else
277+
{
278+
result = -1;
279+
tr_error("Firmware size 0x%" PRIX32 " rounded up to the nearest sector boundary 0x%" \
280+
PRIX32 " is larger than the maximum application size 0x%" PRIX32,
281+
firmwareSize, erase_end_addr - MBED_CONF_APP_APPLICATION_START_ADDRESS,
282+
MBED_CONF_APP_MAX_APPLICATION_SIZE);
227283
}
228-
}
229-
else
230-
{
231-
tr_error("Firmware size 0x%" PRIX32 " rounded up to the nearest sector boundary 0x%" \
232-
PRIX32 " is larger than the maximum application size 0x%" PRIX32,
233-
firmwareSize, erase_address - MBED_CONF_APP_APPLICATION_START_ADDRESS,
234-
MBED_CONF_APP_MAX_APPLICATION_SIZE);
235284
}
236285

237286
return (result == 0);
@@ -249,16 +298,19 @@ bool writeActiveFirmwareHeader(arm_uc_firmware_details_t* details)
249298
const uint32_t pageSize = flash.get_page_size();
250299
const uint32_t programSize = (ARM_UC_INTERNAL_HEADER_SIZE_V2 + pageSize - 1)
251300
/ pageSize * pageSize;
301+
const uint32_t fw_metadata_hdr_size = \
302+
getSectorAlignedSize(FIRMWARE_METADATA_HEADER_ADDRESS,
303+
ARM_UC_INTERNAL_HEADER_SIZE_V2);
252304

253305
/* coverity[no_escape] */
254306
MBED_BOOTLOADER_ASSERT((programSize <= BUFFER_SIZE),
255307
"Header program size %" PRIu32 " bigger than buffer %d\r\n",
256308
programSize, BUFFER_SIZE);
257309

258310
/* coverity[no_escape] */
259-
MBED_BOOTLOADER_ASSERT((programSize <= FIRMWARE_METADATA_HEADER_SIZE),
311+
MBED_BOOTLOADER_ASSERT((programSize <= fw_metadata_hdr_size),
260312
"Header program size %" PRIu32 " bigger than expected header %d\r\n",
261-
programSize, FIRMWARE_METADATA_HEADER_SIZE);
313+
programSize, fw_metadata_hdr_size);
262314

263315
/* pad buffer to 0xFF */
264316
memset(buffer_array, 0xFF, programSize);

source/bootloader_config.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,4 @@
4040
"To use pre configured profiles: mbed compile --app-config configs/<config>.json"
4141
#endif
4242

43-
/* FIRMWARE_METADATA_HEADER_SIZE */
44-
#if defined(MBED_CONF_APP_APPLICATION_START_ADDRESS) && \
45-
defined(FIRMWARE_METADATA_HEADER_ADDRESS)
46-
#define FIRMWARE_METADATA_HEADER_SIZE \
47-
(MBED_CONF_APP_APPLICATION_START_ADDRESS - \
48-
FIRMWARE_METADATA_HEADER_ADDRESS)
49-
#endif
50-
51-
#if !defined(FIRMWARE_METADATA_HEADER_SIZE)
52-
#error "configure application_start_address in mbed_app.json\n" \
53-
"To use pre configured profiles: mbed compile --app-config configs/<config>.json"
54-
#endif
55-
5643
#endif // BOOTLOADER_CONFIG_H

0 commit comments

Comments
 (0)