Difference between revisions of "How to protect the coprocessor firmware"

[quality revision] [pending revision]
m
m (U-Boot update)
 

1 Article purpose[edit]

This article explains how to protect the software loaded by the main processor into the coprocessor, and ensure the authentication of the loaded firmware.

2 Introduction[edit]

The Linux® OS, (through the remoteproc framework) or the U-boot enables the loading of firmware into control remote processors. Thanks to a specific OP-TEE trusted application (TA) running on the Arm® Trustzone and to the ETZPC peripheral, it is possible to authenticate a Cortex®-M4 firmware and install it on isolated RAMs to ensure its integrity during the execution .

From user's point of view the management of a non-authenticated or authenticated firmware does not differ, whether the firmware is managed by the Linux or by the U-Boot. The difference is that the management of the authenticated firmware is delegated to the OP-TEE firmware running in the Arm® Trustzone.

3 Principles[edit]

The protection of the coprocessor firmware relies on hash computation and on the encryption key to authenticate a firmware, as does the isolation of the execution memories to ensure execution integrity.

  • The firmware is signed using a OP-TEE signature script. This script adds to the ELF binary a header that contains elements for the authentication among other firmware information:
  • a hash table, which contains the hash of the segment to load
  • a signature computed with the private key.
  • During the execution phase:
  • the firmware is read from the file system by the remoteproc framework and the image is provided to the OP-TEE trusted application.
  • The firmware is authenticated and installed by the OP-TEE trusted application in the protected Cortex-M memories.

Authenticate rproc fw.png

3.1 Firmware signature[edit]

A common strategy to sign a firmware consists in adding a header that contains the signature required for authentication. The signature is generated by computing a hash on the whole binary including the header, and encrypting this hash using a private key.
On the STM32MP1 microprocessor, the signature procedure is similar except that it is optimized to minimize the use of memory and speed up the authentication process. The principle is to compute the hash of the segments to load, instead of computing the hash of the full image.


STM32CubeMP1 firmware generation Keys generation Sign the STM32CubeMP1_firmware build OPTEE-OS with public KeySignature procedure
  • The signature consists in:
  1. parsing the program table in the ELF file to identify the segments to load.
  2. computing the hash of each segment and save the result in the hash table chunk of the header.
  3. computing the hash of the header and sign the hash with the private key.
  • The public key is embedded in the OPTEE-OS firmware that is in charge of the Cortex-M4 firmware authentication.

3.2 Memory management[edit]

The MCU SRAM and the RETRAM memories can be dedicated to Cortex-M usage (isolated), shared with the Cortex-A non-secure context, or protected for Cortex-A secure access only.
The ETZPC mechanism is used:

  • during the load and authentication phase: to lock the memories for Cortex-A secure access only,
  • during the execution phase: to isolate the memories for MCU usage (such as code execution and data) or share them with the Cortex-A non-secure context (such as RPMsg shared buffers).
Info.png When creating a Cortex-M firmware build, developers must be careful to pack in a same memory bank all the data shared with the Cortex-A. This enables the isolation of the rest of the memory banks for the Cortex-M context.

The information provided in this article respect the mapping described in memory mapping section:

  • RETRAM, MCU SRAM1 and MCU SRAM2 are used for code execution and data. They are only accessible by the Cortex-A secure context when no firmware is running, and assigned to Cortex-M context during authenticated firmware execution.
  • MCU SRAM3 (IPC buffers) is shared between the Cortex-A non-secure context and the Cortex-M. No protection is applied to this memory bank.
  • MCU SRAM4 is reserved for the Cortex-A non-secure context. It is thus free for other usage.

This mapping can be customized depending on project requirements. In this case, the code has to be updated in a synchronized manner in STM32CubeMP1 firmware, Linux Kernel device-tree and the OP-TEE rproc PTA code.

3.3 Authentication[edit]

The authentication is executed in the secure context by an OP-TEE trusted application.

Authentication Fw load phase1.png

1. The firmware is copied by the Linux Kernel (or U-boot) to non-secure DDR memory.
2. The firmware header is copied to a secure memory to ensure its integrity during the authentication steps.
3. The header hash is computed.
4. The signature is decrypted using the public key. The result is the hash of the header computed by the signing tools. Both hashes are compared to authenticate the firmware header.
5. At this step the firmware header is valid. The next step, the loading of the firmware in MCU memories, can start:

Authentication Fw load phase2.png

For each segment to load:
6. The segment is copied to the MCU RAMs that can be accessed only by the secure context to ensure their integrity.
7. The hash of the copied segment is computed and compared to the hash stored in the firmware header.
8. At this step all segments have been copied and authenticated. The firmware is loaded and read for execution.

3.4 Authenticated firmware live-cycle[edit]

Authentication software overview.png

From user's point of view, the management of the firmware live-cycle does not change, except the fact that the firmware must be authenticated. The management of a firmware is described in the remoteproc article.

The main difference compared to a non-authenticated firmware is that the remote processor framework delegates the coprocessor management to the OP-TEE.

Info.png Since the Authentication is activated, it is no longer possible to load and start a non-authenticated firmware.
Info.png The authenticated firmware can also be pre-loaded and started by the U-boot.

3.4.1 Firmware loading and authentication[edit]

  • As for a non authenticated firmware, the firmware is read from the file system by the remoteproc framework. The image is then sent to the OP-TTE trusted application.
  • The authentication and the MCU memory isolation are managed in the secure context by the OP-TEE trusted application.

3.4.2 Firmware start and stop[edit]

  • As for a non-authenticated firmware, the firmware start and stop requests are handled by the remoteproc framework, but they are delegated to the Arm® Trustzone.
  • The firmware start and stop are executed by the OP-TEE. The reset and RAM access rights are only accessible by the secure context.
  • Before starting the firmware, the MCU RAM access rights are updated to isolate execution RAMs for the Cortex-M.
  • After stopping the firmware, the MCU RAMs are cleaned and access rights are updated to Cortex-A secure context.

3.4.3 RPMsg management[edit]

As the resource tables and RPMsg vrings and buffers are in a MCU shared memory and accessible by both Cortexes, it is possible to communicate with the authenticated firmware.

3.4.4 Firmware core dump[edit]

Since the memories are protected, it is not possible to dump the firmware when a crash occurs.

4 Implementation[edit]

The authentication mechanisms require STM32MPU Embedded Software distribution with OP-TEE running in the Arm® Trustzone context.

4.1 Updating the built image to enable the authentication feature[edit]

4.1.1 OP-TEE image installation[edit]

Refer to How to populate and boot a board with OP-TEE for details.

4.1.2 OP-TEE remoteproc TA generation[edit]

First, install the OP-TEE OS build environment.

The OPTEE-OS firmware has to be generated again to include (see here for how to information):

  • the remote processor trusted application (TA),
  • the remote processor platform pseudo trusted application (PTA),
  • the public key.
4.1.2.1 Configuration[edit]

Enable the CFG_RPROC_PTA in core/arch/arm/plat-stm32mp1/conf.mk

CFG_RPROC_PTA ?= y
4.1.2.2 Building the OP-TEE OS[edit]

Below additional directives to build OP-TEE OS:

  • CFG_IN_TREE_EARLY_TAS=remoteproc/80a4c275-0a47-4905-8285-1486a9771a08 : adds remoteproc early TA.
  • CFG_RPROC_SIGN_KEY= <key file path name>: specifies the public key file to authenticate the remote processor firmware. This directive is optional. If it is not defined, the keys/default_rproc.pem default key is used.

Example of build command (<other directives> has to be replaced by usual directives to build OP-TEE OS):

  • Use the default key available in the OP-TEE repository to build the OP-TEE OS (that can be updated): keys/default_rproc.pem
PC $> make <other directives> CFG_IN_TREE_EARLY_TAS=remoteproc/80a4c275-0a47-4905-8285-1486a9771a08
  • Or specify the key to use by defining CFG_RPROC_SIGN_KEY:
PC $> make <other directives> CFG_IN_TREE_EARLY_TAS=remoteproc/80a4c275-0a47-4905-8285-1486a9771a08 CFG_RPROC_SIGN_KEY=my_public_key.pem
Info.png The remoteproc early trusted application and the public key are part of the OP-TEE OS binary.
4.1.2.3 Updating the software on board[edit]

Refer to update OP-TEE software on board for details.

4.1.3 Updating the Linux kernel[edit]

Info.png Even though the remote processor's firmware is managed by the U-Boot, the Linux kernel must be updated to properly attach to the remote processor's pre-loaded firmware, but also to be able to stop and restart a firmware.
4.1.3.1 Kernel configuration[edit]

Activate the remoteproc tee in the kernel configuration, using the Linux Menuconfig tool: Menuconfig or how to configure kernel.

Device drivers --->
   Remoteproc drivers --->
     <*> Support for Remote Processor subsystem
     <*> STM32 remoteproc support
     <*> Trusted firmware support by a trusted application 

4.1.3.2 Device tree configuration[edit]

To be compliant with the memory mapping and protection, the memory region properties described in the Linux remoteproc framework overview have to be updated.
Example:

  • Declare a memory region for the resource table and remoteproc trace memory region. The address and size must be aligned with STM32Cube linker script m_rsc_table definition:
reserved-memory {
 	...
	mcu_rsc_table: mcu_rsc_table@10048000 {
		compatible = "shared-dma-pool";
		reg = <0x10048000 0x8000>;
		no-map;
	};
};

Info.png The U-Boot limits the number of memory regions that can be reserved. Adding this region can lead to a U-boot crash. A simple way to solve the issue is to increase the value of the MAX_LMB_REGIONS defined in include/lmb.h .
  • In the remoteproc DT node:
  • Clean up retram, mcusram and mcusram2 regions that are now handled by OP-TEE.
  • Add the mcu_rsc_table region.
  • Update the compatibility field.
 /* stm32 M4 remoteproc device */
 m4_rproc: m4@0 {
	...
       compatible = "st,stm32mp1-m4_optee";
       memory-region = <&vdev0vring0>, <&vdev0vring1>, <&vdev0buffer>, <&mcu_rsc_table>;
	...
};
Info.png The firmware memory mapping, defined in the STM32Cube firmware linker script, must be set according to the values defined in the STM32Cube firmware linker script.
Info.png If the coprocessor firmware does not embed any resource table, the mcu_rsc_table memory region does not need to be declared

4.1.4 U-Boot update[edit]

This chapter is relevant only for coprocessor firmware preloaded by the bootloader.

4.1.5 Configuration[edit]

Activate the REMOTEPROC_OPTEE in the U-Boot configuration, using the menuconfig tool.

    Remote Processor drivers  --->
       [*] Support for the remoteproc in OPTEE 
       [*] Support for STM32 coprocessor

4.1.6 Device tree[edit]

To enable the management of a preloaded authenticated firmware, the compatible field of the remote proc node has to be updated in the device tree configuration. In arch/arm/dts/stm32mp151.dtsi :

m4_rproc: m4@10000000 {
      compatible = "st,stm32mp1-m4_optee";
};

4.2 STM32CubeMP1 firmware generation[edit]

Most of the STM32CubeMP1 firmware can be isolated. A developer has to pay attention to the memories shared with the Cortex-A7 non-secure context:

  • the resource table,
  • the log buffer shared through the resource table,
  • the shared buffers for RPMsg communication,
  • other shared buffers defined by the developer for its project.

4.2.1 Resource table[edit]

In the STM32CubeMP1 examples, the resource table is linked by default to other firmware data. A specific memory region has to be defined in the linker script to isolate it in a new region. In the following example, a new memory region is created at the end of the MCU_SRAM3 to host for the resource table:

/* Memory definition */
MEMORY
{
 m_interrupts (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000298
 m_text       (RX)  : ORIGIN = 0x10000000, LENGTH = 0x00020000
 m_data       (RW)  : ORIGIN = 0x10020000, LENGTH = 0x00020000
 m_ipc_shm    (RW)  : ORIGIN = 0x10040000, LENGTH = 0x00008000
 m_rsc_table  (RW)  : ORIGIN = 0x10048000, LENGTH = 0x00008000
}

The resource table and log buffer are then mapped in this region:

.resource_table :
{
  . = ALIGN(4);
  KEEP (*(.resource_table*))
  . = ALIGN(4);
} > m_rsc_table

4.2.2 Log buffer[edit]

The log buffer can be enabled in the resource table to get Cortex-M log from the Cortex-A non-secure context. To define it, proceed as follows:

  • Add an attribute to the system_log_buf buffer:
#if defined(__GNUC__) 
#define __section_t(S)          __attribute__((__section__(#S)))
#define __resource              __section_t(.sys_logs)
#endif

char  __resource __attribute__((used)) system_log_buf[SYSTEM_TRACE_BUF_SZ];
  • Update the linker script to add the trace buffer in the m_rsc_table memory region:
.sys_logs :
{
  . = ALIGN(4);
  KEEP (*(.sys_logs*))
  . = ALIGN(4);
} > m_rsc_table

4.2.3 RPMsg shared buffers[edit]

The m_ipc_shm memory region is already reserved for the RPMsg Virtio rings and buffers.

4.3 Cortex-M4 firmware signature[edit]

4.3.1 Generate private and public keys[edit]

An RSA key has to be generated to sign and authenticate the Cortex-M firmware. For instance, the ssh-keygen command can be used.

PC $> ssh-keygen

Two files are created:

  • id_rsa: the private key to sign the firmware.
  • id_rsa.pub: the public key to authenticate the firmware.

4.3.2 Firmware signature[edit]

The OP-TEE ST-Microelectronics distribution integrates the sign_rproc_fw.py that can sign the firmware binary ELF file.
This script

  • adds a header on top of the ELF binary,
  • computes the hash of the program segments that is loaded in the Cortex-M memories and fill the hash table included in the header,
  • computes the hash of the header and signs it using the private key.

To sign the firmware:

PC $> ./scripts/sign_rproc_fw.py sign --in <firmware name>
  • or specify the key to use as parameter:
PC $> ./scripts/sign_rproc_fw.py sign --in <firmware name> --key <id_rsa private key>
  • For more script options:
PC $> ./scripts/sign_rproc_fw.py sign --help

The signed firmware is available in the ELF file directory with a .sign extension.

5 Code source[edit]

5.1 OP-TEE[edit]

 
ta/remoteproc/remoteproc_core.c  
 core/arch/arm/plat-stm32mp1/remoteproc_pta.c  

5.2 Linux Kernel[edit]

drivers/remoteproc/tee_remoteproc.c  
drivers/remoteproc/stm32_rproc.c  

5.3 U-boot[edit]

drivers/remoteproc/rproc-optee.c  



== Article purpose ==
This article explains how to protect the software loaded by the main processor into the coprocessor, and ensure the authentication of the loaded firmware.

== Introduction ==
The Linux<sup>&reg;</sup>  OS, (through the [[Linux_remoteproc_framework_overview|remoteproc framework]]) or the [[How_to_start_the_coprocessor_from_the_bootloader|U-boot]] enables the loading of firmware into control remote processors. Thanks to a specific  [[OP-TEE_overview | OP-TEE trusted application (TA)]] running on the [[Security_overview | Arm<sup>&reg;</sup> Trustzone]] and to the [[ETZPC_internal_peripheral | ETZPC peripheral]], it is possible to authenticate a Cortex<sup>&reg;</sup>-M4 firmware and install it on isolated RAMs to ensure its integrity during the execution .

From user's point of view the management of a non-authenticated or authenticated firmware does not differ, whether the firmware is managed by the Linux or by the U-Boot. The difference is that the management of the authenticated firmware is delegated to the [[OP-TEE_overview | OP-TEE]] firmware running in the  Arm<sup>&reg;</sup> Trustzone.

== Principles ==
The protection of the coprocessor firmware relies on hash computation and on the encryption key to authenticate a firmware, as does the isolation of the execution memories to ensure execution integrity.
* The firmware is signed using a [[OP-TEE_overview | OP-TEE]] signature script. This script adds to the ELF binary a header that contains elements for the authentication among other firmware information:
:* a hash table, which contains the hash of the segment to load
:* a signature computed with the private key.
* During the execution phase:
:*the firmware is read from the file system by the [[Linux_remoteproc_framework_overview|remoteproc framework]] and the image is provided to the OP-TEE trusted application.
:* The firmware is authenticated and installed by the OP-TEE trusted application in the protected Cortex-M memories.

[[File:authenticate_rproc_fw.png|950px|link=]]

=== Firmware signature  ===

A common strategy to sign a firmware consists in adding a header that contains the signature required for authentication. The signature is generated by computing a hash on the whole binary including the header, and encrypting this hash using a private key.<br>

On the STM32MP1 microprocessor, the signature procedure is similar except that it is optimized to minimize the use of memory and speed up the authentication process. The principle is to compute the hash of the segments to load, instead of computing the hash of the full image. 

{{ImageMap | File:rproc_fw_signature.png {{!}} 900px {{!}} Signature procedure
rect 0 758 400 994 [[How_to_protect_the_coprocessor_firmware#STM32CubeMP1_firmware_generation | STM32CubeMP1 firmware generation]]
rect 6 366 406 710 [[#Generate_private_and_public_key | Keys generation]]
rect 442 402 1584 1010 [[#Sign_STM32CubeMP1_firmware | Sign the STM32CubeMP1_firmware]]
rect 442 65 1584 390 [[#OP-TEE_remoteproc | build OPTEE-OS with public Key]]
}}

*The signature consists in: 
:# parsing the program table in the ELF file to identify the segments to load.
:# computing the hash of each segment and save the result in the hash table chunk of the header.
:# computing the hash of the header and sign the hash with the private key.

*The public key is embedded in the OPTEE-OS firmware that is in charge of the Cortex-M4 firmware authentication. 

=== Memory management ===
The [[MCU SRAM internal memory | MCU SRAM]] and the [[RETRAM internal memory|RETRAM]] memories can be dedicated to Cortex-M usage (isolated), shared with the Cortex-A non-secure context, or protected for Cortex-A secure access only.<br>

The [[ETZPC_internal_peripheral | ETZPC]] mechanism is used:
* during the load and authentication phase: to lock the memories for Cortex-A secure access only,
* during the execution phase: to isolate the memories for MCU usage (such as code execution and data) or share them with the Cortex-A non-secure context (such as RPMsg shared buffers).

{{ Info |When creating a Cortex-M firmware build, developers must be careful to pack in a same memory bank all the data shared with the Cortex-A. This enables the isolation of the rest of the memory banks for the Cortex-M context. }}

The information provided in this article respect the mapping described in  [[STM32MP15_RAM_mapping#Zoom in the Cortex-A/Cortex-M shared memory |memory mapping]] section:
* '''RETRAM''', '''MCU SRAM1''' and '''MCU SRAM2'''  are used for code execution and data. They are only accessible by the Cortex-A secure context when no firmware is running, and assigned to Cortex-M context during authenticated firmware execution.  
* '''MCU SRAM3''' (IPC buffers) is shared between the Cortex-A non-secure context and the Cortex-M. No protection is applied to this memory bank.
* '''MCU SRAM4''' is reserved for the Cortex-A non-secure context. It is thus free for other usage.

This mapping can be customized depending on project requirements. In this case, the code has to be updated in a synchronized manner in [[STM32CubeMP1_Package | STM32CubeMP1]] firmware, [[Device_tree |Linux Kernel device-tree]] and the [[OP-TEE_overview |OP-TEE rproc PTA]] code.

=== Authentication ===

The authentication is executed in the secure context by an '''OP-TEE trusted application'''.  

[[File:Authentication_Fw_load_phase1.png|950px|link=]]

'''1.''' The firmware is copied by the Linux Kernel (or U-boot) to non-secure DDR memory.<BR>

'''2.''' The firmware header is copied to a secure memory to ensure its integrity during the authentication steps.<BR>

'''3.''' The header hash is computed.<BR>

'''4.''' The signature is decrypted using the public key. The result is the hash of the header computed by the signing tools. Both hashes are compared to authenticate the firmware header.<BR>

'''5.''' At this step the firmware header is valid. The next step, the loading of the firmware in MCU memories, can start:

[[File:Authentication_Fw_load_phase2.png|950px|link=]]

For each segment to load:<BR>

'''6.''' The segment is copied to the MCU RAMs that can be accessed only by the secure context to ensure their integrity.<BR>

'''7.''' The hash of the copied segment is computed and compared to the hash stored in the firmware header.<BR>

'''8.''' At this step all segments have been copied and authenticated. The firmware is loaded and read for execution.

=== Authenticated firmware live-cycle ===
[[File:Authentication_software_overview.png|950px|link=]]

From user's point of view, the management of the firmware live-cycle does not change, except the fact that the firmware must be authenticated. The management of a firmware is described in the [[Linux_remoteproc_framework_overview#How_to_use_the_framework | remoteproc]] article.

The main difference compared to a non-authenticated firmware is that the remote processor framework delegates the coprocessor management to the OP-TEE. 
{{Info| Since the Authentication is activated, it is no longer possible to load and start a non-authenticated firmware.}}
{{Info| The authenticated firmware can also be [[How_to_start_the_coprocessor_from_the_bootloader |pre-loaded and started]] by the U-boot.}}
==== Firmware loading and authentication ====
* As for a non authenticated firmware, the firmware is read from the file system by the [[Linux_remoteproc_framework_overview|remoteproc framework]]. The image is then sent to the OP-TTE trusted application.
* The authentication and the MCU memory isolation are managed in the secure context by the OP-TEE trusted application.  

==== Firmware start and stop ====
* As for a non-authenticated firmware, the firmware start and stop requests are handled by the [[Linux_remoteproc_framework_overview|remoteproc framework]], but they are delegated to the Arm<sup>&reg;</sup> Trustzone.
* The firmware start and stop are executed by the OP-TEE. The reset and RAM access rights are only accessible by the secure context.
:* Before starting the firmware, the MCU RAM access rights are updated to isolate execution RAMs for the Cortex-M.
:* After stopping the firmware, the MCU RAMs are cleaned and access rights are updated to Cortex-A secure context.

==== RPMsg management ====
As the resource tables and RPMsg vrings and buffers are in a MCU shared memory and accessible by both Cortexes, it is possible to communicate with the authenticated firmware.

==== Firmware core dump ====
Since the memories are protected, it is not possible to dump the firmware when a crash occurs.

== Implementation==
The authentication mechanisms require [[STM32MPU_Embedded_Software_distribution| STM32MPU Embedded Software distribution]] with OP-TEE running in the [[Security_overview | Arm<sup>&reg;</sup> Trustzone]] context.

=== Updating the built image to enable the authentication feature===
====  OP-TEE image installation ====
Refer to [[How_to_populate_and_boot_a_board_with_OP-TEE|How to populate and boot a board with OP-TEE]] for details.

==== OP-TEE remoteproc TA generation====
First, install the [[How to configure OP-TEE | OP-TEE OS build]] environment. <BR><BR>

The OPTEE-OS firmware has to be generated again to include (see [[How to configure OP-TEE | here]] for how to information):
* the remote processor trusted application (TA),
* the remote processor platform pseudo trusted application (PTA),
* the public key.
===== Configuration =====
Enable the CFG_RPROC_PTA in {{ CodeSource | OP-TEE_OS | core/arch/arm/plat-stm32mp1/conf.mk}}
 CFG_RPROC_PTA ?= y

===== Building the OP-TEE OS =====
Below additional directives to build OP-TEE OS:
*'''CFG_IN_TREE_EARLY_TAS=remoteproc/80a4c275-0a47-4905-8285-1486a9771a08''' : adds remoteproc early TA.
*'''CFG_RPROC_SIGN_KEY= <key file path name>''': specifies the public key file to authenticate the remote processor firmware. This directive is optional. If it is not defined, the {{ CodeSource | OP-TEE_OS | keys/default_rproc.pem}} default key is used.

Example of build command (''<other directives>'' has to be replaced by usual directives to [[How to configure OP-TEE#Build_OP-TEE_OS |
build OP-TEE OS]]):

* Use the default key available in the OP-TEE repository to build the OP-TEE OS (that can be updated): {{ CodeSource | OP-TEE_OS | keys/default_rproc.pem}}
 {{PC$}} make ''<other directives>'' CFG_IN_TREE_EARLY_TAS=remoteproc/80a4c275-0a47-4905-8285-1486a9771a08
* Or specify the key to use by defining CFG_RPROC_SIGN_KEY:
 {{PC$}} make ''<other directives>'' CFG_IN_TREE_EARLY_TAS=remoteproc/80a4c275-0a47-4905-8285-1486a9771a08 CFG_RPROC_SIGN_KEY=my_public_key.pem

{{Info | The remoteproc early trusted application and the public key are part of the OP-TEE OS binary. }}

===== Updating the software on board =====
Refer to [[How to configure OP-TEE#Update_software_on_board | update OP-TEE software on board]] for details.

==== Updating the Linux kernel ====
{{Info| Even though the remote processor's firmware is managed by the U-Boot, the Linux kernel must be updated to properly attach to the remote processor's pre-loaded firmware, but also to be able to stop and restart a firmware.}}

===== Kernel configuration =====
Activate the remoteproc tee in the kernel configuration, using the Linux Menuconfig tool: [[Menuconfig or how to configure kernel]].
 Device drivers --->
    Remoteproc drivers ---><*> Support for Remote Processor subsystem<*> STM32 remoteproc support<*> {{highlight|Trusted firmware support by a trusted application }}

===== Device tree configuration =====
To be compliant with the memory mapping and protection, the ''memory region'' properties described in the [[Linux_remoteproc_framework_overview#Device_tree_configuration | Linux remoteproc framework overview]]
have to be updated.<BR>

Example:
* Declare a memory region for the resource table and remoteproc trace memory region. The address and size must be aligned with STM32Cube linker script m_rsc_table definition:
 reserved-memory {
  	...
 {{highlight|	mcu_rsc_table: mcu_rsc_table@10048000 {}}
 {{highlight|		compatible {{=}} "shared-dma-pool";}}
 {{highlight|		reg {{=}} <0x10048000 0x8000>;}}
 {{highlight|		no-map;}}
 {{highlight|	};}}
 };
 {{info| The U-Boot  limits the number of memory regions that can be reserved. Adding this region can lead to a U-boot crash. A simple way to solve the issue is to increase the value of the '''MAX_LMB_REGIONS''' defined in {{CodeSource | U-Boot | include/lmb.h}}.}}

* In the remoteproc DT node:
:*Clean up '''retram''', '''mcusram''' and '''mcusram2''' regions that are now handled by OP-TEE.
:*Add the '''mcu_rsc_table''' region.
:*Update the compatibility field.
  /* stm32 M4 remoteproc device */
  m4_rproc: m4@0 {
 	...
        compatible ={{highlight| "st,stm32mp1-m4_optee"}};
        memory-region = <&vdev0vring0>, <&vdev0vring1>, <&vdev0buffer>, {{highlight|<&mcu_rsc_table>}};
 	...
 };

{{Info| The firmware memory mapping, defined in the STM32Cube firmware linker script, must be set according to the values defined in the [[STM32CubeMP1_Package#STM32CubeMP1 package overview | STM32Cube firmware]] linker script.}}
{{Info| If the coprocessor firmware does not embed any '''resource table''',  the mcu_rsc_table memory region does not need to be declared}}

==== U-Boot update ====
This chapter is relevant only for coprocessor firmware [[How_to_start_the_coprocessor_from_the_bootloader | preloaded]] by the bootloader.<br>

==== Configuration ====
Activate the '''REMOTEPROC_OPTEE''' in the [[U-Boot_overview#U-Boot_configuration| U-Boot configuration]], using the menuconfig tool.
     Remote Processor drivers  --->
        [*] {{highlight|Support for the remoteproc in OPTEE }}
        [*] Support for STM32 coprocessor

==== Device tree ====To enable the management of a preloaded authenticated firmware, the compatible field of the remote proc node has to be updated in the device tree configuration.
In {{CodeSource | U-Boot | arch/arm/dts/stm32mp151.dtsi}}:
 m4_rproc: m4@10000000 {
       compatible ={{highlight| "st,stm32mp1-m4_optee"}};
 };

=== STM32CubeMP1 firmware generation===

Most of the STM32CubeMP1 firmware can be isolated. A developer has to pay attention to the memories shared with the Cortex-A7 non-secure context:
* the [[Coprocessor_resource_table| resource table]],
* the [[Coprocessor_resource_table#How_to_add_trace_for_the_log_buffer | log buffer]] shared through the resource table,
* the shared buffers for [[Linux_RPMsg_framework_overview | RPMsg]] communication,
* other shared buffers defined by the developer for its project.

==== Resource table ====
In the [[STM32CubeMP1_Package | STM32CubeMP1]] examples, the resource table is linked by default to other firmware data. A specific memory region has to be defined in the linker script to isolate it in a new region.
In the following example, a new memory region is created at the end of the MCU_SRAM3 to host for the resource table:
 /* Memory definition */
 MEMORY
 {
  m_interrupts (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000298
  m_text       (RX)  : ORIGIN = 0x10000000, LENGTH = 0x00020000
  m_data       (RW)  : ORIGIN = 0x10020000, LENGTH = 0x00020000
  m_ipc_shm    (RW)  : ORIGIN = 0x10040000, LENGTH = 0x00008000
 {{highlight | m_rsc_table  (RW)  : ORIGIN {{=}} 0x10048000, LENGTH {{=}} 0x00008000}}
 }
The resource table and log buffer are then mapped in this region:

 .resource_table :
 {
   . = ALIGN(4);
   KEEP (*(.resource_table*))
   . = ALIGN(4);
 } > {{highlight |m_rsc_table}}

==== Log buffer ====
The [[Coprocessor_resource_table#How_to_add_trace_for_the_log_buffer | log buffer]] can be enabled in the resource table to get Cortex-M log from the Cortex-A non-secure context. 
To define it, proceed as follows:
* Add an attribute to the '''system_log_buf''' buffer:
 {{highlight |#if defined(__GNUC__) }}
 {{highlight |#define __section_t(S)          __attribute__((__section__(#S)))}}
 {{highlight |#define __resource              __section_t(.sys_logs)}}
 {{highlight |#endif}}

 char {{highlight | __resource __attribute__((used))}} system_log_buf[SYSTEM_TRACE_BUF_SZ];

* Update the linker script to add the trace buffer in the '''m_rsc_table''' memory region:

 {{highlight |.sys_logs :}}
 {{highlight |{}}
 {{highlight |  . {{=}} ALIGN(4);}}
 {{highlight |  KEEP (*(.sys_logs*))}}
 {{highlight |  . {{=}} ALIGN(4);}}
 {{highlight |} > m_rsc_table}}

==== RPMsg shared buffers ====
The '''m_ipc_shm''' memory region is already reserved for the RPMsg Virtio rings and buffers.

=== Cortex-M4  firmware signature===
==== Generate private and public keys ====
An RSA key has to be generated to sign and authenticate the Cortex-M firmware. For instance, the ssh-keygen command can be used.

 {{PC$}} ssh-keygen

Two files are created:
* '''id_rsa''': the private key to sign the firmware.
* '''id_rsa.pub''': the public key to authenticate the firmware.

==== Firmware signature====
The [[How to configure OP-TEE |OP-TEE ST-Microelectronics]] distribution integrates the '''sign_rproc_fw.py''' that can sign the firmware binary ELF file. <br>

This script
* adds a header on top of the ELF binary,
* computes the hash of the program segments that is loaded in the Cortex-M memories and fill the hash table included in the header,
* computes the hash of the header and signs it using the private key.

To sign the firmware:
* Use the default RSA key available in the OP-TEE repository (that can be updated) : {{ CodeSource | OP-TEE_OS | keys/default_rproc.pem}}
 {{PC$}} ./scripts/sign_rproc_fw.py sign --in <firmware name>

* or specify the key to use as parameter:
 {{PC$}} ./scripts/sign_rproc_fw.py sign --in <firmware name> --key <id_rsa private key>

* For more script options:
 {{PC$}} ./scripts/sign_rproc_fw.py sign --help

The signed firmware is available in the ELF file directory with a '''.sign''' extension. <BR><BR>


== Code source ==
=== OP-TEE ===
  {{CodeSource | OP-TEE_OS | ta/remoteproc/remoteproc_core.c}} 
  {{CodeSource | OP-TEE_OS | core/arch/arm/plat-stm32mp1/remoteproc_pta.c}} 
=== Linux Kernel ===
 {{CodeSource | Linux kernel | drivers/remoteproc/tee_remoteproc.c}} 
 {{CodeSource | Linux kernel | drivers/remoteproc/stm32_rproc.c}} 
=== U-boot ===
 {{CodeSource | U-Boot | drivers/remoteproc/rproc-optee.c}} 

{{ReviewsComments|-- [[User:Arnaud Pouliquen|Arnaud Pouliquen]] ([[User talk:Arnaud Pouliquen|talk]]) 13:54, 26 November 2020 (CET)<br />to add Stm32Cube example}}<noinclude>

{{PublicationRequestId | 18837| 202-12-07 |}}
[[Category:How to customize software]]
[[Category:Coprocessor management Linux]]
[[Category:Coprocessor management STM32Cube]]</noinclude>
(One intermediate revision by the same user not shown)
Line 174: Line 174:
 
This chapter is relevant only for coprocessor firmware [[How_to_start_the_coprocessor_from_the_bootloader | preloaded]] by the bootloader.<br>
 
This chapter is relevant only for coprocessor firmware [[How_to_start_the_coprocessor_from_the_bootloader | preloaded]] by the bootloader.<br>
   
  +
==== Configuration ====
  +
Activate the '''REMOTEPROC_OPTEE''' in the [[U-Boot_overview#U-Boot_configuration| U-Boot configuration]], using the menuconfig tool.
  +
    Remote Processor drivers  --->
  +
        [*] {{highlight|Support for the remoteproc in OPTEE }}
  +
        [*] Support for STM32 coprocessor
  +
  +
==== Device tree ====
 
To enable the management of a preloaded authenticated firmware, the compatible field of the remote proc node has to be updated in the device tree configuration.
 
To enable the management of a preloaded authenticated firmware, the compatible field of the remote proc node has to be updated in the device tree configuration.
 
In {{CodeSource | U-Boot | arch/arm/dts/stm32mp151.dtsi}}:
 
In {{CodeSource | U-Boot | arch/arm/dts/stm32mp151.dtsi}}: