Francesco Servidio | 5bc9832 | 2021-11-03 13:19:22 +0100 | [diff] [blame] | 1 | # Porting how-to |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 2 | |
| 3 | This document describes the requirements and necessary steps required to port |
Francesco Servidio | 4ff0c18 | 2021-10-20 15:27:16 +0200 | [diff] [blame] | 4 | `MCUboot` to a new target `OS`. |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 5 | |
| 6 | # Requirements |
| 7 | |
Francesco Servidio | 4ff0c18 | 2021-10-20 15:27:16 +0200 | [diff] [blame] | 8 | * `MCUboot` requires a configuration file, which can be included as |
Marti Bolivar | f91bca5 | 2018-04-12 12:40:46 -0400 | [diff] [blame] | 9 | mcuboot_config/mcuboot_config.h, which configures various options |
| 10 | (that begin with MCUBOOT_). |
| 11 | |
Francesco Servidio | 4ff0c18 | 2021-10-20 15:27:16 +0200 | [diff] [blame] | 12 | * `MCUboot` requires that the target provides a `flash` API with ability to |
Fabio Utzig | e2d99f8 | 2017-06-28 19:33:33 -0300 | [diff] [blame] | 13 | get the flash's minimum write size, and read/write/erase individual sectors. |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 14 | |
Francesco Servidio | 4ff0c18 | 2021-10-20 15:27:16 +0200 | [diff] [blame] | 15 | * `MCUboot` doesn't bundle a cryptographic library, which means the target |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 16 | OS must already have it bundled. The supported libraries at the moment are |
Francesco Servidio | 582367c | 2021-10-20 15:36:45 +0200 | [diff] [blame] | 17 | either `Mbed TLS` or the set `tinycrypt` + `Mbed TLS` (where `Mbed TLS` is |
Fabio Utzig | e2d99f8 | 2017-06-28 19:33:33 -0300 | [diff] [blame] | 18 | used to provide functionality not existing in `tinycrypt`). |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 19 | |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 20 | # Steps to port |
| 21 | |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 22 | ## Main app and calling the bootloader |
| 23 | |
| 24 | From the perspective of the target OS, the bootloader can be seen as a library, |
| 25 | so an entry point must be provided. This is likely a typical `app` for the |
| 26 | target OS, and it must call the following function to run the bootloader: |
| 27 | |
| 28 | ```c |
| 29 | int boot_go(struct boot_rsp *rsp); |
| 30 | ``` |
| 31 | |
| 32 | This function is located at `boot/bootutil/loader.c` and receives a `struct |
| 33 | boot_rsp` pointer. The `struct boot_rsp` is defined as: |
| 34 | |
| 35 | ```c |
| 36 | struct boot_rsp { |
| 37 | /** A pointer to the header of the image to be executed. */ |
| 38 | const struct image_header *br_hdr; |
| 39 | |
| 40 | /** |
| 41 | * The flash offset of the image to execute. Indicates the position of |
| 42 | * the image header. |
| 43 | */ |
| 44 | uint8_t br_flash_id; |
| 45 | uint32_t br_image_addr; |
| 46 | }; |
| 47 | ``` |
| 48 | |
| 49 | After running the management functions of the bootloader, `boot_go` returns |
| 50 | an initialized `boot_rsp` which has pointers to the location of the image |
| 51 | where the target firmware is located which can be used to jump to. |
| 52 | |
Marti Bolivar | f91bca5 | 2018-04-12 12:40:46 -0400 | [diff] [blame] | 53 | ## Configuration file |
| 54 | |
| 55 | You must provide a file, mcuboot_config/mcuboot_config.h. This is |
| 56 | included by several files in the "library" portion of MCUboot; it |
| 57 | provides preprocessor definitions that configure the library's |
| 58 | build. |
| 59 | |
| 60 | See the file samples/mcuboot_config/mcuboot_config.template.h for a |
| 61 | starting point and more information. This is a good place to convert |
| 62 | settings in your environment's configuration system to those required |
| 63 | by MCUboot. For example, Mynewt uses MYNEWT_VAL() and Zephyr uses |
| 64 | Kconfig; these configuration systems are converted to MCUBOOT_ options |
| 65 | in the following files: |
| 66 | |
| 67 | - boot/zephyr/include/mcuboot_config/mcuboot_config.h |
| 68 | - boot/mynewt/mcuboot_config/include/mcuboot_config/mcuboot_config.h |
| 69 | |
Fabio Utzig | 6f9c795 | 2018-07-19 07:53:20 -0300 | [diff] [blame] | 70 | ## Flash Map |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 71 | |
Dominik Ermel | d3f3609 | 2021-05-07 11:16:15 +0000 | [diff] [blame] | 72 | The bootloader requires to be able to address flash regions where the code |
Francesco Servidio | 4ff0c18 | 2021-10-20 15:27:16 +0200 | [diff] [blame] | 73 | for MCUboot and images of applications are stored, in system-agnostic way. |
| 74 | For that purpose the MCUboot uses ID, which is integer (uint8_t) number |
Dominik Ermel | d3f3609 | 2021-05-07 11:16:15 +0000 | [diff] [blame] | 75 | that should uniquely identify each flash region. |
| 76 | Such flash regions are served by object of `const struct flash_area` type while |
| 77 | layout of these objects is gathered under `flash_map`. |
Francesco Servidio | 4ff0c18 | 2021-10-20 15:27:16 +0200 | [diff] [blame] | 78 | The common code of MCUboot, that is non-system specific, does not directly |
Dominik Ermel | d3f3609 | 2021-05-07 11:16:15 +0000 | [diff] [blame] | 79 | access contents of that object and never modifies it, instead it calls |
| 80 | `flash_area_` API to perform any actions on that object. |
| 81 | This way systems are free to implement internal logic of flash map or define |
| 82 | `struct flash_area` as they wish; the only restriction is that ID should be |
| 83 | uniquely tied to region characterized by device, offset and size. |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 84 | |
Francesco Servidio | 4ff0c18 | 2021-10-20 15:27:16 +0200 | [diff] [blame] | 85 | Changes to common MCUboot code should not affect system specific internals |
| 86 | of flash map, on the other side system specific code, within MCUboot, is |
Dominik Ermel | d3f3609 | 2021-05-07 11:16:15 +0000 | [diff] [blame] | 87 | is not restricted from directly accessing `struct flash_area` elements. |
| 88 | |
| 89 | |
| 90 | An implementation of `struct flash_area` may take form of: |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 91 | ```c |
| 92 | struct flash_area { |
| 93 | uint8_t fa_id; /** The slot/scratch identification */ |
| 94 | uint8_t fa_device_id; /** The device id (usually there's only one) */ |
| 95 | uint16_t pad16; |
| 96 | uint32_t fa_off; /** The flash offset from the beginning */ |
| 97 | uint32_t fa_size; /** The size of this sector */ |
| 98 | }; |
| 99 | ``` |
Dominik Ermel | d3f3609 | 2021-05-07 11:16:15 +0000 | [diff] [blame] | 100 | The above example of structure hold all information that is currently required |
Francesco Servidio | 4ff0c18 | 2021-10-20 15:27:16 +0200 | [diff] [blame] | 101 | by MCUboot, although the MCUboot will not be trying to access them directly, |
Dominik Ermel | d3f3609 | 2021-05-07 11:16:15 +0000 | [diff] [blame] | 102 | instead a system is required to provide following mandatory getter functions: |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 103 | |
Dominik Ermel | d3f3609 | 2021-05-07 11:16:15 +0000 | [diff] [blame] | 104 | ```c |
| 105 | /*< Obtains ID of the flash area characterized by `fa` */ |
| 106 | int flash_area_get_id(const struct flash_area *fa); |
| 107 | /*< Obtains ID of a device the flash area `fa` described region resides on */ |
| 108 | int flash_area_get_device_id(const struct flash_area *fa) |
| 109 | /*< Obtains offset, from the beginning of a device, the flash area described |
| 110 | * region starts at */ |
| 111 | uint32_t flash_area_get_off(const struct flash_area *fa) |
| 112 | /*< Obtains size, from the offset, of the flash area `fa` characterized region */ |
| 113 | uint32_t flash_area_get_size(const struct flash_area *fa) |
| 114 | |
| 115 | ``` |
| 116 | |
Francesco Servidio | 4ff0c18 | 2021-10-20 15:27:16 +0200 | [diff] [blame] | 117 | The MCUboot common code uses following defines that should be defined by system |
Dominik Ermel | d3f3609 | 2021-05-07 11:16:15 +0000 | [diff] [blame] | 118 | specific header files and are used to identify destination of flash area by ID: |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 119 | |
| 120 | ```c |
David Vincze | b75c12a | 2019-03-22 14:58:33 +0100 | [diff] [blame] | 121 | /* Independent from multiple image boot */ |
| 122 | #define FLASH_AREA_BOOTLOADER 0 |
| 123 | #define FLASH_AREA_IMAGE_SCRATCH 3 |
| 124 | ``` |
| 125 | ```c |
| 126 | /* Flash area IDs of the first image in case of multiple images */ |
| 127 | #define FLASH_AREA_IMAGE_PRIMARY 1 |
| 128 | #define FLASH_AREA_IMAGE_SECONDARY 2 |
| 129 | ``` |
| 130 | ```c |
| 131 | /* Flash area IDs of the second image in case of multiple images */ |
| 132 | #define FLASH_AREA_IMAGE_PRIMARY 5 |
| 133 | #define FLASH_AREA_IMAGE_SECONDARY 6 |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 134 | ``` |
| 135 | |
Dominik Ermel | d3f3609 | 2021-05-07 11:16:15 +0000 | [diff] [blame] | 136 | The numbers, given above, are provided as an example and depend on system |
| 137 | implementation. |
| 138 | |
| 139 | The main, also required, set of API functions that perform operations on |
| 140 | flash characterized by `struct flash_area` objects is as follows: |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 141 | |
| 142 | ```c |
| 143 | /*< Opens the area for use. id is one of the `fa_id`s */ |
| 144 | int flash_area_open(uint8_t id, const struct flash_area **); |
| 145 | void flash_area_close(const struct flash_area *); |
| 146 | /*< Reads `len` bytes of flash memory at `off` to the buffer at `dst` */ |
| 147 | int flash_area_read(const struct flash_area *, uint32_t off, void *dst, |
| 148 | uint32_t len); |
| 149 | /*< Writes `len` bytes of flash memory at `off` from the buffer at `src` */ |
| 150 | int flash_area_write(const struct flash_area *, uint32_t off, |
| 151 | const void *src, uint32_t len); |
| 152 | /*< Erases `len` bytes of flash memory at `off` */ |
| 153 | int flash_area_erase(const struct flash_area *, uint32_t off, uint32_t len); |
| 154 | /*< Returns this `flash_area`s alignment */ |
| 155 | uint8_t flash_area_align(const struct flash_area *); |
Rajiv Ranganath | b976a4c | 2020-01-13 16:54:19 +0530 | [diff] [blame] | 156 | /*< What is value is read from erased flash bytes. */ |
| 157 | uint8_t flash_area_erased_val(const struct flash_area *); |
Rajiv Ranganath | b976a4c | 2020-01-13 16:54:19 +0530 | [diff] [blame] | 158 | /*< Given flash area ID, return info about sectors within the area. */ |
| 159 | int flash_area_get_sectors(int fa_id, uint32_t *count, |
| 160 | struct flash_sector *sectors); |
| 161 | /*< Returns the `fa_id` for slot, where slot is 0 (primary) or 1 (secondary). |
| 162 | `image_index` (0 or 1) is the index of the image. Image index is |
| 163 | relevant only when multi-image support support is enabled */ |
| 164 | int flash_area_id_from_multi_image_slot(int image_index, int slot); |
| 165 | /*< Returns the slot (0 for primary or 1 for secondary), for the supplied |
| 166 | `image_index` and `area_id`. `area_id` is unique and is represented by |
| 167 | `fa_id` in the `flash_area` struct. */ |
| 168 | int flash_area_id_to_multi_image_slot(int image_index, int area_id); |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 169 | ``` |
| 170 | |
Francesco Servidio | 2fe449d | 2021-10-21 12:38:36 +0200 | [diff] [blame^] | 171 | --- |
| 172 | ***Note*** |
| 173 | |
| 174 | *As of writing, it is possible that MCUboot will open a flash area multiple times simultaneously (through nested calls to `flash_area_open`). As a result, MCUboot may call `flash_area_close` on a flash area that is still opened by another part of MCUboot. As a workaround when porting, it may be necessary to implement a counter of the number of times a given flash area has been opened by MCUboot. The `flash_area_close` implementation should only fully deinitialize the underlying flash area when the open counter is decremented to 0. See [this GitHub PR](https://github.com/mcu-tools/mcuboot/pull/894/) for a more detailed discussion.* |
| 175 | |
| 176 | --- |
George Beckstein | d1233e1 | 2020-12-02 01:57:30 -0500 | [diff] [blame] | 177 | |
Francesco Servidio | 582367c | 2021-10-20 15:36:45 +0200 | [diff] [blame] | 178 | ## Memory management for Mbed TLS |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 179 | |
Francesco Servidio | 582367c | 2021-10-20 15:36:45 +0200 | [diff] [blame] | 180 | `Mbed TLS` employs dynamic allocation of memory, making use of the pair |
| 181 | `calloc/free`. If `Mbed TLS` is to be used for crypto, your target RTOS |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 182 | needs to provide this pair of function. |
| 183 | |
| 184 | To configure the what functions are called when allocating/deallocating |
Francesco Servidio | 582367c | 2021-10-20 15:36:45 +0200 | [diff] [blame] | 185 | memory `Mbed TLS` uses the following call: |
Fabio Utzig | 01ccb19 | 2017-05-08 09:17:50 -0300 | [diff] [blame] | 186 | |
| 187 | ``` |
| 188 | int mbedtls_platform_set_calloc_free (void *(*calloc_func)(size_t, size_t), |
| 189 | void (*free_func)(void *)); |
| 190 | ``` |
| 191 | |
Francesco Servidio | 582367c | 2021-10-20 15:36:45 +0200 | [diff] [blame] | 192 | For reference see [Mbed TLS platform.h](https://tls.mbed.org/api/platform_8h.html). |
Fabio Utzig | 8ebe535 | 2020-10-01 08:09:52 -0300 | [diff] [blame] | 193 | If your system already provides functions with compatible signatures, those can |
| 194 | be used directly here, otherwise create new functions that glue to your |
| 195 | `calloc/free` implementations. |