diff --git a/.mbedignore b/.mbedignore index 2eb5560..8092ece 100755 --- a/.mbedignore +++ b/.mbedignore @@ -3,26 +3,20 @@ mbed-os/rtos/* mbed-os/events/* mbed-os/features/FEATURE_LWIP/* mbed-os/features/FEATURE_BLE/* -mbed-os/features/FEATURE_COMMON_PAL/mbed-client-randlib/* -mbed-os/features/FEATURE_COMMON_PAL/mbed-coap/* -mbed-os/features/FEATURE_COMMON_PAL/nanostack-hal-mbed-cmsis-rtos/* -mbed-os/features/FEATURE_COMMON_PAL/sal-stack-nanostack-eventloop/* -mbed-os/features/FEATURE_COMMON_PAL/mbed-trace/source/* -mbed-os/features/FEATURE_COMMON_PAL/mbed-trace/test/* -mbed-os/features/FEATURE_COMMON_PAL/nanostack-libservice/source/* -mbed-os/features/FEATURE_COMMON_PAL/nanostack-libservice/test/* -mbed-os/features/FEATURE_UVISOR/* mbed-os/features/unsupported/* mbed-os/features/cellular/* mbed-os/features/lorawan/* mbed-os/features/nanostack/* mbed-os/features/netsocket/* -mbed-os/features/filesystem/littlefs/* -mbed-os/features/filesystem/fat/* -mbed-os/features/device_key/* +mbed-os/components/802.15.4_RF/* +mbed-os/components/storage/blockdevice/COMPONENT_SD/util/* mbed-os/components/wifi/* -mbed-os/components/storage/* +mbed-os/features/frameworks/mbed-trace/* mbed-os/features/frameworks/mbed-client-cli/* +mbed-os/features/frameworks/mbed-client-randlib/* +mbed-os/features/frameworks/nanostack-libservice/source/* +mbed-os/features/nanostack/nanostack-hal-mbed-cmsis-rtos/* +mbed-os/features/frameworks/mbed-coap/* mbed-os/features/lwipstack/* mbed-os/features/nfc/* mbed-os/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F437xG/TARGET_UBLOX_C030/onboard_modem_api.c @@ -31,44 +25,5 @@ mbed-os/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F437xG/TARGET_UBLOX_C030/m mbed-os/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F437xG/TARGET_UBLOX_C030/min_battery_voltage.h mbed-os/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F439xI/TARGET_MODULE_UBLOX_ODIN_W2/sdk/ublox-odin-w2-drivers/default_wifi_interface.cpp mbed-os/targets/TARGET_STM/TARGET_STM32F4/TARGET_STM32F439xI/TARGET_MODULE_UBLOX_ODIN_W2/sdk/ublox-odin-w2-drivers/OdinWiFiInterface.cpp -mbed-os/features/frameworks/mbed-client-randlib/* -mbed-os/features/frameworks/mbed-coap/* -mbed-os/features/frameworks/mbed-trace/* -mbed-os/features/frameworks/nanostack-libservice/* -mbed-cloud-client/update-client-hub/source/* -mbed-cloud-client/update-client-hub/modules/atomic-queue/* -mbed-cloud-client/update-client-hub/modules/control-center/* -mbed-cloud-client/update-client-hub/modules/firmware-manager/* -mbed-cloud-client/update-client-hub/modules/manifest-manager/* -mbed-cloud-client/update-client-hub/modules/pal-linux/* -mbed-cloud-client/update-client-hub/modules/source/* -mbed-cloud-client/update-client-hub/modules/source-http-socket/* -mbed-cloud-client/update-client-hub/modules/device-identity/* -mbed-cloud-client/update-client-hub/modules/lwm2m-mbed/* -mbed-cloud-client/update-client-hub/modules/monitor/* -mbed-cloud-client/update-client-hub/modules/pal-filesystem/* -mbed-cloud-client/update-client-hub/modules/pal-target-specific/* -mbed-cloud-client/update-client-hub/modules/source-http/* -mbed-cloud-client/update-client-hub/modules/source-manager/* -mbed-cloud-client/update-client-hub/modules/resume-engine/* -mbed-cloud-client/update-client-hub/modules/common/source/arm_uc_scheduler.c -mbed-cloud-client/mbed-client-pal/* -mbed-cloud-client/CMakeLists.txt -mbed-cloud-client/DOXYGEN_FRONTPAGE.md -mbed-cloud-client/Jenkinsfile -mbed-cloud-client/LICENSE -mbed-cloud-client/README.md -mbed-cloud-client/contributions.md -mbed-cloud-client/doxygen/* -mbed-cloud-client/factory-configurator-client/* -mbed-cloud-client/mbed-client/* -mbed-cloud-client/mbed-client-randlib/* -mbed-cloud-client/mbed-cloud-client/* -mbed-cloud-client/mbed-coap/* -mbed-cloud-client/mbed-trace/* -mbed-cloud-client/mbed_lib.json -mbed-cloud-client/nanostack-libservice/* -mbed-cloud-client/ns-hal-pal/* -mbed-cloud-client/sal-stack-nanostack-eventloop/* -mbed-cloud-client/source/* -mbed-cloud-client/certificate-enrollment-client/* +mbed-os/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_SDK_11/libraries/fds/* +mbed-os/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_SDK_14_2/libraries/fds/* diff --git a/README.md b/README.md index 655773d..2162333 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,40 @@ # mbed-bootloader -Generic bootloader to be used in conjunction with [mbed-cloud-client](https://github.com/ARMmbed/mbed-cloud-client). +Generic bootloader to be used in conjunction with [Pelion Device Management Client](https://github.com/ARMmbed/mbed-cloud-client). ## Build instructions 1. Install `mbed-cli` https://github.com/ARMmbed/mbed-cli 1. Run `mbed deploy` to pull in dependencies 1. Compile by running `mbed compile -t GCC_ARM -m (K64F|NUCLEO_F429ZI|UBLOX_EVK_ODIN_W2) --profile=tiny.json` -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}`. -1. Flash `{combined.bin}` to device by drag and drop. + +## Installation instructions + +An image that contains the bootloader and your application can then be flashed on your device. + +If you use Mbed CLI 1.8.x then two images are created when you compile [Pelion Device Management Client example application](https://github.com/ARMmbed/mbed-cloud-client-example). +1. A full image `mbed-cloud-client-example-internal.bin` which combines the application with the bootloader and is used for the initial programming of the device +1. An update image `mbed-cloud-client-example-internal_update.bin` which contains only the application and is used for updating the device over the air + +In order for Mbed CLI to pick up the bootloader binary you built, set `"target.bootloader_img": ` in your application's `mbed_app.json` For more details, see [Arm Mbed OS managed bootloader](https://os.mbed.com/docs/v5.10/tutorials/bootloader.html#arm-mbed-os-managed-bootloader). + +Flash `mbed-cloud-client-example-internal.bin` to your device by drag and drop. ## Metadata Header The metadata header is the bootloader update interface. Each stage of the boot sequence leading up to and including the application (except the root bootloader) is paired with a metadata header (containing version, size, hash etc.). Information contained in the metadata header allows validation and ordering of available firmwares. -The firmware metadata header structure can be found [here](https://github.com/ARMmbed/mbed-cloud-client/blob/master/update-client-hub/modules/common/update-client-common/arm_uc_metadata_header_v2.h). There are two header formats, internal and external. The external header format is used for storing firmware on external storage which is assumed to be insecure. Hence the external header format contains extra security information to prevent external tampering of the header data. +The firmware metadata header structure can be found [here](https://github.com/ARMmbed/mbed-bootloader/blob/master/modules/metadata-header/update-client-metadata-header/arm_uc_metadata_header_v2.h). There are two header formats, internal and external. The external header format is used for storing firmware on external storage which is assumed to be insecure. Hence the external header format contains extra security information to prevent external tampering of the header data. ## Configurations -NOTE: All these configurations must be set the same in the mbed cloud client when compiling the corresponding application for successful update operation. +NOTE: All these configurations must be set the same in the Pelion Device Management Client when compiling the corresponding application for successful update operation. ### Active Application and Header 1. `update-client.application-details`, Address at which the metadata header of the active firmware is written. **Must align to flash erase boundary** -1. `application-start-address`, Address at which the application starts **Must align to vector table size boundary and flash write page boundary**. -1. `application-jump-address`, Optional address for the application's entry point (vector table) if this is different from `application-start-address`. +1. `mbed-bootloader.application-start-address`, Address at which the application starts **Must align to vector table size boundary and flash write page boundary**. +1. `mbed-bootloader.application-jump-address`, Optional address for the application's entry point (vector table) if this is different from `mbed-bootloader.application-start-address`. 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**. @@ -32,44 +42,64 @@ If `application-jump-address` is not set, the `application-start-address` will b ### Firmware Candidate Storage -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. +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. 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** 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. 1. `update-client.storage-locations`, The number of slots in the firmware storage. -1. `update-client.storage-page`, The write page size of the underlying storage. -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. +NOTE: See the [Pelion Device Management Client documentation](https://cloud.mbed.com/docs/current/porting/update-k64f-port.html) for more information about storage options available and porting to new platforms. ### Device Secret Key -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). +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 bootloader. 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). If the firmware candidate is stored on internal storage, i.e. `MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP` then the device secret key is not needed by the bootloader hence any configuration will be ignored. -You may choose to use NVSTORE to store the device RoT. During first boot mbed cloud client will generate a random number from an available entropy source and storge it in NVSTORE on internal flash. On subsequent boots, the RoT will be read from NVSTORE. To enable NVSTORE RoT, you must set the following: -1. Macro `ARM_BOOTLOADER_USE_NVSTORE_ROT=1` to enable the RoT implementation [here](https://github.com/ARMmbed/mbed-bootloader/blob/master/source/nvstore_rot.cpp). -1. "nvstore.area_1_address", "nvstore.area_1_size", "nvstore.area_2_address", "nvstore.area_2_size". The addresses **Must align to flash erase boundary**. The sizes must be full sector sized and at least 1k. -1. NVSTORE and SOTP are binary compatible hence the bootloader works with any software that uses SOTP as long as the offsets are set the same. +You may choose to use Mbed OS' KVSTORE feature to store and read the device RoT. During first boot Pelion Device Management Client will generate a random number from an available entropy source and storage it in KVSTORE on internal flash. On subsequent boots, the RoT will be read from KVSTORE. To enable KVSTORE RoT, you must set the following: +1. Set `"mbed-bootloader.use-kvstore-rot": 1` in `mbed_app.json` to enable the KVStore RoT implementation [here](https://github.com/ARMmbed/mbed-bootloader/blob/master/source/kvstore_rot.cpp). +1. Set `"storage.storage_type": "FILESYSTEM"`, this configurations will have RoT stored on internal flash. +1. Set `"storage_filesystem.internal_base_address"`. The addresses **Must align to flash erase boundary**. +1. Set `"storage_filesystem.rbp_internal_size"`. It **must contain even number of sectors**. 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/blob/master/source/example_insecure_rot.c#L40). +### Bootloader Information + +Pelion Cloud Client reports some information about the bootloader to the cloud. The bootloader provides this information in the form of a `arm_uc_installer_details_t` struct: +``` +const arm_uc_installer_details_t bootloader = { + .arm_hash = BOOTLOADER_ARM_SOURCE_HASH, + .oem_hash = BOOTLOADER_OEM_SOURCE_HASH, + .layout = BOOTLOADER_STORAGE_LAYOUT +}; +``` + +For this information to propagate to the cloud, the 3 macros (`BOOTLOADER_ARM_SOURCE_HASH`, `BOOTLOADER_OEM_SOURCE_HASH` and `BOOTLOADER_STORAGE_LAYOUT`) in [mbed_bootloader_info.h](https://github.com/ARMmbed/mbed-bootloader/blob/master/source/mbed_bootloader_info.h) need to be populated manually before the bootloader binary is built. + +1. `BOOTLOADER_ARM_SOURCE_HASH` should be the SHA-1 git commit hash of the published mbed-bootloader source code. +1. `BOOTLOADER_OEM_SOURCE_HASH` is used to indicate any modification that OEMs have made on top of the vanilla mbed-bootloader. Hence it should be populated with the OEM modified bootloader SHA-1 git commit hash. +1. `BOOTLOADER_STORAGE_LAYOUT` is a proprietary enum to indicate the storage layout supported by this bootloader. The OEM is free to define the meaning of this number. + +In order for the cloud client to recognise this struct and obtain the information. The offset of the symbol in the bootloader binary needs to be populated in the cloud client's configuration file: +1. Compile the bootloader. Flash and run the bootloader. On the serial UART you will see the following printout: + + > Layout: +1. Keep a note of the `boot_loader_info_address` which we will use in the next step. +1. In the `mbed_app.json` of the Pelion Cloud Client Application, change the following: `"update-client.bootloader-details" : ""` + ### MISC User **may** set in `mbed_app.json`: -1. `MAX_COPY_RETRIES`, The number of retries after a failed copy attempt. -1. `MAX_FIRMWARE_LOCATIONS`, The maximum number of stored firmware candidates. -1. `MAX_BOOT_RETRIES`, The number of retries after a failed forward to application. -1. `SHOW_PROGRESS_BAR`, Set to 1 to print a progress bar for various processes. +1. `mbed-bootloader.max-copy-retries`, The number of retries after a failed copy attempt. +1. `mbed-bootloader.max-boot-retries`, The number of retries after a failed forward to application. +1. `mbed-bootloader.show-progress-bar`, Set to 1 to print a progress bar for various processes. +1. `mbed-bootloader.max-application-size`, Maximum size of the active application. The default value is `FLASH_START_ADDRESS + FLASH_SIZE - APPLICATION_START_ADDRESS`. Bootloader uses this value to reject candidate image that are too large. ## Flash Layout -### The flash layout for K64F with SOTP and firmware storage on internal flash +### The flash layout for K64F with KVStore and firmware storage on internal flash ``` +--------------------------+ - | LittleFS | - | (Does not concern | - | Bootloader) | update-client.storage-address - +--------------------------+ <-+ + - | | update-client.storage-size + | | | | | | |Firmware Candidate Storage| @@ -78,21 +108,19 @@ User **may** set in `mbed_app.json`: | | +--------------------------+ <-+ update-client.storage-address | | + | KVSTORE | + | | + +--------------------------+ <-+ storage_tdb_internal.internal_base_address + | | | | | | | Active App | | | | | -    |                         | -    +--------------------------+ <-+ application-start-address -    |                         | - |Active App Metadata Header| | | + +--------------------------+ <-+ mbed-bootloader.application-start-address + |Active App Metadata Header| +--------------------------+ <-+ update-client.application-details - | NVSTORE_2 | - +--------------------------+ <-+ nvstore.area_2_address - | NVSTORE_1 | - +--------------------------+ <-+ nvstore.area_1_address | | | Bootloader | | | @@ -101,10 +129,10 @@ User **may** set in `mbed_app.json`: ### Notes on Flash Layout -- Internal Flash Only layout can be enabled by compiling the bootloader with the internal_flash_sotp.json configuration file `--app-config configs/internal_flash_sotp.json`. By default the firmware storage region and filesystem is on [external sd card](#external-storage). +- Internal Flash Only layout can be enabled by compiling the bootloader with the configuration file `--app-config configs/internal_flash_no_rot.json`. By default the firmware storage region and filesystem is on [external sd card](#external-storage). - The default flash layout is tested with GCC_ARM compiler and tiny.json compiler profile only. If a different compiler is used, the bootloader binary size will be larger and the offsets needs to be adjusted. -- The NVSTORE regions require 1 flash erase sector each with at least 1k of space. -- The LittleFS requires 2 flash sectors per folder and 1 sector per file as well as 2 sectors for the filesystem itself. +- The KVSTORE regions require even number of flash erase sectors. If the firmware candidate is stored on internal flash, the bootloader does not access the KVStore. But it still needs to be there for the benefit of the Pelion Device Management Client. +- Some micro-controller chips are designed with 2 banks of flash that can be read from and written to independently from each other. Hence it is a good idea to put your bootloader and active application on bank 1, your kvstore and firmware candidate storage on bank 2. This way when the application writes data to flash, it doesn't need to halt the processor execution to do it. ### Alignment @@ -116,7 +144,7 @@ User **may** set in `mbed_app.json`: ## External Storage -The firmware update candidates can be stored on an external sd card. The firmware is stored sequentially on the block device. The expected layout is as follows: +The firmware update candidates is stored on an external sd card if the default configuration is used. The firmware is stored sequentially on the block device. The expected layout is as follows: ``` +--------------------------+<-+ End of SD card block device | | @@ -140,9 +168,60 @@ The firmware update candidates can be stored on an external sd card. The firmwar | Metadata Header | +--------------------------+ <-+ update-client.storage-address | | - +--------------------------+ <-+ Start of SD card block device (ie 0x0) + +--------------------------+ <-+ Start of SD card block device (i.e. 0x0) ``` ## Debug Debug prints can be turned on by enabling the define `#define tr_debug(fmt, ...) printf("[DBG ] " fmt "\r\n", ##__VA_ARGS__)` in `source/bootloader_common.h` and setting the `ARM_UC_ALL_TRACE_ENABLE=1` macro on command line `mbed compile -DARM_UC_ALL_TRACE_ENABLE=1`. + +## Example config case study + +Scenario: Your target is NUCLEO_F429ZI. You have added extra functionality to the bootloader such that the size of the bootloader exceeded the default 32KiB. How to configure your bootloader and application so that everything still work together. + +### STEP 1: Design flash layout + +NUCLEO_F429ZI has 2MiB of flash, and its sector sizes are as follows: 4x16KiB, 1x64KiB, 7x128KiB, 4x16KiB, 1x64KiB, 7x128KiB. +Because the bootloader is larger than 32KiB, it will take the first 3 sectors. The KVStore area can no longer take 2x16KiB sectors. KVStore require even number of sectors. Hence we will move KVSTORE to the last 2x128KiB sectors in the flash region. So we will end up with the following layout: + +``` +0x08000000 - 0x0800C000 Bootloader +0x0800C000 - 0x0800C400 Application Header +0x0800C400 - 0x081C0000 Application +0x081C0000 - 0x08200000 KVSTORE +``` + +The update firmware candidate is still stored on sd-card. + +### STEP 2: Configure the bootloader + +Given the above flash layout the following configuration need to change in the mbed_app.json: + +1. `"storage_filesystem.internal_base_address": "(0x08000000+(2*1024-2*128)*1024)"` +1. `"storage_filesystem.rbp_internal_size": "(2*128*1024)"` +1. `"update-client.application-details": "(0x08000000+3*16*1024)"` +1. `"mbed-bootloader.application-start-address": "(0x08000000+(3*16+1)*1024)"` +1. `"mbed-bootloader.max-application-size" : "((1024*2-128*2-3*16-1)*1024)"` + +Now compile your bootloader. Flash and run the bootloader, on the serial UART you will see the following printout: + +> Layout: + +Keep a note of the `boot_loader_info_address` which we will use in the next step. + +### STEP 3: Configure the Pelion Cloud Client Application + +In mbed_app.json, change the following: + +1. `"update-client.application-details" : "(0x08000000+3*16*1024)"` +1. `"update-client.bootloader-details" : ""` + +Change the following in mbed_app.json: + +1. `"storage_filesystem.internal_base_address": "(0x08000000+(2*1024-2*128)*1024)"` +1. `"storage_filesystem.rbp_internal_size": "(2*128*1024)"` +1. `"target.app_offset": "0x800c400",` +1. `"target.header_offset": "0x800c000",` +1. `"target.bootloader_img": ""` + +Now you can build the application following the [Pelion Device Management Platform Documentation](https://cloud.mbed.com/docs/current/updating-firmware/updating-end-to-end-tutorials.html). diff --git a/configs/block_device_fake_rot.json b/configs/block_device_fake_rot.json new file mode 100644 index 0000000..7da6502 --- /dev/null +++ b/configs/block_device_fake_rot.json @@ -0,0 +1,106 @@ +{ + "config": { + "documentation": { + "options": [ + "In this configuration:", + "- Firmware storage is on an external SD card block device", + "- Root of Trust is hard coded and insecure", + "The flash regions are as follows:", + "1. Bootloader - 32KiB from the beginning of flash", + "4. KVSTORE - 2 flash sectors immediately following the bootloader", + "2. Active App Metadata Header - (1KiB/2KiB) from the end of KVSTORE", + "3. Active App - From end of header to the end of flash", + "+--------------------------+", + "| |", + "| |", + "| |", + "| Active App |", + "| |", + "| |", + "| |", + "+--------------------------+ <-+ mbed-bootloader.application-start-address", + "|Active App Metadata Header|", + "+--------------------------+ <-+ update-client.application-details", + "| |", + "| KVSTORE |", + "| |", + "+--------------------------+ <-+ storage_tdb_internal.internal_base_address", + "| |", + "| Bootloader |", + "| |", + "+--------------------------+ <-+ 0", + "Firmware Candidate Storage is on external SD Card at an offset of 64 MiB.", + "The storage size is the size of the maximum application size (i.e. Active", + "Application region size) multiplied by the number of storage-locations.", + "(storage-locations is set to 1 in this configuration)", + "Because the root of trust is hard code, the bootloader does not use the", + "kvstore the kvstore region here is purely for the benefit of Pelion Device", + "Management Client" + ] + } + }, + "macros": [ + "ARM_UC_USE_PAL_BLOCKDEVICE=1", + "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP_BLOCKDEVICE" + ], + "target_overrides": { + "*": { + "platform.stdio-baud-rate" : 115200, + "platform.stdio-flush-at-exit" : false, + "update-client.firmware-header-version": "2", + "target.components_add" : ["SD"], + "sd.CRC_ENABLED" : 0, + "mbed-bootloader.use-kvstore-rot" : 0, + "update-client.storage-address" : "(1024*1024*64)", + "update-client.storage-size" : "((MBED_ROM_START + MBED_ROM_SIZE - MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS) * MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS)", + "update-client.storage-locations" : 1 + }, + "NRF52_DK": { + "sd.SPI_CS" : "SPI_PSELSS0", + "sd.SPI_MOSI" : "SPI_PSELMOSI0", + "sd.SPI_MISO" : "SPI_PSELMISO0", + "sd.SPI_CLK" : "SPI_PSELSCK0", + "minimal-printf.console-output" : "SWO", + "target.app_offset" : "0x74000", + "update-client.application-details" : "(508*1024)", + "mbed-bootloader.application-start-address": "(152*1024)", + "mbed-bootloader.max-application-size" : "((456-152)*1024)", + "update-client.storage-page" : 512, + "target.extra_labels_remove" : ["SOFTDEVICE_S132_FULL", "SOFTDEVICE_COMMON"], + "target.extra_labels_add" : ["SOFTDEVICE_S132_MBR"] + }, + "K64F": { + "update-client.application-details" : "(MBED_ROM_START+40*1024)", + "mbed-bootloader.application-start-address": "(MBED_ROM_START+41*1024)" + }, + "K66F": { + "update-client.application-details" : "(MBED_ROM_START+40*1024)", + "mbed-bootloader.application-start-address": "(MBED_ROM_START+41*1024)" + }, + "KW24D": { + "update-client.application-details" : "(MBED_ROM_START+36*1024)", + "mbed-bootloader.application-start-address": "(MBED_ROM_START+37*1024)" + }, + "NUCLEO_L476RG": { + "update-client.application-details" : "(MBED_ROM_START+36*1024)", + "mbed-bootloader.application-start-address": "(MBED_ROM_START+38*1024)" + }, + "DISCO_L476VG": { + "update-client.application-details" : "(MBED_ROM_START+36*1024)", + "mbed-bootloader.application-start-address": "(MBED_ROM_START+38*1024)" + }, + "NUCLEO_F429ZI": { + "update-client.application-details" : "(MBED_ROM_START+64*1024)", + "mbed-bootloader.application-start-address": "(MBED_ROM_START+65*1024)" + }, + "UBLOX_EVK_ODIN_W2": { + "target.device_has_remove": ["EMAC"], + "update-client.application-details" : "(MBED_ROM_START+64*1024)", + "mbed-bootloader.application-start-address": "(MBED_ROM_START+65*1024)" + }, + "UBLOX_C030_U201": { + "update-client.application-details" : "(MBED_ROM_START+64*1024)", + "mbed-bootloader.application-start-address": "(MBED_ROM_START+65*1024)" + } + } +} diff --git a/configs/internal_flash_fake_rot.json b/configs/internal_flash_fake_rot.json deleted file mode 100755 index e01c31b..0000000 --- a/configs/internal_flash_fake_rot.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "macros": [ - "MBEDTLS_USER_CONFIG_FILE=\"bootloader_mbedtls_user_config.h\"", - "PAL_USER_DEFINED_CONFIGURATION=\"bootloader_pal_user_config.h\"", - "MAX_COPY_RETRIES=1", - "SHOW_PROGRESS_BAR=1", - "MAX_BOOT_RETRIES=3", - "ARM_UC_USE_PAL_CRYPTO=0", - "ARM_UC_PROFILE_MBED_CLOUD_CLIENT=1", - "ARM_UC_FEATURE_CRYPTO_PAL=0", - "ARM_UC_FEATURE_CRYPTO_MBEDTLS=1", - "ARM_BOOTLOADER_USE_NVSTORE_ROT=0", - "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP", - "Mutex=PlatformMutex" - ], - "config": { - "application-start-address": { - "help": "Address of the active application firmware in flash", - "value": null - }, - "max-application-size": { - "help": "Maximum size of the active application", - "value": null - } - }, - "target_overrides": { - "*": { - "target.features_remove": ["LWIP", "STORAGE"], - "platform.stdio-baud-rate": 115200, - "platform.stdio-flush-at-exit": false, - "update-client.firmware-header-version": "2" - }, - "K64F": { - "update-client.application-details": "( 40*1024)", - "application-start-address" : "( 41*1024)", - "max-application-size" : "(MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS-MBED_CONF_APP_APPLICATION_START_ADDRESS)", - "update-client.storage-address" : "(436*1024)", - "update-client.storage-size" : "(388*1024)", - "update-client.storage-locations" : 1, - "update-client.storage-page" : 8 - }, - "NUCLEO_F429ZI": { - "update-client.application-details": "(0x08000000+64*1024)", - "application-start-address" : "(0x08000000+65*1024)", - "max-application-size" : "(MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS-MBED_CONF_APP_APPLICATION_START_ADDRESS)", - "update-client.storage-address" : "(0x08000000+1024*1024)", - "update-client.storage-size" : "(512*1024)", - "update-client.storage-locations" : 1, - "update-client.storage-page" : 1 - }, - "NUCLEO_F303RE": { - "update-client.application-details": "(0x08000000+36*1024)", - "application-start-address" : "(0x08000000+37*1024)", - "max-application-size" : "(MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS-MBED_CONF_APP_APPLICATION_START_ADDRESS)", - "update-client.storage-address" : "(0x08000000+(256+18)*1024)", - "update-client.storage-size" : "((256-18)*1024)", - "update-client.storage-locations" : 1, - "update-client.storage-page" : 4 - } - } -} diff --git a/configs/internal_flash_no_rot.json b/configs/internal_flash_no_rot.json new file mode 100755 index 0000000..aa336c4 --- /dev/null +++ b/configs/internal_flash_no_rot.json @@ -0,0 +1,89 @@ +{ + "config": { + "documentation": { + "options": [ + "This configuration takes advantage of the fact that most MCUs have 2 banks of flash", + "which can be read from and written to independently of each other. Hence we put all", + "executables on the first bank, and all storage on the second bank such that reading", + "and writing storage does not halt execution. The regions are as follows:", + "1. Bootloader - 32kb from the beginning of flash", + "2. Active App Metadata Header - 1kb from the end of Bootloader", + "3. Active App - From end of header to the end of first bank of flash", + "4. KVSTORE - KVSTORE_SIZE from the beginning of the second bank of flash", + "5. Firmware Candidate Storage - The rest of the second bank of flash", + "+--------------------------+", + "| |", + "| |", + "| |", + "|Firmware Candidate Storage|", + "| |", + "| |", + "| |", + "+--------------------------+ <-+ update-client.storage-address", + "| |", + "| KVSTORE |", + "| |", + "+--------------------------+ <-+ storage_tdb_internal.internal_base_address", + "| |", + "| |", + "| |", + "| Active App |", + "| |", + "| |", + "| |", + "+--------------------------+ <-+ mbed-bootloader.application-start-address", + "|Active App Metadata Header|", + "+--------------------------+ <-+ update-client.application-details", + "| |", + "| Bootloader |", + "| |", + "+--------------------------+ <-+ 0", + "Please note that because the firmware candidate is stored on internal flash, the", + "bootloader does not require a rot to operate. Hence the KVSTORE region is there for", + "the benefit of Pelion Device Management Client only" + ] + }, + "kvstore-size": { + "help": "The size of the area of flash reserved for kvstore, it neeeds to be even number of flash sectors", + "macro_name": "KVSTORE_SIZE", + "required": true + } + }, + "macros": [ + "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP", + "MBED_BOOTLOADER_SIZE=APPLICATION_SIZE", + "MBED_BOOTLOADER_ACTIVE_HEADER_REGION_SIZE=1024", + "FLASH_BANK_SIZE=MBED_ROM_SIZE/2" + ], + "target_overrides": { + "*": { + "platform.stdio-baud-rate": 115200, + "platform.stdio-flush-at-exit": false, + "update-client.firmware-header-version": "2", + "mbed-bootloader.use-kvstore-rot": 0, + "target.restrict_size": "0x8000", + "update-client.application-details" : "(MBED_ROM_START + MBED_BOOTLOADER_SIZE)", + "mbed-bootloader.application-start-address": "(MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS + MBED_BOOTLOADER_ACTIVE_HEADER_REGION_SIZE)", + "mbed-bootloader.max-application-size" : "(MBED_ROM_START + FLASH_BANK_SIZE - MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS)", + "update-client.storage-address" : "(MBED_ROM_START + FLASH_BANK_SIZE + KVSTORE_SIZE)", + "update-client.storage-size" : "(FLASH_BANK_SIZE - KVSTORE_SIZE)", + "update-client.storage-locations" : 1 + }, + "K64F": { + "kvstore-size": "2*24*1024", + "update-client.storage-page": 8 + }, + "K66F": { + "kvstore-size": "2*48*1024", + "update-client.storage-page": 8 + }, + "NUCLEO_F429ZI": { + "kvstore-size": "2*64*1024", + "update-client.storage-page": 1 + }, + "NUCLEO_F303RE": { + "kvstore-size": "2*24*1024", + "update-client.storage-page": 1 + } + } +} diff --git a/configs/internal_flash_nvstore.json b/configs/internal_flash_nvstore.json deleted file mode 100755 index 7e613b2..0000000 --- a/configs/internal_flash_nvstore.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "macros": [ - "MBEDTLS_USER_CONFIG_FILE=\"bootloader_mbedtls_user_config.h\"", - "PAL_USER_DEFINED_CONFIGURATION=\"bootloader_pal_user_config.h\"", - "MAX_COPY_RETRIES=1", - "SHOW_PROGRESS_BAR=1", - "MAX_BOOT_RETRIES=3", - "ARM_UC_USE_PAL_CRYPTO=0", - "ARM_UC_PROFILE_MBED_CLOUD_CLIENT=1", - "ARM_UC_FEATURE_CRYPTO_PAL=0", - "ARM_UC_FEATURE_CRYPTO_MBEDTLS=1", - "ARM_BOOTLOADER_USE_NVSTORE_ROT=1", - "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP", - "Mutex=PlatformMutex" - ], - "config": { - "application-start-address": { - "help": "Address of the active application firmware in flash", - "value": null - }, - "max-application-size": { - "help": "Maximum size of the active application", - "value": null - } - }, - "target_overrides": { - "*": { - "target.features_remove": ["LWIP", "STORAGE"], - "platform.stdio-baud-rate": 115200, - "platform.stdio-flush-at-exit": false, - "update-client.firmware-header-version": "2" - }, - "K64F": { - "nvstore.area_1_address" : "( 32*1024)", - "nvstore.area_1_size" : "( 4*1024)", - "nvstore.area_2_address" : "( 36*1024)", - "nvstore.area_2_size" : "( 4*1024)", - "update-client.application-details": "( 40*1024)", - "application-start-address" : "( 41*1024)", - "max-application-size" : "(MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS-MBED_CONF_APP_APPLICATION_START_ADDRESS)", - "update-client.storage-address" : "(532*1024)", - "update-client.storage-size" : "(492*1024)", - "update-client.storage-locations" : 1, - "update-client.storage-page" : 8 - } - } -} diff --git a/configs/nrf52_block_device_fake_rot.json b/configs/nrf52_block_device_fake_rot.json deleted file mode 100644 index adbf796..0000000 --- a/configs/nrf52_block_device_fake_rot.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "macros": [ - "MBEDTLS_USER_CONFIG_FILE=\"bootloader_mbedtls_user_config.h\"", - "PAL_USER_DEFINED_CONFIGURATION=\"bootloader_pal_user_config.h\"", - "MAX_COPY_RETRIES=1", - "SHOW_PROGRESS_BAR=1", - "MAX_BOOT_RETRIES=3", - "ARM_UC_USE_PAL_CRYPTO=0", - "ARM_UC_PROFILE_MBED_CLIENT_LITE=1", - "ARM_UC_FEATURE_CRYPTO_PAL=0", - "ARM_UC_FEATURE_CRYPTO_MBEDTLS=1", - "ARM_BOOTLOADER_USE_NVSTORE_ROT=0", - "ARM_UC_USE_PAL_BLOCKDEVICE=1", - "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP_BLOCKDEVICE", - "Mutex=PlatformMutex" - ], - "config": { - "application-start-address": { - "help": "Address of the active application firmware in flash", - "value": null - }, - "max-application-size": { - "help": "Maximum size of the active application", - "value": null - } - }, - "target_overrides": { - "*": { - "target.features_remove": ["LWIP", "STORAGE"], - "platform.stdio-baud-rate": 115200, - "platform.stdio-flush-at-exit": false, - "update-client.firmware-header-version": "2" - }, - "NRF52_DK": { - "minimal-printf.console-output" : "SWO", - "target.app_offset" : "0x74000", - "update-client.application-details" : "(508*1024)", - "application-start-address" : "(152*1024)", - "max-application-size" : "((456-152)*1024)", - "update-client.storage-address" : "(64*1024*1024)", - "update-client.storage-size" : "(2*1024*1024)", - "update-client.storage-locations" : 1, - "update-client.storage-page" : 512, - "target.extra_labels_remove" : ["SOFTDEVICE_S132_FULL", "SOFTDEVICE_COMMON"], - "target.extra_labels_add" : ["SOFTDEVICE_S132_MBR"] - } - } -} diff --git a/configs/nrf52_internal_flash_fake_rot.json b/configs/nrf52_internal_flash_fake_rot.json deleted file mode 100644 index 7edfc57..0000000 --- a/configs/nrf52_internal_flash_fake_rot.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "macros": [ - "MBEDTLS_USER_CONFIG_FILE=\"bootloader_mbedtls_user_config.h\"", - "PAL_USER_DEFINED_CONFIGURATION=\"bootloader_pal_user_config.h\"", - "MAX_COPY_RETRIES=1", - "SHOW_PROGRESS_BAR=1", - "MAX_BOOT_RETRIES=3", - "ARM_UC_USE_PAL_CRYPTO=0", - "ARM_UC_PROFILE_MBED_CLIENT_LITE=1", - "ARM_UC_FEATURE_CRYPTO_PAL=0", - "ARM_UC_FEATURE_CRYPTO_MBEDTLS=1", - "ARM_BOOTLOADER_USE_NVSTORE_ROT=0", - "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP", - "Mutex=PlatformMutex" - ], - "config": { - "application-start-address": { - "help": "Address of the active application firmware in flash", - "value": null - }, - "max-application-size": { - "help": "Maximum size of the active application", - "value": null - } - }, - "target_overrides": { - "*": { - "target.features_remove": ["LWIP", "STORAGE"], - "platform.stdio-baud-rate": 115200, - "platform.stdio-flush-at-exit": false, - "update-client.firmware-header-version": "2" - }, - "NRF52_DK": { - "minimal-printf.console-output" : "SWO", - "target.app_offset" : "0x74000", - "update-client.application-details" : "(508*1024)", - "application-start-address" : "(4*1024)", - "max-application-size" : "(232*1024)", - "update-client.storage-address" : "(236*1024)", - "update-client.storage-size" : "(228*1024)", - "update-client.storage-locations" : 1, - "update-client.storage-page" : 4, - "target.extra_labels_remove" : ["SOFTDEVICE_S132_FULL", "SOFTDEVICE_COMMON"], - "target.extra_labels_add" : ["SOFTDEVICE_S132_MBR"] - } - } -} diff --git a/mbed-cloud-client.lib b/mbed-cloud-client.lib deleted file mode 100644 index 71a3dd6..0000000 --- a/mbed-cloud-client.lib +++ /dev/null @@ -1 +0,0 @@ -https://github.com/ARMmbed/mbed-cloud-client/#62de4b89d2350379278893f2f7a3ac937b4ae5f6 diff --git a/mbed-os.lib b/mbed-os.lib index 53a35da..efedfa8 100644 --- a/mbed-os.lib +++ b/mbed-os.lib @@ -1 +1 @@ -https://github.com/ARMmbed/mbed-os/#610e35ddc6d59f153173c1e7b2748cf96d6c9bcd +https://github.com/ARMmbed/mbed-os/#51d55508e8400b60af467005646c4e2164738d48 diff --git a/mbed_app.json b/mbed_app.json index 2d4b85a..44e6df2 100755 --- a/mbed_app.json +++ b/mbed_app.json @@ -1,210 +1,130 @@ { + "config": { + "documentation": { + "options": [ + "In this configuration:", + "- Firmware storage is on an external SD card block device", + "- Root of Trust is obtain from internal flash in kvstore", + "The flash regions are as follows:", + "1. Bootloader - 32KiB from the beginning of flash", + "4. KVSTORE - 2 flash sectors immediately following the bootloader", + "2. Active App Metadata Header - (1KiB/2KiB) from the end of KVSTORE", + "3. Active App - From end of header to the end of flash", + "+--------------------------+", + "| |", + "| |", + "| |", + "| Active App |", + "| |", + "| |", + "| |", + "+--------------------------+ <-+ mbed-bootloader.application-start-address", + "|Active App Metadata Header|", + "+--------------------------+ <-+ update-client.application-details", + "| |", + "| KVSTORE |", + "| |", + "+--------------------------+ <-+ storage_tdb_internal.internal_base_address", + "| |", + "| Bootloader |", + "| |", + "+--------------------------+ <-+ 0", + "Firmware Candidate Storage is on external SD Card at an offset of 64 MiB.", + "The storage size is the size of the maximum application size (i.e. Active", + "Application region size) multiplied by the number of storage-locations.", + "(storage-locations is set to 1 in this configuration)", + "Please note the config for NRF52840_DK is different. The kvstore region is", + "at the end of flash" + ] + } + }, "macros": [ - "MBEDTLS_USER_CONFIG_FILE=\"bootloader_mbedtls_user_config.h\"", - "MAX_COPY_RETRIES=1", - "SHOW_PROGRESS_BAR=1", - "MAX_BOOT_RETRIES=3", - "ARM_UC_USE_PAL_CRYPTO=0", - "ARM_BOOTLOADER_USE_NVSTORE_ROT=1", "ARM_UC_USE_PAL_BLOCKDEVICE=1", - "ARM_UC_PAAL_TRACE_ENABLE=0", "MBED_CLOUD_CLIENT_UPDATE_STORAGE=ARM_UCP_FLASHIAP_BLOCKDEVICE", - "DEFAULT_MAX_APPLICATION_SIZE=(MBED_CONF_APP_FLASH_START_ADDRESS + MBED_CONF_APP_FLASH_SIZE - MBED_CONF_APP_APPLICATION_START_ADDRESS)", - "DISABLE_ERROR_DESCRIPTION=1", - "ARM_UC_PROFILE_MBED_CLOUD_CLIENT=1", - "ARM_UC_FEATURE_CRYPTO_PAL=0", - "ARM_UC_FEATURE_CRYPTO_MBEDTLS=1", - "Mutex=PlatformMutex" + "MBED_BOOTLOADER_SIZE=(32*1024)", + "MBED_BOOTLOADER_ACTIVE_HEADER_REGION_SIZE=1024" ], - "config": { - "application-start-address": { - "help": "Address to the beginning of the active application firmware in flash", - "value": null - }, - "application-jump-address": { - "help": "Jump address for running the active application firmware", - "value": null - }, - "max-application-size": { - "help": "Maximum size of the active application", - "value": null - }, - "flash-start-address": { - "help": "Start address of internal flash. Only used in this config to help the definition of other macros.", - "value": null - }, - "flash-size": { - "help": "Total size of internal flash. Only used in this config to help the definition of other macros.", - "value": null - } - }, "target_overrides": { "*": { - "target.features_remove": ["LWIP", "STORAGE"], - "platform.stdio-baud-rate" : 115200, - "platform.stdio-flush-at-exit": false, - "update-client.storage-address" : "(1024*1024*64)", - "update-client.storage-size" : "(1024*1024*2)", - "update-client.storage-locations": 1, - "update-client.firmware-header-version": "2" + "platform.use-mpu" : false, + "platform.stdio-baud-rate" : 115200, + "platform.stdio-flush-at-exit" : false, + "update-client.storage-address" : "(1024*1024*64)", + "update-client.storage-size" : "((MBED_ROM_START + MBED_ROM_SIZE - MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS) * MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS)", + "update-client.storage-locations" : 1, + "update-client.firmware-header-version" : "2", + "target.components_add" : ["SD"], + "sd.CRC_ENABLED" : 0, + "storage.storage_type" : "FILESYSTEM", + "storage_filesystem.internal_base_address" : "(MBED_ROM_START + MBED_BOOTLOADER_SIZE)", + "update-client.application-details" : "(MBED_CONF_STORAGE_FILESYSTEM_INTERNAL_BASE_ADDRESS + MBED_CONF_STORAGE_FILESYSTEM_RBP_INTERNAL_SIZE)", + "mbed-bootloader.application-start-address": "(MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS + MBED_BOOTLOADER_ACTIVE_HEADER_REGION_SIZE)" }, "K64F": { - "flash-start-address" : "0x0", - "flash-size" : "(1024*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+32*1024)", - "nvstore.area_1_size" : "(4*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+36*1024)", - "nvstore.area_2_size" : "(4*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+40*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+41*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + "storage_filesystem.rbp_internal_size" : "(2*4*1024)" }, "K66F": { - "flash-start-address" : "0x0", - "flash-size" : "(2048*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+32*1024)", - "nvstore.area_1_size" : "(4*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+36*1024)", - "nvstore.area_2_size" : "(4*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+40*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+41*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + "storage_filesystem.rbp_internal_size" : "(2*4*1024)" }, "KW24D": { - "flash-start-address" : "0x0", - "flash-size" : "(512*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+32*1024)", - "nvstore.area_1_size" : "(2*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+34*1024)", - "nvstore.area_2_size" : "(2*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+36*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+37*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + "storage_filesystem.rbp_internal_size" : "(2*2*1024)", + "sd.SPI_CS" : "PTC4", + "sd.SPI_MOSI" : "PTC6", + "sd.SPI_MISO" : "PTC7", + "sd.SPI_CLK" : "PTC5" }, "NUCLEO_L476RG": { - "flash-start-address" : "0x08000000", - "flash-size" : "(1024*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+32*1024)", - "nvstore.area_1_size" : "(2*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+34*1024)", - "nvstore.area_2_size" : "(2*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+36*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+38*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + "storage_filesystem.rbp_internal_size" : "(2*2*1024)", + "mbed-bootloader.application-start-address": "(MBED_ROM_START+38*1024)" }, "DISCO_L476VG": { - "flash-start-address" : "0x08000000", - "flash-size" : "(1024*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+32*1024)", - "nvstore.area_1_size" : "(2*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+34*1024)", - "nvstore.area_2_size" : "(2*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+36*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+38*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + "storage_filesystem.rbp_internal_size" : "(2*2*1024)", + "mbed-bootloader.application-start-address": "(MBED_ROM_START+38*1024)" }, "DISCO_L475VG_IOT01A": { - "flash-start-address" : "0x08000000", - "flash-size" : "(1024*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+32*1024)", - "nvstore.area_1_size" : "(2*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+34*1024)", - "nvstore.area_2_size" : "(2*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+36*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+38*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + "storage_filesystem.rbp_internal_size" : "(2*2*1024)", + "mbed-bootloader.application-start-address": "(MBED_ROM_START+38*1024)" }, "NUCLEO_F411RE": { - "flash-start-address" : "0x08000000", - "flash-size" : "(512*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+32*1024)", - "nvstore.area_1_size" : "(16*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+48*1024)", - "nvstore.area_2_size" : "(16*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+64*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+65*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE", - "sd.SPI_CS" : "PB_9", - "sd.SPI_MOSI" : "PC_3", - "sd.SPI_MISO" : "PC_2", - "sd.SPI_CLK" : "PC_7" + "storage_filesystem.rbp_internal_size" : "(2*16*1024)", + "sd.SPI_CS" : "PB_9", + "sd.SPI_MOSI" : "PC_3", + "sd.SPI_MISO" : "PC_2", + "sd.SPI_CLK" : "PC_7" }, "NUCLEO_F429ZI": { - "flash-start-address" : "0x08000000", - "flash-size" : "(2048*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+32*1024)", - "nvstore.area_1_size" : "(16*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+48*1024)", - "nvstore.area_2_size" : "(16*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+64*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+65*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + "storage_filesystem.rbp_internal_size" : "(2*16*1024)" }, "NUCLEO_F207ZG": { - "flash-start-address" : "0x08000000", - "flash-size" : "(1024*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+32*1024)", - "nvstore.area_1_size" : "(16*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+48*1024)", - "nvstore.area_2_size" : "(16*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+64*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+65*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE", - "sd.SPI_MOSI": "PC_12", - "sd.SPI_MISO": "PC_11", - "sd.SPI_CLK": "PC_10", - "sd.SPI_CS": "PA_15" + "storage_filesystem.rbp_internal_size" : "(2*16*1024)", + "sd.SPI_MOSI" : "PC_12", + "sd.SPI_MISO" : "PC_11", + "sd.SPI_CLK" : "PC_10", + "sd.SPI_CS" : "PA_15" }, "UBLOX_EVK_ODIN_W2": { "target.device_has_remove": ["EMAC"], - "flash-start-address" : "0x08000000", - "flash-size" : "(2048*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+32*1024)", - "nvstore.area_1_size" : "(16*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+48*1024)", - "nvstore.area_2_size" : "(16*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+64*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+65*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + "storage_filesystem.rbp_internal_size" : "(2*16*1024)" }, "UBLOX_C030_U201": { - "flash-start-address" : "0x08000000", - "flash-size" : "(1024*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+32*1024)", - "nvstore.area_1_size" : "(16*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+48*1024)", - "nvstore.area_2_size" : "(16*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+64*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+65*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE" + "storage_filesystem.rbp_internal_size" : "(2*16*1024)" }, "NRF52840_DK": { - "flash-start-address" : "0x0", - "flash-size" : "(1024*1024)", - "nvstore.area_1_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+1024*1016)", - "nvstore.area_1_size" : "(4*1024)", - "nvstore.area_2_address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+1024*1020)", - "nvstore.area_2_size" : "(4*1024)", - "update-client.application-details": "(MBED_CONF_APP_FLASH_START_ADDRESS+236*1024)", - "application-start-address" : "(MBED_CONF_APP_FLASH_START_ADDRESS+237*1024)", - "max-application-size" : "DEFAULT_MAX_APPLICATION_SIZE", - "target.OUTPUT_EXT" : "hex", - "update-client.storage-address" : "(1024*1024*1)", - "update-client.storage-size" : "(1024*1024*1)", - "update-client.storage-locations" : 1, - "update-client.storage-page" : 1, - "target.features_remove": [ - "CRYPTOCELL310" - ], - "target.macros_remove": [ - "MBEDTLS_CONFIG_HW_SUPPORT" - ], - "target.macros_add": [ - "PAL_USE_INTERNAL_FLASH=1", - "PAL_USE_HW_ROT=0", - "PAL_USE_HW_RTC=0", - "PAL_INT_FLASH_NUM_SECTIONS=2" - ] + "storage_filesystem.internal_base_address" : "(1016*1024)", + "storage_filesystem.rbp_internal_size" : "(2*4*1024)", + "update-client.application-details" : "(236*1024)", + "mbed-bootloader.max-application-size" : "MBED_CONF_STORAGE_FILESYSTEM_INTERNAL_BASE_ADDRESS - MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS", + "target.OUTPUT_EXT" : "hex", + "update-client.storage-address" : "(1024*1024*1)", + "update-client.storage-size" : "(1024*1024*1)", + "update-client.storage-locations" : 1, + "update-client.storage-page" : 1, + "sd.SPI_CS" : "A0", + "sd.SPI_MOSI" : "A1", + "sd.SPI_MISO" : "A2", + "sd.SPI_CLK" : "A3", + "target.features_remove" : ["CRYPTOCELL310"], + "target.macros_remove" : ["MBEDTLS_CONFIG_HW_SUPPORT"] } } } diff --git a/mbed_lib.json b/mbed_lib.json new file mode 100644 index 0000000..cbb9218 --- /dev/null +++ b/mbed_lib.json @@ -0,0 +1,51 @@ +{ + "name": "mbed-bootloader", + "config": { + "application-start-address": { + "help": "Address to the beginning of the active application firmware in flash", + "required": true + }, + "application-jump-address": { + "help": "Jump address for running the active application firmware (if different from application-start-address)" + }, + "max-application-size": { + "help": "Maximum size of the active application", + "value": "DEFAULT_MAX_APPLICATION_SIZE" + }, + "max-copy-retries": { + "help": "number of retries for copying candidate image onto the active image area", + "value": 1, + "macro_name": "MAX_COPY_RETRIES" + }, + "max-boot-retries": { + "help": "number of retries for booting into the active image", + "value": 3, + "macro_name": "MAX_BOOT_RETRIES" + }, + "show-progress-bar": { + "help": "show a progress bar during various stages of bootloader operation", + "value": 1, + "macro_name": "SHOW_PROGRESS_BAR" + }, + "use-kvstore-rot": { + "help": "use nvstore implementation of the ROT to authenticate firmware headers", + "value": 1, + "macro_name": "ARM_BOOTLOADER_USE_KVSTORE_ROT" + } + }, + "macros": [ + "MBED_FAULT_HANDLER_DISABLED", + "MBEDTLS_USER_CONFIG_FILE=\"bootloader_mbedtls_user_config.h\"", + "DEFAULT_MAX_APPLICATION_SIZE=(MBED_ROM_START + MBED_ROM_SIZE - MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS)", + "ARM_UC_PROFILE_MBED_CLOUD_CLIENT=1", + "ARM_UC_FEATURE_CRYPTO_PAL=0", + "ARM_UC_FEATURE_CRYPTO_MBEDTLS=1", + "Mutex=PlatformMutex", + "ARM_UC_PAAL_TRACE_ENABLE=0" + ], + "target_overrides": { + "*": { + "target.features_remove": ["LWIP", "STORAGE"] + } + } +} diff --git a/modules/metadata-header/source/arm_uc_buffer_utilities.c b/modules/metadata-header/source/arm_uc_buffer_utilities.c new file mode 100644 index 0000000..e57919a --- /dev/null +++ b/modules/metadata-header/source/arm_uc_buffer_utilities.c @@ -0,0 +1,115 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-metadata-header/arm_uc_buffer_utilities.h" + + +uint32_t arm_uc_crc32(const uint8_t *buffer, uint32_t length) +{ + const uint8_t *current = buffer; + uint32_t crc = 0xFFFFFFFF; + + while (length--) { + crc ^= *current++; + + for (uint32_t counter = 0; counter < 8; counter++) { + if (crc & 1) { + crc = (crc >> 1) ^ 0xEDB88320; + } else { + crc = crc >> 1; + } + } + } + + return (crc ^ 0xFFFFFFFF); +} + +uint32_t arm_uc_parse_uint32(const uint8_t *input) +{ + uint32_t result = 0; + + if (input) { + result = input[0]; + result = (result << 8) | input[1]; + result = (result << 8) | input[2]; + result = (result << 8) | input[3]; + } + + return result; +} + +uint64_t arm_uc_parse_uint64(const uint8_t *input) +{ + uint64_t result = 0; + + if (input) { + result = input[0]; + result = (result << 8) | input[1]; + result = (result << 8) | input[2]; + result = (result << 8) | input[3]; + result = (result << 8) | input[4]; + result = (result << 8) | input[5]; + result = (result << 8) | input[6]; + result = (result << 8) | input[7]; + } + + return result; +} + +void arm_uc_write_uint32(uint8_t *buffer, uint32_t value) +{ + if (buffer) { + buffer[3] = value; + buffer[2] = (value >> 8); + buffer[1] = (value >> 16); + buffer[0] = (value >> 24); + } +} + +void arm_uc_write_uint64(uint8_t *buffer, uint64_t value) +{ + if (buffer) { + buffer[7] = value; + buffer[6] = (value >> 8); + buffer[5] = (value >> 16); + buffer[4] = (value >> 24); + buffer[3] = (value >> 32); + buffer[2] = (value >> 40); + buffer[1] = (value >> 48); + buffer[0] = (value >> 56); + } +} + +// Constant time binary comparison +uint32_t ARM_UC_BinCompareCT(const arm_uc_buffer_t *a, const arm_uc_buffer_t *b) +{ + uint32_t result; + uint32_t i; + const uint32_t bytes = a->size; + + // Check sizes + if (a->size != b->size) { + return 1; + } + result = 0; + for (i = 0; i < bytes; i++) { + result = result | (a->ptr[i] ^ b->ptr[i]); + } + // Reduce to 0 or 1 in constant time + return (result | -result) >> 31; +} diff --git a/modules/metadata-header/source/arm_uc_crypto_hmac_mbedtls.c b/modules/metadata-header/source/arm_uc_crypto_hmac_mbedtls.c new file mode 100644 index 0000000..67777cb --- /dev/null +++ b/modules/metadata-header/source/arm_uc_crypto_hmac_mbedtls.c @@ -0,0 +1,48 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-common/arm_uc_types.h" +#include "update-client-common/arm_uc_error.h" +#include + +#include "arm_uc_config.h" +#if defined(ARM_UC_FEATURE_CRYPTO_MBEDTLS) && (ARM_UC_FEATURE_CRYPTO_MBEDTLS == 1) +#include "mbedtls/md_internal.h" + +arm_uc_error_t ARM_UC_cryptoHMACSHA256(arm_uc_buffer_t *key, + arm_uc_buffer_t *input, + arm_uc_buffer_t *output) +{ + arm_uc_error_t result = (arm_uc_error_t) { ARM_UC_CU_ERR_INVALID_PARAMETER }; + + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + if (md_info != NULL) { + int8_t rv = mbedtls_md_hmac(md_info, + key->ptr, key->size, + input->ptr, input->size, + output->ptr); + if (rv == 0) { + output->size = ARM_UC_SHA256_SIZE; + result = (arm_uc_error_t) { ERR_NONE }; + } + } + + return result; +} + +#endif diff --git a/modules/metadata-header/source/arm_uc_metadata_header_v2.c b/modules/metadata-header/source/arm_uc_metadata_header_v2.c new file mode 100644 index 0000000..26d37cb --- /dev/null +++ b/modules/metadata-header/source/arm_uc_metadata_header_v2.c @@ -0,0 +1,280 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-metadata-header/arm_uc_metadata_header_v2.h" +#include "update-client-metadata-header/arm_uc_buffer_utilities.h" +#include + +extern arm_uc_error_t ARM_UC_cryptoHMACSHA256(arm_uc_buffer_t *key, arm_uc_buffer_t *input, arm_uc_buffer_t *output); + +arm_uc_error_t ARM_UC_getDeviceKey256Bit(arm_uc_buffer_t *output) +{ + arm_uc_error_t result = (arm_uc_error_t) { ARM_UC_CU_ERR_INVALID_PARAMETER }; + + if (output->size_max >= ARM_UC_DEVICE_KEY_SIZE) { + int8_t rv = mbed_cloud_client_get_rot_128bit(output->ptr, output->size_max); + if (rv == 0) { + arm_uc_buffer_t input = { + .size_max = ARM_UC_DEVICE_HMAC_KEY_SIZE, + .size = ARM_UC_DEVICE_HMAC_KEY_SIZE, + .ptr = (uint8_t *) &ARM_UC_DEVICE_HMAC_KEY + }; + output->size = ARM_UC_ROT_SIZE; +#if defined(PAL_DEVICE_KEY_DERIVATION_BACKWARD_COMPATIBILITY_CALC) && \ + (PAL_DEVICE_KEY_DERIVATION_BACKWARD_COMPATIBILITY_CALC == 1) + result = ARM_UC_cryptoHMACSHA256(&input, output, output); +#else + result = ARM_UC_cryptoHMACSHA256(output, &input, output); +#endif + } + } + + if (result.code != ERR_NONE) { + /* clear buffer on failure so we don't leak the rot */ + memset(output->ptr, 0, output->size_max); + } + + return result; +} + +arm_uc_error_t arm_uc_parse_internal_header_v2(const uint8_t *input, + arm_uc_firmware_details_t *details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (input && details) { + /* calculate CRC */ + uint32_t calculatedChecksum = arm_uc_crc32(input, ARM_UC_INTERNAL_HEADER_CRC_OFFSET_V2); + + /* read out CRC */ + uint32_t temp32 = arm_uc_parse_uint32(&input[ARM_UC_INTERNAL_HEADER_CRC_OFFSET_V2]); + + if (temp32 == calculatedChecksum) { + /* parse content */ + details->version = arm_uc_parse_uint64(&input[ARM_UC_INTERNAL_FIRMWARE_VERSION_OFFSET_V2]); + details->size = arm_uc_parse_uint64(&input[ARM_UC_INTERNAL_FIRMWARE_SIZE_OFFSET_V2]); + + memcpy(details->hash, + &input[ARM_UC_INTERNAL_FIRMWARE_HASH_OFFSET_V2], + ARM_UC_SHA256_SIZE); + + memcpy(details->campaign, + &input[ARM_UC_INTERNAL_CAMPAIGN_OFFSET_V2], + ARM_UC_GUID_SIZE); + + /* set result */ + result.code = ERR_NONE; + } + } + + return result; +} + +arm_uc_error_t arm_uc_create_internal_header_v2(const arm_uc_firmware_details_t *input, + arm_uc_buffer_t *output) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (input && + output && + (output->size_max >= ARM_UC_INTERNAL_HEADER_SIZE_V2)) { + /* zero buffer */ + memset(output->ptr, 0, ARM_UC_INTERNAL_HEADER_SIZE_V2); + + /* MSB encode header magic and version */ + arm_uc_write_uint32(&output->ptr[0], + ARM_UC_INTERNAL_HEADER_MAGIC_V2); + arm_uc_write_uint32(&output->ptr[4], + ARM_UC_INTERNAL_HEADER_VERSION_V2); + + /* MSB encode firmware version */ + arm_uc_write_uint64(&output->ptr[ARM_UC_INTERNAL_FIRMWARE_VERSION_OFFSET_V2], + input->version); + + /* MSB encode firmware size to header */ + arm_uc_write_uint64(&output->ptr[ARM_UC_INTERNAL_FIRMWARE_SIZE_OFFSET_V2], + input->size); + + /* raw copy firmware hash to header */ + memcpy(&output->ptr[ARM_UC_INTERNAL_FIRMWARE_HASH_OFFSET_V2], + input->hash, + ARM_UC_SHA256_SIZE); + + /* raw copy campaign ID to header */ + memcpy(&output->ptr[ARM_UC_INTERNAL_CAMPAIGN_OFFSET_V2], + input->campaign, + ARM_UC_GUID_SIZE); + + /* calculate CRC */ + uint32_t checksum = arm_uc_crc32(output->ptr, + ARM_UC_INTERNAL_HEADER_CRC_OFFSET_V2); + + /* MSB encode checksum to header */ + arm_uc_write_uint32(&output->ptr[ARM_UC_INTERNAL_HEADER_CRC_OFFSET_V2], + checksum); + + /* set output size */ + output->size = ARM_UC_INTERNAL_HEADER_SIZE_V2; + + /* set error code */ + result.code = ERR_NONE; + } + + return result; +} + +arm_uc_error_t arm_uc_parse_external_header_v2(const uint8_t *input, + arm_uc_firmware_details_t *details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (input && details) { + + /* read 128 bit root-of-trust */ + uint8_t key_buf[ARM_UC_DEVICE_KEY_SIZE] = { 0 }; + arm_uc_buffer_t key = { + .size_max = ARM_UC_DEVICE_KEY_SIZE, + .size = 0, + .ptr = key_buf + }; + arm_uc_error_t status = ARM_UC_getDeviceKey256Bit(&key); + + if (status.error == ERR_NONE) { + arm_uc_buffer_t input_buf = { + .size_max = ARM_UC_EXTERNAL_HMAC_OFFSET_V2, + .size = ARM_UC_EXTERNAL_HMAC_OFFSET_V2, + .ptr = (uint8_t *) input + }; + arm_uc_hash_t hmac = { 0 }; + arm_uc_buffer_t output_buf = { + .size_max = sizeof(arm_uc_hash_t), + .size = sizeof(arm_uc_hash_t), + .ptr = (uint8_t *) &hmac + }; + + /* calculate header HMAC */ + status = ARM_UC_cryptoHMACSHA256(&key, &input_buf, &output_buf); + + if (status.error == ERR_NONE) { + input_buf.size_max = sizeof(arm_uc_hash_t); + input_buf.size = sizeof(arm_uc_hash_t); + input_buf.ptr = (uint8_t *) &input[ARM_UC_EXTERNAL_HMAC_OFFSET_V2]; + + int diff = ARM_UC_BinCompareCT(&input_buf, &output_buf); + + if (diff == 0) { + details->version = arm_uc_parse_uint64(&input[ARM_UC_EXTERNAL_FIRMWARE_VERSION_OFFSET_V2]); + details->size = arm_uc_parse_uint64(&input[ARM_UC_EXTERNAL_FIRMWARE_SIZE_OFFSET_V2]); + + memcpy(details->hash, + &input[ARM_UC_EXTERNAL_FIRMWARE_HASH_OFFSET_V2], + ARM_UC_SHA256_SIZE); + + memcpy(details->campaign, + &input[ARM_UC_EXTERNAL_CAMPAIGN_OFFSET_V2], + ARM_UC_GUID_SIZE); + + details->signatureSize = 0; + + result.code = ERR_NONE; + } + } + } + } + + return result; +} + +arm_uc_error_t arm_uc_create_external_header_v2(const arm_uc_firmware_details_t *input, + arm_uc_buffer_t *output) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (input && + output && + (output->size_max >= ARM_UC_EXTERNAL_HEADER_SIZE_V2)) { + /* zero buffer and reset size*/ + memset(output->ptr, 0, ARM_UC_EXTERNAL_HEADER_SIZE_V2); + output->size = 0; + + /* MSB encode header magic and version */ + arm_uc_write_uint32(&output->ptr[0], + ARM_UC_EXTERNAL_HEADER_MAGIC_V2); + arm_uc_write_uint32(&output->ptr[4], + ARM_UC_EXTERNAL_HEADER_VERSION_V2); + + /* MSB encode firmware version */ + arm_uc_write_uint64(&output->ptr[ARM_UC_EXTERNAL_FIRMWARE_VERSION_OFFSET_V2], + input->version); + + /* MSB encode firmware size to header */ + arm_uc_write_uint64(&output->ptr[ARM_UC_EXTERNAL_FIRMWARE_SIZE_OFFSET_V2], + input->size); + + /* raw copy firmware hash to header */ + memcpy(&output->ptr[ARM_UC_EXTERNAL_FIRMWARE_HASH_OFFSET_V2], + input->hash, + ARM_UC_SHA256_SIZE); + + /* MSB encode payload size to header */ + arm_uc_write_uint64(&output->ptr[ARM_UC_EXTERNAL_PAYLOAD_SIZE_OFFSET_V2], + input->size); + + /* raw copy payload hash to header */ + memcpy(&output->ptr[ARM_UC_EXTERNAL_PAYLOAD_HASH_OFFSET_V2], + input->hash, + ARM_UC_SHA256_SIZE); + + /* raw copy campaign ID to header */ + memcpy(&output->ptr[ARM_UC_EXTERNAL_CAMPAIGN_OFFSET_V2], + input->campaign, + ARM_UC_GUID_SIZE); + + /* read 256 bit device key */ + uint8_t key_buf[ARM_UC_DEVICE_KEY_SIZE] = { 0 }; + arm_uc_buffer_t key = { + .size_max = ARM_UC_DEVICE_KEY_SIZE, + .size = 0, + .ptr = key_buf + }; + + arm_uc_error_t status = ARM_UC_getDeviceKey256Bit(&key); + + if (status.error == ERR_NONE) { + arm_uc_buffer_t input_buf = { + .size_max = ARM_UC_EXTERNAL_HMAC_OFFSET_V2, + .size = ARM_UC_EXTERNAL_HMAC_OFFSET_V2, + .ptr = output->ptr + }; + arm_uc_buffer_t output_buf = { + .size_max = sizeof(arm_uc_hash_t), + .size = sizeof(arm_uc_hash_t), + .ptr = &output->ptr[ARM_UC_EXTERNAL_HMAC_OFFSET_V2] + }; + + /* calculate header HMAC */ + result = ARM_UC_cryptoHMACSHA256(&key, &input_buf, &output_buf); + if (result.error == ERR_NONE) { + /* set output size */ + output->size = ARM_UC_EXTERNAL_HEADER_SIZE_V2; + } + } + } + + return result; +} diff --git a/modules/metadata-header/update-client-metadata-header/arm_uc_buffer_utilities.h b/modules/metadata-header/update-client-metadata-header/arm_uc_buffer_utilities.h new file mode 100644 index 0000000..631c947 --- /dev/null +++ b/modules/metadata-header/update-client-metadata-header/arm_uc_buffer_utilities.h @@ -0,0 +1,79 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_BUFFER_UTILITIES_H +#define ARM_UPDATE_BUFFER_UTILITIES_H + +#include "update-client-common/arm_uc_types.h" +#include "update-client-common/arm_uc_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @brief Calculate CRC 32 + * + * @param buffer Input array. + * @param length Length of array in bytes. + * + * @return 32 bit CRC. + */ +uint32_t arm_uc_crc32(const uint8_t *buffer, uint32_t length); + +/** + * @brief Parse 4 byte array into uint32_t + * + * @param input 4 byte array. + * @return uint32_t + */ +uint32_t arm_uc_parse_uint32(const uint8_t *input); + +/** + * @brief Parse 8 byte array into uint64_t + * + * @param input 8 byte array. + * @return uint64_t + */ +uint64_t arm_uc_parse_uint64(const uint8_t *input); + +/** + * @brief Write uint32_t to array. + * + * @param buffer Pointer to buffer. + * @param value Value to be written. + */ +void arm_uc_write_uint32(uint8_t *buffer, uint32_t value); + +/** + * @brief Write uint64_t to array. + * + * @param buffer Pointer to buffer. + * @param value Value to be written. + */ +void arm_uc_write_uint64(uint8_t *buffer, uint64_t value); + + +uint32_t ARM_UC_BinCompareCT(const arm_uc_buffer_t *a, const arm_uc_buffer_t *b); + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UPDATE_BUFFER_UTILITIES_H diff --git a/modules/metadata-header/update-client-metadata-header/arm_uc_metadata_header_v2.h b/modules/metadata-header/update-client-metadata-header/arm_uc_metadata_header_v2.h new file mode 100644 index 0000000..ea9569d --- /dev/null +++ b/modules/metadata-header/update-client-metadata-header/arm_uc_metadata_header_v2.h @@ -0,0 +1,213 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_METADATA_HEADER_V2_H +#define ARM_UC_METADATA_HEADER_V2_H + +#include "update-client-common/arm_uc_types.h" +#include "update-client-common/arm_uc_error.h" +#include "arm_uc_buffer_utilities.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ARM_UC_INTERNAL_HEADER_MAGIC_V2 (0x5a51b3d4UL) +#define ARM_UC_INTERNAL_HEADER_VERSION_V2 (2) + +#define ARM_UC_EXTERNAL_HEADER_MAGIC_V2 (0x5a51b3d4UL) +#define ARM_UC_EXTERNAL_HEADER_VERSION_V2 (2) + +#define ARM_UC_INTERNAL_FIRMWARE_VERSION_OFFSET_V2 (8) +#define ARM_UC_INTERNAL_FIRMWARE_SIZE_OFFSET_V2 (16) +#define ARM_UC_INTERNAL_FIRMWARE_HASH_OFFSET_V2 (24) +#define ARM_UC_INTERNAL_CAMPAIGN_OFFSET_V2 (88) +#define ARM_UC_INTERNAL_SIGNATURE_SIZE_OFFSET_V2 (104) +#define ARM_UC_INTERNAL_HEADER_CRC_OFFSET_V2 (108) + +#define ARM_UC_INTERNAL_HEADER_SIZE_V2 (112) + +#define ARM_UC_EXTERNAL_FIRMWARE_VERSION_OFFSET_V2 (8) +#define ARM_UC_EXTERNAL_FIRMWARE_SIZE_OFFSET_V2 (16) +#define ARM_UC_EXTERNAL_FIRMWARE_HASH_OFFSET_V2 (24) +#define ARM_UC_EXTERNAL_PAYLOAD_SIZE_OFFSET_V2 (88) +#define ARM_UC_EXTERNAL_PAYLOAD_HASH_OFFSET_V2 (96) +#define ARM_UC_EXTERNAL_CAMPAIGN_OFFSET_V2 (160) +#define ARM_UC_EXTERNAL_HMAC_OFFSET_V2 (232) + +#define ARM_UC_EXTERNAL_HEADER_SIZE_V2 (296) + +typedef struct _arm_uc_internal_header_t { + /* Metadata-header specific magic code */ + uint32_t headerMagic; + + /* Revision number for metadata header. */ + uint32_t headerVersion; + + /* Version number accompanying the firmware. Larger numbers imply more + recent and preferred versions. This is used for determining the + selection order when multiple versions are available. For downloaded + firmware the manifest timestamp is used as the firmware version. + */ + uint64_t firmwareVersion; + + /* Total space (in bytes) occupied by the firmware BLOB. */ + uint64_t firmwareSize; + + /* Firmware hash calculated over the firmware size. Should match the hash + generated by standard command line tools, e.g., shasum on Linux/Mac. + */ + uint8_t firmwareHash[ARM_UC_SHA512_SIZE]; + + /* The ID for the update campaign that resulted in the firmware update. + */ + uint8_t campaign[ARM_UC_GUID_SIZE]; + + /* Size of the firmware signature. Must be 0 if no signature is supplied. */ + uint32_t firmwareSignatureSize; + + /* Header 32 bit CRC. Calculated over the entire header, including the CRC + field, but with the CRC set to zero. + */ + uint32_t headerCRC; + + /* Optional firmware signature. Hashing algorithm should be the same as the + one used for the firmware hash. The firmwareSignatureSize must be set. + */ + uint8_t firmwareSignature[0]; +} arm_uc_internal_header_t; + +typedef struct _arm_uc_external_header_t { + /* Metadata-header specific magic code */ + uint32_t headerMagic; + + /* Revision number for metadata header. */ + uint32_t headerVersion; + + /* Version number accompanying the firmware. Larger numbers imply more + recent and preferred versions. This is used for determining the + selection order when multiple versions are available. For downloaded + firmware the manifest timestamp is used as the firmware version. + */ + uint64_t firmwareVersion; + + /* Total space (in bytes) occupied by the firmware BLOB. */ + uint64_t firmwareSize; + + /* Firmware hash calculated over the firmware size. Should match the hash + generated by standard command line tools, e.g., shasum on Linux/Mac. + */ + uint8_t firmwareHash[ARM_UC_SHA512_SIZE]; + + /* Total space (in bytes) occupied by the payload BLOB. + The payload is the firmware after some form of transformation like + encryption and/or compression. + */ + uint64_t payloadSize; + + /* Payload hash calculated over the payload size. Should match the hash + generated by standard command line tools, e.g., shasum on Linux/Mac. + The payload is the firmware after some form of transformation like + encryption and/or compression. + */ + uint8_t payloadHash[ARM_UC_SHA512_SIZE]; + + /* The ID for the update campaign that resulted in the firmware update. + */ + uint8_t campaign[ARM_UC_GUID_SIZE]; + + /* Type of transformation used to turn the payload into the firmware image. + Possible values are: + * * NONE + * * AES128_CTR + * * AES128_CBC + * * AES256_CTR + * * AES256_CBC + */ + uint32_t firmwareTransformationMode; + + /* Encrypted firmware encryption key. + * To decrypt the firmware, the bootloader combines the bootloader secret + * and the firmwareKeyDerivationFunctionSeed to create an AES key. It uses + * This AES key to decrypt the firmwareCipherKey. The decrypted + * firmwareCipherKey is the FirmwareKey, which is used with the + * firmwareInitVector to decrypt the firmware. + */ + uint8_t firmwareCipherKey[ARM_UC_AES256_KEY_SIZE]; + + /* AES Initialization vector. This is a random number used to protect the + encryption algorithm from attack. It must be unique for every firmware. + */ + uint8_t firmwareInitVector[ARM_UC_AES_BLOCK_SIZE]; + + /* Size of the firmware signature. Must be 0 if no signature is supplied. */ + uint32_t firmwareSignatureSize; + + /* Hash based message authentication code for the metadata header. Uses per + device secret as key. Should use same hash algorithm as firmware hash. + The headerHMAC field and firmwareSignature field are not part of the hash. + */ + uint8_t headerHMAC[ARM_UC_SHA512_SIZE]; + + /* Optional firmware signature. Hashing algorithm should be the same as the + one used for the firmware hash. The firmwareSignatureSize must be set. + */ + uint8_t firmwareSignature[0]; +} arm_uc_external_header_t; + +/** + * @brief Get a 256 device key. + * + * @param output buffer struct to cotain output device key. + The size member of the struct will be set on success. + * + * @return ERR_NONE on success, error code on failure. + */ +arm_uc_error_t ARM_UC_getDeviceKey256Bit(arm_uc_buffer_t *output); + +/** + * @brief Function to get the device root of trust + * @details The device root of trust should be a 128 bit value. It should never leave the device. + * It should be unique to the device. It should have enough entropy to avoid contentional + * entropy attacks. The porter should implement the following device signature to provide + * device root of trust on different platforms. + * + * @param key_buf buffer to be filled with the device root of trust. + * @param length length of the buffer provided to make sure no overflow occurs. + * + * @return 0 on success, non-zero on failure. + */ +int8_t mbed_cloud_client_get_rot_128bit(uint8_t *key_buf, uint32_t length); + +arm_uc_error_t arm_uc_parse_internal_header_v2(const uint8_t *input, + arm_uc_firmware_details_t *output); + +arm_uc_error_t arm_uc_create_internal_header_v2(const arm_uc_firmware_details_t *input, + arm_uc_buffer_t *output); + +arm_uc_error_t arm_uc_parse_external_header_v2(const uint8_t *input, + arm_uc_firmware_details_t *output); + +arm_uc_error_t arm_uc_create_external_header_v2(const arm_uc_firmware_details_t *input, + arm_uc_buffer_t *output); + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UC_METADATA_HEADER_V2_H diff --git a/minimal-printf.lib b/modules/minimal-printf.lib similarity index 100% rename from minimal-printf.lib rename to modules/minimal-printf.lib diff --git a/modules/storage/paal/LICENSE b/modules/storage/paal/LICENSE new file mode 100644 index 0000000..c2bccaf --- /dev/null +++ b/modules/storage/paal/LICENSE @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + diff --git a/modules/storage/paal/TESTS/syntax/main.cpp b/modules/storage/paal/TESTS/syntax/main.cpp new file mode 100644 index 0000000..f7912a9 --- /dev/null +++ b/modules/storage/paal/TESTS/syntax/main.cpp @@ -0,0 +1,61 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include +#include +#include + +#include "update-client-paal/arm_uc_paal_update_api.h" + +using namespace utest::v1; + +#if defined(TARGET_LIKE_POSIX) +#include +#define __WFI() usleep(100) +#endif + +control_t syntax_check() +{ + ARM_UC_PAAL_UPDATE test = { 0 }; + + return CaseNext; +} + +Case cases[] = { + Case("syntax_check", syntax_check), +}; + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ +#if defined(TARGET_LIKE_MBED) + GREENTEA_SETUP(60, "default_auto"); +#endif + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_setup, cases); + +#if defined(TARGET_LIKE_MBED) +int main() +#elif defined(TARGET_LIKE_POSIX) +void app_start(int argc __unused, char **argv __unused) +#endif +{ + // Run the test specification + Harness::run(specification); +} diff --git a/modules/storage/paal/circle.yml b/modules/storage/paal/circle.yml new file mode 100644 index 0000000..05a961f --- /dev/null +++ b/modules/storage/paal/circle.yml @@ -0,0 +1,18 @@ +dependencies: + pre: + - sudo apt-get update + - sudo apt-get install python-setuptools cmake build-essential ninja-build python-dev libffi-dev libssl-dev lcov gcc-4.8-multilib g++-4.8-multilib + - pip install yotta + - mkdir ~/.yotta/ && echo $yotta_config > ~/.yotta/config.json + - sudo ln -s /usr/include/asm-generic /usr/include/asm + - sudo chmod 777 -R /usr/local/lib/ + - cd ../ && git clone https://github.com/ARMmbed/run_tests_linux.git --depth 1 + - pip install -r ../run_tests_linux/requirements.txt + - mv TESTS test + +test: + override: + - yt target mcc-linux-x86 + - yt install + - yt ls -a + - MCC_LINUX_X86_EXTRA_DEFS="-DTARGET_IS_PC_LINUX -DMBEDTLS_X509_CSR_WRITE_C=1 -DMBEDTLS_X509_CREATE_C=1 -DMBEDTLS_CIPHER_MODE_CTR=1 -DMBEDTLS_PEM_WRITE_C -DMBEDTLS_PLATFORM_TIME_ALT -DMBEDTLS_CMAC_C -DMBEDTLS_AES_ROM_TABLES=1 -DARM_UC_BUFFER_SIZE=10240 -DARM_UC_USE_PAL_CRYPTO=0 -DPAL_USE_FATFS_SD=1 -D__LINUX__" MCC_LINUX_X86_EXTRA_C_FLAGS="-m32" MCC_LINUX_X86_EXTRA_CXX_FLAGS="-m32 -std=gnu++11" MCC_LINUX_X86_EXTRA_LIBS="pthread;rt" yt test diff --git a/modules/storage/paal/source/arm_uc_paal_update.c b/modules/storage/paal/source/arm_uc_paal_update.c new file mode 100644 index 0000000..d2b76cd --- /dev/null +++ b/modules/storage/paal/source/arm_uc_paal_update.c @@ -0,0 +1,317 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +// fixup the compilation on ARMCC for PRIu32 +#define __STDC_FORMAT_MACROS +#include + +#include "update-client-paal/arm_uc_paal_update.h" +#include "update-client-paal/arm_uc_paal_update_api.h" + +static const ARM_UC_PAAL_UPDATE *paal_update_implementation = NULL; + +/** + * @brief Set PAAL Update implementation. + * + * @param implementation Function pointer struct to implementation. + * @return Returns ERR_NONE on accept and ERR_INVALID_PARAMETER otherwise. + */ +arm_uc_error_t ARM_UCP_SetPAALUpdate(const ARM_UC_PAAL_UPDATE *implementation) +{ + UC_PAAL_TRACE("ARM_UCP_SetPAALUpdate"); + + paal_update_implementation = implementation; + + return (arm_uc_error_t) { ERR_NONE }; +} + +/** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) +{ + UC_PAAL_TRACE("ARM_UCP_Initialize"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation) { + result = paal_update_implementation->Initialize(callback); + } + + return result; +} + +/** + * @brief Get a bitmap indicating supported features. + * @details The bitmap is used in conjunction with the firmware and + * installer details struct to indicate what fields are supported + * and which values are valid. + * + * @return Capability bitmap. + */ +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UCP_GetCapabilities(void) +{ + UC_PAAL_TRACE("ARM_UCP_GetCapabilities"); + + ARM_UC_PAAL_UPDATE_CAPABILITIES result = { 0 }; + + if (paal_update_implementation) { + result = paal_update_implementation->GetCapabilities(); + } + + return result; +} + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UCP_GetMaxID(void) +{ + UC_PAAL_TRACE("ARM_UCP_GetMaxID"); + + uint32_t result = 0; + + if (paal_update_implementation) { + result = paal_update_implementation->GetMaxID(); + } + + return result; +} + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Prepare(uint32_t location, + const arm_uc_firmware_details_t *details, + arm_uc_buffer_t *buffer) +{ + UC_PAAL_TRACE("ARM_UCP_Prepare"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && details && buffer) { + result = paal_update_implementation->Prepare(location, + details, + buffer); + } + + return result; +} + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t *buffer) +{ + UC_PAAL_TRACE("ARM_UCP_Write: %p %p", paal_update_implementation, buffer); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && buffer) { + result = paal_update_implementation->Write(location, offset, buffer); + } + + return result; +} + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Finalize(uint32_t location) +{ + UC_PAAL_TRACE("ARM_UCP_Finalize"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation) { + result = paal_update_implementation->Finalize(location); + } + + return result; +} + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. buffer->size + * contains the intended read size. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + * buffer->size contains actual bytes read on return. + */ +arm_uc_error_t ARM_UCP_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t *buffer) +{ + UC_PAAL_TRACE("ARM_UCP_Read: %" PRIX32 " %p", offset, buffer); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && buffer) { + result = paal_update_implementation->Read(location, offset, buffer); + } + + return result; +} + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Activate(uint32_t location) +{ + UC_PAAL_TRACE("ARM_UCP_Activate"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation) { + result = paal_update_implementation->Activate(location); + } + + return result; +} + +/** + * @brief Get firmware details for the actively running firmware. + * @details This call populates the passed details struct with information + * about the currently active firmware image. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetActiveFirmwareDetails(arm_uc_firmware_details_t *details) +{ + UC_PAAL_TRACE("ARM_UCP_GetActiveFirmwareDetails"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && details) { + result = paal_update_implementation->GetActiveFirmwareDetails(details); + } + + return result; +} + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetFirmwareDetails(uint32_t location, + arm_uc_firmware_details_t *details) +{ + UC_PAAL_TRACE("ARM_UCP_GetFirmwareDetails"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && details) { + result = paal_update_implementation->GetFirmwareDetails(location, + details); + } + + return result; +} + +/** + * @brief Get details for the component responsible for installation. + * @details This call populates the passed details struct with information + * about the local installer. Only the fields marked as supported + * in the capabilities bitmap will have valid values. The + * installer could be the bootloader, a recovery image, or some + * other component responsible for applying the new firmware + * image. + * + * @param details Pointer to installer details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetInstallerDetails(arm_uc_installer_details_t *details) +{ + UC_PAAL_TRACE("ARM_UCP_GetInstallerDetails"); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (paal_update_implementation && details) { + result = paal_update_implementation->GetInstallerDetails(details); + } + + return result; +} diff --git a/modules/storage/paal/update-client-paal/arm_uc_paal_update.h b/modules/storage/paal/update-client-paal/arm_uc_paal_update.h new file mode 100644 index 0000000..14987b2 --- /dev/null +++ b/modules/storage/paal/update-client-paal/arm_uc_paal_update.h @@ -0,0 +1,189 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "update-client-paal/arm_uc_paal_update_api.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set PAAL Update implementation. + * + * @param implementation Function pointer struct to implementation. + * @return Returns ERR_NONE on accept and ERR_INVALID_PARAMETER otherwise. + */ +arm_uc_error_t ARM_UCP_SetPAALUpdate(const ARM_UC_PAAL_UPDATE *implementation); + +/** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); + +/** + * @brief Get a bitmap indicating supported features. + * @details The bitmap is used in conjunction with the firmware and + * installer details struct to indicate what fields are supported + * and which values are valid. + * + * @return Capability bitmap. + */ +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UCP_GetCapabilities(void); + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UCP_GetMaxID(void); + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Prepare(uint32_t location, + const arm_uc_firmware_details_t *details, + arm_uc_buffer_t *buffer); + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t *buffer); + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Finalize(uint32_t location); + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. buffer->size + * contains the intended read size. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + * buffer->size contains actual bytes read on return. + */ +arm_uc_error_t ARM_UCP_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t *buffer); + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_Activate(uint32_t location); + +/** + * @brief Get firmware details for the actively running firmware. + * @details This call populates the passed details struct with information + * about the currently active firmware image. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetActiveFirmwareDetails(arm_uc_firmware_details_t *details); + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetFirmwareDetails(uint32_t location, + arm_uc_firmware_details_t *details); + +/** + * @brief Get details for the component responsible for installation. + * @details This call populates the passed details struct with information + * about the local installer. Only the fields marked as supported + * in the capabilities bitmap will have valid values. The + * installer could be the bootloader, a recovery image, or some + * other component responsible for applying the new firmware + * image. + * + * @param details Pointer to installer details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_GetInstallerDetails(arm_uc_installer_details_t *details); + +#ifdef __cplusplus +} +#endif diff --git a/modules/storage/paal/update-client-paal/arm_uc_paal_update_api.h b/modules/storage/paal/update-client-paal/arm_uc_paal_update_api.h new file mode 100644 index 0000000..cac51b5 --- /dev/null +++ b/modules/storage/paal/update-client-paal/arm_uc_paal_update_api.h @@ -0,0 +1,270 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAAL_UPDATE_API_H +#define ARM_UC_PAAL_UPDATE_API_H + +#include "update-client-common/arm_uc_error.h" +#include "update-client-common/arm_uc_types.h" + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include +#include +#include + +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +#if defined(MBED_CONF_MBED_TRACE_ENABLE) && MBED_CONF_MBED_TRACE_ENABLE == 1 + +#include "mbed-trace/mbed_trace.h" +#ifndef TRACE_GROUP +#define TRACE_GROUP "UCPI" +#endif + +#define ARM_UC_TRACE_DEBUG_PRINTF(module, fmt, ...) tr_debug("[%-4s] %s:%d: " fmt, module, __FILENAME__, __LINE__, ##__VA_ARGS__) +#define ARM_UC_TRACE_ERROR_PRINTF(module, fmt, ...) tr_error("[%-4s] %s:%d: " fmt, module, __FILENAME__, __LINE__, ##__VA_ARGS__) + +#else // if defined(MBED_CONF_MBED_TRACE_ENABLE) && MBED_CONF_MBED_TRACE_ENABLE == 1 + +#include + +#define ARM_UC_TRACE_DEBUG_PRINTF(module, fmt, ...) printf("[TRACE][%-4s] %s:%d: " fmt "\r\n", module, __FILENAME__, __LINE__, ##__VA_ARGS__) +#define ARM_UC_TRACE_ERROR_PRINTF(module, fmt, ...) printf("[ERROR][%-4s] %s:%d: " fmt "\r\n", module, __FILENAME__, __LINE__, ##__VA_ARGS__) + +#endif // if defined(MBED_CONF_MBED_TRACE_ENABLE) && MBED_CONF_MBED_TRACE_ENABLE == 1 + +#if ARM_UC_PAAL_TRACE_ENABLE +#define UC_PAAL_TRACE(fmt, ...) ARM_UC_TRACE_DEBUG_PRINTF("PAAL", fmt, ##__VA_ARGS__) +#define UC_PAAL_ERR_MSG(fmt, ...) ARM_UC_TRACE_ERROR_PRINTF("PAAL", fmt, ##__VA_ARGS__) +#else +#define UC_PAAL_TRACE(fmt, ...) +#define UC_PAAL_ERR_MSG(fmt, ...) +#endif // if ARM_UC_PAAL_TRACE_ENABLE + +/** + * @brief Prototype for event handler. + */ +typedef void (*ARM_UC_PAAL_UPDATE_SignalEvent_t)(uint32_t event); + +/** + * @brief Asynchronous events. + */ +enum { + ARM_UC_PAAL_EVENT_INITIALIZE_DONE, + ARM_UC_PAAL_EVENT_PREPARE_DONE, + ARM_UC_PAAL_EVENT_WRITE_DONE, + ARM_UC_PAAL_EVENT_FINALIZE_DONE, + ARM_UC_PAAL_EVENT_READ_DONE, + ARM_UC_PAAL_EVENT_ACTIVATE_DONE, + ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE, + ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE, + ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE, + ARM_UC_PAAL_EVENT_INITIALIZE_ERROR, + ARM_UC_PAAL_EVENT_PREPARE_ERROR, + ARM_UC_PAAL_EVENT_FIRMWARE_TOO_LARGE_ERROR, + ARM_UC_PAAL_EVENT_WRITE_ERROR, + ARM_UC_PAAL_EVENT_FINALIZE_ERROR, + ARM_UC_PAAL_EVENT_READ_ERROR, + ARM_UC_PAAL_EVENT_ACTIVATE_ERROR, + ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_ERROR, + ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_ERROR, + ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_ERROR, +}; + +/** + * @brief Bitmap with supported header features. + * @details The PAAL Update implementation indicates what features are + * supported. This can be used after a call to one of the GetDetails + * to see which fields have valid values and what fields should be set + * in the call to Prepare. + */ +typedef struct _ARM_UC_PAAL_UPDATE_CAPABILITIES { + uint32_t installer_arm_hash: 1; + uint32_t installer_oem_hash: 1; + uint32_t installer_layout: 1; + uint32_t firmware_hash: 1; + uint32_t firmware_hmac: 1; + uint32_t firmware_campaign: 1; + uint32_t firmware_version: 1; + uint32_t firmware_size: 1; + uint32_t reserved: 24; +} ARM_UC_PAAL_UPDATE_CAPABILITIES; + +/** + * @brief Structure definition holding API function pointers. + */ +typedef struct _ARM_UC_PAAL_UPDATE { + + /** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*Initialize)(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); + + /** + * @brief Get a bitmap indicating supported features. + * @details The bitmap is used in conjunction with the firmware and + * installer details struct to indicate what fields are supported + * and which values are valid. + * + * @return Capability bitmap. + */ + ARM_UC_PAAL_UPDATE_CAPABILITIES(*GetCapabilities)(void); + + /** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ + uint32_t (*GetMaxID)(void); + + /** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*Prepare)(uint32_t location, + const arm_uc_firmware_details_t *details, + arm_uc_buffer_t *buffer); + + /** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*Write)(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t *buffer); + + /** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*Finalize)(uint32_t location); + + /** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. buffer->size + * contains the intended read size. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + * buffer->size contains actual bytes read on return. + */ + arm_uc_error_t (*Read)(uint32_t location, + uint32_t offset, + arm_uc_buffer_t *buffer); + + /** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*Activate)(uint32_t location); + + /** + * @brief Get firmware details for the actively running firmware. + * @details This call populates the passed details struct with information + * about the currently active firmware image. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*GetActiveFirmwareDetails)(arm_uc_firmware_details_t *details); + + /** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*GetFirmwareDetails)(uint32_t location, + arm_uc_firmware_details_t *details); + + /** + * @brief Get details for the component responsible for installation. + * @details This call populates the passed details struct with information + * about the local installer. Only the fields marked as supported + * in the capabilities bitmap will have valid values. The + * installer could be the bootloader, a recovery image, or some + * other component responsible for applying the new firmware + * image. + * + * @param details Pointer to installer details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ + arm_uc_error_t (*GetInstallerDetails)(arm_uc_installer_details_t *details); + +} ARM_UC_PAAL_UPDATE; + +#endif /* ARM_UC_PAAL_UPDATE_API_H */ diff --git a/modules/storage/pal-blockdevice/.mbedignore b/modules/storage/pal-blockdevice/.mbedignore new file mode 100644 index 0000000..1a5e403 --- /dev/null +++ b/modules/storage/pal-blockdevice/.mbedignore @@ -0,0 +1 @@ +*/test/* diff --git a/modules/storage/pal-blockdevice/TESTS/mbed_app.json b/modules/storage/pal-blockdevice/TESTS/mbed_app.json new file mode 100644 index 0000000..492db14 --- /dev/null +++ b/modules/storage/pal-blockdevice/TESTS/mbed_app.json @@ -0,0 +1,13 @@ +{ + "target_overrides": { + "macros": [ + "ARM_UC_FEATURE_PAL_BLOCKDEVICE=1", + "ARM_UC_FEATURE_PAL_FLASHIAP=1", + "ARM_UC_PROFILE_MBED_CLOUD_CLIENT=1" + ], + "*": { + "mbed-trace.enable": 1, + "platform.stdio-baud-rate": 115200 + } + } +} diff --git a/modules/storage/pal-blockdevice/TESTS/tests/write_size/main.cpp b/modules/storage/pal-blockdevice/TESTS/tests/write_size/main.cpp new file mode 100644 index 0000000..b281e7a --- /dev/null +++ b/modules/storage/pal-blockdevice/TESTS/tests/write_size/main.cpp @@ -0,0 +1,209 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include +#include +#include + +#include +#include +#include + +#include "update-client-paal/arm_uc_paal_update.h" + +using namespace utest::v1; + +#include "pal_plat_rtos.h" + +palStatus_t pal_plat_osGetRoT128Bit(uint8_t *keyBuf, size_t keyLenBytes) +{ + return PAL_SUCCESS; +} + +#define SIZEOF_SHA256 256/8 +/* lookup table for printing hexadecimal values */ +const char hexTable[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' + }; + +/** + * Helper function to print a SHA-256 in a nice format. + * @param [in] SHA The array of PAL_SHA256_SIZE containing the SHA256 + */ +void printSHA256(const uint8_t SHA[SIZEOF_SHA256]) +{ + /* allocate space for string */ + char buffer[2 * SIZEOF_SHA256 + 1] = { 0 }; + + for (uint_least8_t index = 0; index < SIZEOF_SHA256; index++) { + uint8_t value = SHA[index]; + + buffer[2 * index] = hexTable[value >> 4]; + buffer[2 * index + 1] = hexTable[value & 0x0F]; + } + + printf("SHA256: %s\r\n", buffer); +} + +extern ARM_UC_PAAL_UPDATE ARM_UCP_FLASHIAP_BLOCKDEVICE; + +#if defined (MBED_CONF_APP_SPI_MOSI) && defined (MBED_CONF_APP_SPI_MISO) && defined (MBED_CONF_APP_SPI_CLK) && defined (MBED_CONF_APP_SPI_CS) +SDBlockDevice sd(MBED_CONF_APP_SPI_MOSI, MBED_CONF_APP_SPI_MISO, MBED_CONF_APP_SPI_CLK, MBED_CONF_APP_SPI_CS); +#else +SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS); +#endif + +BlockDevice *arm_uc_blockdevice = &sd; +volatile uint8_t event_received = 0; + +void callback(uint32_t event) +{ + switch (event) { + case ARM_UC_PAAL_EVENT_INITIALIZE_DONE: + case ARM_UC_PAAL_EVENT_PREPARE_DONE: + case ARM_UC_PAAL_EVENT_WRITE_DONE: + case ARM_UC_PAAL_EVENT_FINALIZE_DONE: + case ARM_UC_PAAL_EVENT_READ_DONE: + case ARM_UC_PAAL_EVENT_ACTIVATE_DONE: + case ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE: + case ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE: + case ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE: + event_received = 1; + break; + default: + break; + } +} + +void test_unit() +{ + uint32_t program_size = arm_uc_blockdevice->get_program_size(); + TEST_ASSERT_TRUE(program_size > 0); + + /* setup firmware size unaligned to page size */ + uint32_t firmware_size = program_size * 10 - 1; + uint32_t BUFFER_SIZE = program_size * 3; + uint8_t buf[BUFFER_SIZE] = {0}; + uint8_t storage_location = 0; + + event_received = 0; + arm_uc_error_t err = ARM_UCP_FLASHIAP_BLOCKDEVICE.Initialize(callback); + TEST_ASSERT_EQUAL_HEX(ERR_NONE, err.code); + while (!event_received) { __WFI(); } + + /* firmware details struct */ + arm_uc_firmware_details_t details = { 0 }; + + memset(details.hash, 0xff, SIZEOF_SHA256); + details.version = 0; + details.size = firmware_size; + + arm_uc_buffer_t buffer = { + .size_max = BUFFER_SIZE, + .size = 0, + .ptr = buf + }; + + event_received = 0; + err = ARM_UCP_FLASHIAP_BLOCKDEVICE.Prepare(storage_location, &details, &buffer); + TEST_ASSERT_EQUAL_HEX(ERR_NONE, err.code); + while (!event_received) { __WFI(); } + + /* prepare hash context */ + unsigned char write_hash[SIZEOF_SHA256]; + unsigned char read_hash[SIZEOF_SHA256]; + mbedtls_sha256_context ctx; + mbedtls_sha256_init(&ctx); + mbedtls_sha256_starts(&ctx, 0); + + /* write firmware to storage */ + uint32_t offset = 0; + while (offset < details.size) { + buffer.size = (details.size - offset) > buffer.size_max ? buffer.size_max : details.size - offset; + + /* generate some pseudo random data */ + for (int i = 0; i < buffer.size; i += SIZEOF_SHA256) { + mbedtls_sha256(buffer.ptr, buffer.size_max, write_hash, 0); + uint32_t copy_size = buffer.size - i < SIZEOF_SHA256 ? buffer.size - i : SIZEOF_SHA256; + memcpy(&buffer.ptr[i], write_hash, copy_size); + } + + printf("writing %u bytes at offset %u\r\n", buffer.size, offset); + event_received = 0; + err = ARM_UCP_FLASHIAP_BLOCKDEVICE.Write(storage_location, offset, &buffer); + TEST_ASSERT_EQUAL_HEX(ERR_NONE, err.code); + while (!event_received) { __WFI(); } + offset += buffer.size; + + mbedtls_sha256_update(&ctx, buffer.ptr, buffer.size); + } + + mbedtls_sha256_finish(&ctx, write_hash); + + event_received = 0; + err = ARM_UCP_FLASHIAP_BLOCKDEVICE.Finalize(storage_location); + TEST_ASSERT_EQUAL_HEX(ERR_NONE, err.code); + while (!event_received) { __WFI(); } + + /* read firmware back */ + offset = 0; + mbedtls_sha256_starts(&ctx, 0); + while (offset < details.size) { + buffer.size = (details.size - offset) > buffer.size_max ? buffer.size_max : details.size - offset; + + + printf("reading %u bytes at offset %u\r\n", buffer.size, offset); + event_received = 0; + err = ARM_UCP_FLASHIAP_BLOCKDEVICE.Read(storage_location, offset, &buffer); + TEST_ASSERT_EQUAL_HEX(ERR_NONE, err.code); + while (!event_received) { __WFI(); } + offset += buffer.size; + + mbedtls_sha256_update(&ctx, buffer.ptr, buffer.size); + } + + mbedtls_sha256_finish(&ctx, read_hash); + + printSHA256(write_hash); + printSHA256(read_hash); + TEST_ASSERT_EQUAL_MEMORY(write_hash, read_hash, sizeof(write_hash)); +} + +Case cases[] = { + Case("test_write_size", test_unit) +}; + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ +#if defined(TARGET_LIKE_MBED) + GREENTEA_SETUP(60, "default_auto"); +#endif + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_setup, cases); + +#if defined(TARGET_LIKE_MBED) +int main() +#elif defined(TARGET_LIKE_POSIX) +void app_start(int argc __unused, char **argv __unused) +#endif +{ + // Run the test specification + Harness::run(specification); +} diff --git a/modules/storage/pal-blockdevice/source/arm_uc_pal_blockdevice.c b/modules/storage/pal-blockdevice/source/arm_uc_pal_blockdevice.c new file mode 100644 index 0000000..2ca5fa7 --- /dev/null +++ b/modules/storage/pal-blockdevice/source/arm_uc_pal_blockdevice.c @@ -0,0 +1,83 @@ +// ---------------------------------------------------------------------------- +// Copyright 2017-2018 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_config.h" +#if defined(ARM_UC_FEATURE_PAL_BLOCKDEVICE) && (ARM_UC_FEATURE_PAL_BLOCKDEVICE == 1) + +#include "update-client-paal/arm_uc_paal_update_api.h" + +#include "update-client-pal-blockdevice/arm_uc_pal_blockdevice_implementation.h" +#include "update-client-pal-flashiap/arm_uc_pal_flashiap_implementation.h" + +/** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UCP_FashIAP_BlockDevice_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (callback) { + arm_uc_error_t status1 = ARM_UC_PAL_FlashIAP_Initialize(callback); + arm_uc_error_t status2 = ARM_UC_PAL_BlockDevice_Initialize(callback); + + if ((status1.error == ERR_NONE) && (status2.error == ERR_NONE)) { + result.code = ERR_NONE; + } else { + result.code = ERR_NOT_READY; + } + } + + return result; +} + +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UCP_FashIAP_BlockDevice_GetCapabilities(void) +{ + ARM_UC_PAAL_UPDATE_CAPABILITIES result = { + .installer_arm_hash = 0, + .installer_oem_hash = 0, + .installer_layout = 0, + .firmware_hash = 1, + .firmware_hmac = 0, + .firmware_campaign = 0, + .firmware_version = 1, + .firmware_size = 1 + }; + + return result; +} + +const ARM_UC_PAAL_UPDATE ARM_UCP_FLASHIAP_BLOCKDEVICE = { + .Initialize = ARM_UCP_FashIAP_BlockDevice_Initialize, + .GetCapabilities = ARM_UCP_FashIAP_BlockDevice_GetCapabilities, + .GetMaxID = ARM_UC_PAL_BlockDevice_GetMaxID, + .Prepare = ARM_UC_PAL_BlockDevice_Prepare, + .Write = ARM_UC_PAL_BlockDevice_Write, + .Finalize = ARM_UC_PAL_BlockDevice_Finalize, + .Read = ARM_UC_PAL_BlockDevice_Read, + .Activate = ARM_UC_PAL_BlockDevice_Activate, + .GetActiveFirmwareDetails = ARM_UC_PAL_FlashIAP_GetActiveDetails, + .GetFirmwareDetails = ARM_UC_PAL_BlockDevice_GetFirmwareDetails, + .GetInstallerDetails = ARM_UC_PAL_FlashIAP_GetInstallerDetails +}; + +#endif // #if defined(ARM_UC_FEATURE_PAL_BLOCKDEVICE) diff --git a/modules/storage/pal-blockdevice/source/arm_uc_pal_blockdevice_implementation.c b/modules/storage/pal-blockdevice/source/arm_uc_pal_blockdevice_implementation.c new file mode 100644 index 0000000..736a45f --- /dev/null +++ b/modules/storage/pal-blockdevice/source/arm_uc_pal_blockdevice_implementation.c @@ -0,0 +1,538 @@ +// ---------------------------------------------------------------------------- +// Copyright 2017-2018 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_config.h" +#if defined(ARM_UC_FEATURE_PAL_BLOCKDEVICE) && (ARM_UC_FEATURE_PAL_BLOCKDEVICE == 1) + +#define __STDC_FORMAT_MACROS + +#include "update-client-pal-blockdevice/arm_uc_pal_blockdevice.h" +#include "update-client-pal-blockdevice/arm_uc_pal_blockdevice_platform.h" + +#include "update-client-metadata-header/arm_uc_metadata_header_v2.h" + +#include + +#ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS +#define MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS 0 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE +#define MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE 0 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE +#define MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE 1 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS +#define MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS 1 +#endif + +/* consistency check */ +#if (MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE == 0) +#error Update client storage page cannot be zero. +#endif + +#if (MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS == 0) +#error Update client storage locations must be at least 1. +#endif + +#if (MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE == 0) +#error Update client storage size cannot be zero. +#endif + +/* Check that the statically allocated buffers are aligned with the block size */ +#define ARM_UC_PAL_ONE_BUFFER (ARM_UC_BUFFER_SIZE / 2) +#define ARM_UC_PAL_PAGES (ARM_UC_PAL_ONE_BUFFER / MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) + +#if !((ARM_UC_PAL_PAGES * MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) == ARM_UC_PAL_ONE_BUFFER) +#error Update client buffer must be divisible by the block page size +#endif + +static ARM_UC_PAAL_UPDATE_SignalEvent_t pal_blockdevice_event_handler = NULL; +static uint32_t pal_blockdevice_firmware_size = 0; +static uint32_t pal_blockdevice_page_size = 0; +static uint32_t pal_blockdevice_sector_size = 0; +static uint32_t pal_blockdevice_hdr_size = 0; + +static void pal_blockdevice_signal_internal(uint32_t event) +{ + if (pal_blockdevice_event_handler) { + pal_blockdevice_event_handler(event); + } +} + +/** + * @brief Round size up to nearest page + * + * @param size The size that need to be rounded up + * @return Returns the size rounded up to the nearest page + */ +static uint32_t pal_blockdevice_round_up_to_page(uint32_t size) +{ + uint32_t round_up = 0; + /* 0 is an aligned address and math operation below would not return 0. + It would return pal_blockdevice_page_size*/ + if (size != 0) { + round_up = ((size - 1) / pal_blockdevice_page_size + 1) * pal_blockdevice_page_size; + } + return round_up; +} + +/** + * @brief Round size down to nearest page + * + * @param size The size that need to be rounded up + * @return Returns the size rounded up to the nearest page + */ +static uint32_t pal_blockdevice_round_down_to_page(uint32_t size) +{ + return (size / pal_blockdevice_page_size) * pal_blockdevice_page_size; +} + +/** + * @brief Align size up to sector size + * + * @param size The size that need to be rounded up + * @return Returns the size aligned to sector size + */ +static uint32_t pal_blockdevice_round_up_to_sector(uint32_t size) +{ + uint32_t round_up = 0; + /* 0 is an aligned address and math operation below would not return 0. + It would return pal_blockdevice_sector_size*/ + if (size != 0) { + round_up = ((size - 1) / pal_blockdevice_sector_size + 1) * pal_blockdevice_sector_size; + } + return round_up; +} + +/** + * @brief Align size down to sector size + * + * @param size The size that need to be rounded up + * @return Returns the size aligned to sector boundary + */ +static uint32_t pal_blockdevice_round_down_to_sector(uint32_t size) +{ + return (size / pal_blockdevice_sector_size) * pal_blockdevice_sector_size; +} + +/** + * @brief Get the physicl slot address and size given slot_id + * + * @param slot_id Storage location ID. + * @param slot_addr the slot address is returned in this pointer + * @param slot_size the slot size is returned in this pointer + * @return Returns ERR_NONE on success. + * Returns ERR_INVALID_PARAMETER on error. + */ +static arm_uc_error_t pal_blockdevice_get_slot_addr_size(uint32_t slot_id, + uint32_t *slot_addr, + uint32_t *slot_size) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if ((slot_id < MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS) && + (slot_addr != NULL) && + (slot_size != NULL)) { + /* find the start address of the whole storage area. It needs to be aligned to + sector boundary and we cannot go outside user defined storage area, hence + rounding up to sector boundary */ + uint32_t storage_start_addr = pal_blockdevice_round_up_to_sector( + MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS); + /* find the end address of the whole storage area. It needs to be aligned to + sector boundary and we cannot go outside user defined storage area, hence + rounding down to sector boundary */ + uint32_t storage_end_addr = pal_blockdevice_round_down_to_sector( + MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS + \ + MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE); + /* find the maximum size each slot can have given the start and end, without + considering the alignment of individual slots */ + uint32_t max_slot_size = (storage_end_addr - storage_start_addr) / \ + MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS; + /* find the start address of slot. It needs to align to sector boundary. We + choose here to round down at each slot boundary */ + *slot_addr = storage_start_addr + pal_blockdevice_round_down_to_sector( + slot_id * max_slot_size); + /* Rounding down slot size to sector boundary same as + the slot start address so that we make sure two slot don't overlap */ + *slot_size = pal_blockdevice_round_down_to_sector(max_slot_size); + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (callback) { + UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Initialize"); + + int status = arm_uc_blockdevice_init(); + pal_blockdevice_page_size = arm_uc_blockdevice_get_program_size(); + pal_blockdevice_sector_size = arm_uc_blockdevice_get_erase_size(); + pal_blockdevice_hdr_size = pal_blockdevice_round_up_to_page(ARM_UC_EXTERNAL_HEADER_SIZE_V2); + + if (status == ARM_UC_BLOCKDEVICE_SUCCESS) { + pal_blockdevice_event_handler = callback; + pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_INITIALIZE_DONE); + result.code = ERR_NONE; + } + } + + return result; +} + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UC_PAL_BlockDevice_GetMaxID(void) +{ + return MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS; +} + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param slot_id Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Prepare(uint32_t slot_id, + const arm_uc_firmware_details_t *details, + arm_uc_buffer_t *buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details && buffer && buffer->ptr) { + UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Prepare: %" PRIX32 " %" PRIX64, + slot_id, details->size); + + /* encode firmware details in buffer */ + arm_uc_error_t header_status = arm_uc_create_external_header_v2(details, + buffer); + if (header_status.error == ERR_NONE) { + /* find the size needed to erase. Header is stored contiguous with firmware */ + uint32_t erase_size = pal_blockdevice_round_up_to_sector(pal_blockdevice_hdr_size + \ + details->size); + + /* find address of slot */ + uint32_t slot_addr = ARM_UC_BLOCKDEVICE_INVALID_SIZE; + uint32_t slot_size = ARM_UC_BLOCKDEVICE_INVALID_SIZE; + result = pal_blockdevice_get_slot_addr_size(slot_id, &slot_addr, &slot_size); + + UC_PAAL_TRACE("erase: %" PRIX32 " %" PRIX32 " %" PRIX32, slot_addr, erase_size, slot_size); + + int status = ARM_UC_BLOCKDEVICE_FAIL; + if (result.error == ERR_NONE) { + if (erase_size <= slot_size) { + /* erase */ + status = arm_uc_blockdevice_erase(slot_addr, erase_size); + } else { + UC_PAAL_ERR_MSG("not enough space for firmware image"); + result.code = PAAL_ERR_FIRMWARE_TOO_LARGE; + } + } + + if (status == ARM_UC_BLOCKDEVICE_SUCCESS) { + /* write header */ + status = arm_uc_blockdevice_program(buffer->ptr, + slot_addr, + pal_blockdevice_hdr_size); + + if (status == ARM_UC_BLOCKDEVICE_SUCCESS) { + /* set return code */ + result.code = ERR_NONE; + + /* store firmware size in global */ + pal_blockdevice_firmware_size = details->size; + + /* signal done */ + pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_PREPARE_DONE); + } else { + UC_PAAL_ERR_MSG("arm_uc_blockdevice_program failed"); + } + } else { + UC_PAAL_ERR_MSG("arm_uc_blockdevice_erase failed"); + } + } else { + UC_PAAL_ERR_MSG("arm_uc_create_external_header_v2 failed"); + } + } + + return result; +} + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param slot_id Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Write(uint32_t slot_id, + uint32_t offset, + const arm_uc_buffer_t *buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (buffer && buffer->ptr) { + UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Write: %" PRIX32 " %" PRIX32 " %" PRIX32, + slot_id, offset, buffer->size); + int status = ARM_UC_BLOCKDEVICE_SUCCESS; + + /* find address of slot */ + uint32_t slot_addr = ARM_UC_BLOCKDEVICE_INVALID_SIZE; + uint32_t slot_size = ARM_UC_BLOCKDEVICE_INVALID_SIZE; + result = pal_blockdevice_get_slot_addr_size(slot_id, &slot_addr, &slot_size); + uint32_t physical_address = slot_addr + pal_blockdevice_hdr_size + offset; + + /* check that we are not writing too much */ + uint32_t aligned_size = 0; + if (pal_blockdevice_firmware_size < offset + buffer->size) { + UC_PAAL_ERR_MSG("programming more than firmware size %" PRIu32 + " < %" PRIu32 " + %" PRIu32, + pal_blockdevice_firmware_size, offset, buffer->size); + } else if ((pal_blockdevice_firmware_size > offset + buffer->size) && + (buffer->size % pal_blockdevice_page_size != 0)) { + UC_PAAL_ERR_MSG("program size %" PRIu32 " does not align to page size %" PRIu32, + buffer->size, pal_blockdevice_page_size); + } else if (pal_blockdevice_firmware_size == offset + buffer->size) { + /* last chunk write page aligned data first */ + aligned_size = pal_blockdevice_round_down_to_page(buffer->size); + } else { + aligned_size = buffer->size; + } + + /* aligned write */ + if (result.error == ERR_NONE && aligned_size > 0) { + status = arm_uc_blockdevice_program(buffer->ptr, + physical_address, + aligned_size); + if (status == ARM_UC_BLOCKDEVICE_FAIL) { + UC_PAAL_ERR_MSG("arm_uc_blockdevice_program failed"); + } + } + + /* last chunk write remainder */ + uint32_t remainder_size = buffer->size - aligned_size; + + if ((status == ARM_UC_BLOCKDEVICE_SUCCESS) && (remainder_size > 0)) { + /* check if it is safe to use buffer, i.e. buffer is larger than a page */ + if (buffer->size_max >= pal_blockdevice_page_size) { + memmove(buffer->ptr, &(buffer->ptr[aligned_size]), remainder_size); + status = arm_uc_blockdevice_program(buffer->ptr, + physical_address + aligned_size, + pal_blockdevice_page_size); + } else { + UC_PAAL_ERR_MSG("arm_uc_blockdevice_program failed"); + + status = ARM_UC_BLOCKDEVICE_FAIL; + } + } + + if (status == ARM_UC_BLOCKDEVICE_SUCCESS) { + /* set return code */ + result.code = ERR_NONE; + + /* signal done */ + pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_WRITE_DONE); + } else { + UC_PAAL_ERR_MSG("arm_uc_blockdevice_program failed"); + } + } + + return result; +} + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param slot_id Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Finalize(uint32_t slot_id) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Finalize"); + + pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_FINALIZE_DONE); + + return result; +} + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param slot_id Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. buffer->size + * contains the intended read size. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + * buffer->size contains actual bytes read on return. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Read(uint32_t slot_id, + uint32_t offset, + arm_uc_buffer_t *buffer) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (buffer && buffer->ptr) { + UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Read: %" PRIX32 " %" PRIX32 " %" PRIX32, + slot_id, offset, buffer->size); + + /* find address of slot */ + uint32_t slot_addr = ARM_UC_BLOCKDEVICE_INVALID_SIZE; + uint32_t slot_size = ARM_UC_BLOCKDEVICE_INVALID_SIZE; + result = pal_blockdevice_get_slot_addr_size(slot_id, + &slot_addr, + &slot_size); + uint32_t physical_address = slot_addr + pal_blockdevice_hdr_size + offset; + uint32_t read_size = pal_blockdevice_round_up_to_page(buffer->size); + int32_t status = ARM_UC_BLOCKDEVICE_FAIL; + + if (read_size <= buffer->size_max) { + status = arm_uc_blockdevice_read(buffer->ptr, + physical_address, + read_size); + } + + if (status == ARM_UC_BLOCKDEVICE_SUCCESS) { + /* set return code */ + result.code = ERR_NONE; + + /* signal done */ + pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_READ_DONE); + } else { + UC_PAAL_ERR_MSG("arm_uc_blockdevice_read failed"); + } + } + + return result; +} + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param slot_id Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Activate(uint32_t slot_id) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_Activate"); + + pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_ACTIVATE_DONE); + + return result; +} + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param slot_id Storage location ID. + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_GetFirmwareDetails( + uint32_t slot_id, + arm_uc_firmware_details_t *details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) { + UC_PAAL_TRACE("ARM_UC_PAL_BlockDevice_GetFirmwareDetails"); + + /* find address of slot */ + uint32_t slot_addr = ARM_UC_BLOCKDEVICE_INVALID_SIZE; + uint32_t slot_size = ARM_UC_BLOCKDEVICE_INVALID_SIZE; + result = pal_blockdevice_get_slot_addr_size(slot_id, &slot_addr, &slot_size); + uint8_t buffer[pal_blockdevice_hdr_size]; + + int status = arm_uc_blockdevice_read(buffer, + slot_addr, + pal_blockdevice_hdr_size); + + if (status == ARM_UC_BLOCKDEVICE_SUCCESS) { + result = arm_uc_parse_external_header_v2(buffer, details); + + if (result.error == ERR_NONE) { + /* signal done */ + pal_blockdevice_signal_internal(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE); + } else { + UC_PAAL_ERR_MSG("arm_uc_parse_external_header_v2 failed"); + } + } else { + UC_PAAL_ERR_MSG("arm_uc_blockdevice_read failed"); + } + } + + return result; +} + +#endif // #if defined(ARM_UC_FEATURE_PAL_BLOCKDEVICE) diff --git a/modules/storage/pal-blockdevice/source/arm_uc_pal_blockdevice_mbed.cpp b/modules/storage/pal-blockdevice/source/arm_uc_pal_blockdevice_mbed.cpp new file mode 100644 index 0000000..3987c2e --- /dev/null +++ b/modules/storage/pal-blockdevice/source/arm_uc_pal_blockdevice_mbed.cpp @@ -0,0 +1,63 @@ +// ---------------------------------------------------------------------------- +// Copyright 2017-2018 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_config.h" +#if defined(ARM_UC_FEATURE_PAL_BLOCKDEVICE) && (ARM_UC_FEATURE_PAL_BLOCKDEVICE == 1) +#if defined(TARGET_LIKE_MBED) + +#include "update-client-pal-blockdevice/arm_uc_pal_blockdevice_platform.h" +#include "mbed.h" + +BlockDevice *arm_uc_blockdevice_ext = BlockDevice::get_default_instance(); + +int32_t arm_uc_blockdevice_init(void) +{ + return arm_uc_blockdevice_ext->init(); +} + +uint32_t arm_uc_blockdevice_get_program_size(void) +{ + return arm_uc_blockdevice_ext->get_program_size(); +} + +uint32_t arm_uc_blockdevice_get_erase_size(void) +{ + return arm_uc_blockdevice_ext->get_erase_size(); +} + +int32_t arm_uc_blockdevice_erase(uint64_t address, uint64_t size) +{ + return arm_uc_blockdevice_ext->erase(address, size); +} + +int32_t arm_uc_blockdevice_program(const uint8_t *buffer, + uint64_t address, + uint32_t size) +{ + return arm_uc_blockdevice_ext->program(buffer, address, size); +} + +int32_t arm_uc_blockdevice_read(uint8_t *buffer, + uint64_t address, + uint32_t size) +{ + return arm_uc_blockdevice_ext->read(buffer, address, size); +} + +#endif /* #if defined(TARGET_LIKE_MBED) */ +#endif /* defined(ARM_UC_FEATURE_PAL_BLOCKDEVICE) */ diff --git a/modules/storage/pal-blockdevice/update-client-pal-blockdevice/arm_uc_pal_blockdevice.h b/modules/storage/pal-blockdevice/update-client-pal-blockdevice/arm_uc_pal_blockdevice.h new file mode 100644 index 0000000..fd65e6e --- /dev/null +++ b/modules/storage/pal-blockdevice/update-client-pal-blockdevice/arm_uc_pal_blockdevice.h @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------- +// Copyright 2017-2018 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_FLASHIAP_BLOCKDEVICE_H +#define ARM_UC_PAL_FLASHIAP_BLOCKDEVICE_H + +#include "update-client-paal/arm_uc_paal_update_api.h" + +extern ARM_UC_PAAL_UPDATE ARM_UCP_FLASHIAP_BLOCKDEVICE; + +#endif /* ARM_UC_PAL_FLASHIAP_BLOCKDEVICE_H */ diff --git a/modules/storage/pal-blockdevice/update-client-pal-blockdevice/arm_uc_pal_blockdevice_implementation.h b/modules/storage/pal-blockdevice/update-client-pal-blockdevice/arm_uc_pal_blockdevice_implementation.h new file mode 100644 index 0000000..4d7048e --- /dev/null +++ b/modules/storage/pal-blockdevice/update-client-pal-blockdevice/arm_uc_pal_blockdevice_implementation.h @@ -0,0 +1,146 @@ +// ---------------------------------------------------------------------------- +// Copyright 2017-2018 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_BLOCKDEVICE_IMPLEMENTATION_H +#define ARM_UC_PAL_BLOCKDEVICE_IMPLEMENTATION_H + +#include "update-client-paal/arm_uc_paal_update_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize the underlying storage and set the callback handler. + * + * @param callback Function pointer to event handler. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); + +/** + * @brief Get maximum number of supported storage IDs. + * + * @return Number of storage locations. + */ +uint32_t ARM_UC_PAL_BlockDevice_GetMaxID(void); + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param slot_id Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Prepare(uint32_t slot_id, + const arm_uc_firmware_details_t *details, + arm_uc_buffer_t *buffer); + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param slot_id Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Write(uint32_t slot_id, + uint32_t offset, + const arm_uc_buffer_t *buffer); + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param slot_id Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Finalize(uint32_t slot_id); + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param slot_id Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. buffer->size + * contains the intended read size. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + * buffer->size contains actual bytes read on return. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Read(uint32_t slot_id, + uint32_t offset, + arm_uc_buffer_t *buffer); + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param slot_id Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_Activate(uint32_t slot_id); + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param slot_id Storage location ID. + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_BlockDevice_GetFirmwareDetails( + uint32_t slot_id, + arm_uc_firmware_details_t *details); + +#ifdef __cplusplus +} +#endif + +#endif /* ARM_UC_PAL_BLOCKDEVICE_H */ diff --git a/modules/storage/pal-blockdevice/update-client-pal-blockdevice/arm_uc_pal_blockdevice_platform.h b/modules/storage/pal-blockdevice/update-client-pal-blockdevice/arm_uc_pal_blockdevice_platform.h new file mode 100644 index 0000000..aaef0b6 --- /dev/null +++ b/modules/storage/pal-blockdevice/update-client-pal-blockdevice/arm_uc_pal_blockdevice_platform.h @@ -0,0 +1,97 @@ +// ---------------------------------------------------------------------------- +// Copyright 2017-2018 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_BLOCKDEVICE_PLATFORM_H +#define ARM_UC_PAL_BLOCKDEVICE_PLATFORM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + ARM_UC_BLOCKDEVICE_SUCCESS = 0, + ARM_UC_BLOCKDEVICE_FAIL = -1 +}; + +#define ARM_UC_BLOCKDEVICE_INVALID_SIZE 0xFFFFFFFF + +/** Initialize a block device + * + * @return 0 on success or a negative error code on failure + */ +int32_t arm_uc_blockdevice_init(void); + +/** Erase blocks on a block device + * + * The state of an erased block is undefined until it has been programmed + * + * @param address Address of block to begin erasing + * @param size Size to erase in bytes, must be a multiple of erase block size + * @return 0 on success, negative error code on failure + */ +int32_t arm_uc_blockdevice_erase(uint64_t address, uint64_t size); + +/** Program blocks to a block device + * + * The blocks must have been erased prior to being programmed + * + * If a failure occurs, it is not possible to determine how many bytes succeeded + * + * @param buffer Buffer of data to write to blocks + * @param address Address of block to begin writing to + * @param size Size to write in bytes, must be a multiple of program block size + * @return 0 on success, negative error code on failure + */ +int32_t arm_uc_blockdevice_program(const uint8_t *buffer, + uint64_t address, + uint32_t size); + +/** Read blocks from a block device + * + * If a failure occurs, it is not possible to determine how many bytes succeeded + * + * @param buffer Buffer to write blocks to + * @param address Address of block to begin reading from + * @param size Size to read in bytes, must be a multiple of read block size + * @return 0 on success, negative error code on failure + */ +int32_t arm_uc_blockdevice_read(uint8_t *buffer, + uint64_t address, + uint32_t size); + +/** Get the size of a programable block + * + * @return Size of a programable block in bytes + * @note Must be a multiple of the read size + */ +uint32_t arm_uc_blockdevice_get_program_size(void); + +/** Get the size of a eraseable block + * + * @return Size of a eraseable block in bytes + * @note Must be a multiple of the program size + */ +uint32_t arm_uc_blockdevice_get_erase_size(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ARM_UC_PAL_BLOCKDEVICE_PLATFORM_H */ diff --git a/modules/storage/pal-flashiap/LICENSE b/modules/storage/pal-flashiap/LICENSE new file mode 100644 index 0000000..c2bccaf --- /dev/null +++ b/modules/storage/pal-flashiap/LICENSE @@ -0,0 +1,166 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + diff --git a/modules/storage/pal-flashiap/source/arm_uc_pal_flashiap.c b/modules/storage/pal-flashiap/source/arm_uc_pal_flashiap.c new file mode 100644 index 0000000..2fe1898 --- /dev/null +++ b/modules/storage/pal-flashiap/source/arm_uc_pal_flashiap.c @@ -0,0 +1,56 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_config.h" +#if defined(ARM_UC_FEATURE_PAL_FLASHIAP) && (ARM_UC_FEATURE_PAL_FLASHIAP == 1) + +#include "update-client-paal/arm_uc_paal_update_api.h" + +#include "update-client-pal-flashiap/arm_uc_pal_flashiap_implementation.h" + +ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UC_PAL_FlashIAP_GetCapabilities(void) +{ + ARM_UC_PAAL_UPDATE_CAPABILITIES result = { + .installer_arm_hash = 0, + .installer_oem_hash = 0, + .installer_layout = 0, + .firmware_hash = 1, + .firmware_hmac = 0, + .firmware_campaign = 0, + .firmware_version = 1, + .firmware_size = 1 + }; + + return result; +} + +const ARM_UC_PAAL_UPDATE ARM_UCP_FLASHIAP = { + .Initialize = ARM_UC_PAL_FlashIAP_Initialize, + .GetCapabilities = ARM_UC_PAL_FlashIAP_GetCapabilities, + .GetMaxID = ARM_UC_PAL_FlashIAP_GetMaxID, + .Prepare = ARM_UC_PAL_FlashIAP_Prepare, + .Write = ARM_UC_PAL_FlashIAP_Write, + .Finalize = ARM_UC_PAL_FlashIAP_Finalize, + .Read = ARM_UC_PAL_FlashIAP_Read, + .Activate = ARM_UC_PAL_FlashIAP_Activate, + .GetActiveFirmwareDetails = ARM_UC_PAL_FlashIAP_GetActiveDetails, + .GetFirmwareDetails = ARM_UC_PAL_FlashIAP_GetFirmwareDetails, + .GetInstallerDetails = ARM_UC_PAL_FlashIAP_GetInstallerDetails +}; + +#endif /* ARM_UC_FEATURE_PAL_FLASHIAP */ diff --git a/modules/storage/pal-flashiap/source/arm_uc_pal_flashiap_implementation.c b/modules/storage/pal-flashiap/source/arm_uc_pal_flashiap_implementation.c new file mode 100644 index 0000000..9f546d4 --- /dev/null +++ b/modules/storage/pal-flashiap/source/arm_uc_pal_flashiap_implementation.c @@ -0,0 +1,701 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_config.h" +#if defined(ARM_UC_FEATURE_PAL_FLASHIAP) && (ARM_UC_FEATURE_PAL_FLASHIAP == 1) +#if defined(TARGET_LIKE_MBED) + +#define __STDC_FORMAT_MACROS + +#include "update-client-pal-flashiap/arm_uc_pal_flashiap.h" +#include "update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h" +#include "update-client-metadata-header/arm_uc_metadata_header_v2.h" + +#include +#include + +#ifndef MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS +#define MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS 0 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS +#define MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS 0 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS +#define MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS 0 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE +#define MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE 0 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE +#define MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE 1 +#endif + +#ifndef MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS +#define MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS 1 +#endif + +/* consistency check */ +#if (MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE == 0) +#error Update client storage page cannot be zero. +#endif + +#if (MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS == 0) +#error Update client storage locations must be at least 1. +#endif + +/* Check that the statically allocated buffers are aligned with the block size */ +#define ARM_UC_PAL_ONE_BUFFER (ARM_UC_BUFFER_SIZE / 2) +#define ARM_UC_PAL_PAGES (ARM_UC_PAL_ONE_BUFFER / MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) + +#if !((ARM_UC_PAL_PAGES * MBED_CONF_UPDATE_CLIENT_STORAGE_PAGE) == ARM_UC_PAL_ONE_BUFFER) +#error Update client buffer must be divisible by the block page size +#endif + +/* Use internal header format because we are using internal flash and + is assumed to be trusted */ +#define ARM_UC_PAL_HEADER_SIZE (uint32_t) ARM_UC_INTERNAL_HEADER_SIZE_V2 + +static uint64_t arm_uc_pal_flashiap_firmware_size = 0; + +static void (*arm_uc_pal_flashiap_callback)(uint32_t) = NULL; + +static void arm_uc_pal_flashiap_signal_internal(uint32_t event) +{ + if (arm_uc_pal_flashiap_callback) { + arm_uc_pal_flashiap_callback(event); + } +} + +/** + * @brief Align address up/down to sector boundary + * + * @param addr The address that need to be rounded up + * @param round_down if the value is 1, will align down to sector + boundary otherwise align up. + * @return Returns the address aligned to sector boundary + */ +static uint32_t arm_uc_pal_flashiap_align_to_sector(uint32_t addr, int8_t round_down) +{ + uint32_t sector_start_addr = arm_uc_flashiap_get_flash_start(); + + /* check the address is pointing to internal flash */ + if ((addr > sector_start_addr + arm_uc_flashiap_get_flash_size()) || + (addr < sector_start_addr)) { + return ARM_UC_FLASH_INVALID_SIZE; + } + + /* add sectors from start of flash until exeeced the required address + we cannot assume uniform sector size as in some mcu sectors have + drastically different sizes */ + uint32_t sector_size = ARM_UC_FLASH_INVALID_SIZE; + while (sector_start_addr < addr) { + sector_size = arm_uc_flashiap_get_sector_size(sector_start_addr); + if (sector_size != ARM_UC_FLASH_INVALID_SIZE) { + sector_start_addr += sector_size; + } else { + return ARM_UC_FLASH_INVALID_SIZE; + } + } + + /* if round down to nearest section, remove the last sector from addr */ + if (round_down != 0 && sector_start_addr > addr) { + sector_start_addr -= sector_size; + } + + return sector_start_addr; +} + +/** + * @brief Round size up to nearest page + * + * @param size The size that need to be rounded up + * @return Returns the size rounded up to the nearest page + */ +static uint32_t arm_uc_pal_flashiap_round_up_to_page_size(uint32_t size) +{ + uint32_t page_size = arm_uc_flashiap_get_page_size(); + + if (size != 0) { + size = ((size - 1) / page_size + 1) * page_size; + } + + return size; +} + +/** + * @brief Get the physicl slot address and size given slot_id + * + * @param slot_id Storage location ID. + * @param slot_addr the slot address is returned in this pointer + * @param slot_size the slot size is returned in this pointer + * @return Returns ERR_NONE on success. + * Returns ERR_INVALID_PARAMETER on error. + */ +static arm_uc_error_t arm_uc_pal_flashiap_get_slot_addr_size(uint32_t slot_id, + uint32_t *slot_addr, + uint32_t *slot_size) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + /* find the start address of the whole storage area. It needs to be aligned to + sector boundary and we cannot go outside user defined storage area, hence + rounding up to sector boundary */ + uint32_t storage_start_addr = arm_uc_pal_flashiap_align_to_sector( + MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS, 0); + /* find the end address of the whole storage area. It needs to be aligned to + sector boundary and we cannot go outside user defined storage area, hence + rounding down to sector boundary */ + uint32_t storage_end_addr = arm_uc_pal_flashiap_align_to_sector( + MBED_CONF_UPDATE_CLIENT_STORAGE_ADDRESS + \ + MBED_CONF_UPDATE_CLIENT_STORAGE_SIZE, 1); + /* find the maximum size each slot can have given the start and end, without + considering the alignment of individual slots */ + uint32_t max_slot_size = (storage_end_addr - storage_start_addr) / \ + MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS; + /* find the start address of slot. It needs to align to sector boundary. We + choose here to round down at each slot boundary */ + uint32_t slot_start_addr = arm_uc_pal_flashiap_align_to_sector( + storage_start_addr + \ + slot_id * max_slot_size, 1); + /* find the end address of the slot, rounding down to sector boundary same as + the slot start address so that we make sure two slot don't overlap */ + uint32_t slot_end_addr = arm_uc_pal_flashiap_align_to_sector( + slot_start_addr + \ + max_slot_size, 1); + + /* Any calculation above might result in an invalid address. */ + if ((storage_start_addr == ARM_UC_FLASH_INVALID_SIZE) || + (storage_end_addr == ARM_UC_FLASH_INVALID_SIZE) || + (slot_start_addr == ARM_UC_FLASH_INVALID_SIZE) || + (slot_end_addr == ARM_UC_FLASH_INVALID_SIZE) || + (slot_id >= MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS)) { + UC_PAAL_ERR_MSG("Aligning fw storage slot to erase sector failed" + " storage_start_addr %" PRIX32 " slot_start_addr %" PRIX32 + " max_slot_size %" PRIX32, storage_start_addr, slot_start_addr, + max_slot_size); + *slot_addr = ARM_UC_FLASH_INVALID_SIZE; + *slot_size = ARM_UC_FLASH_INVALID_SIZE; + } else { + *slot_addr = slot_start_addr; + *slot_size = slot_end_addr - slot_start_addr; + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Initialise the flash IAP API + * + * @param callback function pointer to the PAAL event handler + * @return Returns ERR_NONE on success. + * Returns ERR_INVALID_PARAMETER on error. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Initialize(void (*callback)(uint32_t)) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + int32_t status = arm_uc_flashiap_init(); + + if (status == ARM_UC_FLASHIAP_SUCCESS) { + arm_uc_pal_flashiap_callback = callback; + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_INITIALIZE_DONE); + + result.code = ERR_NONE; + } + + return result; +} + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UC_PAL_FlashIAP_GetMaxID(void) +{ + return MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS; +} + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param slot_id Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Prepare(uint32_t slot_id, + const arm_uc_firmware_details_t *details, + arm_uc_buffer_t *buffer) +{ + UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Prepare slot_id %" PRIu32 " details %p buffer %p", + slot_id, details, buffer); + + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + uint32_t slot_addr = ARM_UC_FLASH_INVALID_SIZE; + uint32_t slot_size = ARM_UC_FLASH_INVALID_SIZE; + uint32_t erase_size = ARM_UC_FLASH_INVALID_SIZE; + + /* validate input */ + if (details && buffer && buffer->ptr && \ + slot_id < MBED_CONF_UPDATE_CLIENT_STORAGE_LOCATIONS) { + UC_PAAL_TRACE("FW size %" PRIu64, details->size); + result.error = ERR_NONE; + } else { + UC_PAAL_TRACE("Input validation failed"); + } + + /* calculate space for new firmware */ + if (result.error == ERR_NONE) { + /* find slot start address */ + result = arm_uc_pal_flashiap_get_slot_addr_size(slot_id, &slot_addr, &slot_size); + + /* find the amount of space that need to be erased */ + erase_size = arm_uc_pal_flashiap_align_to_sector( + slot_addr + \ + arm_uc_pal_flashiap_round_up_to_page_size(details->size) + \ + arm_uc_pal_flashiap_round_up_to_page_size(ARM_UC_PAL_HEADER_SIZE), + 0) - slot_addr; + + if ((result.error == ERR_NONE) && (erase_size > slot_size)) { + result.code = PAAL_ERR_FIRMWARE_TOO_LARGE; + UC_PAAL_ERR_MSG("Firmware too large! required %" PRIX32 " available: %" PRIX32, + erase_size, slot_size); + } + } + + /* erase space for new firmware */ + if (result.error == ERR_NONE) { + uint32_t erase_addr = slot_addr; + while (erase_addr < slot_addr + erase_size) { + uint32_t sector_size = arm_uc_flashiap_get_sector_size(erase_addr); + UC_PAAL_TRACE("erase: addr %" PRIX32 " size %" PRIX32, + erase_addr, sector_size); + if (sector_size != ARM_UC_FLASH_INVALID_SIZE) { + int32_t status = arm_uc_flashiap_erase(erase_addr, sector_size); + if (status == ARM_UC_FLASHIAP_SUCCESS) { + erase_addr += sector_size; + } else { + UC_PAAL_ERR_MSG("Flash erase failed with status %" PRIi32, status); + result.code = ERR_INVALID_PARAMETER; + break; + } + } else { + UC_PAAL_ERR_MSG("Get sector size for addr %" PRIX32 " failed", erase_addr); + result.code = ERR_INVALID_PARAMETER; + break; + } + } + } + + /* generate header blob */ + if (result.error == ERR_NONE) { + result = arm_uc_create_internal_header_v2(details, buffer); + if (result.error != ERR_NONE) { + UC_PAAL_ERR_MSG("arm_uc_create_internal_header_v2 failed"); + } + } + + /* write header blob */ + if (result.error == ERR_NONE) { + uint32_t hdr_size = arm_uc_pal_flashiap_round_up_to_page_size(ARM_UC_PAL_HEADER_SIZE); + UC_PAAL_TRACE("program: %" PRIX32 " %" PRIX32, + slot_addr, hdr_size); + + /* write header */ + int32_t status = arm_uc_flashiap_program((const uint8_t *) buffer->ptr, + slot_addr, + hdr_size); + if (status != ARM_UC_FLASHIAP_SUCCESS) { + /* set return code */ + result.code = ERR_INVALID_PARAMETER; + } + } + + if (result.error == ERR_NONE) { + /* store firmware size in global */ + arm_uc_pal_flashiap_firmware_size = details->size; + + /* signal done */ + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_PREPARE_DONE); + } + + return result; +} + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param slot_id Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Write(uint32_t slot_id, + uint32_t offset, + const arm_uc_buffer_t *buffer) +{ + /* find slot address and size */ + uint32_t slot_addr = ARM_UC_FLASH_INVALID_SIZE; + uint32_t slot_size = ARM_UC_FLASH_INVALID_SIZE; + arm_uc_error_t result = arm_uc_pal_flashiap_get_slot_addr_size(slot_id, + &slot_addr, + &slot_size); + + if (buffer && buffer->ptr && result.error == ERR_NONE) { + UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Write: %p %" PRIX32 " %" PRIX32 " %" PRIX32, + buffer->ptr, buffer->size, slot_addr, offset); + + /* set default error */ + result.code = ERR_INVALID_PARAMETER; + + /* find physical address of the write */ + uint32_t page_size = arm_uc_flashiap_get_page_size(); + uint32_t hdr_size = arm_uc_pal_flashiap_round_up_to_page_size(ARM_UC_PAL_HEADER_SIZE); + uint32_t physical_address = slot_addr + hdr_size + offset; + uint32_t write_size = buffer->size; + + /* if last chunk, pad out to page_size aligned size */ + if ((buffer->size % page_size != 0) && + ((offset + buffer->size) >= arm_uc_pal_flashiap_firmware_size) && + (arm_uc_pal_flashiap_round_up_to_page_size(buffer->size) <= buffer->size_max)) { + write_size = arm_uc_pal_flashiap_round_up_to_page_size(buffer->size); + } + + /* check page alignment of the program address and size */ + if ((write_size % page_size == 0) && (physical_address % page_size == 0)) { + UC_PAAL_TRACE("programming addr %" PRIX32 " size %" PRIX32, + physical_address, write_size); + int status = arm_uc_flashiap_program((const uint8_t *) buffer->ptr, + physical_address, + write_size); + if (status != ARM_UC_FLASHIAP_SUCCESS) { + UC_PAAL_ERR_MSG("arm_uc_flashiap_program failed"); + } else { + result.code = ERR_NONE; + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_WRITE_DONE); + } + } else { + UC_PAAL_ERR_MSG("program size %" PRIX32 " or address %" PRIX32 + " not aligned to page size %" PRIX32, buffer->size, + physical_address, page_size); + } + } else { + result.code = ERR_INVALID_PARAMETER; + } + + return result; +} + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param slot_id Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Finalize(uint32_t slot_id) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Finalize"); + + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_FINALIZE_DONE); + + return result; +} + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param slot_id Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. buffer->size + * contains the intended read size. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + * buffer->size contains actual bytes read on return. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Read(uint32_t slot_id, + uint32_t offset, + arm_uc_buffer_t *buffer) +{ + /* find slot address and size */ + uint32_t slot_addr = ARM_UC_FLASH_INVALID_SIZE; + uint32_t slot_size = ARM_UC_FLASH_INVALID_SIZE; + arm_uc_error_t result = arm_uc_pal_flashiap_get_slot_addr_size(slot_id, + &slot_addr, + &slot_size); + + if (buffer && buffer->ptr && result.error == ERR_NONE) { + UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Read: %" PRIX32 " %" PRIX32 " %" PRIX32, + slot_id, offset, buffer->size); + + /* find physical address of the read */ + uint32_t read_size = buffer->size; + uint32_t hdr_size = arm_uc_pal_flashiap_round_up_to_page_size(ARM_UC_PAL_HEADER_SIZE); + uint32_t physical_address = slot_addr + hdr_size + offset; + + UC_PAAL_TRACE("reading addr %" PRIX32 " size %" PRIX32, + physical_address, read_size); + + int status = arm_uc_flashiap_read(buffer->ptr, + physical_address, + read_size); + + if (status == ARM_UC_FLASHIAP_SUCCESS) { + result.code = ERR_NONE; + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_READ_DONE); + } else { + result.code = ERR_INVALID_PARAMETER; + UC_PAAL_ERR_MSG("arm_uc_flashiap_read failed"); + } + } else { + result.code = ERR_INVALID_PARAMETER; + } + + return result; +} + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param slot_id Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Activate(uint32_t slot_id) +{ + arm_uc_error_t result = { .code = ERR_NONE }; + + UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_Activate"); + + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_ACTIVATE_DONE); + + return result; +} + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetFirmwareDetails( + uint32_t slot_id, + arm_uc_firmware_details_t *details) +{ + UC_PAAL_TRACE("ARM_UC_PAL_FlashIAP_GetFirmwareDetails"); + + /* find slot address and size */ + uint32_t slot_addr = ARM_UC_FLASH_INVALID_SIZE; + uint32_t slot_size = ARM_UC_FLASH_INVALID_SIZE; + arm_uc_error_t result = arm_uc_pal_flashiap_get_slot_addr_size(slot_id, + &slot_addr, + &slot_size); + + if (details && result.error == ERR_NONE) { + uint8_t buffer[ARM_UC_PAL_HEADER_SIZE] = { 0 }; + + int status = arm_uc_flashiap_read(buffer, + slot_addr, + ARM_UC_PAL_HEADER_SIZE); + + if (status == ARM_UC_FLASHIAP_SUCCESS) { + result = arm_uc_parse_internal_header_v2(buffer, details); + + if (result.error == ERR_NONE) { + /* signal done */ + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_FIRMWARE_DETAILS_DONE); + } else { + UC_PAAL_ERR_MSG("arm_uc_parse_internal_header_v2 failed"); + } + } else { + UC_PAAL_ERR_MSG("arm_uc_flashiap_read failed"); + } + } + + return result; +} + +/*****************************************************************************/ + +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetActiveDetails(arm_uc_firmware_details_t *details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) { + /* read details from memory if offset is set */ + if (MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS) { + /* set default error code */ + result.code = ERR_NOT_READY; + + /* Use flash driver eventhough we are reading from internal flash. + This will make it easier to use with uVisor. + */ + uint8_t version_buffer[8] = { 0 }; + + /* read metadata magic and version from flash */ + int rc = arm_uc_flashiap_read(version_buffer, + MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS, + 8); + + if (rc == ARM_UC_FLASHIAP_SUCCESS) { + /* read out header magic */ + uint32_t headerMagic = arm_uc_parse_uint32(&version_buffer[0]); + + /* read out header magic */ + uint32_t headerVersion = arm_uc_parse_uint32(&version_buffer[4]); + + /* choose version to decode */ + switch (headerVersion) { + case ARM_UC_INTERNAL_HEADER_VERSION_V2: { + result.code = ERR_NONE; + /* Check the header magic */ + if (headerMagic != ARM_UC_INTERNAL_HEADER_MAGIC_V2) { + UC_PAAL_ERR_MSG("firmware header is v2, but does not contain v2 magic"); + result.code = ERR_NOT_READY; + } + + uint8_t read_buffer[ARM_UC_INTERNAL_HEADER_SIZE_V2] = { 0 }; + /* Read the rest of the header */ + if (result.error == ERR_NONE) { + rc = arm_uc_flashiap_read(read_buffer, + MBED_CONF_UPDATE_CLIENT_APPLICATION_DETAILS, + ARM_UC_INTERNAL_HEADER_SIZE_V2); + if (rc != 0) { + result.code = ERR_NOT_READY; + UC_PAAL_ERR_MSG("failed to read v2 header"); + } + } + /* Parse the header */ + if (result.error == ERR_NONE) { + result = arm_uc_parse_internal_header_v2(read_buffer, details); + if (result.error != ERR_NONE) { + UC_PAAL_ERR_MSG("failed to parse v2 header"); + } + } + break; + } + /* + * Other firmware header versions can be supported here. + */ + default: { + UC_PAAL_ERR_MSG("unrecognized firmware header version"); + result.code = ERR_NOT_READY; + } + } + } else { + UC_PAAL_ERR_MSG("flash read failed"); + } + } else { + /* offset not set - zero out struct */ + memset(details, 0, sizeof(arm_uc_firmware_details_t)); + + result.code = ERR_NONE; + } + + /* signal event if operation was successful */ + if (result.error == ERR_NONE) { + UC_PAAL_TRACE("callback"); + + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE); + } + } + + return result; +} + +/** + * @brief Get details for the firmware installer. + * @details This call populates the passed details struct with information + * about the firmware installer. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetInstallerDetails(arm_uc_installer_details_t *details) +{ + arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER }; + + if (details) { + /* only read from memory if offset is set */ + if (MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS) { + uint8_t *arm = (uint8_t *)(MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS + + offsetof(arm_uc_installer_details_t, arm_hash)); + + uint8_t *oem = (uint8_t *)(MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS + + offsetof(arm_uc_installer_details_t, oem_hash)); + + uint8_t *layout = (uint8_t *)(MBED_CONF_UPDATE_CLIENT_BOOTLOADER_DETAILS + + offsetof(arm_uc_installer_details_t, layout)); + + /* populate installer details struct */ + memcpy(&details->arm_hash, arm, ARM_UC_SHA256_SIZE); + memcpy(&details->oem_hash, oem, ARM_UC_SHA256_SIZE); + details->layout = arm_uc_parse_uint32(layout); + } else { + /* offset not set, zero details struct */ + memset(details, 0, sizeof(arm_uc_installer_details_t)); + } + + arm_uc_pal_flashiap_signal_internal(ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE); + + result.code = ERR_NONE; + } + + return result; +} + +#endif /* TARGET_LIKE_MBED */ +#endif /* ARM_UC_FEATURE_PAL_FLASHIAP */ diff --git a/modules/storage/pal-flashiap/source/arm_uc_pal_flashiap_mbed.cpp b/modules/storage/pal-flashiap/source/arm_uc_pal_flashiap_mbed.cpp new file mode 100644 index 0000000..941d7f5 --- /dev/null +++ b/modules/storage/pal-flashiap/source/arm_uc_pal_flashiap_mbed.cpp @@ -0,0 +1,89 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#include "arm_uc_config.h" +#if defined(ARM_UC_FEATURE_PAL_FLASHIAP) && (ARM_UC_FEATURE_PAL_FLASHIAP == 1) +#if defined(TARGET_LIKE_MBED) + +#include "update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h" +#include "mbed.h" + +SingletonPtr flash; + +int32_t arm_uc_flashiap_init(void) +{ + /* Workaround for https://github.com/ARMmbed/mbed-os/issues/4967 + * pal_init calls flash.init() before here. Second call to flash.init() will + * return -1 error state. Hence we ignore the result of flash.init here. + */ + flash->init(); + return 0; +} + +int32_t arm_uc_flashiap_erase(uint32_t address, uint32_t size) +{ + return flash->erase(address, size); +} + +int32_t arm_uc_flashiap_program(const uint8_t *buffer, uint32_t address, uint32_t size) +{ + uint32_t page_size = flash->get_page_size(); + int status = ARM_UC_FLASHIAP_FAIL; + + for (uint32_t i = 0; i < size; i += page_size) { + status = flash->program(buffer + i, address + i, page_size); + if (status != ARM_UC_FLASHIAP_SUCCESS) { + break; + } + } + + return status; +} + +int32_t arm_uc_flashiap_read(uint8_t *buffer, uint32_t address, uint32_t size) +{ + return flash->read(buffer, address, size); +} + +uint32_t arm_uc_flashiap_get_page_size(void) +{ + return flash->get_page_size(); +} + +uint32_t arm_uc_flashiap_get_sector_size(uint32_t address) +{ + uint32_t sector_size = flash->get_sector_size(address); + if (sector_size == ARM_UC_FLASH_INVALID_SIZE || sector_size == 0) { + return ARM_UC_FLASH_INVALID_SIZE; + } else { + return sector_size; + } +} + +uint32_t arm_uc_flashiap_get_flash_size(void) +{ + return flash->get_flash_size(); +} + +uint32_t arm_uc_flashiap_get_flash_start(void) +{ + return flash->get_flash_start(); +} + +#endif /* TARGET_LIKE_MBED */ +#endif /* ARM_UC_FEATURE_PAL_FLASHIAP */ diff --git a/modules/storage/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap.h b/modules/storage/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap.h new file mode 100644 index 0000000..80804ad --- /dev/null +++ b/modules/storage/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap.h @@ -0,0 +1,26 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_FLASHIAP_H +#define ARM_UC_PAL_FLASHIAP_H + +#include "update-client-paal/arm_uc_paal_update_api.h" + +extern ARM_UC_PAAL_UPDATE ARM_UCP_FLASHIAP; + +#endif /* ARM_UC_PAL_FLASHIAP_H */ diff --git a/modules/storage/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap_implementation.h b/modules/storage/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap_implementation.h new file mode 100644 index 0000000..df125be --- /dev/null +++ b/modules/storage/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap_implementation.h @@ -0,0 +1,143 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_FLASHIAP_IMPLEMENTATION_H +#define ARM_UC_PAL_FLASHIAP_IMPLEMENTATION_H + +#include "update-client-paal/arm_uc_paal_update_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +arm_uc_error_t ARM_UC_PAL_FlashIAP_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); + +/** + * @brief Get maximum number of supported storage locations. + * + * @return Number of storage locations. + */ +uint32_t ARM_UC_PAL_FlashIAP_GetMaxID(void); + +/** + * @brief Prepare the storage layer for a new firmware image. + * @details The storage location is set up to receive an image with + * the details passed in the details struct. + * + * @param location Storage location ID. + * @param details Pointer to a struct with firmware details. + * @param buffer Temporary buffer for formatting and storing metadata. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Prepare(uint32_t location, + const arm_uc_firmware_details_t *details, + arm_uc_buffer_t *buffer); + +/** + * @brief Write a fragment to the indicated storage location. + * @details The storage location must have been allocated using the Prepare + * call. The call is expected to write the entire fragment before + * signaling completion. + * + * @param location Storage location ID. + * @param offset Offset in bytes to where the fragment should be written. + * @param buffer Pointer to buffer struct with fragment. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Write(uint32_t location, + uint32_t offset, + const arm_uc_buffer_t *buffer); + +/** + * @brief Close storage location for writing and flush pending data. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Finalize(uint32_t location); + +/** + * @brief Read a fragment from the indicated storage location. + * @details The function will read until the buffer is full or the end of + * the storage location has been reached. The actual amount of + * bytes read is set in the buffer struct. + * + * @param location Storage location ID. + * @param offset Offset in bytes to read from. + * @param buffer Pointer to buffer struct to store fragment. buffer->size + * contains the intended read size. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + * buffer->size contains actual bytes read on return. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Read(uint32_t location, + uint32_t offset, + arm_uc_buffer_t *buffer); + +/** + * @brief Set the firmware image in the slot to be the new active image. + * @details This call is responsible for initiating the process for + * applying a new/different image. Depending on the platform this + * could be: + * * An empty call, if the installer can deduce which slot to + * choose from based on the firmware details. + * * Setting a flag to indicate which slot to use next. + * * Decompressing/decrypting/installing the firmware image on + * top of another. + * + * @param location Storage location ID. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_Activate(uint32_t location); + +/** + * @brief Get firmware details for the firmware image in the slot passed. + * @details This call populates the passed details struct with information + * about the firmware image in the slot passed. Only the fields + * marked as supported in the capabilities bitmap will have valid + * values. + * + * @param details Pointer to firmware details struct to be populated. + * @return Returns ERR_NONE on accept, and signals the event handler with + * either DONE or ERROR when complete. + * Returns ERR_INVALID_PARAMETER on reject, and no signal is sent. + */ +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetFirmwareDetails( + uint32_t location, + arm_uc_firmware_details_t *details); + +/*****************************************************************************/ + +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetActiveDetails(arm_uc_firmware_details_t *details); + +arm_uc_error_t ARM_UC_PAL_FlashIAP_GetInstallerDetails(arm_uc_installer_details_t *details); + +#ifdef __cplusplus +} +#endif + +#endif // ARM_UC_PAL_FLASHIAP_IMPLEMENTATION_H diff --git a/modules/storage/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h b/modules/storage/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h new file mode 100644 index 0000000..bba51e6 --- /dev/null +++ b/modules/storage/pal-flashiap/update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h @@ -0,0 +1,110 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UC_PAL_FLASHIAP_PLATFORM_H +#define ARM_UC_PAL_FLASHIAP_PLATFORM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + ARM_UC_FLASHIAP_SUCCESS = 0, + ARM_UC_FLASHIAP_FAIL = -1 +}; + +#define ARM_UC_FLASH_INVALID_SIZE 0xFFFFFFFF + +/** Initialize a flash IAP device + * + * Should be called once per lifetime of the object. + * @return 0 on success or a negative error code on failure + */ +int32_t arm_uc_flashiap_init(void); + +/** Erase sectors + * + * The state of an erased sector is undefined until it has been programmed + * + * @param address Address of a sector to begin erasing, must be a multiple of the sector size + * @param size Size to erase in bytes, must be a multiple of the sector size + * @return 0 on success, negative error code on failure + */ +int32_t arm_uc_flashiap_erase(uint32_t address, uint32_t size); + +/** Program data to pages + * + * The sectors must have been erased prior to being programmed + * + * @param buffer Buffer of data to be written + * @param address Address of a page to begin writing to, must be a multiple of program and sector sizes + * @param size Size to write in bytes, must be a multiple of program and sector sizes + * @return 0 on success, negative error code on failure + */ +int32_t arm_uc_flashiap_program(const uint8_t *buffer, + uint32_t address, + uint32_t size); + +/** Read data from a flash device. + * + * This method invokes memcpy - reads number of bytes from the address + * + * @param buffer Buffer to write to + * @param address Flash address to begin reading from + * @param size Size to read in bytes + * @return 0 on success, negative error code on failure + */ +int32_t arm_uc_flashiap_read(uint8_t *buffer, + uint32_t address, + uint32_t size); + +/** Get the program page size + * + * @return Size of a program page in bytes + */ +uint32_t arm_uc_flashiap_get_page_size(void); + +/** Get the sector size at the defined address + * + * Sector size might differ at address ranges. + * An example <0-0x1000, sector size=1024; 0x10000-0x20000, size=2048> + * + * @param address Address of or inside the sector to query + * @return Size of a sector in bytes + */ +uint32_t arm_uc_flashiap_get_sector_size(uint32_t address); + +/** Get the flash size + * + * @return Size of the flash in bytes + */ +uint32_t arm_uc_flashiap_get_flash_size(void); + + +/** Get the flash start address + * + * @return Start address of the flash + */ +uint32_t arm_uc_flashiap_get_flash_start(void); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/modules/update-client-common/arm_uc_config.h b/modules/update-client-common/arm_uc_config.h new file mode 100644 index 0000000..585da5e --- /dev/null +++ b/modules/update-client-common/arm_uc_config.h @@ -0,0 +1,352 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_CONFIG_H +#define ARM_UPDATE_CONFIG_H + +#ifdef MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#include MBED_CLOUD_CLIENT_USER_CONFIG_FILE +#endif + +#ifndef MAX_SOURCES +#define MAX_SOURCES 10 +#endif + +#ifndef ARM_UC_SOCKET_MAX_RETRY +#define ARM_UC_SOCKET_MAX_RETRY 3 +#endif + +/* PROFILE FLAGS +ARM_UC_PROFILE_MBED_CLIENT_LITE +ARM_UC_PROFILE_MBED_CLOUD_CLIENT +*/ + +/* FEATURE FLAGS +ARM_UC_FEATURE_PAL_BLOCKDEVICE +ARM_UC_FEATURE_PAL_FILESYSTEM +ARM_UC_FEATURE_PAL_FLASHIAP +ARM_UC_FEATURE_PAL_LINUX +ARM_UC_FEATURE_PAL_RTL8195AM +ARM_UC_FEATURE_FW_SOURCE_HTTP +ARM_UC_FEATURE_FW_SOURCE_COAP +ARM_UC_FEATURE_FW_SOURCE_LOCAL_FILE +ARM_UC_FEATURE_RESUME_ENGINE +ARM_UC_FEATURE_MANIFEST_PUBKEY +ARM_UC_FEATURE_MANIFEST_PSK +ARM_UC_FEATURE_IDENTITY_NVSTORE +ARM_UC_FEATURE_IDENTITY_KCM +ARM_UC_FEATURE_IDENTITY_RAW_CONFIG +ARM_UC_FEATURE_CRYPTO_PAL +ARM_UC_FEATURE_CRYPTO_MBEDTLS +ARM_UC_FEATURE_CERT_STORE_KCM +ARM_UC_FEATURE_CERT_STORE_RAW +ARM_UC_FEATURE_PSK_STORE_NVSTORE +ARM_UC_FEATURE_PSK_STORE_RAW +*/ + +#define MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL_COAP 1 +#define MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL_HTTP 2 + +/* Map MCC Fetcher-flag to internal flag */ +#if defined(MBED_CONF_MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL) +#if MBED_CONF_MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL == MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL_COAP +#define ARM_UC_FEATURE_FW_SOURCE_COAP 1 +#define ARM_UC_FEATURE_FW_SOURCE_HTTP 0 +#elif MBED_CONF_MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL == MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL_HTTP +#define ARM_UC_FEATURE_FW_SOURCE_COAP 0 +#define ARM_UC_FEATURE_FW_SOURCE_HTTP 1 +#else +#error "Invalid value for MBED_CONF_MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL. Must be either MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL_HTTP or MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL_COAP." +#endif +#endif + +#if defined(MBED_CONF_MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL) && MBED_CONF_MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL == MBED_CLOUD_CLIENT_UPDATE_DOWNLOAD_PROTOCOL_HTTP +#define ARM_UC_FEATURE_FW_SOURCE_COAP 0 +#define ARM_UC_FEATURE_FW_SOURCE_HTTP 1 +#endif + +/* Map Legacy flags to new flags */ +#if defined(ARM_UC_USE_PAL_CRYPTO) && ARM_UC_USE_PAL_CRYPTO == 1 +#warning "ARM_UC_USE_PAL_CRYPTO DEPRECATED, See arm_uc_config.h for new flags." +#define ARM_UC_FEATURE_CRYPTO_PAL 1 +#endif + +#if defined(ARM_UC_USE_KCM) && ARM_UC_USE_KCM == 1 +#warning "ARM_UC_USE_KCM DEPRECATED, See arm_uc_config.h for new flags." +#define ARM_UC_FEATURE_IDENTITY_NVSTORE 0 +#define ARM_UC_FEATURE_IDENTITY_KCM 1 +#define ARM_UC_FEATURE_IDENTITY_RAW_CONFIG 0 +#define ARM_UC_FEATURE_PSK_STORE_NVSTORE 0 +#define ARM_UC_FEATURE_PSK_STORE_RAW 0 +#define ARM_UC_FEATURE_CERT_STORE_KCM 1 +#define ARM_UC_FEATURE_CERT_STORE_RAW 0 +#endif + +#if defined(ARM_UC_USE_CFSTORE) && ARM_UC_USE_CFSTORE != 0 +#error "CFSTORE SUPPORT DEPRECATED!" +#endif + +#if defined (ARM_UC_USE_RAW_CONFIG) && ARM_UC_USE_RAW_CONFIG == 1 +#warning "ARM_UC_USE_RAW_CONFIG DEPRECATED, See arm_uc_config.h for new flags." +#define ARM_UC_FEATURE_IDENTITY_NVSTORE 0 +#define ARM_UC_FEATURE_IDENTITY_KCM 0 +#define ARM_UC_FEATURE_IDENTITY_RAW_CONFIG 1 +#define ARM_UC_FEATURE_PSK_STORE_NVSTORE 0 +#define ARM_UC_FEATURE_PSK_STORE_RAW 1 +#define ARM_UC_FEATURE_CERT_STORE_KCM 0 +#define ARM_UC_FEATURE_CERT_STORE_RAW 1 +#endif + +#if defined (ARM_UC_USE_NVSTORE) && ARM_UC_USE_NVSTORE == 1 +#warning "ARM_UC_USE_NVSTORE DEPRECATED, See arm_uc_config.h for new flags." +#define ARM_UC_FEATURE_IDENTITY_NVSTORE 1 +#define ARM_UC_FEATURE_IDENTITY_KCM 0 +#define ARM_UC_FEATURE_IDENTITY_RAW_CONFIG 0 +#define ARM_UC_FEATURE_PSK_STORE_NVSTORE 1 +#define ARM_UC_FEATURE_PSK_STORE_RAW 0 +#define ARM_UC_FEATURE_CERT_STORE_KCM 0 +#define ARM_UC_FEATURE_CERT_STORE_RAW 0 +#endif + +/* Profile feature modifiers */ +#if defined(ARM_UC_PROFILE_MBED_CLIENT_LITE) && (ARM_UC_PROFILE_MBED_CLIENT_LITE == 1) + +#ifndef ARM_UC_FEATURE_MANIFEST_PUBKEY +#define ARM_UC_FEATURE_MANIFEST_PUBKEY 0 +#endif /* ARM_UC_FEATURE_MANIFEST_PUBKEY */ + +#ifndef ARM_UC_FEATURE_MANIFEST_PSK +#define ARM_UC_FEATURE_MANIFEST_PSK 1 +#endif /* ARM_UC_FEATURE_MANIFEST_PSK */ + +#ifndef ARM_UC_FEATURE_FW_SOURCE_COAP +#define ARM_UC_FEATURE_FW_SOURCE_COAP 1 +#endif /* ARM_UC_FEATURE_FW_SOURCE_COAP */ + +#ifndef ARM_UC_FEATURE_RESUME_ENGINE +#define ARM_UC_FEATURE_RESUME_ENGINE 0 +#endif /* ARM_UC_FEATURE_RESUME_ENGINE */ + +#ifndef ARM_UC_FEATURE_FW_SOURCE_HTTP +#define ARM_UC_FEATURE_FW_SOURCE_HTTP 0 +#endif /* ARM_UC_FEATURE_FW_SOURCE_HTTP */ + +#ifndef ARM_UC_FEATURE_FW_SOURCE_LOCAL_FILE +#define ARM_UC_FEATURE_FW_SOURCE_LOCAL_FILE 0 +#endif /* ARM_UC_FEATURE_FW_SOURCE_LOCAL_FILE */ + +#ifndef ARM_UC_FEATURE_CRYPTO_MBEDTLS +#define ARM_UC_FEATURE_CRYPTO_MBEDTLS 1 +#endif /* ARM_UC_FEATURE_CRYPTO_MBEDTLS */ + +#ifndef ARM_UC_FEATURE_IDENTITY_NVSTORE +#define ARM_UC_FEATURE_IDENTITY_NVSTORE 1 +#endif /* ARM_UC_FEATURE_IDENTITY_NVSTORE */ + +#ifndef ARM_UC_FEATURE_CERT_STORE_KCM +#define ARM_UC_FEATURE_CERT_STORE_KCM 0 +#endif /* ARM_UC_FEATURE_CERT_STORE_KCM */ + +#ifndef ARM_UC_FEATURE_CERT_STORE_RAW +#define ARM_UC_FEATURE_CERT_STORE_RAW 0 +#endif /* ARM_UC_FEATURE_CERT_STORE_RAW */ + +#ifndef ARM_UC_FEATURE_PSK_STORE_NVSTORE +#define ARM_UC_FEATURE_PSK_STORE_NVSTORE 1 +#endif /* ARM_UC_FEATURE_PSK_STORE_NVSTORE */ + +#ifndef ARM_UC_FEATURE_PSK_STORE_RAW +#define ARM_UC_FEATURE_PSK_STORE_RAW 0 +#endif /* ARM_UC_FEATURE_PSK_STORE_RAW */ + +#elif defined(ARM_UC_PROFILE_MBED_CLOUD_CLIENT) && (ARM_UC_PROFILE_MBED_CLOUD_CLIENT == 1) + +#ifndef ARM_UC_FEATURE_MANIFEST_PUBKEY +#define ARM_UC_FEATURE_MANIFEST_PUBKEY 1 +#endif /* ARM_UC_FEATURE_MANIFEST_PUBKEY */ + +#ifndef ARM_UC_FEATURE_MANIFEST_PSK +#define ARM_UC_FEATURE_MANIFEST_PSK 0 +#endif /* ARM_UC_FEATURE_MANIFEST_PSK */ + +#ifndef ARM_UC_FEATURE_FW_SOURCE_COAP +#define ARM_UC_FEATURE_FW_SOURCE_COAP 0 +#endif /* ARM_UC_FEATURE_FW_SOURCE_COAP */ + +#ifndef ARM_UC_FEATURE_FW_SOURCE_HTTP +#define ARM_UC_FEATURE_FW_SOURCE_HTTP 1 +#endif /* ARM_UC_FEATURE_FW_SOURCE_HTTP */ + +#ifndef ARM_UC_FEATURE_FW_SOURCE_LOCAL_FILE +#define ARM_UC_FEATURE_FW_SOURCE_LOCAL_FILE 0 +#endif /* ARM_UC_FEATURE_FW_SOURCE_LOCAL_FILE */ + +#ifndef ARM_UC_FEATURE_RESUME_ENGINE +#define ARM_UC_FEATURE_RESUME_ENGINE 1 +#endif /* ARM_UC_FEATURE_RESUME_ENGINE */ + +#ifndef ARM_UC_FEATURE_IDENTITY_KCM +#define ARM_UC_FEATURE_IDENTITY_KCM 1 +#endif /* ARM_UC_FEATURE_IDENTITY_RAW_CONFIG */ + +#ifndef ARM_UC_FEATURE_CRYPTO_PAL +#define ARM_UC_FEATURE_CRYPTO_PAL 1 +#endif /* ARM_UC_FEATURE_CRYPTO_PAL */ + +#ifndef ARM_UC_FEATURE_CERT_STORE_KCM +#define ARM_UC_FEATURE_CERT_STORE_KCM 1 +#endif /* ARM_UC_FEATURE_CERT_STORE_KCM */ + +#ifndef ARM_UC_FEATURE_CERT_STORE_RAW +#define ARM_UC_FEATURE_CERT_STORE_RAW 0 +#endif /* ARM_UC_FEATURE_CERT_STORE_RAW */ + +#ifndef ARM_UC_FEATURE_PSK_STORE_NVSTORE +#define ARM_UC_FEATURE_PSK_STORE_NVSTORE 0 +#endif /* ARM_UC_FEATURE_PSK_STORE_NVSTORE */ + +#ifndef ARM_UC_FEATURE_PSK_STORE_RAW +#define ARM_UC_FEATURE_PSK_STORE_RAW 0 +#endif /* ARM_UC_FEATURE_PSK_STORE_RAW */ + +#else + +#error "Please define macro ARM_UC_PROFILE_MBED_CLIENT_LITE=1 or ARM_UC_PROFILE_MBED_CLOUD_CLIENT=1." + +#endif /* ARM_UC_PROFILE_MBED_CLIENT_LITE */ + +/* Always have only one PAAL implementation */ +#if defined(UPDATE_CLIENT_STORAGE_FLASHIAP_BLOCKDEVICE) + +#define ARM_UC_FEATURE_PAL_FLASHIAP 1 +#define ARM_UC_FEATURE_PAL_BLOCKDEVICE 1 +#define ARM_UC_FEATURE_PAL_FILESYSTEM 0 +#define ARM_UC_FEATURE_PAL_LINUX 0 +#define ARM_UC_FEATURE_PAL_RTL8195AM 0 + +#elif defined(UPDATE_CLIENT_STORAGE_FLASHIAP) + +#define ARM_UC_FEATURE_PAL_FLASHIAP 1 +#define ARM_UC_FEATURE_PAL_BLOCKDEVICE 0 +#define ARM_UC_FEATURE_PAL_FILESYSTEM 0 +#define ARM_UC_FEATURE_PAL_LINUX 0 +#define ARM_UC_FEATURE_PAL_RTL8195AM 0 + +#elif defined(UPDATE_CLIENT_STORAGE_FILESYSTEM) + +#define ARM_UC_FEATURE_PAL_FLASHIAP 1 +#define ARM_UC_FEATURE_PAL_BLOCKDEVICE 0 +#define ARM_UC_FEATURE_PAL_FILESYSTEM 1 +#define ARM_UC_FEATURE_PAL_LINUX 0 +#define ARM_UC_FEATURE_PAL_RTL8195AM 0 + +#elif defined(UPDATE_CLIENT_STORAGE_LINUX_GENERIC) + +#define ARM_UC_FEATURE_PAL_FLASHIAP 0 +#define ARM_UC_FEATURE_PAL_BLOCKDEVICE 0 +#define ARM_UC_FEATURE_PAL_FILESYSTEM 0 +#define ARM_UC_FEATURE_PAL_LINUX 1 +#define ARM_UC_FEATURE_PAL_RTL8195AM 0 + +#elif defined(UPDATE_CLIENT_STORAGE_REALTEK_RTL8195AM) + +#define ARM_UC_FEATURE_PAL_FLASHIAP 0 +#define ARM_UC_FEATURE_PAL_BLOCKDEVICE 0 +#define ARM_UC_FEATURE_PAL_FILESYSTEM 0 +#define ARM_UC_FEATURE_PAL_LINUX 0 +#define ARM_UC_FEATURE_PAL_RTL8195AM 1 + +#else /* support legacy configuration method for storage */ + +#if defined(ARM_UC_USE_PAL_BLOCKDEVICE) && (ARM_UC_USE_PAL_BLOCKDEVICE == 1) +#define ARM_UC_FEATURE_PAL_BLOCKDEVICE 1 +#endif + +#if defined(TARGET_LIKE_MBED) +#define ARM_UC_FEATURE_PAL_FLASHIAP 1 +#endif + +#if defined(ARM_UC_PROFILE_MBED_CLOUD_CLIENT) && (ARM_UC_PROFILE_MBED_CLOUD_CLIENT == 1) +/* turn on all possible implementations */ +#define ARM_UC_FEATURE_PAL_FILESYSTEM 1 +#define ARM_UC_FEATURE_PAL_LINUX 1 +#define ARM_UC_FEATURE_PAL_RTL8195AM 1 + +#elif defined(ARM_UC_PROFILE_MBED_CLIENT_LITE) && (ARM_UC_PROFILE_MBED_CLIENT_LITE == 1) +/* turn on only pal flashiap */ +#define ARM_UC_FEATURE_PAL_FILESYSTEM 0 +#define ARM_UC_FEATURE_PAL_LINUX 0 +#define ARM_UC_FEATURE_PAL_RTL8195AM 0 + +#endif /* ARM_UC_PROFILE_MBED_CLOUD_CLIENT */ + +#endif + +/* Always have only one IDENTITY implementation */ +#if defined(ARM_UC_FEATURE_IDENTITY_NVSTORE) && (ARM_UC_FEATURE_IDENTITY_NVSTORE == 1) +#define ARM_UC_FEATURE_IDENTITY_KCM 0 +#define ARM_UC_FEATURE_IDENTITY_RAW_CONFIG 0 +#elif defined(ARM_UC_FEATURE_IDENTITY_KCM) && (ARM_UC_FEATURE_IDENTITY_KCM == 1) +#define ARM_UC_FEATURE_IDENTITY_NVSTORE 0 +#define ARM_UC_FEATURE_IDENTITY_RAW_CONFIG 0 +#elif defined(ARM_UC_FEATURE_IDENTITY_RAW_CONFIG) && (ARM_UC_FEATURE_IDENTITY_RAW_CONFIG == 1) +#define ARM_UC_FEATURE_IDENTITY_NVSTORE 0 +#define ARM_UC_FEATURE_IDENTITY_KCM 0 +#endif + +/* Always have only one CRYPTO implementation */ +#if defined(ARM_UC_FEATURE_CRYPTO_PAL) && (ARM_UC_FEATURE_CRYPTO_PAL == 1) +#define ARM_UC_FEATURE_CRYPTO_MBEDTLS 0 +#elif defined(ARM_UC_FEATURE_CRYPTO_MBEDTLS) && (ARM_UC_FEATURE_CRYPTO_MBEDTLS == 1) +#define ARM_UC_FEATURE_CRYPTO_PAL 0 +#endif + +/* Total memory allocated for download buffers. + For HTTP sources, this number cannot be below 1 KiB. +*/ +#ifdef MBED_CLOUD_CLIENT_UPDATE_BUFFER +#if MBED_CLOUD_CLIENT_UPDATE_BUFFER < 1024 +#error MBED_CLOUD_CLIENT_UPDATE_BUFFER must be 1024 bytes or more +#else +#define ARM_UC_BUFFER_SIZE MBED_CLOUD_CLIENT_UPDATE_BUFFER +#endif +#endif + +#ifndef ARM_UC_BUFFER_SIZE +#define ARM_UC_BUFFER_SIZE 1024 +#endif + +#define MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX "mbed.UpdateAuthCert." +#define MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_DEFAULT "mbed.UpdateAuthCert" +#define MBED_CLOUD_SHA256_BYTES (256/8) +#define MBED_CLOUD_BASE64_SIZE(X) (((X + 2)/3)*4) +#define MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_NAME_SIZE (MBED_CLOUD_BASE64_SIZE(MBED_CLOUD_SHA256_BYTES) + sizeof(MBED_CLOUD_CLIENT_UPDATE_CERTIFICATE_PREFIX)) + + +// NOTE: The charset must be sorted except for the trailing character which is used as a padding character. +#define MBED_CLOUD_UPDATE_BASE64_CHARSET "0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-" + +#ifndef ARM_UC_SCHEDULER_STORAGE_POOL_SIZE +#define ARM_UC_SCHEDULER_STORAGE_POOL_SIZE 32 +#endif + +#if defined(ARM_UC_FEATURE_ROOTLESS_STAGE_1) && (ARM_UC_FEATURE_ROOTLESS_STAGE_1 == 1) && !defined(TARGET_IS_PC_LINUX) +#error The rootless update feature can be enabled only for Linux builds. +#endif + +#endif // ARM_UPDATE_CONFIG_H diff --git a/modules/update-client-common/arm_uc_error.h b/modules/update-client-common/arm_uc_error.h new file mode 100644 index 0000000..1831641 --- /dev/null +++ b/modules/update-client-common/arm_uc_error.h @@ -0,0 +1,246 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_ERROR_H +#define ARM_UPDATE_ERROR_H + +#include + +// Use two characters to form the 16bit module code +#define TWO_CC(A,B) (((A) & 0xFF) | (((B) & 0xFF) << 8)) +#define CC_ASCII(X) ((((X) < ' ') || ((X) > '~' )) ? '.' : (X)) + +#define MANIFEST_MANAGER_PREFIX TWO_CC('M','M') +#define CERTIFICATE_MANAGER_PREFIX TWO_CC('C','M') +#define SOURCE_MANAGER_PREFIX TWO_CC('S','M') +#define SOURCE_PREFIX TWO_CC('S','E') +#define FIRMWARE_MANAGER_PREFIX TWO_CC('F','M') +#define DER_PARSER_PREFIX TWO_CC('D','P') +#define MBED_TLS_ERROR_PREFIX TWO_CC('M','T') +#define UPDATE_CRYPTO_PREFIX TWO_CC('C','U') +#define DEVICE_IDENTITY_PREFIX TWO_CC('D','I') +#define HUB_PREFIX TWO_CC('H','B') +#define EVENT_QUEUE_PREFIX TWO_CC('E','Q') +#define PAAL_PREFIX TWO_CC('P','L') + +#define ARM_UC_COMMON_ERR_LIST\ + ENUM_FIXED(ERR_NONE,0)\ + ENUM_AUTO(ERR_UNSPECIFIED)\ + ENUM_AUTO(ERR_INVALID_PARAMETER)\ + ENUM_AUTO(ERR_NULL_PTR)\ + ENUM_AUTO(ERR_NOT_READY)\ + ENUM_AUTO(ERR_INVALID_STATE)\ + +// Manifest manager +#define ARM_UC_MM_ERR_LIST\ + ENUM_FIXED(MFST_ERR_FIRST, MANIFEST_MANAGER_PREFIX << 16)\ + ENUM_AUTO(MFST_ERR_NULL_PTR)\ + ENUM_AUTO(MFST_ERR_NOT_READY)\ + ENUM_AUTO(MFST_ERR_PENDING)\ + ENUM_AUTO(MFST_ERR_SIZE)\ + ENUM_AUTO(MFST_ERR_DER_FORMAT)\ + ENUM_AUTO(MFST_ERR_FORMAT)\ + ENUM_AUTO(MFST_ERR_VERSION)\ + ENUM_AUTO(MFST_ERR_ROLLBACK)\ + ENUM_AUTO(MFST_ERR_CRYPTO_MODE)\ + ENUM_AUTO(MFST_ERR_HASH)\ + ENUM_AUTO(MFST_ERR_GUID_VENDOR)\ + ENUM_AUTO(MFST_ERR_GUID_DEVCLASS)\ + ENUM_AUTO(MFST_ERR_GUID_DEVICE)\ + ENUM_AUTO(MFST_ERR_CFG_CREATE_FAILED)\ + ENUM_AUTO(MFST_ERR_KEY_SIZE)\ + ENUM_AUTO(MFST_ERR_CERT_INVALID)\ + ENUM_AUTO(MFST_ERR_CERT_NOT_FOUND)\ + ENUM_AUTO(MFST_ERR_CERT_READ)\ + ENUM_AUTO(MFST_ERR_INVALID_SIGNATURE)\ + ENUM_AUTO(MFST_ERR_INVALID_STATE)\ + ENUM_AUTO(MFST_ERR_BAD_EVENT)\ + ENUM_AUTO(MFST_ERR_EMPTY_FIELD)\ + ENUM_AUTO(MFST_ERR_NO_MANIFEST)\ + ENUM_AUTO(MFST_ERR_SIGNATURE_ALGORITHM)\ + ENUM_AUTO(MFST_ERR_UNSUPPORTED_CONDITION)\ + ENUM_AUTO(MFST_ERR_CTR_IV_SIZE)\ + ENUM_AUTO(MFST_ERR_MISSING_KEYTABLE)\ + ENUM_AUTO(MFST_ERR_BAD_KEYTABLE)\ + ENUM_AUTO(MFST_ERR_LAST)\ + +// Certificate Manager +#define ARM_UC_CM_ERR_LIST\ + ENUM_FIXED(ARM_UC_CM_ERR_FIRST, CERTIFICATE_MANAGER_PREFIX << 16)\ + ENUM_AUTO(ARM_UC_CM_ERR_INVALID_PARAMETER)\ + ENUM_AUTO(ARM_UC_CM_ERR_NOT_FOUND)\ + ENUM_AUTO(ARM_UC_CM_ERR_INVALID_CERT)\ + ENUM_AUTO(ARM_UC_CM_ERR_BLACKLISTED)\ + ENUM_AUTO(ARM_UC_CM_ERR_LAST)\ + +// temporary declaration to avoid CI issues. +#define ARM_UC_CM_ERR_NONE ERR_NONE + +// DER Parser +#define ARM_UC_DP_ERR_LIST\ + ENUM_FIXED(ARM_UC_DP_ERR_FIRST, DER_PARSER_PREFIX << 16)\ + ENUM_AUTO(ARM_UC_DP_ERR_UNKNOWN)\ + ENUM_AUTO(ARM_UC_DP_ERR_NOT_FOUND)\ + ENUM_AUTO(ARM_UC_DP_ERR_NO_MORE_ELEMENTS)\ + ENUM_AUTO(ARM_UC_DP_ERR_LAST)\ + +// Source Manager +#define ARM_UC_SM_ERR_LIST\ + ENUM_FIXED(SOMA_ERR_FIRST, SOURCE_MANAGER_PREFIX << 16)\ + ENUM_AUTO(SOMA_ERR_UNSPECIFIED)\ + ENUM_AUTO(SOMA_ERR_NETWORK_TIMEOUT)\ + ENUM_AUTO(SOMA_ERR_CONNECTION_FAILURE)\ + ENUM_AUTO(SOMA_ERR_DNS_LOOKUP_FAILURE)\ + ENUM_AUTO(SOMA_ERR_CONNECTION_LOSS)\ + ENUM_AUTO(SOMA_ERR_NO_ROUTE_TO_SOURCE)\ + ENUM_AUTO(SOMA_ERR_SOURCE_REGISTRY_FULL)\ + ENUM_AUTO(SOMA_ERR_SOURCE_NOT_FOUND)\ + ENUM_AUTO(SOMA_ERR_INVALID_URI)\ + ENUM_AUTO(SOMA_ERR_INVALID_REQUEST)\ + ENUM_AUTO(SOMA_ERR_INVALID_PARAMETER)\ + ENUM_AUTO(SOMA_ERR_INVALID_MANIFEST_STATE)\ + ENUM_AUTO(SOMA_ERR_INVALID_FW_STATE)\ + ENUM_AUTO(SOMA_ERR_INVALID_EVENT)\ + ENUM_AUTO(SOMA_ERR_LAST)\ + +// Source +#define ARM_UC_SRC_ERR_LIST\ + ENUM_FIXED(SRCE_ERR_FIRST, SOURCE_PREFIX << 16)\ + ENUM_AUTO(SRCE_ERR_UNINITIALIZED)\ + ENUM_AUTO(SRCE_ERR_INVALID_PARAMETER)\ + ENUM_AUTO(SRCE_ERR_FAILED)\ + ENUM_AUTO(SRCE_ERR_ABORT)\ + ENUM_AUTO(SRCE_ERR_BUSY)\ + ENUM_AUTO(SRCE_ERR_LAST)\ + +// Firmware Manager +#define ARM_UC_FM_ERR_LIST\ + ENUM_FIXED(FIRM_ERR_FIRST, FIRMWARE_MANAGER_PREFIX << 16)\ + ENUM_AUTO(FIRM_ERR_WRITE)\ + ENUM_AUTO(FIRM_ERR_INVALID_PARAMETER)\ + ENUM_AUTO(FIRM_ERR_INVALID_STATE)\ + ENUM_AUTO(FIRM_ERR_ACTIVATE)\ + ENUM_AUTO(FIRM_ERR_UNINITIALIZED)\ + ENUM_AUTO(FIRM_ERR_INVALID_HASH)\ + ENUM_AUTO(FIRM_ERR_FIRMWARE_TOO_LARGE)\ + ENUM_AUTO(FIRM_ERR_LAST)\ + +#define ARM_UC_CU_ERR_LIST\ + ENUM_FIXED(ARM_UC_CU_ERR_FIRST, UPDATE_CRYPTO_PREFIX << 16)\ + ENUM_AUTO(ARM_UC_CU_ERR_INVALID_PARAMETER)\ + ENUM_AUTO(ARM_UC_CU_ERR_LAST)\ + +#define ARM_UC_DI_ERR_LIST\ + ENUM_FIXED(ARM_UC_DI_ERR_FIRST, DEVICE_IDENTITY_PREFIX << 16)\ + ENUM_AUTO(ARM_UC_DI_ERR_INVALID_PARAMETER)\ + ENUM_AUTO(ARM_UC_DI_ERR_NOT_READY)\ + ENUM_AUTO(ARM_UC_DI_ERR_NOT_FOUND)\ + ENUM_AUTO(ARM_UC_DI_ERR_SIZE)\ + ENUM_AUTO(ARM_UC_DI_ERR_LAST)\ + +#define ARM_UC_HB_ERR_LIST\ + ENUM_FIXED(HUB_ERR_FIRST, HUB_PREFIX << 16)\ + ENUM_AUTO(HUB_ERR_INTERNAL_ERROR)\ + ENUM_AUTO(HUB_ERR_ROLLBACK_PROTECTION)\ + ENUM_AUTO(ARM_UC_HUB_ERR_NOT_AVAILABLE)\ + ENUM_AUTO(HUB_ERR_CONNECTION)\ + ENUM_AUTO(HUB_ERR_LAST)\ + +#define ARM_UC_EQ_ERR_LIST\ + ENUM_FIXED(ARM_UC_EQ_ERR_FIRST, EVENT_QUEUE_PREFIX << 16)\ + ENUM_AUTO(ARM_UC_EQ_ERR_POOL_EXHAUSTED)\ + ENUM_AUTO(ARM_UC_EQ_ERR_FAILED_TAKE)\ + ENUM_AUTO(ARM_UC_EQ_ERR_LAST)\ + +// PAAL +#define ARM_UC_PAAL_ERR_LIST\ + ENUM_FIXED(PAAL_ERR_FIRST, PAAL_PREFIX << 16)\ + ENUM_AUTO(PAAL_ERR_FIRMWARE_TOO_LARGE)\ + ENUM_AUTO(PAAL_ERR_LAST)\ + +#define ARM_UC_ERR_LIST\ + ARM_UC_COMMON_ERR_LIST\ + ARM_UC_MM_ERR_LIST\ + ARM_UC_CM_ERR_LIST\ + ARM_UC_DP_ERR_LIST\ + ARM_UC_SM_ERR_LIST\ + ARM_UC_SRC_ERR_LIST\ + ARM_UC_FM_ERR_LIST\ + ARM_UC_CU_ERR_LIST\ + ARM_UC_DI_ERR_LIST\ + ARM_UC_HB_ERR_LIST\ + ARM_UC_EQ_ERR_LIST\ + ARM_UC_PAAL_ERR_LIST\ + +enum arm_uc_error { +#define ENUM_AUTO(name) name, +#define ENUM_FIXED(name, val) name = val, + ARM_UC_ERR_LIST +#undef ENUM_AUTO +#undef ENUM_FIXED +}; +union arm_uc_error_code { + int32_t code; + struct { + int16_t error; + union { + uint16_t module; + uint8_t modulecc[2]; + }; + }; +}; + +typedef union arm_uc_error_code arm_uc_error_t; + +#define ARM_UC_ERROR(CODE) ((arm_uc_error_t){ CODE }) +#define ARM_UC_IS_ERROR(VAR) ((VAR).code != ERR_NONE) +#define ARM_UC_IS_NOT_ERROR(VAR) (!ARM_UC_IS_ERROR(VAR)) +#define ARM_UC_ERROR_MATCHES(VAR,CODE) ((VAR).code == CODE) + +#define ARM_UC_CLEAR_ERROR(ERR) ((ERR).code = (ERR_NONE)) +#define ARM_UC_INIT_ERROR(VAR, CODE) arm_uc_error_t (VAR) = arm_uc_code_to_error( CODE ) +#define ARM_UC_GET_ERROR(VAR) ((VAR).code) + +#if ARM_UC_ERROR_TRACE_ENABLE +#define ARM_UC_SET_ERROR(VAR, CODE)\ + do { (VAR).code = (CODE);\ + if ( ARM_UC_IS_ERROR(VAR) ) \ + UC_ERROR_TRACE("set error %" PRIx32, (long unsigned int)CODE);\ + } while (0) +#else +#define ARM_UC_SET_ERROR(VAR, CODE) (VAR).code = (CODE) +#endif +// have a way to set errors without trace for values that are not strictly errors. +#define ARM_UC_SET_ERROR_NEVER_TRACE(VAR, CODE) (VAR).code = (CODE) + +#ifdef __cplusplus +extern "C" { +#endif + +const char *ARM_UC_err2Str(arm_uc_error_t err); +static inline arm_uc_error_t arm_uc_code_to_error(int32_t code) +{ + arm_uc_error_t err; + err.code = code; + return err; +} + +#ifdef __cplusplus +} +#endif +#endif // ARM_UPDATE_ERROR_H diff --git a/modules/update-client-common/arm_uc_types.h b/modules/update-client-common/arm_uc_types.h new file mode 100644 index 0000000..d31e2f8 --- /dev/null +++ b/modules/update-client-common/arm_uc_types.h @@ -0,0 +1,75 @@ +// ---------------------------------------------------------------------------- +// Copyright 2016-2017 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef ARM_UPDATE_COMMON_TYPES_H +#define ARM_UPDATE_COMMON_TYPES_H + +#include + +typedef struct { + uint32_t size_max; // maximum size of the buffer + uint32_t size; // index of the first empty byte in the buffer + uint8_t *ptr; // pointer to buffer's memory +} arm_uc_buffer_t; + +#define ARM_UC_GUID_SIZE (128/8) +#define ARM_UC_SHA256_SIZE (256/8) +#define ARM_UC_SHA512_SIZE (512/8) +#define ARM_UC_AES256_KEY_SIZE (256/8) +#define ARM_UC_AES_BLOCK_SIZE (128/8) +#define ARM_UC_ROT_SIZE (128/8) +#define ARM_UC_DEVICE_KEY_SIZE (256/8) + +#define ARM_UC_DEVICE_HMAC_KEY "StorageEnc256HMACSHA256SIGNATURE" +#define ARM_UC_DEVICE_HMAC_KEY_SIZE (sizeof(ARM_UC_DEVICE_HMAC_KEY) - 1) + +/** + * @brief GUID type + */ +typedef uint8_t arm_uc_guid_t[ARM_UC_GUID_SIZE]; + +/** + * @brief SHA256 hash + */ +typedef uint8_t arm_uc_hash_t[ARM_UC_SHA256_SIZE]; + +/** + * @brief Firmware details struct. + * @details Struct for passing information between the Update client and the + * PAAL implementation describing the firmware image. + */ +typedef struct _arm_uc_firmware_details_t { + uint64_t version; + uint64_t size; + arm_uc_hash_t hash; + arm_uc_guid_t campaign; + uint32_t signatureSize; + uint8_t signature[0]; +} arm_uc_firmware_details_t; + +/** + * @brief Installer details struct. + * @details Struct for reading the installer information. + */ +typedef struct _arm_uc_installer_details_t { + arm_uc_hash_t arm_hash; + arm_uc_hash_t oem_hash; + uint32_t layout; +} arm_uc_installer_details_t; + +#endif // ARM_UPDATE_COMMON_TYPES_H diff --git a/modules/update-client-common/mbed_lib.json b/modules/update-client-common/mbed_lib.json new file mode 100644 index 0000000..635550b --- /dev/null +++ b/modules/update-client-common/mbed_lib.json @@ -0,0 +1,63 @@ +{ + "name": "update-client", + "config": { + "application-details": { + "help": "Location in memory where the application information can be read.", + "value": "0" + }, + "bootloader-details": { + "help": "Location in memory where the bootloader information can be read.", + "value": "0" + }, + "storage-address": { + "help": "When using address based storage (FlashIAP, Block Device), this is the starting address.", + "value": "0" + }, + "storage-size": { + "help": "Total storage allocated.", + "value": "0" + }, + "storage-locations": { + "help": "Number of equally sized locations the storage space should be split into.", + "value": "1" + }, + "storage-page": { + "help": "Smallest write unit on storage device. Used for compile time check of download/write buffers.", + "value": "512" + }, + "firmware-header-version": { + "help": "Version of the firmware metadata header.", + "value": "0" + }, + "http-resume-attempt-test-messages-enable": { + "help": "Print messages indicating HTTP-resume actions for QA/test purposes.", + "macro_name": "ARM_UC_HTTP_RESUME_TEST_MESSAGES_ENABLE", + "value": "0" + }, + "http-resume-fragments-per-burst": { + "help": "Number of fragments to be requested per HTTP GET from server.", + "macro_name": "ARM_UC_MULTI_FRAGS_PER_HTTP_BURST", + "value": "64" + }, + "http-resume-exponentiation-factor": { + "help": "Multiplier for consecutive resume-attempt delay periods.", + "macro_name": "ARM_UC_HTTP_RESUME_EXPONENTIATION_FACTOR", + "value": "2" + }, + "http-resume-initial-delay-secs": { + "help": "Initial delay for HTTP-resume actions after which period resume goes active.", + "macro_name": "ARM_UC_HTTP_RESUME_INITIAL_DELAY_SECS", + "value": "5" + }, + "http-resume-maximum-delay-secs": { + "help": "Maximum delay for HTTP-resume actions after which period resume goes active.", + "macro_name": "ARM_UC_HTTP_RESUME_MAXIMUM_DELAY_SECS", + "value": "(60*60)" + }, + "http-resume-maximum-download-time-secs": { + "help": "Period for HTTP-resume actions after which resume gives up and terminates.", + "macro_name": "ARM_UC_HTTP_RESUME_MAXIMUM_DOWNLOAD_TIME_SECS", + "value": "(7*24*60*60)" + } + } +} diff --git a/sd-driver.lib b/sd-driver.lib deleted file mode 100644 index 8e74be5..0000000 --- a/sd-driver.lib +++ /dev/null @@ -1 +0,0 @@ -https://github.com/ARMmbed/sd-driver/#ae7e7440054c9447f8255bdccbcc523b3f6dffe4 diff --git a/source/active_application.cpp b/source/active_application.cpp index 5399a0f..ce424ef 100755 --- a/source/active_application.cpp +++ b/source/active_application.cpp @@ -23,8 +23,7 @@ #include "active_application.h" #include "bootloader_common.h" -#include "update-client-common/arm_uc_metadata_header_v2.h" -#include "update-client-common/arm_uc_utilities.h" +#include "update-client-metadata-header/arm_uc_metadata_header_v2.h" #include "update-client-paal/arm_uc_paal_update.h" #include "mbedtls/sha256.h" #include "mbed.h" @@ -107,7 +106,7 @@ int checkActiveApplication(arm_uc_firmware_details_t *details) /* calculate hash if header is valid and slot is not empty */ if ((headerValid) && (details->size > 0)) { - uint32_t appStart = MBED_CONF_APP_APPLICATION_START_ADDRESS; + uint32_t appStart = MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS; tr_debug("header start: 0x%08" PRIX32, (uint32_t) FIRMWARE_METADATA_HEADER_ADDRESS); @@ -224,8 +223,8 @@ bool eraseActiveFirmware(uint32_t firmwareSize) int result = 0; if (((FIRMWARE_METADATA_HEADER_ADDRESS + fw_metadata_hdr_size) < \ - (MBED_CONF_APP_APPLICATION_START_ADDRESS)) || \ - (FIRMWARE_METADATA_HEADER_ADDRESS > MBED_CONF_APP_APPLICATION_START_ADDRESS)) { + (MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS)) || \ + (FIRMWARE_METADATA_HEADER_ADDRESS > MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS)) { /* header separate from app */ tr_debug("Erasing header separately from active application"); @@ -234,10 +233,10 @@ bool eraseActiveFirmware(uint32_t firmwareSize) /* setup erase of the application region */ size_needed = firmwareSize; - erase_start_addr = MBED_CONF_APP_APPLICATION_START_ADDRESS; + erase_start_addr = MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS; } else { /* header contiguous with app */ /* setup erase of the header + application region */ - size_needed = (MBED_CONF_APP_APPLICATION_START_ADDRESS - FIRMWARE_METADATA_HEADER_ADDRESS) + firmwareSize; + size_needed = (MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS - FIRMWARE_METADATA_HEADER_ADDRESS) + firmwareSize; erase_start_addr = FIRMWARE_METADATA_HEADER_ADDRESS; } @@ -245,17 +244,17 @@ bool eraseActiveFirmware(uint32_t firmwareSize) uint32_t erase_end_addr = erase_start_addr + \ getSectorAlignedSize(erase_start_addr, size_needed); - uint32_t max_end_addr = MBED_CONF_APP_MAX_APPLICATION_SIZE + \ - MBED_CONF_APP_APPLICATION_START_ADDRESS; - /* check that the erase will not exceed MBED_CONF_APP_MAX_APPLICATION_SIZE */ + uint32_t max_end_addr = MBED_CONF_MBED_BOOTLOADER_MAX_APPLICATION_SIZE + \ + MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS; + /* check that the erase will not exceed MBED_CONF_MBED_BOOTLOADER_MAX_APPLICATION_SIZE */ if (erase_end_addr <= max_end_addr) { result = eraseSectorBySector(erase_start_addr, size_needed); } else { result = -1; tr_error("Firmware size 0x%" PRIX32 " rounded up to the nearest sector boundary 0x%" \ PRIX32 " is larger than the maximum application size 0x%" PRIX32, - firmwareSize, erase_end_addr - MBED_CONF_APP_APPLICATION_START_ADDRESS, - MBED_CONF_APP_MAX_APPLICATION_SIZE); + firmwareSize, erase_end_addr - MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS, + (uint32_t) MBED_CONF_MBED_BOOTLOADER_MAX_APPLICATION_SIZE); } } @@ -284,7 +283,7 @@ bool writeActiveFirmwareHeader(arm_uc_firmware_details_t *details) /* coverity[no_escape] */ MBED_BOOTLOADER_ASSERT((programSize <= fw_metadata_hdr_size), - "Header program size %" PRIu32 " bigger than expected header %d\r\n", + "Header program size %" PRIu32 " bigger than expected header %" PRIu32 "\r\n", programSize, fw_metadata_hdr_size); /* pad buffer to 0xFF */ @@ -324,7 +323,7 @@ bool writeActiveFirmware(uint32_t index, arm_uc_firmware_details_t *details) const uint32_t pageSize = flash.get_page_size(); /* we require app_start_addr fall on a page size boundary */ - uint32_t app_start_addr = MBED_CONF_APP_APPLICATION_START_ADDRESS; + uint32_t app_start_addr = MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS; /* coverity[no_escape] */ MBED_BOOTLOADER_ASSERT((app_start_addr % pageSize) == 0, diff --git a/bootloader_mbedtls_user_config.h b/source/bootloader_mbedtls_user_config.h similarity index 100% rename from bootloader_mbedtls_user_config.h rename to source/bootloader_mbedtls_user_config.h diff --git a/source/example_insecure_rot.c b/source/example_insecure_rot.c index 0be26ab..0ae3f34 100644 --- a/source/example_insecure_rot.c +++ b/source/example_insecure_rot.c @@ -16,7 +16,7 @@ // limitations under the License. // ---------------------------------------------------------------------------- -#if !defined(ARM_BOOTLOADER_USE_NVSTORE_ROT) || ARM_BOOTLOADER_USE_NVSTORE_ROT == 0 +#if !defined(ARM_BOOTLOADER_USE_KVSTORE_ROT) || ARM_BOOTLOADER_USE_KVSTORE_ROT == 0 #include #include @@ -52,4 +52,4 @@ int8_t mbed_cloud_client_get_rot_128bit(uint8_t *key_buf, uint32_t length) return 0; } -#endif // #if !defined(ARM_BOOTLOADER_USE_NVSTORE_ROT) || ARM_BOOTLOADER_USE_NVSTORE_ROT == 0 +#endif // #if !defined(ARM_BOOTLOADER_USE_KVSTORE_ROT) || ARM_BOOTLOADER_USE_KVSTORE_ROT == 0 diff --git a/firmware_update_test/firmware_update_test.cpp b/source/firmware_update_test/firmware_update_test.cpp similarity index 97% rename from firmware_update_test/firmware_update_test.cpp rename to source/firmware_update_test/firmware_update_test.cpp index 958979f..f9fe9d1 100755 --- a/firmware_update_test/firmware_update_test.cpp +++ b/source/firmware_update_test/firmware_update_test.cpp @@ -37,7 +37,7 @@ void copyAppToSDCard(uint32_t firmware_size) tr_info("calculate firmware SHA256\r\n"); const uint8_t *appStart = - (const uint8_t *)(MBED_CONF_APP_APPLICATION_START_ADDRESS); + (const uint8_t *)(MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS); mbedtls_sha256(appStart, firmware_size, details.hash, 0); details.version = UINT32_MAX - 1; diff --git a/firmware_update_test/firmware_update_test.h b/source/firmware_update_test/firmware_update_test.h similarity index 100% rename from firmware_update_test/firmware_update_test.h rename to source/firmware_update_test/firmware_update_test.h diff --git a/fix-mbed-os-compile/arm_uc_pal_flashiap_blockdevice_readonly.c b/source/fix-mbed-os-compile/arm_uc_pal_flashiap_blockdevice_readonly.c similarity index 93% rename from fix-mbed-os-compile/arm_uc_pal_flashiap_blockdevice_readonly.c rename to source/fix-mbed-os-compile/arm_uc_pal_flashiap_blockdevice_readonly.c index 8a1cca3..ea893f2 100644 --- a/fix-mbed-os-compile/arm_uc_pal_flashiap_blockdevice_readonly.c +++ b/source/fix-mbed-os-compile/arm_uc_pal_flashiap_blockdevice_readonly.c @@ -5,8 +5,7 @@ extern arm_uc_error_t ARM_UCP_FashIAP_BlockDevice_Initialize(ARM_UC_PAAL_UPDATE_SignalEvent_t callback); -ARM_UC_PAAL_UPDATE ARM_UCP_FLASHIAP_BLOCKDEVICE_READ_ONLY = -{ +ARM_UC_PAAL_UPDATE ARM_UCP_FLASHIAP_BLOCKDEVICE_READ_ONLY = { .Initialize = ARM_UCP_FashIAP_BlockDevice_Initialize, .GetCapabilities = 0, .GetMaxID = 0, diff --git a/fix-mbed-os-compile/cmsis_os.h b/source/fix-mbed-os-compile/cmsis_os.h similarity index 100% rename from fix-mbed-os-compile/cmsis_os.h rename to source/fix-mbed-os-compile/cmsis_os.h diff --git a/fix-mbed-os-compile/cmsis_os2.h b/source/fix-mbed-os-compile/cmsis_os2.h similarity index 100% rename from fix-mbed-os-compile/cmsis_os2.h rename to source/fix-mbed-os-compile/cmsis_os2.h diff --git a/source/fix-mbed-os-compile/mbed_trace.h b/source/fix-mbed-os-compile/mbed_trace.h new file mode 100644 index 0000000..e899002 --- /dev/null +++ b/source/fix-mbed-os-compile/mbed_trace.h @@ -0,0 +1,25 @@ +// ---------------------------------------------------------------------------- +// Copyright 2018 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#ifndef MBED_TRACE_H +#define MBED_TRACE_H + +// bootloader common contains a redefinition of mbed_trace functions +#include "bootloader_common.h" + +#endif diff --git a/fix-mbed-os-compile/rtos.h b/source/fix-mbed-os-compile/rtos.h similarity index 100% rename from fix-mbed-os-compile/rtos.h rename to source/fix-mbed-os-compile/rtos.h diff --git a/source/kvstore_rot.cpp b/source/kvstore_rot.cpp new file mode 100644 index 0000000..7548efc --- /dev/null +++ b/source/kvstore_rot.cpp @@ -0,0 +1,72 @@ +// ---------------------------------------------------------------------------- +// Copyright 2019 ARM Ltd. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------- + +#if defined(ARM_BOOTLOADER_USE_KVSTORE_ROT) && ARM_BOOTLOADER_USE_KVSTORE_ROT == 1 + +#include +#include +#include "DirectAccessDevicekey.h" + +#define DEVICE_KEY_SIZE_IN_BYTES (128/8) + +/** +* @brief Function to get the device root of trust +* @details The device root of trust should be a 128 bit value. It should never leave the device. +* It should be unique to the device. It should have enough entropy to avoid conventional +* entropy attacks. The porter should implement the following device signature to provide +* device root of trust on different platforms. +* +* @param key_buf buffer to be filled with the device root of trust. +* @param length length of the buffer provided to make sure no overflow occurs. +* +* @return 0 on success, non-zero on failure. +*/ +extern "C" int8_t mbed_cloud_client_get_rot_128bit(uint8_t *key_buf, uint32_t length) +{ + int8_t error = 0; + uint32_t tdb_start_offset = 0; + uint32_t tdb_end_offset = 0; + size_t actual_len_bytes = 0; + + // Check params + if (length < DEVICE_KEY_SIZE_IN_BYTES || key_buf == NULL) { + error = -1; + } + + // Get TDB parameters + if (error == 0) { + error = get_expected_internal_TDBStore_position(&tdb_start_offset, + &tdb_end_offset); + } + + // Read ROT + if (error == 0) { + error = direct_access_to_devicekey(tdb_start_offset, + tdb_end_offset, + key_buf, + DEVICE_KEY_SIZE_IN_BYTES, + &actual_len_bytes); + if (actual_len_bytes != DEVICE_KEY_SIZE_IN_BYTES) { + error = -1; + } + } + + return error; +} + +#endif // #if defined(ARM_BOOTLOADER_USE_KVSTORE_ROT) && ARM_BOOTLOADER_USE_KVSTORE_ROT == 1 diff --git a/source/main.cpp b/source/main.cpp index 37433c7..c1e6c70 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -53,6 +53,7 @@ const arm_uc_installer_details_t bootloader = { binary size if ARM_UC_USE_PAL_BLOCKDEVICE is set and not running tests */ #if defined(ARM_UC_USE_PAL_BLOCKDEVICE) && (ARM_UC_USE_PAL_BLOCKDEVICE==1) && \ (!defined(BOOTLOADER_POWER_CUT_TEST) || (BOOTLOADER_POWER_CUT_TEST != 1)) +#undef MBED_CLOUD_CLIENT_UPDATE_STORAGE #define MBED_CLOUD_CLIENT_UPDATE_STORAGE ARM_UCP_FLASHIAP_BLOCKDEVICE_READ_ONLY #endif @@ -62,29 +63,13 @@ extern ARM_UC_PAAL_UPDATE MBED_CLOUD_CLIENT_UPDATE_STORAGE; #error Update client storage must be defined in user configuration file #endif -#if defined(ARM_UC_USE_PAL_BLOCKDEVICE) && (ARM_UC_USE_PAL_BLOCKDEVICE==1) -#include "SDBlockDevice.h" - -/* initialise sd card blockdevice */ -#if defined(MBED_CONF_APP_SPI_MOSI) && defined(MBED_CONF_APP_SPI_MISO) && \ - defined(MBED_CONF_APP_SPI_CLK) && defined(MBED_CONF_APP_SPI_CS) -SDBlockDevice sd(MBED_CONF_APP_SPI_MOSI, MBED_CONF_APP_SPI_MISO, - MBED_CONF_APP_SPI_CLK, MBED_CONF_APP_SPI_CS); -#else -SDBlockDevice sd(MBED_CONF_SD_SPI_MOSI, MBED_CONF_SD_SPI_MISO, - MBED_CONF_SD_SPI_CLK, MBED_CONF_SD_SPI_CS); -#endif - -BlockDevice *arm_uc_blockdevice = &sd; -#endif - -#ifndef MBED_CONF_APP_APPLICATION_START_ADDRESS +#ifndef MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS #error Application start address must be defined #endif /* If jump address is not set then default to start address. */ #ifndef MBED_CONF_APP_APPLICATION_JUMP_ADDRESS -#define MBED_CONF_APP_APPLICATION_JUMP_ADDRESS MBED_CONF_APP_APPLICATION_START_ADDRESS +#define MBED_CONF_APP_APPLICATION_JUMP_ADDRESS MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS #endif int main(void) @@ -176,7 +161,7 @@ int main(void) #elif defined(FIRMWARE_UPDATE_TEST) && (FIRMWARE_UPDATE_TEST == 1) firmware_update_test_end(); #endif - uint32_t app_start_addr = MBED_CONF_APP_APPLICATION_START_ADDRESS; + uint32_t app_start_addr = MBED_CONF_MBED_BOOTLOADER_APPLICATION_START_ADDRESS; uint32_t app_stack_ptr = *((uint32_t *)(MBED_CONF_APP_APPLICATION_JUMP_ADDRESS + 0)); uint32_t app_jump_addr = *((uint32_t *)(MBED_CONF_APP_APPLICATION_JUMP_ADDRESS + 4)); diff --git a/mbed_bootloader_info.h b/source/mbed_bootloader_info.h similarity index 100% rename from mbed_bootloader_info.h rename to source/mbed_bootloader_info.h diff --git a/source/nvstore_rot.cpp b/source/nvstore_rot.cpp deleted file mode 100644 index 419ca7a..0000000 --- a/source/nvstore_rot.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// ---------------------------------------------------------------------------- -// Copyright 2016-2017 ARM Ltd. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ---------------------------------------------------------------------------- - -#if defined(ARM_BOOTLOADER_USE_NVSTORE_ROT) && ARM_BOOTLOADER_USE_NVSTORE_ROT == 1 - -#include -#include -#include -// #include "pal.h" -#include "nvstore.h" - -#define NVSTORE_TYPE_ROT 4 -#define DEVICE_KEY_SIZE_IN_BYTES (128/8) - -/** - * @brief Function to get the device root of trust - * @details The device root of trust should be a 128 bit value. It should never leave the device. - * It should be unique to the device. It should have enough entropy to avoid contentional - * entropy attacks. The porter should implement the following device signature to provide - * device root of trust on different platforms. - * - * @param key_buf buffer to be filled with the device root of trust. - * @param length length of the buffer provided to make sure no overflow occurs. - * - * @return 0 on success, non-zero on failure. - */ - -extern "C" int8_t mbed_cloud_client_get_rot_128bit(uint8_t *key_buf, uint32_t length) -{ - static bool initialized = false; - uint32_t rot[DEVICE_KEY_SIZE_IN_BYTES / sizeof(uint32_t)]; - uint16_t actual_len_bytes = 0; - NVStore &nvstore = NVStore::get_instance(); - - if (length < DEVICE_KEY_SIZE_IN_BYTES || key_buf == NULL) { - return -1; - } - - if (!initialized) { - if (nvstore.init() != NVSTORE_SUCCESS) { - return -1; - } - initialized = true; - } - - int status = nvstore.get(NVSTORE_TYPE_ROT, DEVICE_KEY_SIZE_IN_BYTES, rot, actual_len_bytes); - if (status != NVSTORE_SUCCESS || actual_len_bytes != DEVICE_KEY_SIZE_IN_BYTES) { - return -1; - } - memcpy(key_buf, rot, DEVICE_KEY_SIZE_IN_BYTES); - return 0; -} - -#endif // #if defined(ARM_BOOTLOADER_USE_NVSTORE_ROT) && ARM_BOOTLOADER_USE_NVSTORE_ROT == 1 diff --git a/power_cut_test/bootloader_power_cut_test.cpp b/source/power_cut_test/bootloader_power_cut_test.cpp similarity index 100% rename from power_cut_test/bootloader_power_cut_test.cpp rename to source/power_cut_test/bootloader_power_cut_test.cpp diff --git a/power_cut_test/bootloader_power_cut_test.h b/source/power_cut_test/bootloader_power_cut_test.h similarity index 100% rename from power_cut_test/bootloader_power_cut_test.h rename to source/power_cut_test/bootloader_power_cut_test.h diff --git a/power_cut_test/host_tests/power-cut-test.py b/source/power_cut_test/host_tests/power-cut-test.py similarity index 100% rename from power_cut_test/host_tests/power-cut-test.py rename to source/power_cut_test/host_tests/power-cut-test.py diff --git a/power_cut_test/test_spec_armcc.json b/source/power_cut_test/test_spec_armcc.json similarity index 100% rename from power_cut_test/test_spec_armcc.json rename to source/power_cut_test/test_spec_armcc.json diff --git a/power_cut_test/test_spec_gcc.json b/source/power_cut_test/test_spec_gcc.json similarity index 100% rename from power_cut_test/test_spec_gcc.json rename to source/power_cut_test/test_spec_gcc.json diff --git a/source/upgrade.cpp b/source/upgrade.cpp index 8197c3f..5d1bc8c 100755 --- a/source/upgrade.cpp +++ b/source/upgrade.cpp @@ -319,7 +319,7 @@ bool upgradeApplicationFromStorage(void) tr_info("Version: %" PRIu64, imageDetails.version); /* check firmware size fits */ - if (imageDetails.size <= MBED_CONF_APP_MAX_APPLICATION_SIZE) { + if (imageDetails.size <= MBED_CONF_MBED_BOOTLOADER_MAX_APPLICATION_SIZE) { /* Update best candidate information */ bestStoredFirmwareIndex = index; bestStoredFirmwareImageDetails.version = imageDetails.version; @@ -335,7 +335,7 @@ bool upgradeApplicationFromStorage(void) tr_error("Slot %" PRIu32 " firmware size too large %" PRIu32 " > %" PRIu32, index, (uint32_t) imageDetails.size, - (uint32_t) MBED_CONF_APP_MAX_APPLICATION_SIZE); + (uint32_t) MBED_CONF_MBED_BOOTLOADER_MAX_APPLICATION_SIZE); } } else { /* Integrity check failed */