Partition Manager
The Partition Manager is a Python script that sets the start address and size of all the flash and RAM partitions in a multi-image build context. When creating an application that requires child images, like a bootloader, you can configure the Partition Manager to control where each image should be placed in memory, and how the RAM should be shared.
See Multi-image builds for more information about multi-image builds.
The Partition Manager is activated for all multi-image builds, regardless of which build strategy is used for the child image.
Note
When you build a multi-image application using the Partition Manager, the devicetree source flash partitions are ignored.
Overview
The Partition Manager script reads the configuration files named pm.yml
, which define flash and RAM partitions.
A definition of a flash partition includes the name and the constraints on both size and placement in the flash memory.
A definition of a RAM partition includes the name and the constraints on its size.
The Partition Manager allocates a start address and, when set, a size to each partition in a way that complies with these constraints.
There are different types of flash partitions and RAM partitions, as described in the following section.
Flash partition types
- Image partitions
An image partition is the flash memory area reserved for an image to which the image binary is written.
When the Partition Manager is active, there is one root image and one or more child images. The name of the root image is
app
. It is always implicitly defined. Child images are explicitly defined inpm.yml
files. The size of the root image partition is dynamic, while the sizes of all child image partitions are statically defined.- Placeholder partitions
A placeholder partition does not contain an image, but reserves space for other uses. For example, you might want to reserve space in the flash memory to hold an updated application image while it is being downloaded and before it is copied to the application image partition.
- Container partitions
A container partition does not reserve space but is used to logically and (or) physically group other partitions.
The start addresses and sizes of image partitions are used in the preprocessing of the linker script for each image.
RAM partition types
- Default image RAM partition
The default image RAM partition consists of all the RAM that is not defined as a permanent image RAM partition or placeholder RAM partition. It is the default RAM partition associated with an image and is set as the RAM region when linking the image. If an image must reserve its RAM area permanently (that is, at the same time as other images are running), it must use a permanent image RAM partition, described below.
- Permanent image RAM partitions
A permanent image RAM partition reserves RAM for an image permanently. It is typically used for images that will remain active after they have booted the next step in the boot chain. If an image has configured a permanent image RAM partition, it is set as the RAM region when linking the image, instead of the default image RAM partition.
- Permanent placeholder RAM partitions
A permanent placeholder RAM partition is used to permanently reserve RAM regions that are not associated with an image.
Configuration
Each child image must define its Partition Manager configuration in a file called pm.yml
.
This file must be stored in the same folder as the main CMakeLists.txt
file of the child image.
Note
pm.yml
is only used for child images.
The root application does not need to define a pm.yml
file, because its partition size and placement is implied by the size and placement of the child image partitions.
If a root application defines a pm.yml
file, it is silently ignored.
The Partition Manager configuration can be also provided by a subsystem, intended as a software component. For example, the support for a file system. Subsystem Partition Manager configurations cannot define image partitions.
See subsys/partition_manager/CMakeLists.txt
for details on how to add the subsystem-specific Partition Manager configuration files.
The following code shows how the settings
subsystem configuration is added.
if (CONFIG_SETTINGS_FCB OR CONFIG_SETTINGS_NVS)
add_partition_manager_config(pm.yml.settings)
endif()
When multiple application images, within the same domain, build the same subsystem code, there are some limitations if the code adds a Partition Manager configuration file using this methodology.
In particular, partition definitions are global per domain, and must be identical across all the calls to add_partition_manager_config()
.
If the same partition is defined twice with different configurations within a domain, the Partition Manager will fail.
Note
If Partition Manager configurations are only defined by subsystems, so that only one image is included in the build, you must set the option CONFIG_PM_SINGLE_IMAGE
to execute the Partition Manager script.
Configuration file format
A pm.yml
file contains partition definitions.
Each partition is defined as follows:
partition_name:
partition_property:
property_value
partition_name is the name of the partition (for example, mcuboot
).
The following partition properties and property values are available:
- placement: dict
This property specifies the placement of the partition relative to other partitions, to the start or end of the flash, or to the root image
app
.A partition with the placement property set is either an image partition or a placeholder partition. If the partition name is the same as the image name (as defined in a
CMakeLists.txt
; see Defining and enabling a child image for details), this partition is the image partition. All other partitions are placeholder partitions. Eachpm.yml
file must define exactly one image partition.The placement is formatted as a YAML dict. The valid keywords are listed below:
- before: list
Place the partition before the first existing partition in the list.
- after: list
Place the partition after the first existing partition in the list.
Valid values in the lists are
app
,start
,end
, or the name of any partition. The valuestart
refers to the start address of the flash device’s memory. The valueend
refers to its end address. It is not possible to place the partition afterend
or beforestart
.- align: dict
Ensure the alignment of the start or the end of the partition by specifying a dict with a
start
orend
key respectively, where the value is the number of bytes to align to. If necessary, empty partitions are inserted in front of or behind the partition to ensure that the alignment is correct. Only one key can be specified. Partitions that directly or indirectly (through spans) share size with theapp
partitions can only be aligned if they are placed directly after theapp
partition.- align_next: int
Ensure that the _next_ partition is aligned on this number of bytes. This is equivalent to ensuring the alignment of the start of the next partition. If the start of the next partition is already aligned, the largest alignment takes effect.
align_next
fails if the alignment of the start of the next partition is not a divisor or multiple of thealign_next
value.align_next
also fails if the end of the next partition is aligned.
- span: list OR span: string
This property is used to define container partitions. Its value may be a list or string.
Since this property is used to define container partitions, it cannot be used together with the
placement
property.If the value is a list, its elements are the names of the partitions that should be placed in the container:
The following example shows a partition that spans, or contains, partition_1
through partition_n
, in any order:
container_partition_name: span: [partition_1, partition_2, ..., partition_n]The list elements are interpreted as the set of potential partitions in the container, which the Partition Manager may place in the flash in any order. For example,
partition_2
could be placed beforepartition_1
.If the value is a string, it is interpreted as a list with one item:
The following 2 examples are equivalent:
container_partition_name: span: foo container_partition_name: span: [foo]Non-existent partitions are removed from the
span
list before processing. Partitions with emptyspan
lists are removed altogether, unless filled by the inside property.If the Partition Manager is forced to place a partition that is not declared in the
span
list between two partitions that are in the list, the configuration is unsatisfiable and therefore invalid. See Span property example 1 for an example of an invalid configuration.Note
You can specify configurations with an ambiguous ordering. Different versions of the Partition Manager script may produce different partition orders for such configurations, or fail to find a solution even if one is possible. The Partition Manager always detects unsatisfiable configurations (no false positives), but it might fail on some valid inputs (false negatives).
Here are 3 examples of valid and invalid configurations:
In the following example, the mcuboot and spm configurations result in this partition order:
mcuboot
,spm
,app
. Therefore, the foo partition configuration is invalid, becausespm
must be placed betweenmcuboot
andapp
, but is not in the span list.mcuboot: placement: before: [spm, app] spm: placement: before: [app] foo: span: [mcuboot, app]In the following example, these mcuboot, spm, and app configurations have two possible orders:
Order 1: mcuboot, spm, app
Order 2: mcuboot, app, spm
In the absence of additional configuration, the Partition Manager may choose either order. However, since a span configuring the foo partition is present, the Partition Manager should choose order 2, since it is the only order that results in a valid configuration for the foo partition.
mcuboot: placement: spm: placement: after: [mcuboot] app: placement: after: [mcuboot] foo: span: [mcuboot, app]In the following example, these mcuboot, spm, and app configurations have two possible orders:
Order 1: mcuboot, spm, app
Order 2: mcuboot, app, spm
However, the overall configuration is unsatisfiable: foo requires order 2, while bar requires order 1.
mcuboot: placement: spm: placement: after: [mcuboot] app: placement: after: [mcuboot] foo: span: [mcuboot, app] bar: span: [mcuboot, spm]
- inside: list
This property is the inverse of
span
. The name of the partition that specifies this property is added to thespan
list of the first existing container partition in the list. This property can be set for image or placeholder partitions.mcuboot: inside: [b0] b0: span: [] # During processing, this span will contain mcuboot.
- size: hexadecimal value
This property defines the size of the partition. You can provide a Kconfig option as the value, which allows the user to easily modify the size (see Configuration file preprocessing for an example).
- share_size: list
This property defines the size of the current partition to be the same as the size of the first existing partition in the list. This property can be set for image or placeholder partitions. It cannot be used by container partitions. The list can contain any kind of partition.
share_size
takes precedence oversize
if one or more partitions inshare_size
exists.If the target partition is the
app
or a partition that spans over theapp
, the size is effectively split between them, because the size of theapp
is dynamically decided.If none of the partitions in the
share_size
list exists, and the partition does not define asize
property, then the partition is removed. If none of the partitions in theshare_size
list exists, and the partition does define asize
property, then thesize
property is used to set the size.- region: string
Specify the region where a partition should be placed. See Regions.
- RAM partition configuration
RAM partitions are partitions located in the
sram_primary
region. A RAM partition is specified by having the partition name end with_sram
. If a partition name is composed of an image name plus the_sram
ending, it is used as a permanent image RAM partition for the image.
The following 2 examples are equivalent:
some_permament_sram_block_used_for_logging: size: 0x1000 region: sram_primarysome_permament_sram_block_used_for_logging_sram: size: 0x1000
The following example specifies a permanent image RAM partition for MCUboot, that will be used by the MCUboot linker script.
mcuboot_sram: size: 0xa000
All occurrences of a partition name can be replaced by a dict with the key one_of
.
This dict is resolved to the first existing partition in the one_of
value.
The value of the one_of
key must be a list of placeholder or image partitions, and it cannot be a span.
See the following 2 examples, they are equivalent:
some_span: span: [something, {one_of: [does_not_exist_0, does_not_exist_1, exists1, exists2]}]some_span: span: [something, exists1]
An error is triggered if none of the partitions listed inside the one_of
dict exists.
To use this functionality, the properties that must explicitly define the one_of
keyword are the following:
span
share_size
The placement property contains the functionality of one_of
by default.
As such, you must not use one_of
with the placement
property.
Doing so will trigger a build error.
The keywords before
and after
already check for the first existing partition in their list.
Therefore, you can pass a list of partitions into these keywords.
Configuration file preprocessing
Each pm.yml
file is preprocessed to resolve symbols from Kconfig and devicetree.
The following example is taken from the pm.yml
file for the First-stage immutable bootloader provided with the nRF Connect SDK.
It includes autoconf.h
and devicetree_legacy_unfixed.h
(generated by Kconfig and devicetree respectively) to read application configurations and hardware properties.
In this example the application configuration is used to configure the size of the image and placeholder partitions.
The application configuration is also used to decide in which region the otp
partition should be stored.
The information extracted from devicetree is the alignment value for some partitions.
#include <autoconf.h>
#include <devicetree_legacy_unfixed.h>
b0:
size: CONFIG_PM_PARTITION_SIZE_B0_IMAGE
placement:
after: start
b0_container:
span: [b0, provision]
s0_pad:
share_size: mcuboot_pad
placement:
after: b0
align: {start: CONFIG_FPROTECT_BLOCK_SIZE}
app_image:
span: [tfm, spm, app]
s0_image:
# S0 spans over the image booted by B0
span: {one_of: [mcuboot, app_image]}
s0:
# Phony container to allow hex overriding
span: [s0_pad, s0_image]
s1_pad:
# This partition will only exist if mcuboot_pad exists.
share_size: mcuboot_pad
placement:
after: s0
align: {start: DT_FLASH_ERASE_BLOCK_SIZE}
s1_image:
share_size: {one_of: [mcuboot, s0_image]}
placement:
after: [s1_pad, s0]
align: {end: CONFIG_FPROTECT_BLOCK_SIZE}
s1:
# Partition which contains the whole S1 partition.
span: [s1_pad, s1_image]
provision:
size: CONFIG_PM_PARTITION_SIZE_PROVISION
#if defined(CONFIG_SOC_NRF9160) || defined(CONFIG_SOC_NRF5340_CPUAPP)
region: otp
#else
placement:
after: b0
align: {start: DT_FLASH_ERASE_BLOCK_SIZE}
#endif
Regions
The Partition Manager places partitions in different regions. For example, you can use regions for internal flash memory and external flash memory.
To define in which region a partition should be placed, use the region
property in the configuration of the partition.
If no region is specified, the predefined internal flash region is used.
Defining a region
Each region is defined by a name, a start address, a size, a placement strategy, and, if applicable, a device name. A region only specifies a device name if there is a device driver associated with the region, for example, a driver for an external SPI flash.
There are three types of placement strategies, which affect how partitions are placed in regions:
- start_to_end
Place partitions sequentially from start to end. Partitions stored in a region with this placement strategy cannot affect their placement through the
placement
property. The unused part of the region is assigned to a partition with the same name as the region.- end_to_start
Place partitions sequentially from end to start. Partitions stored in a region with this placement strategy cannot affect their placement through the
placement
property. The unused part of the region is exposed through a partition with the same name as the region.- complex
Place partitions according to their
placement
configuration. The unused part of the region is exposed through a partition namedapp
.
Regions are defined in partition_manager.cmake
.
For example, see the following definitions for default regions:
add_region( # Define region without device name
otp # Name
756 # Size
0xff8108 # Base address
start_to_end # Placement strategy
)
add_region_with_dev( # Define region with device name
flash_primary # Name
${flash_size} # Size
${CONFIG_FLASH_BASE_ADDRESS} # Base address
complex # Placement strategy
NRF_FLASH_DRV_NAME # Device name
)
External flash memory partitions
The Partition Manager supports partitions in the external flash memory through the use of Regions. Any placeholder partition can specify that it should be stored in the external flash memory region. External flash memory regions always use the start_to_end placement strategy.
To store partitions in the external flash memory, you must choose a value for the nordic,pm-ext-flash
property in the devicetree.
See the following example of an overlay file that sets this value:
/ {
chosen {
nordic,pm-ext-flash = &mx25r64;
};
};
After the nordic,pm-ext-flash
value is set, you can place partitions in the external flash memory as follows:
# Name of partition
external_plz:
region: external_flash
size: CONFIG_EXTERNAL_PLZ_SIZE
Note
Use the
CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL
,CONFIG_PM_PARTITION_REGION_SETTINGS_STORAGE_EXTERNAL
, andCONFIG_PM_PARTITION_REGION_NVS_STORAGE_EXTERNAL
to specify that the relevant partition must be located in external flash memory. You must add achosen
entry fornordic,pm-ext-flash
in your devicetree to make this option available. Seetests/subsys/partition_manager
for example configurations.If the external flash device is not using the QSPI NOR driver, you must enable
CONFIG_PM_OVERRIDE_EXTERNAL_DRIVER_CHECK
to override the Partition Manager’s external flash driver check, and the required driver must also be enabled for all applications that need it.
See Using external flash memory partitions for more details on using external flash memory with MCUboot.
Build system
The build system finds the child images that have been enabled and their configurations.
For each image, the Partition Manager’s CMake code infers the paths to the following files and folders from the name and from other global properties:
The
pm.yml
fileThe compiled HEX file
The generated include folder
After CMake finishes configuring the child images, the Partition Manager script is executed in configure time (execute_process
) with the lists of names and paths as arguments.
The configurations generated by the Partition Manager script are imported as CMake variables (see CMake).
The Partition Manager script outputs a partitions.yml
file.
This file contains the internal state of the Partition Manager at the end of processing.
This means it contains the merged contents of all pm.yml
files, the sizes and addresses of all partitions, and other information generated by the Partition Manager.
Generated output
After the main Partition Manager script has finished, another script runs.
This script takes the partitions.yml
file as input and creates the following output files:
A C header file
pm_config.h
for each child image and for the root applicationA key-value file
pm.config
The header files are used in the C code, while the key-value file is imported into the CMake namespace. Both kinds of files contain, among other information, the start address and size of all partitions.
Usage
The output that the Partition Manager generates can be used in various areas of your code.
C code
When the Partition Manager is enabled, all source files are compiled with the define USE_PARTITION_MANAGER
set to 1.
If you use this define in your code, the preprocessor can choose what code to include depending on whether the Partition Manager is being used.
#if USE_PARTITION_MANAGER
#include <pm_config.h>
#define NON_SECURE_APP_ADDRESS PM_APP_ADDRESS
#else
...
HEX files
The Partition Manager may implicitly or explicitly assign a HEX file to a partition.
Image partitions are implicitly assigned the compiled HEX file, that is, the HEX file that is generated when building the corresponding image. Container partitions are implicitly assigned the result of merging the HEX files that are assigned to the underlying partitions. Placeholder partitions are not implicitly assigned a HEX file.
To explicitly assign a HEX file to a partition, set the global properties partition_name_PM_HEX_FILE and partition_name_PM_TARGET in CMake, where partition_name is the name of the partition. partition_name_PM_TARGET specifies the build target that generates the HEX file specified in partition_name_PM_HEX_FILE.
See the following example, which assigns a cryptographically signed HEX file built by the sign_target
build target to the root application:
set_property(
GLOBAL PROPERTY
app_PM_HEX_FILE # Must match "*_PM_HEX_FILE"
${PROJECT_BINARY_DIR}/signed.hex
)
set_property(
GLOBAL PROPERTY
app_PM_TARGET # Must match "*_PM_TARGET"
sign_target
)
As output, the Partition Manager creates a HEX file called merged.hex
, which is programmed to the development kit when calling ninja flash
.
When creating merged.hex
, all assigned HEX files are included in the merge operation.
If the HEX files overlap, the conflict is resolved as follows:
HEX files assigned to container partitions overwrite HEX files assigned to their underlying partitions.
HEX files assigned to larger partitions overwrite HEX files assigned to smaller partitions.
Explicitly assigned HEX files overwrite implicitly assigned HEX files.
This means that you can overwrite a partition’s HEX file by wrapping that partition in another partition and assigning a HEX file to the new partition.
Partition Manager report
When using the Partition Manager, run ninja partition_manager_report
to see the addresses and sizes of all the configured partitions.
CMake
The CMake variables from the Partition Manager are typically used through generator expressions, because these variables are only made available late in the CMake configure stage.
To read a Partition Manager variable through a generator expression, the variable must be assigned as a target property.
The Partition Manager stores all variables as target properties on the partition_manager
target, which means they can be used in generator expressions in the following way:
--slot-size $<TARGET_PROPERTY:partition_manager,PM_MCUBOOT_PARTITIONS_PRIMARY_SIZE>
Partition placement reports
You can generate an ASCII-art map report to get an overview of how the partition manager creates flash memory partitions. This is especially useful when using multiple bootloaders.
To generate the report, use the ninja partition_manager_report
or west build -t partition_manager_report
commands.
For example, if you generate a partition placement report on the build of zephyr/samples/hello_world
with the nRF52840 development kit using nRF Secure Immutable Bootloader and MCUboot, you would get as an output an ASCII partition map that looks like the following:
(0x100000 - 1024.0kB):
+------------------------------------------+
+---0x0: b0 (0x9000)-----------------------+
| 0x0: b0_image (0x8000) |
| 0x8000: provision (0x1000) |
+---0x9000: s0 (0xc200)--------------------+
| 0x9000: s0_pad (0x200) |
+---0x9200: s0_image (0xc000)--------------+
| 0x9200: mcuboot (0xc000) |
| 0x15200: EMPTY_0 (0xe00) |
+---0x16000: s1 (0xc200)-------------------+
| 0x16000: s1_pad (0x200) |
| 0x16200: EMPTY_1 (0xe00) |
| 0x17000: s1_image (0xc000) |
+---0x23000: mcuboot_primary (0x6e000)-----+
| 0x23000: mcuboot_pad (0x200) |
+---0x23200: mcuboot_primary_app (0x6de00)-+
+---0x23200: app_image (0x6de00)-----------+
| 0x23200: app (0x6de00) |
| 0x91000: mcuboot_secondary (0x6e000) |
| 0xff000: EMPTY_2 (0x1000) |
+------------------------------------------+
The sizes of each partition are determined by the associated pm.yml file, such as nrf/samples/bootloader/pm.yml
for nRF Secure Immutable Bootloader and bootloader/mcuboot/boot/zephyr/pm.yml
for MCUboot.
Static configuration
By default, the Partition Manager dynamically places the partitions in memory. However, if you have a deployed product that consists of multiple images, where only a subset of the included images can be upgraded through a firmware update mechanism, the upgradable images must be statically configured. For example, if a device includes a non-upgradable first-stage bootloader and an upgradable application, the application image to be upgraded must be linked to the same address as the one that is deployed.
For this purpose, the Partition Manager provides static configuration to define static partitions.
The area used by the static partitions is called the static area.
The static area comes in addition to the dynamic area, which consists of the app
partition and all memory adjacent to the app
partition that is not occupied by a static partition.
Note that there is only one dynamic area.
When the Partition Manager is executed, it operates only on the dynamic area, assuming that all other memory is reserved.
Within the dynamic area, you can define new partitions or configure existing partitions even if you are using static partitions. The dynamic area is resized as required when updating the static configuration.
Configuring static partitions
Static partitions are defined through a YAML-formatted configuration file in the root application’s source directory.
This file is similar to the regular pm.yml
configuration files, except that it also defines the start address for all partitions.
You can set PM_STATIC_YML_FILE
to contain exactly the static configuration you want to use.
If you do not set PM_STATIC_YML_FILE
, the build system will use the following order to look for files in your application source directory to use as a static configuration layout:
If build type is used, Configuring build types, the following order applies:
If the file
pm_static_<board>_<revision>_<buildtype>.yml
exists, it will be used.Otherwise, if the file
pm_static_<board>_<buildtype>.yml
exists, it will be used.Otherwise, if the file
pm_static_<buildtype>.yml
exists, it will be used.Otherwise, if the file
pm_static.yml
exists, it will be used.
If build type is not used, then the same order as above applies, except that <buildtype> is not part of the file name:
If the file
pm_static_<board>_<revision>.yml
exists, it will be used.Otherwise, if the file
pm_static_<board>.yml
exists, it will be used.Otherwise, if the file
pm_static.yml
exists, it will be used.
For Multi-image builds where the image targets a different domain, Updating the build scripts uses the same search algorithm, but a domain specific configuration file is also searched.
For example, pm_static_<board>_<buildtype>_<domain>.yml
or pm_static_<board>_<domain>.yml
.
Use a static partition layout to ensure consistency between builds, as the settings storage will be at the same location after the DFU.
The current partition configuration for a build can be found in $BUILD_DIR/partitions.yml
.
To apply the current configuration as a static configuration, copy this file to $APPLICATION_CONFIG_DIR/pm_static.yml
.
It is also possible to build a pm_static.yml
from scratch by following the description in Adding a static partition
When modifying static configurations, keep in mind the following:
There can only be one unoccupied gap per region.
All statically defined partitions in regions with
end_to_start
orstart_to_end
placement strategy must be packed at the end or the start of the region, respectively.
The default flash_primary
region uses the complex
placement strategy, so these limitations do not apply there.
You can add or remove partitions as described in the following sections.
Note
If the static configuration contains an entry for the app
partition, this entry is ignored.
Adding a dynamic partition
New dynamic partitions that are listed in a pm.yml
file are automatically added.
However, if a partition is defined both as a static partition and as a dynamic partition, the dynamic definition is ignored.
Note
When resolving the relative placement of dynamic partitions, any placement properties referencing static partitions are ignored.
Adding a static partition
To add a static partition, add an entry for it in pm_static.yml
.
This entry must define the properties address
, size
, and - if applicable - span
.
The region defaults to flash_primary
if no region
property is specified.
partition_name:
address: 0xab00
size: 0x1000
span: [example] # Only if this partition had the span property set originally.
Note
Child images that are built with the build strategy partition_name_BUILD_STRATEGY_SKIP_BUILD or partition_name_BUILD_STRATEGY_USE_HEX_FILE must define a static partition to ensure correct placement of the dynamic partitions.
Removing a static partition
To remove a static partition, delete its entry in pm_static.yml
.
Only partitions adjacent to the app
partition or other removed partitions can be removed.