Last edited one month ago

How to optimize the boot time

Applicable for STM32MP13x lines, STM32MP15x lines, STM32MP25x lines



1. Article purpose[edit | edit source]

The purpose of this document is to provide information on how to measure and improve the boot-time[1] of a typical STM32MP1 series Linux system. This article is not an exhaustive list of possible optimizations, and those that are considered insufficiently reliable for industrial use are intentionally omitted.

2. Overview[edit | edit source]

On a typical STM32MP1 Linux system, the boot-chain is performed, respectively, by: the ROM code, TF-A, U-Boot, the Linux kernel, and the user-land[2]. All these components except the ROM code can be modified, and thus configured to start more quickly. For each of them, the procedure is the same: features that are not required at boot-time must be initiated after system boot (or disabled), and features that improve the boot time must be enabled.

3. Measuring boot-time[edit | edit source]

Before optimizing the performance of any piece of software, the time duration of each part must be considered so that the effort can be focused effectively.

3.1. Using a serial console[edit | edit source]

One of the easiest way to measure the boot-time of a Linux system is to observe traces emitted on a serial console using timing software, such as serialgrab or like the script measure-timing.txt based on microcom and p2f.

For example:

microcom -p /dev/ttyACM0 | bash Measure-timing.txt
Waiting for board reset...
NOTICE:  Model: STMicroelectronics STM32MP157C eval daughter on eval mother
NOTICE:  Board: MB1263 Var1 Rev.C-01
…
U-Boot 2018.11-stm32mp-r2 (Nov 14 2018 - 16:10:06 +0000)

CPU: STM32MP157AAA Rev.B
Model: STMicroelectronics STM32MP157C eval daughter on eval mother
…
Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
…
Freeing unused kernel memory: 1024K
Run /sbin/init as init process
…
ST OpenSTLinux - Weston - (A Yocto Project Based Distro) 2.6-openstlinux-4.19-thud-mp1-19-02-20 stm32mp1 ttySTM0

stm32mp1 login:

Timing results:
FSBL:  1.23s
SSBL:  2.34s
Linux: 2.34s
init:  1.23s
total: 7.14s

Note: these are illustrative figures since the boot-time depends on too many parameters to provide meaningful figures here.

3.2. Using hardware timers[edit | edit source]

When measuring traces from a serial console is not precise enough, or when traces are not available, it is possible to use hardware timers. Some components of the boot chain provide timing information based on hardware timers; for instance with U-Boot, the following options can be enabled:

CONFIG_BOOTSTAGE=y
CONFIG_BOOTSTAGE_REPORT=y

This prints on the serial console — just before booting the OS — something similar to the output below (illustrative figures):

Starting kernel ...

Timer summary in microseconds (11 records):
       Mark    Elapsed  Stage
          0          0  reset
    123,456    123,456  board_init_f
  2,345,678  2,222,222  board_init_r
  3,456,789  1,111,111  id=64
  3,567,890    111,101  id=65
  3,678,901    111,011  main_loop
  4,567,890    888,989  bootm_start
  4,678,901    111,011  id=15
  4,789,012    110,111  start_kernel

Accumulated time:
                23,456  dm_r
               567,890  dm_f
Booting Linux on physical CPU 0x0

If the serial console is not available, this timing information can also be stored in the device-tree or in memory:

CONFIG_BOOTSTAGE_FDT=y
CONFIG_BOOTSTAGE_STASH=y

It is possible to add this feature to boot-chain components that do not implement it by default, like TF-A. See the file arch/arm/cpu/armv7/arch_timer.c from U-Boot for an example.

3.3. Using GPIOs[edit | edit source]

When the console is disabled, the boot-chain components can be modified to trigger events on GPIOs according to the current stage of the boot-process. Then a logical analyzer can be used to measure the time between each such event.

Example of trace captured by Sigrok and displayed by PulseView.

4. Optimizing boot-time by modifying SW components[edit | edit source]

4.1. TF-A[edit | edit source]

4.1.1. Configuration[edit | edit source]

The TF-A execution time can be noticeably reduced by disabling features that are not required. To achieve this, the right options have to be specified when building the TF-A such as the debug configuration:

make DEBUG=0 …

These build options must of course be adjusted according to the expected usage and the TF-A version.

4.1.2. Traces[edit | edit source]

Traces are time consuming and can be removed if not needed anymore at the end of a product development. The risk is of course to not be able to debug without any logs. Use this at the end of your project, and only if it can match with your risks:

make LOG_LEVEL=0 …

4.1.3. I2C timing[edit | edit source]

I2C driver computes device timing at init, in order to guarantee correct data hold and setup times. The execution time of the computation algorithm is not so important, but with all associated device tree accesses, it can last several 10ms. It has to be done for each instance, so it can happen several times in the boot sequence.

For specific needs, a hard-coded timing (and its related frequency) can be used in order to optimize boot performances. Dedicated fields can be added in the I2C instance related handle structure. Then, once retrieved, these boot values can be configured by the client, this avoids to compute timings (and to do several device tree accesses) on first init for each instance.


4.2. OP-TEE[edit | edit source]

4.2.1. Traces[edit | edit source]

As we can see below in Linux chapter, traces can be time consuming for information we do not necessarily need in product production phase.

In OP-TEE, you can remove then by adjusting compilation option CFG_TEE_CORE_LOG_LEVEL=0 and CFG_TEE_CORE_DEBUG=0.

4.3. U-Boot[edit | edit source]

4.3.1. Delay[edit | edit source]

Before loading the Linux kernel and its device tree, U-Boot, by default, waits one second for a potential user input. This behavior — undesirable when boot time is a concern — can be easily removed by specifying bootdelay=0 in include/configs/stm32mp1.h.

4.3.2. Configuration and device tree[edit | edit source]

More broadly, removing support for all unused devices from U-Boot configuration and unused nodes from the device-tree drastically reduces the U-Boot execution time, since this eliminates the initialization time of those devices and the time to parse the device-tree.

There are also a couple of U-Boot features that are specially designed to improve the boot-time, for example:

CONFIG_MTD_UBI_FASTMAP=y
CONFIG_SYS_MALLOC_CLEAR_ON_INIT=n

Regarding support for UBI fastmap (for NOR and NAND storage media), please see the "Linux" section below for more information.

4.3.3. Configuration access[edit | edit source]

By default U-Boot searches a boot configuration file extlinux.conf or a boot script boot.scr.uimg from a bootable partition ("bootfs" for OpenSTLinux), see U-Boot_overview#Generic_Distro_configuration for details. Such access to a file system on storage media can take a short of time, but fortunately it is possible to embed a boot command into the U-Boot binary instead. To do this, the whole U-Boot environment must be specified from scratch:

CONFIG_USE_DEFAULT_ENV_FILE=y
CONFIG_DEFAULT_ENV_FILE="path/to/env.txt"

Or the U-Boot "distro" mode must be disabled:

CONFIG_DISTRO_DEFAULTS=n

In the latter case, be aware that if booting from an ext2/4 partition — typically when booting from an SD card or from eMMC — the following options must be explicitly selected (they were previously selected implicitly by CONFIG_DISTRO_DEFAULTS):

CONFIG_CMD_EXT2=y
CONFIG_CMD_EXT4=y

In both cases only CONFIG_ENV_IS_NOWHERE must be set to y (remove all the other CONFIG_ENV_IS...) , and the environment variable bootcmd must contain the expected boot command in your configuration file

For example:

CONFIG_BOOTCOMMAND="run bootcmd_ubi"
bootcmd_ubi=env set bootargs ubi.mtd=UBI root=ubi0:rootfs \
                         rootfstype=ubifs rootwait  \
                         rw console=ttySTM0,115200; \
         ubi part UBI;                              \
         ubifsmount ubi0:boot;                      \
         ubifsload 0xc2000000 /fitImage;              \
         ubifsload 0xc4000000 /stm32mp157c-ev1.dtb; \
         bootm 0xc2000000 - 0xc4000000

In this case, STM32CubeProgrammer is no more supported in U-Boot and you need to use an other FIP to update the device

An other example with STM32CubeProgrammer support and with the same bootcmd_ubi is:

CONFIG_BOOTCOMMAND="run bootcmd_stm32mp"
bootcmd_stm32mp= \
	if test ${boot_device} = serial || test ${boot_device} = usb; \
	then stm32prog ${boot_device} ${boot_instance}; \ 
	else run bootcmd_ubi; \
	fi

4.4. Linux[edit | edit source]

4.4.1. Configuration and device-tree[edit | edit source]

For U-Boot, one of the most efficient ways to decrease the Linux boot time is to remove support for all unused devices from its configuration and device-tree, since this eliminates the time taken to initialize those devices. Also, support for devices and features that are required but not mandatory at boot-time can be compiled as modules, and then loaded by the user-land once the boot-process is done (see the "Init" subsection below).

4.4.2. Traces[edit | edit source]

Linux boot traces have a size of about 2 Kbytes, so they take about 2 seconds to transfer on a serial link configured at 115200 bauds. If this is an issue, the following kernel parameters (bootargs variable in U-Boot) can be used to remove these traces:

quiet loglevel=0

This is automatically done by U-Boot when silent mode is required (see CONFIG_SILENT_CONSOLE and CONFIG_SILENT_U_BOOT_ONLY): silent=1 in used U-Boot environment.

4.4.3. UBI volume[edit | edit source]

When partitions such as "bootfs" and "rootfs" are stored on a UBI volume, the following two actions are highly recommended to greatly reduce the volume attachment time at boot-time, both by U-Boot and by the Linux kernel:

1. Decrease the size of the UBI volume 2. Enable the fastmap feature. For this, the CONFIG_MTD_UBI_FASTMAP option must be set to y both for Linux and U-Boot, and ubi.fm_autoconvert=1 has to be added to the kernel boot parameters. Note that the very first boot is used to create the fastmap information, thus this one does not get faster.

A lot of other volume/file-systems exist for Flash media, such as JFFS, LogFS, F2FS, and so on. Depending on the use-case, some may be faster than others.

4.5. User-land[edit | edit source]

4.5.1. Init[edit | edit source]

The very first user-land process launched by the Linux kernel is init; it is in charge of launching other processes in the right order. As a consequence, removing all unnecessary services can greatly speed up this part of the boot-process. The way services can be removed highly depends on the system in use (systemd, OpenRC and so on), so please refer to its documentation.

Ultimately, when no services are required, the init system can be replaced by the final application itself; either by storing its binary in /sbin/init, or by passing the following Linux boot parameter:

init=/path/to/application/binary

4.5.2. Framework[edit | edit source]

For graphical applications, the choice of display framework can seriously impact the startup time of the application itself. For instance, one could use the Linux framebuffer instead of Weston or Xorg, since the former is set up faster than the latter.

Likewise for video applications; if the boot-time is a concern, direct use of the V4L2 interface instead of higher-level interfaces such as GStreamer is recommended.


5. Optimizing boot-time by removing U-Boot[edit | edit source]

In the previous chapters, we saw some tips to individually save time in each software components without touching the boot chain. Now in this chapter, we will see how to consider a boot chain modification to remove U-Boot and jump directly into the Linux kernel entry point. Indeed, U-Boot is time-consuming as it checks the flash memories available, relocates itself in memory ... Removing U-Boot is equivalent to saving precious time on operations that we do not necessarily need anymore at the end of our product development.

Please make sure to be familiar with Boot chain overview and STM32MPU Developer Package articles before going further. As the different steps are multiple and can be complex for non-experienced users, please be sure to have a global understanding of the system before trying to implement the setup below.

Note that this chapter is made to help users go deeper in boot time optimization. However, keep in mind that removing U-Boot makes your system less flexible.

5.1. Step 0 : Preamble[edit | edit source]

The steps below have been done and tested on SDMMC and eMMC flash memories. Maybe NOR and NAND flashes may need more adjustments.

Moreover, we assume that you know how to modify and recompile the different BSP components as described in the STM32MPU Developer Package.

5.2. Step 1 : Modifying TF-A BL2[edit | edit source]

In the STM32MPU boot chain, TF-A BL2 is in charge of loading the TF-A FIP components into memory, including the Non-Trusted firmware, also known as BL33 in the boot chain. This BL33 was originally U-Boot, but now it is our Linux kernel. The size is not the same and the load address is not the same, so we need to adapt it depending on the SoC used. In both cases, the information is declared in the <tf-a_sources>/plat/st/<stm32mpX>/<stm32mpX>_def.h file from TF-A sources.

Two pieces of information need to be adapted: STM32MP_BL33_BASE and STM32MP_BL33_MAX_SIZE:

  • STM32MP_BL33_BASE = The load address of our Linux kernel.
  • STM32MP_BL33_MAX_SIZE= The size between our Linux kernel start address and our Linux DTB start address.

A second point of attention is the Linux kernel copy into DDR. As the Linux kernel has a bigger size than U-Boot binary, it takes a longer time to read/copy it, and this time can reach the STM32 SDMMC read timeout defined by default. We will adapt its value to avoid such a situation.

After the two modifications above (detailed below), we can recompile TF-A BL2 as explained in the How to configure TF-A BL2 article.

5.2.1. STM32MP1 series[edit | edit source]

For these series we have:

  • DDR base address = 0xC0000000
  • Linux kernel load address = 0xC2008000
  • Linux kernel DTB load address = 0xC6000000
  • Delta between Linux and DTB is = 0xC6000000 - 0xC2008000 = 0x3FF8000

We will so adapt our plat/st/stm32mp1/stm32mp1_def.h with following declarations :

#define STM32MP_BL33_BASE       (STM32MP_DDR_BASE + U(0x2008000))
#define STM32MP_BL33_MAX_SIZE       U(0x3FF8000)

5.2.2. STM32MP2 series[edit | edit source]

For these series we have:

  • DDR base address = 0x80000000
  • Linux kernel load address = 0x84000000
  • Linux kernel DTB load address = 0x8C000000
  • Delta between Linux and DTB is = 0x8C000000 - 0x84000000 = 0x8000000

We will so adapt our plat/st/stm32mp2/stm32mp2_def.h with following declarations :

#define STM32MP_BL33_BASE       (STM32MP_DDR_BASE + U(0x4000000))
#define STM32MP_BL33_MAX_SIZE       U(0x8000000)

5.2.3. STM32 SDMMC timeout adaptation (STM32MP1 and STM32MP2)[edit | edit source]

The file we have to target is <tf-a_sources>/drivers/st/mmc/stm32_sdmmc2.c, and more precisely the function stm32_sdmmc2_read(...).

Inside this file, we initialize a 1 second timeout thanks to this line :

timeout = timeout_init_us(TIMEOUT_US_1_S);

We need to modify it and raise it a bit :

timeout = timeout_init_us(TIMEOUT_US_1_S * 5);

5.3. Step 2 : Modifying TF-A BL31 (STM32MP2 series only)[edit | edit source]

STM32MP2 series have an ARM64 bits architecture. In this case, primary CPU general-purpose register settings given at jump time by TF-A BL31 are different than the standard ones we have with ARM32, as described in this documentation:

   - x0 = physical address of device tree blob (dtb) in system RAM.
   - x1 = 0 (reserved for future use)
   - x2 = 0 (reserved for future use)
   - x3 = 0 (reserved for future use)

This results in two cases:

  • If we want to jump into U-Boot, we keep the original registers configuration.
  • If we want to jump into Linux kernel (which is what we want here), we need to change this configuration to pass the Linux DTB into x0 register.

To get a generic option to do this, TF-A working group added a new compilation flag called ARM_LINUX_KERNEL_AS_BL33. This flag is not yet present in our ecosystem, but we can add it manually by patching TF-A Bl31 source code.

  • Modifications in <tf-a_source>/plat/st/stm32mp2/bl31_plat_setup.c, function bl31_early_platform_setup2(...):
	while (bl_params != NULL) {
		/*
		 * Copy BL33 entry point information.
		 * They are stored in Secure RAM, in BL2's address space.
		 */
		if (bl_params->image_id == BL33_IMAGE_ID) {
			bl33_image_ep_info = *bl_params->ep_info;
			/*
			 *  Check if hw_configuration is given to BL32 and
			 *  share it to BL33
			 */
			if (arg2 != 0U) {
#if ARM_LINUX_KERNEL_AS_BL33
				/*
				 * According to the file ``Documentation/arm64/booting.txt`` of
				 * the Linux kernel tree, Linux expects the physical address of
				 * the device tree blob (DTB) in x0, while x1-x3 are reserved
				 * for future use and must be 0.
				 */
				bl33_image_ep_info.args.arg0 = arg2; /*new*/
				bl33_image_ep_info.args.arg1 = 0U; /*new*/
				bl33_image_ep_info.args.arg2 = 0U; /*new*/
				bl33_image_ep_info.args.arg3 = 0U; /*new*/
#else
				bl33_image_ep_info.args.arg0 = 0U;
				bl33_image_ep_info.args.arg1 = 0U;
				bl33_image_ep_info.args.arg2 = arg2;
#endif
  • Modifications in <tf-a_sources>/plat/st/stm32mp2/platform.mk (to add ARM_LINUX_KERNEL_AS_BL33) :
# The Linux kernel as a BL33 image by default
ARM_LINUX_KERNEL_AS_BL33	:=	1

<...>

# Enable flags for C files
$(eval $(call assert_booleans,\
	$(sort \
		ARM_LINUX_KERNEL_AS_BL33 \
		PKA_USE_BRAINPOOL_P256T1 \
		PKA_USE_NIST_P256 \
		STM32MP_CRYPTO_ROM_LIB \

<...>

$(eval $(call add_defines,\
	$(sort \
		ARM_LINUX_KERNEL_AS_BL33 \
		DWL_BUFFER_BASE \
		PKA_USE_BRAINPOOL_P256T1 \
		PKA_USE_NIST_P256 \
		PLAT_DEF_FIP_UUID \

We can now recompile TF-A BL31 (same way as TF-A BL2) by following How to configure TF-A BL2 article.

5.4. Step 3 : Modifying Linux kernel[edit | edit source]

We now have the necessary components in TF-A to jump directly from BL31 (TF-A for STM32MP2 and OP-TEE for STM32MP1) into the Linux kernel entry point. However, it was the role of U-Boot to give Linux its kernel boot command line. Now, nobody has this role anymore, and we need to tell Linux that it will have to handle it itself. Fortunately, we have a Linux configuration that aims to describe this kernel command line (CONFIG_CMDLINE), and one to force the kernel to use this one (CONFIG_CMDLINE_FORCE).

Following Menuconfig or how to configure kernel article, change the following configurations :

[*] Boot options -->
   (<command_line>)  Default kernel command string
   Kernel command line type (Always use the default kernel command string)  ---> 
Info white.png Information
See below some kernel command line examples in different setups:
  • STM32MP157F-DK (SDMMC) : root=PARTUUID=e91c4e10-16e6-4c0e-bd0e-77becf4a3582 rootwait rw earlyprintk earlycon console=ttySTM0,115200
  • STM32MP257F-EV1 (eMMC) : root=PARTUUID=491f6117-415d-4f53-88c9-6e0de54deac6 rootwait rw earlyprintk earlycon console=ttySTM0,115200
  • STM32MP257F-EV1 (SDMMC) : root=PARTUUID=e91c4e10-16e6-4c0e-bd0e-77becf4a3582 rootwait rw earlyprintk earlycon console=ttySTM0,115200 quiet loglevel=0

5.5. Step 4 : Replace U-Boot by Linux in TF-A FIP[edit | edit source]

First of all, let's talk about the TF-A FIP. It contains all the information about the images TF-A BL2 has to load into memory.

In the standard situation, TF-A BL2 loads the U-Boot binary as non-trusted firmware (NT-FW) and U-Boot device tree as hardware configuration (HW-CONFIG). Then, U-Boot's goal is to decompress and load the Linux kernel image into memory. However, remember our target: we want to remove U-Boot from the boot chain. To do this, we will replace U-Boot binary and DTB in the TF-A FIP by the Linux kernel ones :

  • nt-fw = Image (Linux kernel binary image got by the compilation)
  • hw-config = <board>.dtb (Linux kernel board device tree blob got by compilation)
  • Command example :
fiptool update --nt-fw Image --hw-config <board>.dtb <fip.bin>
Info white.png Information
For the example command above please see some examples of file location :
  • Image for STM32MP1 series : <linux_build_folder>/arch/arm/boot/Image
  • <board>.dtb for STM32MP1 series : <linux_build_folder>/arch/arm/boot/dts/st-<board>.dtb

Now that we have our TF-A FIP with the good content, we need to observe the biggest impact of this modification, the TF-A FIP size ! Indeed, the Linux kernel image decompressed size is something around 20MB and 25MB, in comparison with U-Boot binary with a size around 1MB.

We will see just below the consequence of a such size modification.

5.6. Step 5 : Adjusting the TSV Flashlayout file[edit | edit source]

TSV files are used by CubeProgrammer to flash the image on the board's flash memory and manage dedicated partitions for different components. You can find all the information about this kind of file in STM32CubeProgrammer flashlayout article. With the Linux now in the TF-A FIP, the dedicated space set to store the Non-Trusted Firmware is no longer sufficient. We need to resize it ourselves.

Let's take an example with a TSV file we can find in the STM32MP15 Discovery kits - Starter Package. After downloading it and decompressing it, you can find the TSV files in <Starter_folder>/images/<stm32mpX>/flashlayout_st-image-weston/optee/.

We will take the one of STM32MP157F-DK2 for SDCARD (FlashLayout_sdcard_stm32mp157f-dk2-optee.tsv) :

#Opt	Id	Name	Type	IP	Offset	Binary
-	0x01	fsbl-boot	Binary	none	0x0	arm-trusted-firmware/tf-a-stm32mp157f-dk2-usb.stm32
-	0x03	fip-boot	FIP	none	0x0	fip/fip-stm32mp157f-dk2-optee-sdcard.bin
P	0x04	fsbl1	Binary	mmc0	0x00004400	arm-trusted-firmware/tf-a-stm32mp157f-dk2-optee-sdcard.stm32
P	0x05	fsbl2	Binary	mmc0	0x00044400	arm-trusted-firmware/tf-a-stm32mp157f-dk2-optee-sdcard.stm32
P	0x06	metadata1	FWU_MDATA	mmc0	0x00084400	arm-trusted-firmware/metadata.bin
P	0x07	metadata2	FWU_MDATA	mmc0	0x000C4400	arm-trusted-firmware/metadata.bin
P	0x08	fip-a	FIP	mmc0	0x00104400	fip/fip-stm32mp157f-dk2-optee-sdcard.bin
PED	0x09	fip-b	FIP	mmc0	0x00504400	none
PED	0x0A	u-boot-env	ENV	mmc0	0x00904400	none
P	0x10	bootfs	System	mmc0	0x00984400	st-image-bootfs-openstlinux-weston-stm32mp1.ext4
P	0x11	vendorfs	FileSystem	mmc0	0x04984400	st-image-vendorfs-openstlinux-weston-stm32mp1.ext4
P	0x12	rootfs	FileSystem	mmc0	0x05984400	core-image-minimal-openstlinux-weston-stm32mp1.ext4
P	0x13	userfs	FileSystem	mmc0	0x105984400	st-image-userfs-openstlinux-weston-stm32mp1.ext4

We see the original offset of fip-a equals to 0x00104400 and the offset of the next section equals to 0x00504400. It means we currently have 0x00504400 - 0x00104400 ~= 4MB. This is not enough in our case.

We will create a copy of this TSV file named FlashLayout_sdcard_stm32mp157f-dk2-optee-modified.tsv and raise this second offset to get more space for our TF-A FIP. We also need to apply this offset to the following partitions to not reduce their size:

#Opt	Id	Name	Type	IP	Offset	Binary
-	0x01	fsbl-boot	Binary	none	0x0	arm-trusted-firmware/tf-a-stm32mp157f-dk2-usb.stm32
-	0x03	fip-boot	FIP	none	0x0	fip/fip-stm32mp157f-dk2-optee-sdcard.bin
P	0x04	fsbl1	Binary	mmc0	0x00004400	arm-trusted-firmware/tf-a-stm32mp157f-dk2-optee-sdcard.stm32
P	0x05	fsbl2	Binary	mmc0	0x00044400	arm-trusted-firmware/tf-a-stm32mp157f-dk2-optee-sdcard.stm32
P	0x06	metadata1	FWU_MDATA	mmc0	0x00084400	arm-trusted-firmware/metadata.bin
P	0x07	metadata2	FWU_MDATA	mmc0	0x000C4400	arm-trusted-firmware/metadata.bin
P	0x08	fip-a	FIP	mmc0	0x00104400	fip/fip-stm32mp157f-dk2-optee-sdcard.bin
PED	0x09	fip-b	FIP	mmc0	0x02104400	none
PED	0x0A	u-boot-env	ENV	mmc0	0x02904400	none
P	0x10	bootfs	System	mmc0	0x02984400	st-image-bootfs-openstlinux-weston-stm32mp1.ext4
P	0x11	vendorfs	FileSystem	mmc0	0x06984400	st-image-vendorfs-openstlinux-weston-stm32mp1.ext4
P	0x12	rootfs	FileSystem	mmc0	0x12084400	core-image-minimal-openstlinux-weston-stm32mp1.ext4
P	0x13	userfs	FileSystem	mmc0	0x112084400	st-image-userfs-openstlinux-weston-stm32mp1.ext4

The new size for fip-a is now 0x02104400 - 0x00104400 ~= 32MB which is OK now.

We adjusted the size, now we can change the sources in the partitions we modified. For this let's add a new folder next to other sources with the components we compiled ourselves (the TF-A BL2 and the TF-A FIP):

cd <Starter_folder>/images/<stm32mpX>/flashlayout_st-image-weston/optee/
mkdir modified_components
cd modified_components
cp <path_tf-a_bl2>.stm32 .
cp <path_tf-a_fip>.bin .

Then we can modify the TSV file:

#Opt	Id	Name	Type	IP	Offset	Binary
-	0x01	fsbl-boot	Binary	none	0x0	arm-trusted-firmware/tf-a-stm32mp157f-dk2-usb.stm32
-	0x03	fip-boot	FIP	none	0x0	fip/fip-stm32mp157f-dk2-optee-sdcard.bin
P	0x04	fsbl1	Binary	mmc0	0x00004400	modified_components/<path_tf-a_bl2>.stm32
P	0x05	fsbl2	Binary	mmc0	0x00044400	modified_components/<path_tf-a_bl2>.stm32
P	0x06	metadata1	FWU_MDATA	mmc0	0x00084400	arm-trusted-firmware/metadata.bin
P	0x07	metadata2	FWU_MDATA	mmc0	0x000C4400	arm-trusted-firmware/metadata.bin
P	0x08	fip-a	FIP	mmc0	0x00104400	modified_components/<path_tf-a_fip>.bin
PED	0x09	fip-b	FIP	mmc0	0x02104400	none
PED	0x0A	u-boot-env	ENV	mmc0	0x02904400	none
P	0x10	bootfs	System	mmc0	0x02984400	st-image-bootfs-openstlinux-weston-stm32mp1.ext4
P	0x11	vendorfs	FileSystem	mmc0	0x06984400	st-image-vendorfs-openstlinux-weston-stm32mp1.ext4
P	0x12	rootfs	FileSystem	mmc0	0x12084400	core-image-minimal-openstlinux-weston-stm32mp1.ext4
P	0x13	userfs	FileSystem	mmc0	0x112084400	st-image-userfs-openstlinux-weston-stm32mp1.ext4

5.7. Step 6 : Flashing the new TSV file[edit | edit source]

We have all the elements to flash our image now. We can follow the guidelines provided by the Wiki depending on your SoC (flashing STM32MP15, flashing STM32MP13 or flashing STM32MP25).

We just need to adapt the command to point to our new TSV file. Before making a attempt, be sure to be located in the right folder :

cd <Starter_folder>/images/<stm32mpX>/
  • Example :
STM32_Programmer_CLI -c port=usb1 -w flashlayout_st-image-weston/optee/FlashLayout_sdcard_stm32mp157f-dk2-optee-modified.tsv

6. Conclusion[edit | edit source]

There is no universal recipe to improve the boot-time of a Linux system, since it depends on the constraints of the final use-case. However the universal rule is: always benchmark, before and after optimizing.

7. Further reading[edit | edit source]

8. References[edit | edit source]

  1. Sometimes referred to as startup-time.
  2. Sometimes referred to as user-space.