Partition Manager

Partition Manager is a Python script that sets the start address and size of all image partitions in a multi-image build context. When creating an application that requires child images (for example, a bootloader), you can configure Partition Manager to control where in memory each image should be placed.

See Multi-image builds and Building and Configuring multiple images in Application Development for more information about multi-image builds.

By default, all nRF Connect SDK samples that require multiple images are configured to use the Partition Manager. If you prefer to build and program each image separately and disable the Partition Manager, configure your parent image (the application) to skip building the child images. Note that the Partition Manager is invoked only in multi-image builds.

Overview

The Partition Manager script reads a set of Partition Manager configurations. Using this information, it deduces the start address and size of each partition.

There are different kinds of partitions:

Image partitions

An image partition is the flash area reserved for an image, to which the image binary is written.

In a multi-image build context, there is one root image and one or more sub-images. The size of the root image partition is dynamic, while the sizes of all sub-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 flash 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 for image partitions are used in the preprocessing of the linker script for each image.

Configuration

Each sub-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 sub-image.

Note

pm.yml is only used for sub-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 sub-image partitions. If a root application defines a pm.yml file, it is silently ignored.

Configuration file format

The format of the pm.yml file is as follows:

partition_name:
   option_dict_name:
      option_specific_values

partition_name is the name of the partition (for example, mcuboot). option_dict_name and option_specific values can be any of the following:

placement: dict

This property specifies the placement of the partition relative to other partitions, to the end of flash, or to the root image partition 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 CMakeLists.txt, see Defining new child images in Application Development), this partition is the image partition. All other partitions are placeholder partitions. Each pm.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. It is not possible to place the partition after end or before start.

align: dict
Ensure alignment of start or end of partition by specifying a dict with a start or end 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 which directly or indirectly (through spans) share size with the app partitions can only be aligned if they are placed directly after the app partition.
span: list OR dict: list

If the value type is a list, this property lists which partitions this partition should span across. If the value type is a dict with key one_of, the semantics are equivalent to having a list with only the first existing partition in the one_of-list. A string formatted value is interpreted as a single item list. Partitions with this property are container partitions. Therefore, this property cannot be used together with the placement property.

Non-existing partitions are removed from the span list before processing, and partitions with empty span lists are removed altogether (unless filled via inside).

Note

You can specify configurations with an ambiguous ordering (see the following examples). However, different versions of the script might produce a different ordering for such configurations, and the Partition Manager might fail to find a solution even if one is theoretically possible. The Partition Manager always detects unsatisfiable configurations (no false positives), but it might fail on some valid inputs (false negatives).

See the following examples of valid and invalid configurations:

Span example 1 (fixed order, cannot work)
mcuboot:
   placement:
      before: [spm, app]

spm:
   placement:
      before: [app]

foo:
   span: [mcuboot, app] # This will fail, because 'spm' will be placed between mcuboot and app.

# Order: mcuboot, spm, app
Span example 2 (ambiguous order)
mcuboot:
   placement:

spm:
   placement:
      after: [mcuboot]

app:
   placement:
      after: [mcuboot]

foo:
   span: [mcuboot, app] # The order of spm and app is ambiguous in this case, but since
                        # this span exists, Partition Manager will try to increase the
                        # likelihood that mcuboot and app are placed next to each other.

# Order 1: mcuboot, spm, app
# Order 2: mcuboot, app, spm
# The algorithm should coerce order 2 to make foo work.
Span example 3 (ambiguous order, cannot work)
mcuboot:
   placement:

spm:
   placement:
      after: [mcuboot]

app:
   placement:
      after: [mcuboot]

foo:
   span: [mcuboot, app]

bar:
   span: [mcuboot, spm]

# Order 1: mcuboot, spm, app
# Order 2: mcuboot, app, spm
# foo requires order 2, while bar requires order 1.
inside: list

This property is the inverse of span. The name of the partition that specifies this property is added to the span list of the first existing container partition in the list. This property can be set for image or placeholder partitions.

Example for the inside property
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 value, which allows the user to easily modify the size (see Configuration file preprocessing for an example).
share_size: list

This properties 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 over size if one or more partitions in share_size exists.

If the target partition is the app or a partition that spans over the app, the size is effectively split between them, because the size of the app is dynamically decided.

If none of the partitions in the share_size list exists, and the partition does not define a size property, then the partition is removed. If none of the partitions in the share_size list exists, and the partition does define a size property, then the size property is used to set the size.

Configuration file preprocessing

Each pm.yml file is preprocessed to resolve symbols from Kconfig and DTS.

The following example shows a typical pm.yml file. It includes autoconf.h (which is generated by Kconfig) and uses a Kconfig variable to configure the size of the b0 partition.

#include <autoconf.h>
#include <generated_dts_board_unfixed.h>

# 'b0' is the name of the image partition.
b0:

  # b0 is placed before the mcuboot partition if the mcuboot partition
  # exists, otherwise it is stored before the app partition.
  placement:
    before: [mcuboot, app]
    align: {end: 0x8000}  # Align to size of SPU-lockable region.

  # The size of the b0 partition is configured in Kconfig.
  size: CONFIG_BOOTLOADER_PARTITION_SIZE

# Don't define the provision partition if the SoC is nRF9160, because
# the provisioning data is stored in the UICR->OTP data region.

#ifndef CONFIG_SOC_NRF9160

# 'provision' is the name of the placeholder partition.
provision:
  # This partition is stored at the very end of flash.
  placement: {before: end}

#endif /* CONFIG_SOC_NRF9160 */

Build system

The Partition Manager uses Zephyr’s multi-image build system to collect configurations for all sub-images. If one or more sub-images are included in a build, their names are appended to a global list.

For each image, 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 file
  • The compiled HEX file
  • The generated include folder

After CMake finishes configuring the sub-images, the Partition Manager script is executed in configure time (execute_process) with the lists of names and paths as argument. 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 sub-image and for the root application
  • A Kconfig file pm.config

The C header files are used in the C code, while the Kconfig file is imported in CMake. Both kinds of files contain, among other information, the start address and size of all partitions.

Usage

The output that Partition Manager generates can be used in various areas of your code.

C code

When 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 Partition Manager is being used.

#if USE_PARTITION_MANAGER
#include <pm_config.h>
#define NON_SECURE_APP_ADDRESS PM_APP_ADDRESS
#else
...

HEX files

Partition Manager may implicitly or explicitly assign a HEX file to a partition.

Image partitions are implicitly assigned the compiled HEX file, i.e. 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, Partition Manager creates a HEX file called merged.hex, which is programmed to the board 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.

ROM report

When using the Partition Manager, run ninja rom_report to see the addresses and sizes of flash partitions.

CMake

The CMake variables from 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. 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.

Reading partition manager variables in generator expressions.
--slot-size $<TARGET_PROPERTY:partition_manager,PM_MCUBOOT_PARTITIONS_PRIMARY_SIZE>

Static configuration

By default, 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, 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 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.

If the build system discovers a file named pm_static.yml in an application’s source directory, it automatically provides it to the Partition Manager script as static configuration.

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_SOURCE_DIR/pm_static.yml.

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.

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.

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 static partition and as 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.

Example of static configuration of a partition with span
partition_name:
   address: 0xab00
   size: 0x1000
   span: [example]  # Only if this partition had the span property set originally.

Note

Sub-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.