Partition Manager not using flash efficiently

Dear Nordic Team

When I run the command `west build -t partition_manager_report` from inside our build folder I get :

  flash_primary (0x100000 - 1024kB): 
+--------------------------------------------------+
| 0x0: mcuboot (0xc000 - 48kB)                     |
| 0xc000: EMPTY_0 (0x4000 - 16kB)                  |
+---0x10000: mcuboot_primary (0x70000 - 448kB)-----+
+---0x10000: tfm_secure (0xc200 - 48kB)------------+
| 0x10000: mcuboot_pad (0x200 - 512B)              |
+---0x10200: mcuboot_primary_app (0x6fe00 - 447kB)-+
| 0x10200: tfm (0xc000 - 48kB)                     |
+---0x1c200: tfm_nonsecure (0x63e00 - 399kB)-------+
| 0x1c200: app (0x63e00 - 399kB)                   |
+--------------------------------------------------+
| 0x80000: mcuboot_secondary (0x70000 - 448kB)     |
| 0xf0000: EMPTY_1 (0x8000 - 32kB)                 |
+---0xf8000: nonsecure_storage (0x6000 - 24kB)-----+
| 0xf8000: nvs_storage (0x6000 - 24kB)             |
+---0xfe000: tfm_storage (0x2000 - 8kB)------------+
| 0xfe000: tfm_its (0x2000 - 8kB)                  |
+--------------------------------------------------+


This seems like an inefficient use of flash and flash is quite valuable to us. We have to make use of every kB we can.
It seems like a waste in the following respects:

1. Why is there an EMPTY_0 partition? Potential gain 16kB
2. Why is there an EMPTY_1 partition? Potential gain 32kB
3. Why does mcuboot take 48kB, it only needs 33996B in our build? Potential gain at least ~12kB

My main question is, how can the flash layout be optimized (by Hand)? If it cannot, how can partition manager be disable, so that the partitions from the device-tree are used instead?

My assumption is, that to optimize the flash layout one has to move to a static partition setup as described here: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/scripts/partition_manager/partition_manager.html#static-configuration
So I copied the `build/paritions.yml` file to the `pm_static.yml` and started hand-optimizing. This is quite difficult, but I managed to achieve the following temporary result:

  flash_primary (0x100000 - 1024kB): 
+-------------------------------------------------+
| 0x0: mcuboot (0x9000 - 36kB)                    |
+---0x9000: mcuboot_primary (0x77000 - 476kB)-----+
+---0x9000: tfm_secure (0x13200 - 76kB)-----------+
| 0x9000: mcuboot_pad (0x200 - 512B)              |
+---0x9200: mcuboot_primary_app (0x76e00 - 475kB)-+
| 0x9200: tfm (0x13200 - 76kB)                    |
+---0x1c200: tfm_nonsecure (0x63e00 - 399kB)------+
| 0x1c400: app (0x63c00 - 399kB)                  |
+-------------------------------------------------+
| 0x80000: EMPTY_1 (0x1000 - 4kB)                 |
| 0x81000: mcuboot_secondary (0x77000 - 476kB)    |
+---0xf8000: nonsecure_storage (0x6000 - 24kB)----+
| 0xf8000: nvs_storage (0x6000 - 24kB)            |
+---0xfe000: tfm_storage (0x2000 - 8kB)-----------+
| 0xfe000: tfm_its (0x2000 - 8kB)                 |
+-------------------------------------------------+


I managed to reduce the empty partitions and move the free space into the mcuboot_primary and secondary partitions respectively. To achieve this, I had to increase the tfm-partitions, instead the goal is to increase the app partitions. Trying to reduce the tfm partition size again to the original 48kB and moving the free space into the app partition I run into a linker issue.

That leaves me with the following secondary questions:
1. Is this approach to optimize the flash-layout correct?
2. Is there a reason, that the tfm partition is expected to be located at a certain address?
3. What is the mcubootpad partition for?
4. Why do some of the partitions use the keyword "align" in the pm_static.yml? The documentation reads "Ensure the alignment of the start or the end of the 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...." In our case it is "align: -start: 0x8000", does this mean, that the start of those partitions needs to be a multiple of 0x8000 for maximum space efficiency (or the partition manager will insert empty partitions)? What are the alignment requirements?
5. We are using mcuboot for firmware upgrades as described here: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/mcuboot/design.html#swap-without-using-scratch. As described there, the primary partition needs to be bigger by a certain amount than the secondary partition. Can this be baked into the flash layout, such that an offending (too big) image is not only discovered when trying to switch to it after reboot when upgrading, but earlier? Ideally the secondary slot has exactly the size, such that it fits into the primary slot with enough padding for the move algorithm as described in the link.

  • I will try to create a sample to move TF-M partitions to test this tomorrow or Monday.

    Could it be, that tfm is using sub-regions?

    https://infocenter.nordicsemi.com/pdf/nRF9160_PS_v2.0.pdf#%5B%7B%22num%22%3A2810%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C85.039%2C465.123%2Cnull%5D

    "6.15.2.1 Non-secure callable (NSC) region definition in flash"

    I interpret this section to mean, that in each region there can be a "non-secure" and a "secure"-callable sub-region. This might explain, why the tfm-partition does not need to be aligned to the region border?

  • To test the placement of the tfm partition, I did the following:

    Use nrf/samples/crypto/aes_cbc, with CONFIG_BOOTLOADER_MCUBOOT=y.

    Now the partition manager report is as follows:

    +-------------------------------------------------+
    | 0x0: mcuboot (0xc000 - 48kB)                    |
    +---0xc000: mcuboot_primary (0x74000 - 464kB)-----+
    +---0xc000: tfm_secure (0x40200 - 256kB)----------+
    | 0xc000: mcuboot_pad (0x200 - 512B)              |
    +---0xc200: mcuboot_primary_app (0x73e00 - 463kB)-+
    | 0xc200: tfm (0x40000 - 256kB)                   |
    +---0x4c200: tfm_nonsecure (0x33e00 - 207kB)------+
    | 0x4c200: app (0x33e00 - 207kB)                  |
    +-------------------------------------------------+
    | 0x80000: mcuboot_secondary (0x74000 - 464kB)    |
    | 0xf4000: EMPTY_0 (0x4000 - 16kB)                |
    +---0xf8000: tfm_storage (0x8000 - 32kB)----------+
    | 0xf8000: tfm_its (0x2000 - 8kB)                 |
    | 0xfa000: tfm_otp_nv_counters (0x2000 - 8kB)     |
    | 0xfc000: tfm_ps (0x4000 - 16kB)                 |
    +-------------------------------------------------+
    
      otp (0x2fc - 764B): 
    +------------------------------+
    | 0xff8100: otp (0x2fc - 764B) |
    +------------------------------+
    
      sram_primary (0x80000 - 512kB): 
    +------------------------------------------------+
    +---0x20000000: sram_secure (0x40000 - 256kB)----+
    | 0x20000000: tfm_sram (0x40000 - 256kB)         |
    +---0x20040000: sram_nonsecure (0x40000 - 256kB)-+
    | 0x20040000: sram_primary (0x40000 - 256kB)     |
    +------------------------------------------------+
    
    

    To move the tfm partition, I increased the size of mcuboot.
    Then the tfm partition would have to move to make space.

    I used the following pm_static.yml:

    mcuboot:
      address: 0x0
      end_address: 0x10000
      placement:
        before:
        - mcuboot_primary
      region: flash_primary
      size: 0x10000
    

    And get the following partition manager report:

    +--------------------------------------------------+
    | 0x0: mcuboot (0x10000 - 64kB)                    |
    +---0x10000: mcuboot_primary (0x74000 - 464kB)-----+
    +---0x10000: tfm_secure (0x40200 - 256kB)----------+
    | 0x10000: mcuboot_pad (0x200 - 512B)              |
    +---0x10200: mcuboot_primary_app (0x73e00 - 463kB)-+
    | 0x10200: tfm (0x40000 - 256kB)                   |
    +---0x50200: tfm_nonsecure (0x33e00 - 207kB)-------+
    | 0x50200: app (0x33e00 - 207kB)                   |
    +--------------------------------------------------+
    | 0x84000: mcuboot_secondary (0x74000 - 464kB)     |
    +---0xf8000: tfm_storage (0x8000 - 32kB)-----------+
    | 0xf8000: tfm_its (0x2000 - 8kB)                  |
    | 0xfa000: tfm_otp_nv_counters (0x2000 - 8kB)      |
    | 0xfc000: tfm_ps (0x4000 - 16kB)                  |
    +--------------------------------------------------+
    
      otp (0x2fc - 764B): 
    +------------------------------+
    | 0xff8100: otp (0x2fc - 764B) |
    +------------------------------+
    
      sram_primary (0x80000 - 512kB): 
    +------------------------------------------------+
    +---0x20000000: sram_secure (0x40000 - 256kB)----+
    | 0x20000000: tfm_sram (0x40000 - 256kB)         |
    +---0x20040000: sram_nonsecure (0x40000 - 256kB)-+
    | 0x20040000: sram_primary (0x40000 - 256kB)     |
    +------------------------------------------------+

    Observe that in the first build, tfm starts at 0xc200.
    At the second build, tfm starts at 0x10200

    Regards,
    Sigurd Hellesvik

  • Very good, thanks.
    So, just for my understanding, the tfm partition does not have to be aligned to the flash-regions (and can therefore share a region with the `app`), because it makes use of non-secure-callable sub-regions (https://infocenter.nordicsemi.com/pdf/nRF9160_PS_v2.0.pdf#%5B%7B%22num%22%3A2810%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C85.039%2C465.123%2Cnull%5D)?

  • Hi,

    Cla said:
    So, just for my understanding, the tfm partition does not have to be aligned to the flash-regions (and can therefore share a region with the `app`), because it makes use of non-secure-callable sub-regions

    Since we have 2 different regions we talk about here, I am a bit unsure what you ask about.
    But I asked our experts the following question:

    "Does the TF-M partition need to be aligned to fit with The SPUs 32 KiB regions?"

    And they answer:

    "The answer is yes.
    Or to be more precise. The application needs to start on an SPU aligned 32 / 16 KB region.
    So that means if you have bootloaders, that affects it also. As the sum of bootloaders + TF-M sizes is what you need to look at."

    and
    "Correct it needs to be aligned within the locking granularity of https://infocenter.nordicsemi.com/topic/ps_nrf9160/spu.html?cp=2_0_0_5_14_1#register.FLASHREGION.PERM
    So that you are ensured that the flash can be set to secure.
    "

    Is this what you were looking for?

    My example might have misled you some.
    When testing it, I had to increase the size of MCUboot by exactly 16KiB as you see.
    If I remember correctly, it did not build for smaller increases.
    I should have realized this when testing, but oh well.
    Good job asking questions about this, it increases both our understanding on the matter.

    Regards,
    Sigurd Hellesvik

  • Is this what you were looking for?

    Not quite. I am sorry, that I did not express myself well.

    I was wondering, why the end of the `tfm` partition, bordering the `app` did not have to be aligned to `0x8000`. My guess would be, that FLASHNSC[n].REGION and FLASHNSC[n].SIZE are use to define the secure-callable and non-secure-callable sub-regions within a region?

    This is more an understanding question out of interest. The original question can be considered answered.
    Thanks for your help.

Related