From 9423624ab4d977aeffa7caedc80190016f64cd31 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Fri, 26 Jul 2024 10:20:58 -0600 Subject: [PATCH] documentation updates --- IDE/AURIX/README.md | 44 +++++++++++++++++++++++++++++++++++++++--- docs/HAL.md | 32 +++++++++++++++++++----------- docs/firmware_image.md | 17 ++++++++++------ 3 files changed, 73 insertions(+), 20 deletions(-) diff --git a/IDE/AURIX/README.md b/IDE/AURIX/README.md index e30e8c19e..48a266d20 100644 --- a/IDE/AURIX/README.md +++ b/IDE/AURIX/README.md @@ -1,14 +1,18 @@ # Overview +This example demonstrates using wolfBoot on the Infineon AURIX TC3xx family of microcontrollers. The example is based on the TC375 Lite-Kit V2, but should be easily adaptable to other TC3xx devices. This README assumes basic familiarity with the TC375 SoC, the AURIX IDE, and Lauterbach Trace32 debugger. + +The example contains two projects: `wolfBoot-tc3xx` and `test-app`. The `wolfBoot-tc3xx` project contains the wolfBoot bootloader, and the `test-app` project contains a simple firmware application that will be loaded and executed by wolfBoot. The `test-app` project is a simple blinky application that blinks LED2 on the TC375 Lite-Kit V2 once per second when running the base image, and rapidly (~3x/sec) when running the update image. The test app determines if it is a base or update image by inspecting the firmware version (obtained through the wolfBoot API). The firmware version is set in the image header by the wolfBoot keytools when signing the test app binaries. The same test app binary is used for both the base and update images, with the only difference being the firmware version set by the keytools. ## Important notes -- In the UCBs, BMDHx.STAD must point to the wolfBoot entrypoint `0xA000_0000`. This is the default value of the TC375 and so need not be changed unless it has already been modified or you wish to rearrange the memory map. -- Because TC3xx PFLASH ECC prevents reading from erased flash, the `EXT_FLASH` option is used to redirect flash reads to a HAL API, where the flash pages requested to be read can be blank-checked by hardware before reading. + +- In the TC375 UCBs, BMDHx.STAD must point to the wolfBoot entrypoint `0xA000_0000`. This is the default value of the TC375 and so need not be changed unless it has already been modified or you wish to rearrange the memory map. +- Because TC3xx PFLASH ECC prevents reading from erased flash, the `EXT_FLASH` option is used to redirect flash reads to the `ext_flash_read()` HAL API, where the flash pages requested to be read can be blank-checked by hardware before reading. - TC3xx PFLASH is write-once (`NVM_FLASH_WRITEONCE`), however wolfBoot `NVM_FLASH_WRITEONCE` does not support `EXT_FLASH`. Therefore the write-once functionality is re-implemented in the `HAL` layer. ## Flash Partitioning -The TC3xx AURIX port of wolfBoot places all images in PFLASH, and uses both PFLASH0 and PFLASH1 banks. The wolfBoot executable code and the image swap sector are located in PFLASH0, with the remainder available for use. PFLASH1 is divided in half, with the first half holding the BOOT partition and the second half holding the UPDATE partion. User firmware images are directly executed in place from the BOOT partition in PFLASH1, and so must be linked to execute within this address space, with an offset of `IMAGE_HEADER_SIZE` to account for the wolfBoot image header. +The TC3xx AURIX port of wolfBoot places all images in PFLASH, and uses both PFLASH0 and PFLASH1 banks. The wolfBoot executable code and the image swap sector are located in PFLASH0, with the remainder available for use. PFLASH1 is divided in half, with the first half holding the BOOT partition and the second half holding the UPDATE partition. User firmware images are directly executed in place from the BOOT partition in PFLASH1, and so must be linked to execute within this address space, with an offset of `IMAGE_HEADER_SIZE` to account for the wolfBoot image header. ``` +==========+ @@ -65,6 +69,40 @@ Please refer to the [wolfBoot](wolfBoot-tc3xx/Lcf_Gnu_Tricore_Tc.lsl) and [test- 1. Open a WSL terminal and navigate to `wolfBoot/tools/scripts/tc3xx` 2. Run `./gen-tc3xx-signed-test-apps-debug.sh` or `gen-tc3xx-signed-test-apps-release.sh` to sign either the debug or release build, respectively. This creates the signed image files `test-app_v1_signed.bin` and `test-app_v2_signed.bin` in the test-app output build directory. The v1 image is the initial image that will be loaded to the `BOOT` partition, and the v2 image is the update image that will be loaded to the `UPDATE` partition. +``` +$ ./gen-tc3xx-signed-test-apps-release.sh ++ ../../keytools/sign --rsa4096 --sha256 '../../../IDE/AURIX/test-app/TriCore Release (GCC)/test-app.bin' ../../../priv.der 1 +wolfBoot KeyTools (Compiled C version) +wolfBoot version 2010000 +Update type: Firmware +Input image: ../../../IDE/AURIX/test-app/TriCore Release (GCC)/test-app.bin +Selected cipher: RSA4096 +Selected hash : SHA256 +Public key: ../../../priv.der +Output image: ../../../IDE/AURIX/test-app/TriCore Release (GCC)/test-app_v1_signed.bin +Target partition id : 1 +Found RSA512 key +image header size calculated at runtime (1024 bytes) +Calculating SHA256 digest... +Signing the digest... +Output image(s) successfully created. ++ ../../keytools/sign --rsa4096 --sha256 '../../../IDE/AURIX/test-app/TriCore Release (GCC)/test-app.bin' ../../../priv.der 2 +wolfBoot KeyTools (Compiled C version) +wolfBoot version 2010000 +Update type: Firmware +Input image: ../../../IDE/AURIX/test-app/TriCore Release (GCC)/test-app.bin +Selected cipher: RSA4096 +Selected hash : SHA256 +Public key: ../../../priv.der +Output image: ../../../IDE/AURIX/test-app/TriCore Release (GCC)/test-app_v2_signed.bin +Target partition id : 1 +Found RSA512 key +image header size calculated at runtime (1024 bytes) +Calculating SHA256 digest... +Signing the digest... +Output image(s) successfully created. +``` + ### Load and run the wolfBoot demo 8. Load wolfBoot and the firmware application images to the tc3xx device using Trace32 and a Lauterbach probe diff --git a/docs/HAL.md b/docs/HAL.md index 28f48b50d..ada1c71cc 100644 --- a/docs/HAL.md +++ b/docs/HAL.md @@ -44,8 +44,11 @@ flash. On some targets, this function may be empty. This function provides an implementation of the flash write function, using the target's IAP interface. `address` is the offset from the beginning of the flash area, `data` is the payload to be stored in the flash using the IAP interface, -and `len` is the size of the payload. `hal_flash_write` should return 0 upon success, -or a negative value in case of failure. +and `len` is the size of the payload. Implementations of this function must be able to +handle writes of any size and alignment. Targets with a minimum programmable size +> 1 byte must implement the appropriate read-modify-write logic in order to enable +wolfBoot to perform unaligned single-byte writes. `hal_flash_write` should return 0 upon +success, or a negative value in case of failure. `void hal_flash_lock(void)` @@ -58,8 +61,9 @@ by the bootloader at the end of every write and erase operations. Called by the bootloader to erase part of the flash memory to allow subsequent boots. Erase operations must be performed via the specific IAP interface of the target microcontroller. `address` marks the start of the area that the bootloader wants to erase, and `len` specifies -the size of the area to be erased. This function must take into account the geometry of the flash -sectors, and erase all the sectors in between. +the size of the area to be erased. `address` is guaranteed to be aligned to `WOLFBOOT_SECTOR_SIZE`, +and `len` is guaranteed to be a multiple of `WOLFBOOT_SECTOR_SIZE`. This function must take into account +the geometry of the flash sectors, and erase all the sectors in between. `void hal_prepare_boot(void)` @@ -71,11 +75,14 @@ that the state of the microcontroller is restored to its original settings. WolfBoot can be compiled with the makefile option `EXT_FLASH=1`. When the external flash support is enabled, update and swap partitions can be associated to an external memory, and will use alternative -HAL function for read/write/erase access. +HAL function for read/write/erase access. It can also be used in any scenario where flash reads require +special handling and must be redirected to a custom implementation. Note that `EXT_FLASH=1` is incompatible +with the `NVM_FLASH_WRITEONCE` option. + To associate the update or the swap partition to an external memory, define `PART_UPDATE_EXT` and/or `PART_SWAP_EXT`, respectively. -The following functions are used to access the external memory, and must be defined when `EXT\_FLASH` +The following functions are used to access the external memory, and must be defined when `EXT_FLASH` is on: `int ext_flash_write(uintptr_t address, const uint8_t *data, int len)` @@ -83,7 +90,8 @@ is on: This function provides an implementation of the flash write function, using the external memory's specific interface. `address` is the offset from the beginning of the addressable space in the device, `data` is the payload to be stored, -and `len` is the size of the payload. `ext_flash_write` should return 0 upon success, +and `len` is the size of the payload. The function is subject to the same restrictions as +`hal_flash_write()`. `ext_flash_write` should return 0 upon success, or a negative value in case of failure. `int ext_flash_read(uintptr_t address, uint8_t *data, int len)` @@ -91,16 +99,18 @@ or a negative value in case of failure. This function provides an indirect read of the external memory, using the driver's specific interface. `address` is the offset from the beginning of the addressable space in the device, `data` is a pointer where payload is stored upon a successful -call, and `len` is the maximum size allowed for the payload. `ext_flash_read` should return 0 -upon success, or a negative value in case of failure. +call, and `len` is the maximum size allowed for the payload. This function must be able to handle +reads of any size and alignment. `ext_flash_read` should return 0 upon success, or a negative value +in case of failure. `int ext_flash_erase(uintptr_t address, int len)` Called by the bootloader to erase part of the external memory. Erase operations must be performed via the specific interface of the target driver (e.g. SPI flash). `address` marks the start of the area relative to the device, that the bootloader wants to erase, -and `len` specifies the size of the area to be erased. This function must take into account the -geometry of the sectors, and erase all the sectors in between. +and `len` specifies the size of the area to be erased. This function is subject to the same restrictions +as `hal_flash_erase()` and must take into account the geometry of the sectors, and erase all the sectors +in between. `void ext_flash_lock(void)` diff --git a/docs/firmware_image.md b/docs/firmware_image.md index f9429c07c..4cceaa9a1 100644 --- a/docs/firmware_image.md +++ b/docs/firmware_image.md @@ -14,15 +14,20 @@ of 256B from the beginning of the flash partition. ## Firmware image header -Each (signed) firmware image is prepended with a fixed-size **image header**, containing -useful information about the firmware. The **image header** is padded to fit in 256B, in order -to guarantee that the entry point of the actual firmware is stored on the flash starting from -a 256-Bytes aligned address. This ensures that the bootloader can relocate the vector table before -chain-loading the firmware the interrupt continue to work properly after the boot is complete. +Each (signed) firmware image is prepended with a fixed-size **image header**, containing useful information about the +firmware. The exact size of the **image header** depends on the size of the image digest and signature, which depend on +the algorithms/key sizes used. Larger key sizes will result in a larger image header. The size of the image header is +determined by the build system and provided to the application code in the `IMAGE_HEADER_SIZE` macro. The size of the generated +image header is also output by the keytools during the signing operation. The **image header** data is padded out to the next +multiple of 256B, in order to guarantee that the entry point of the actual firmware is stored on the flash starting from a +256-Bytes aligned address. This ensures that the bootloader can relocate the vector table before chain-loading the firmware +so interrupts continue to work properly after the boot is complete. When porting wolfBoot to a platform that doesn't use wolfBoot's +Makefile-based build system, extra care should be taken to ensure `IMAGE_HEADER_SIZE` is set to a value that matches the output of +the wolfBoot `sign` key tool. ![Image header](png/image_header.png) -*The image header is stored at the beginning of the slot and the actual firmware image starts 256 Bytes after it* +*The image header is stored at the beginning of the slot and the actual firmware image starts `IMAGE_HEADER_SIZE` Bytes after it* ### Image header: Tags