mirror of https://github.com/ARMmbed/mbed-os.git
Python script automate tf-m build build process
The python script (tools/psa/build_tfm.py) automates tf-m build process for a particular target or all supported tf-m targets and copies generated binary to a predefined location. Updated documentation describing steps to add single v7-m and dual v7-M targets and building tf-m using python script. Added following attributes to dual v7-M and v8-M SPE generic target, * inherits: PSA generic target PSA_DUAL_V7_M_SPE * tfm_target_name: Target name in TF-M * tfm_bootloader_supported: If TF-M bootloader is supported by the target. Values supported are "true" and "false" * tfm_default_toolchain: Default TF-M toolchain supported. Values supported are "ARMCLANG" and "GNUARM" * tfm_supported_toolchains: Supported TF-M toolchains. Values supported are "ARMCLANG" and "GNUARM" * delivery_dir: The directory to which TF-M binary will be copied to Signed-off-by: Devaraj Ranganna <devaraj.ranganna@arm.com>pull/12402/head
parent
e7f2d62e16
commit
6405b44ff6
|
@ -0,0 +1 @@
|
||||||
|
dualcpu_l2_v01-18-g11d373ee8eb6
|
|
@ -1,15 +1,19 @@
|
||||||
# Supporting PSA in Mbed OS
|
# Supporting PSA in Mbed OS
|
||||||
|
|
||||||
This document is still a work in progress. It describes the process of adding new PSA targets to Mbed OS. It also outlines the new directory structure created to support PSA on single v7-M, dual v7-M and single v8-M.
|
This document is still a work in progress. It describes the process of adding new PSA targets to Mbed OS and building [TF-M](https://git.trustedfirmware.org/trusted-firmware-m.git/tree/?h=feature-twincpu) for dual v7-M and single v8-M SPE. It also outlines the new directory structure created to support PSA on single v7-M, dual v7-M and single v8-M.
|
||||||
|
|
||||||
## TODO
|
*Note*
|
||||||
* Adding dual v7-M targets
|
PSA - Platform Security Architecture
|
||||||
|
TF-M - Trusted Firmware M
|
||||||
|
SPE - Secure Processing Environment
|
||||||
|
NSPE - Non-Secure Processing Environment
|
||||||
|
|
||||||
|
# TODO
|
||||||
* Adding v8-M targets
|
* Adding v8-M targets
|
||||||
* Building TF-M
|
|
||||||
* Running PSA compliance tests
|
* Running PSA compliance tests
|
||||||
|
|
||||||
## Adding new PSA targets
|
# Adding new PSA targets
|
||||||
To help with the creation of new PSA targets, couple of generic PSA targets have been added to `targets/targets.json`.
|
To help with the creation of new PSA targets, couple of generic targets have been added to `targets/targets.json`.
|
||||||
* `PSA_Target` (Root level PSA target)
|
* `PSA_Target` (Root level PSA target)
|
||||||
* `PSA_V7_M_NSPE` (Single v7-M NSPE generic target)
|
* `PSA_V7_M_NSPE` (Single v7-M NSPE generic target)
|
||||||
* `PSA_V7_M_SPE` (Single v7-M SPE generic target)
|
* `PSA_V7_M_SPE` (Single v7-M SPE generic target)
|
||||||
|
@ -18,16 +22,32 @@ To help with the creation of new PSA targets, couple of generic PSA targets have
|
||||||
* `PSA_V8_M_NSPE` (v8-M NSPE generic target)
|
* `PSA_V8_M_NSPE` (v8-M NSPE generic target)
|
||||||
* `PSA_V8_M_SPE` (v8-M SPE generic target)
|
* `PSA_V8_M_SPE` (v8-M SPE generic target)
|
||||||
|
|
||||||
The new PSA targets **MUST** `inherit` from one of these targets depending on the architecture:
|
A Single v7-M target doesn't support hardware separation to isolate NSPE from SPE. Therefore for single v7-M targets only NSPE target is defined. The PSA API compliance is achieved with the help of emulation of PSA secure services.
|
||||||
|
|
||||||
Example:
|
A Dual v7-M target will have at least two Armv7-M cores to isolate NSPE from SPE. On dual v7-M targets, TF-M will be running on SPE providing PSA services. Therefore, it is **MANDATORY** to define both SPE and NSPE target for dual v7-M targets.
|
||||||
|
|
||||||
|
A Armv8-M target supports hardware separation to isolate NSPE from SPE. On v8-M targets, TF-M will be running on SPE providing PSA services. Therefore, it is **MANDATORY** to define both SPE and NSPE target for v8-M targets.
|
||||||
|
|
||||||
|
The new PSA targets **MUST** `inherit` from one of the generic PSA targets depending on the architecture. Also, in case of dual v7-M and v8-M targets, SPE and NSPE targets **MUST** inherit from the respective SPE and NSPE PSA generic targets.
|
||||||
|
|
||||||
|
Example single v7-M:
|
||||||
```json
|
```json
|
||||||
"K64F": {
|
"K64F": {
|
||||||
"inherits": ["PSA_V7_M_NSPE", "Target"],
|
"inherits": ["PSA_V7_M_NSPE", "Target"],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
In addition, the new PSA target **MUST** `inherit` from `Target` which defines default target config options. The only exception is, if the new PSA target is inheriting from another generic target which inherits from `Target`.
|
Example dual v7-M:
|
||||||
|
```json
|
||||||
|
"CY8CPROTO_064_SB_S": {
|
||||||
|
"inherits": ["PSA_DUAL_V7_M_SPE"],
|
||||||
|
},
|
||||||
|
"CY8CPROTO_064_SB": {
|
||||||
|
"inherits": ["PSA_DUAL_V7_M_NSPE", "MCU_PSOC6_M4"],
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In addition, the new PSA NSPE target **MUST** `inherit` from `Target` which defines default target config options. The only exception is, if the new PSA target is inheriting from another generic target which inherits from `Target`.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```json
|
```json
|
||||||
|
@ -40,8 +60,8 @@ Example:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Adding single v7-M targets
|
## Adding single v7-M targets
|
||||||
The PSA on single v7-M is supported with the help of Mbed OS PSA services. The following is taken from `targets/targets.json` and shows a PSA enabled target, `K64F`.
|
A target can ge categorized as a single v7-M target if it only has a single Armv7-M core. The PSA on single v7-M is supported with the help of emulated PSA services implemented in Mbed OS. The following is taken from `targets/targets.json` and shows a PSA enabled single v7-M target, `K64F`.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"K64F": {
|
"K64F": {
|
||||||
|
@ -104,11 +124,72 @@ The PSA on single v7-M is supported with the help of Mbed OS PSA services. The f
|
||||||
Please pay attention to config options `extra_labels_add` and `device_has_add`. If needed then a PSA target definition **MUST** use [extra_labels/device_has]`_add` or [extra_labels/device_has]`_remove` (not `extra_labels` or `device_has`) to add/remove either extra_labels or target capabilities. Also, use `[feature_]`add/remove to add/remove a feature.
|
Please pay attention to config options `extra_labels_add` and `device_has_add`. If needed then a PSA target definition **MUST** use [extra_labels/device_has]`_add` or [extra_labels/device_has]`_remove` (not `extra_labels` or `device_has`) to add/remove either extra_labels or target capabilities. Also, use `[feature_]`add/remove to add/remove a feature.
|
||||||
Check [extra_labels](https://os.mbed.com/docs/mbed-os/v5.14/reference/adding-and-configuring-targets.html), [device_has](https://os.mbed.com/docs/mbed-os/v5.14/reference/adding-and-configuring-targets.html) and [features](https://os.mbed.com/docs/mbed-os/v5.14/reference/adding-and-configuring-targets.html) for more information.
|
Check [extra_labels](https://os.mbed.com/docs/mbed-os/v5.14/reference/adding-and-configuring-targets.html), [device_has](https://os.mbed.com/docs/mbed-os/v5.14/reference/adding-and-configuring-targets.html) and [features](https://os.mbed.com/docs/mbed-os/v5.14/reference/adding-and-configuring-targets.html) for more information.
|
||||||
|
|
||||||
### Adding dual v7-M targets
|
## Adding dual v7-M targets
|
||||||
|
A target can ge categorized as a dual v7-M target if it has at least two Armv7-M cores. On dual v7-M targets, TF-M will be running on SPE providing PSA services. Therefore, it is **MANDATORY** to define both SPE and NSPE target for dual v7-M targets.
|
||||||
|
|
||||||
### Adding v8-M targets
|
The SPE target **MUST** contain following attributes,
|
||||||
|
|
||||||
## Enabling PSA at application level
|
* inherits: PSA generic target PSA_DUAL_V7_M_SPE
|
||||||
|
* tfm_target_name: Target name in TF-M
|
||||||
|
* tfm_bootloader_supported: If TF-M bootloader is supported by the target. Values supported are "true" and "false"
|
||||||
|
* tfm_default_toolchain: Default TF-M toolchain supported. Values supported are "ARMCLANG" and "GNUARM"
|
||||||
|
* tfm_supported_toolchains: Supported TF-M toolchains. Values supported are "ARMCLANG" and "GNUARM"
|
||||||
|
* delivery_dir: The directory to which TF-M binary will be copied to
|
||||||
|
|
||||||
|
The following is taken from `targets/targets.json` and shows a PSA enabled dual v7-M target, `PSoC64`,
|
||||||
|
|
||||||
|
```json
|
||||||
|
"CY8CPROTO_064_SB_S": {
|
||||||
|
"inherits": [
|
||||||
|
"PSA_DUAL_V7_M_SPE"
|
||||||
|
],
|
||||||
|
"tfm_target_name": "psoc64",
|
||||||
|
"tfm_bootloader_supported": false,
|
||||||
|
"tfm_default_toolchain": "ARMCLANG",
|
||||||
|
"tfm_supported_toolchains": [
|
||||||
|
"ARMCLANG",
|
||||||
|
"GNUARM"
|
||||||
|
],
|
||||||
|
"delivery_dir": "TARGET_Cypress/TARGET_PSOC6/TARGET_CY8CPROTO_064_SB/prebuilt"
|
||||||
|
},
|
||||||
|
"CY8CPROTO_064_SB": {
|
||||||
|
"inherits": [
|
||||||
|
"PSA_DUAL_V7_M_NSPE",
|
||||||
|
"MCU_PSOC6_M4"
|
||||||
|
],
|
||||||
|
"components_remove": [
|
||||||
|
"QSPIF"
|
||||||
|
],
|
||||||
|
"device_has_remove": [
|
||||||
|
"QSPI"
|
||||||
|
],
|
||||||
|
"extra_labels_add": [
|
||||||
|
"PSOC6_01",
|
||||||
|
"MXCRYPTO_01"
|
||||||
|
],
|
||||||
|
"macros_add": [
|
||||||
|
"CYB06447BZI_D54",
|
||||||
|
"PSOC6_DYNSRM_DISABLE=1",
|
||||||
|
"CY_CFG_SYSCLK_WCO_ENABLED=1",
|
||||||
|
"SEMAPHORE"
|
||||||
|
],
|
||||||
|
"detect_code": [
|
||||||
|
"1907"
|
||||||
|
],
|
||||||
|
"forced_reset_timeout": 5,
|
||||||
|
"reset_method": "default",
|
||||||
|
"post_binary_hook": {
|
||||||
|
"function": "PSOC6Code.sign_image"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
Please pay attention to config options `extra_labels_add` and `device_has_remove`. If needed then a PSA target definition **MUST** use [extra_labels/device_has]`_add` or [extra_labels/device_has]`_remove` (not `extra_labels` or `device_has`) to add/remove either extra_labels or target capabilities. Also, use `[feature_]`add/remove to add/remove a feature.
|
||||||
|
Check [extra_labels](https://os.mbed.com/docs/mbed-os/v5.14/reference/adding-and-configuring-targets.html), [device_has](https://os.mbed.com/docs/mbed-os/v5.14/reference/adding-and-configuring-targets.html) and [features](https://os.mbed.com/docs/mbed-os/v5.14/reference/adding-and-configuring-targets.html) for more information.
|
||||||
|
|
||||||
|
## Adding v8-M targets
|
||||||
|
|
||||||
|
# Enabling PSA at application level
|
||||||
Having an entropy source is crucial for Mbed TLS and Mbed Crypto. The [document](https://os.mbed.com/docs/mbed-os/v5.14/porting/entropy-sources.html) talks about entropy and how to add an entropy source. Sometimes a target might not have a True Random Number Generator (TRNG), in that case the target will be configured as a non-PSA target in `targets/targets.json`. In that scenario, if an application wants to use that target as a PAS target then it is the responsibility of application to provide an entropy source and mark that target as PSA target at application level. The config option [target_overrides](https://os.mbed.com/docs/mbed-os/v5.14/reference/configuration.html) can be used to enable PSA for a target.
|
Having an entropy source is crucial for Mbed TLS and Mbed Crypto. The [document](https://os.mbed.com/docs/mbed-os/v5.14/porting/entropy-sources.html) talks about entropy and how to add an entropy source. Sometimes a target might not have a True Random Number Generator (TRNG), in that case the target will be configured as a non-PSA target in `targets/targets.json`. In that scenario, if an application wants to use that target as a PAS target then it is the responsibility of application to provide an entropy source and mark that target as PSA target at application level. The config option [target_overrides](https://os.mbed.com/docs/mbed-os/v5.14/reference/configuration.html) can be used to enable PSA for a target.
|
||||||
|
|
||||||
example mbed_app.json:
|
example mbed_app.json:
|
||||||
|
@ -120,8 +201,36 @@ example mbed_app.json:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Building TF-M
|
||||||
|
On dual v7-M and v8-M targets, TF-M will be running on SPE providing PSA services. A python script `tools/psa/build_tfm.py` automates building TF-M and copying the binary to predefined location defined by attribute `delivery_dir`.
|
||||||
|
|
||||||
## New directory structure
|
Usage:
|
||||||
|
```console
|
||||||
|
python3 tools/psa/build_tfm.py
|
||||||
|
```
|
||||||
|
Supported options:
|
||||||
|
```console
|
||||||
|
usage: build_tfm.py [-h] [-m {CY8CPROTO_064_SB_S}] [-t {ARMCLANG,GNUARM}] [-d]
|
||||||
|
[-l] [--clone] [--commit] [--clean-build] [-v]
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-m {CY8CPROTO_064_SB_S}, --mcu {CY8CPROTO_064_SB_S}
|
||||||
|
Build for the given MCU
|
||||||
|
-t {ARMCLANG,GNUARM}, --toolchain {ARMCLANG,GNUARM}
|
||||||
|
Build for the given tool chain (default is
|
||||||
|
tfm_default_toolchain)
|
||||||
|
-d, --debug Set build profile to debug
|
||||||
|
-l, --list Print supported TF-M secure targets
|
||||||
|
--clone Clone TF-M git repo and its dependencies
|
||||||
|
--commit Create a git commit for each platform
|
||||||
|
--clean-build Remove cmake build directory
|
||||||
|
-v, --verbose Verbose output
|
||||||
|
```
|
||||||
|
|
||||||
|
If the python script is invoked without any options then TF-M will be built for all the supported targets and the binary will be copied to predefined location defined by attribute `delivery_dir`.
|
||||||
|
|
||||||
|
# New directory structure
|
||||||
|
|
||||||
```console
|
```console
|
||||||
features/FEATURE_PSA/
|
features/FEATURE_PSA/
|
||||||
|
@ -160,50 +269,6 @@ features/FEATURE_PSA/
|
||||||
│ ├── test_s003
|
│ ├── test_s003
|
||||||
│ ├── test_s002
|
│ ├── test_s002
|
||||||
│ └── test_s001
|
│ └── test_s001
|
||||||
├── compliance_crypto
|
|
||||||
│ ├── test_c043
|
|
||||||
│ ├── test_c042
|
|
||||||
│ ├── test_c041
|
|
||||||
│ ├── test_c040
|
|
||||||
│ ├── test_c039
|
|
||||||
│ ├── test_c038
|
|
||||||
│ ├── test_c037
|
|
||||||
│ ├── test_c036
|
|
||||||
│ ├── test_c035
|
|
||||||
│ ├── test_c034
|
|
||||||
│ ├── test_c033
|
|
||||||
│ ├── test_c032
|
|
||||||
│ ├── test_c031
|
|
||||||
│ ├── test_c030
|
|
||||||
│ ├── test_c029
|
|
||||||
│ ├── test_c028
|
|
||||||
│ ├── test_c027
|
|
||||||
│ ├── test_c026
|
|
||||||
│ ├── test_c025
|
|
||||||
│ ├── test_c024
|
|
||||||
│ ├── test_c023
|
|
||||||
│ ├── test_c022
|
|
||||||
│ ├── test_c021
|
|
||||||
│ ├── test_c020
|
|
||||||
│ ├── test_c019
|
|
||||||
│ ├── test_c018
|
|
||||||
│ ├── test_c017
|
|
||||||
│ ├── test_c016
|
|
||||||
│ ├── test_c015
|
|
||||||
│ ├── test_c014
|
|
||||||
│ ├── test_c013
|
|
||||||
│ ├── test_c012
|
|
||||||
│ ├── test_c011
|
|
||||||
│ ├── test_c010
|
|
||||||
│ ├── test_c009
|
|
||||||
│ ├── test_c008
|
|
||||||
│ ├── test_c007
|
|
||||||
│ ├── test_c006
|
|
||||||
│ ├── test_c005
|
|
||||||
│ ├── test_c004
|
|
||||||
│ ├── test_c003
|
|
||||||
│ ├── test_c002
|
|
||||||
│ └── test_c001
|
|
||||||
└── compliance_attestation
|
└── compliance_attestation
|
||||||
└── test_a001
|
└── test_a001
|
||||||
```
|
```
|
||||||
|
|
Binary file not shown.
|
@ -119,6 +119,11 @@
|
||||||
"inherits": [
|
"inherits": [
|
||||||
"PSA_Target"
|
"PSA_Target"
|
||||||
],
|
],
|
||||||
|
"tfm_target_name": "",
|
||||||
|
"tfm_bootloader_supported": "",
|
||||||
|
"tfm_default_toolchain": "ARMCLANG",
|
||||||
|
"tfm_supported_toolchains": null,
|
||||||
|
"delivery_dir": "",
|
||||||
"public": false
|
"public": false
|
||||||
},
|
},
|
||||||
"PSA_V8_M_NSPE": {
|
"PSA_V8_M_NSPE": {
|
||||||
|
@ -138,6 +143,11 @@
|
||||||
"inherits": [
|
"inherits": [
|
||||||
"PSA_Target"
|
"PSA_Target"
|
||||||
],
|
],
|
||||||
|
"tfm_target_name": "",
|
||||||
|
"tfm_bootloader_supported": "",
|
||||||
|
"tfm_default_toolchain": "ARMCLANG",
|
||||||
|
"tfm_supported_toolchains": null,
|
||||||
|
"delivery_dir": "",
|
||||||
"public": false
|
"public": false
|
||||||
},
|
},
|
||||||
"CM4_UARM": {
|
"CM4_UARM": {
|
||||||
|
@ -12861,8 +12871,22 @@
|
||||||
],
|
],
|
||||||
"bootloader_supported": false
|
"bootloader_supported": false
|
||||||
},
|
},
|
||||||
|
"CY8CPROTO_064_SB_S": {
|
||||||
|
"inherits": [
|
||||||
|
"PSA_DUAL_V7_M_SPE"
|
||||||
|
],
|
||||||
|
"tfm_target_name": "psoc64",
|
||||||
|
"tfm_bootloader_supported": false,
|
||||||
|
"tfm_default_toolchain": "ARMCLANG",
|
||||||
|
"tfm_supported_toolchains": [
|
||||||
|
"ARMCLANG",
|
||||||
|
"GNUARM"
|
||||||
|
],
|
||||||
|
"delivery_dir": "TARGET_Cypress/TARGET_PSOC6/TARGET_CY8CPROTO_064_SB/prebuilt"
|
||||||
|
},
|
||||||
"CY8CPROTO_064_SB": {
|
"CY8CPROTO_064_SB": {
|
||||||
"inherits": [
|
"inherits": [
|
||||||
|
"PSA_DUAL_V7_M_NSPE",
|
||||||
"MCU_PSOC6_M4"
|
"MCU_PSOC6_M4"
|
||||||
],
|
],
|
||||||
"components_remove": [
|
"components_remove": [
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Copyright (c) 2019 ARM Limited. All rights reserved.
|
Copyright (c) 2019 ARM Limited. All rights reserved.
|
||||||
|
|
||||||
|
@ -18,22 +18,24 @@ limitations under the License.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from os.path import join, abspath, dirname, isdir
|
from os.path import join, abspath, dirname, isdir, relpath
|
||||||
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger('TF-M-Builder')
|
ROOT = abspath(join(dirname(__file__), os.pardir, os.pardir))
|
||||||
|
sys.path.insert(0, ROOT)
|
||||||
|
from tools.targets import Target, TARGET_MAP, TARGET_NAMES
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO,
|
logging.basicConfig(level=logging.INFO,
|
||||||
format='[%(name)s] %(asctime)s: %(message)s.',
|
format='[%(name)s] %(asctime)s: %(message)s.',
|
||||||
datefmt='%H:%M:%S')
|
datefmt='%H:%M:%S')
|
||||||
|
logger = logging.getLogger('TF-M-Builder')
|
||||||
|
|
||||||
ROOT = abspath(join(dirname(__file__), os.pardir, os.pardir))
|
TF_M_BUILD_DIR = abspath(join(ROOT, os.pardir, 'tfm_build_dir'))
|
||||||
sys.path.insert(0, ROOT)
|
VERSION_FILE_PATH = join(ROOT, 'features/FEATURE_PSA/TARGET_TFM')
|
||||||
|
|
||||||
TF_M_BUILD_DIR = join(ROOT, os.pardir, 'tfm_build_dir')
|
|
||||||
VERSION_FILE_PATH = join(ROOT, 'features/FEATURE_PSA/FEATURE_TFM')
|
|
||||||
|
|
||||||
dependencies = {
|
dependencies = {
|
||||||
"trusted-firmware-m":
|
"trusted-firmware-m":
|
||||||
|
@ -46,22 +48,37 @@ dependencies = {
|
||||||
"CMSIS_5": ['https://github.com/ARM-software/CMSIS_5.git', '5.5.0'],
|
"CMSIS_5": ['https://github.com/ARM-software/CMSIS_5.git', '5.5.0'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def is_cmake_installed():
|
||||||
|
"""
|
||||||
|
Check if cmake is installed
|
||||||
|
"""
|
||||||
|
command = ['cmake', '--version']
|
||||||
|
return(run_cmd_and_return_errorcode(command))
|
||||||
|
|
||||||
def is_git_installed():
|
def is_git_installed():
|
||||||
"""
|
"""
|
||||||
Check if git is installed
|
Check if git is installed
|
||||||
"""
|
"""
|
||||||
command = ['git', '--version']
|
command = ['git', '--version']
|
||||||
try:
|
return(run_cmd_and_return_errorcode(command))
|
||||||
with open(os.devnull, 'w') as fnull:
|
|
||||||
return subprocess.call(command, stdout=fnull, stderr=fnull)
|
|
||||||
except OSError as e:
|
|
||||||
return e.errno
|
|
||||||
|
|
||||||
def is_git_lfs_installed():
|
def is_git_lfs_installed():
|
||||||
"""
|
"""
|
||||||
Check if git-lfs is installed
|
Check if git-lfs is installed
|
||||||
"""
|
"""
|
||||||
command = ['git-lfs', '--version']
|
command = ['git-lfs', '--version']
|
||||||
|
return(run_cmd_and_return_errorcode(command))
|
||||||
|
|
||||||
|
def run_cmd_and_return_errorcode(command):
|
||||||
|
"""
|
||||||
|
Run the command in the sytem and return errorcode.
|
||||||
|
Commands are passed as a list of tokens.
|
||||||
|
E.g. The command 'git remote -v' would be passed in as:
|
||||||
|
['git', 'remote', '-v']
|
||||||
|
|
||||||
|
:param command: System command as a list of tokens
|
||||||
|
"""
|
||||||
|
logger.debug('[Exec] %s', ' '.join(command))
|
||||||
try:
|
try:
|
||||||
with open(os.devnull, 'w') as fnull:
|
with open(os.devnull, 'w') as fnull:
|
||||||
return subprocess.call(command, stdout=fnull, stderr=fnull)
|
return subprocess.call(command, stdout=fnull, stderr=fnull)
|
||||||
|
@ -88,7 +105,7 @@ def run_cmd_and_return_output(command):
|
||||||
clean_up_cloned_repos()
|
clean_up_cloned_repos()
|
||||||
return output.decode("utf-8")
|
return output.decode("utf-8")
|
||||||
|
|
||||||
def detect_and_write_tfm_version(tfm_dir):
|
def detect_and_write_tfm_version(tfm_dir, commit):
|
||||||
"""
|
"""
|
||||||
Identify the version of TF-M and write it to VERSION.txt
|
Identify the version of TF-M and write it to VERSION.txt
|
||||||
:param tfm_dir: The filesystem path where TF-M repo is cloned
|
:param tfm_dir: The filesystem path where TF-M repo is cloned
|
||||||
|
@ -102,9 +119,12 @@ def detect_and_write_tfm_version(tfm_dir):
|
||||||
with open(join(VERSION_FILE_PATH, 'VERSION.txt'), 'w') as f:
|
with open(join(VERSION_FILE_PATH, 'VERSION.txt'), 'w') as f:
|
||||||
f.write(tfm_version)
|
f.write(tfm_version)
|
||||||
|
|
||||||
|
if commit:
|
||||||
|
commit_changes(VERSION_FILE_PATH)
|
||||||
|
|
||||||
def check_repo_version(name, deps):
|
def check_repo_version(name, deps):
|
||||||
"""
|
"""
|
||||||
Compare the version of cloned and expected and exit if they dont match
|
Compare the version of cloned and expected and exit if they don't match
|
||||||
:param name: Name of the git repository
|
:param name: Name of the git repository
|
||||||
:param deps: Dictionary containing dependency details
|
:param deps: Dictionary containing dependency details
|
||||||
"""
|
"""
|
||||||
|
@ -142,7 +162,7 @@ def check_and_clone_repo(name, deps):
|
||||||
logger.info('%s repo exists, checking git version...', name)
|
logger.info('%s repo exists, checking git version...', name)
|
||||||
check_repo_version(name, deps)
|
check_repo_version(name, deps)
|
||||||
|
|
||||||
def clone_tfm_repo():
|
def clone_tfm_repo(commit):
|
||||||
"""
|
"""
|
||||||
Clone TF-M git repos and it's dependencies
|
Clone TF-M git repos and it's dependencies
|
||||||
"""
|
"""
|
||||||
|
@ -150,7 +170,8 @@ def clone_tfm_repo():
|
||||||
check_and_clone_repo('mbedtls', dependencies)
|
check_and_clone_repo('mbedtls', dependencies)
|
||||||
check_and_clone_repo('mbed-crypto', dependencies)
|
check_and_clone_repo('mbed-crypto', dependencies)
|
||||||
check_and_clone_repo('CMSIS_5', dependencies)
|
check_and_clone_repo('CMSIS_5', dependencies)
|
||||||
detect_and_write_tfm_version(join(TF_M_BUILD_DIR, 'trusted-firmware-m'))
|
detect_and_write_tfm_version(join(TF_M_BUILD_DIR, 'trusted-firmware-m'),
|
||||||
|
commit)
|
||||||
|
|
||||||
def clean_up_cloned_repos():
|
def clean_up_cloned_repos():
|
||||||
"""
|
"""
|
||||||
|
@ -160,22 +181,301 @@ def clean_up_cloned_repos():
|
||||||
shutil.rmtree(TF_M_BUILD_DIR)
|
shutil.rmtree(TF_M_BUILD_DIR)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.error('Unable to cleanup cloned repos')
|
logger.error('Unable to cleanup cloned repos')
|
||||||
logger.error('"%s" occured', e.strerror)
|
logger.error('"%s" occurred', e.strerror)
|
||||||
|
|
||||||
|
def get_tfm_secure_targets():
|
||||||
|
"""
|
||||||
|
Creates a list of TF-M secure targets.
|
||||||
|
|
||||||
|
:return: List of TF-M secure targets.
|
||||||
|
"""
|
||||||
|
return [str(t) for t in TARGET_NAMES if
|
||||||
|
Target.get_target(t).is_TFM_target]
|
||||||
|
|
||||||
|
def get_target_info(target, toolchain=None):
|
||||||
|
"""
|
||||||
|
Creates a TF-M target tuple with default toolchain and
|
||||||
|
artifact delivery directory.
|
||||||
|
|
||||||
|
:param target: Target name.
|
||||||
|
:param toolchain: Toolchain
|
||||||
|
:return: tuple (target, toolchain, delivery directory).
|
||||||
|
"""
|
||||||
|
if toolchain:
|
||||||
|
if not TARGET_MAP[target].tfm_supported_toolchains:
|
||||||
|
msg = "Supported Toolchains is not configured for target %s" % (
|
||||||
|
TARGET_MAP[target].name)
|
||||||
|
raise Exception(msg)
|
||||||
|
elif toolchain not in TARGET_MAP[target].tfm_supported_toolchains:
|
||||||
|
msg = "Toolchain %s is not supported by %s" % (toolchain,
|
||||||
|
TARGET_MAP[target].name)
|
||||||
|
raise Exception(msg)
|
||||||
|
tc = toolchain
|
||||||
|
else:
|
||||||
|
tc = TARGET_MAP[target].tfm_default_toolchain
|
||||||
|
|
||||||
|
delivery_dir = join(ROOT, 'targets',
|
||||||
|
TARGET_MAP[target].delivery_dir)
|
||||||
|
|
||||||
|
if not os.path.exists(delivery_dir):
|
||||||
|
msg = "Delivery directory (delivery_dir) missing for %s" % target
|
||||||
|
raise FileNotFoundError(msg)
|
||||||
|
|
||||||
|
bl_sup = True if TARGET_MAP[target].tfm_bootloader_supported else False
|
||||||
|
return tuple([TARGET_MAP[target].name,
|
||||||
|
TARGET_MAP[target].tfm_target_name,
|
||||||
|
tc,
|
||||||
|
delivery_dir,
|
||||||
|
bl_sup])
|
||||||
|
|
||||||
|
def get_mbed_supported_tfm_targets():
|
||||||
|
tfm_secure_targets = get_tfm_secure_targets()
|
||||||
|
logger.debug("Found the following TF-M targets: {}".format(
|
||||||
|
', '.join(tfm_secure_targets)))
|
||||||
|
|
||||||
|
return [get_target_info(t) for t in tfm_secure_targets]
|
||||||
|
|
||||||
|
def commit_changes(directory, target=None, toolchain=None):
|
||||||
|
"""
|
||||||
|
Check for changes in `directory` and if any then commit them
|
||||||
|
:param directory: path to be checked for changes
|
||||||
|
:param target: Target name
|
||||||
|
:param toolchain: Toolchain name
|
||||||
|
"""
|
||||||
|
# Use --intent-to-add option of git status to identify un-tracked files
|
||||||
|
cmd = ['git', '-C', ROOT, 'status', 'N', directory]
|
||||||
|
run_cmd_and_return_errorcode(cmd)
|
||||||
|
|
||||||
|
cmd = ['git', '-C', ROOT, 'diff', '--exit-code', '--quiet', directory]
|
||||||
|
changes_made = run_cmd_and_return_errorcode(cmd)
|
||||||
|
|
||||||
|
if changes_made:
|
||||||
|
if target:
|
||||||
|
logger.info("Change in image for %s has been detected" % target)
|
||||||
|
else:
|
||||||
|
logger.info("Change detected in directory %s" % directory)
|
||||||
|
cmd = ['git', '-C', ROOT, 'add', relpath(directory, ROOT)]
|
||||||
|
run_cmd_and_return_errorcode(cmd)
|
||||||
|
|
||||||
|
if target:
|
||||||
|
logger.info("Committing image for %s" % target)
|
||||||
|
msg = '--message="Updated secure binary for %s (%s)"' % (target,
|
||||||
|
toolchain)
|
||||||
|
else:
|
||||||
|
logger.info("Committing changes in directory %s" % directory)
|
||||||
|
msg = '--message="Updated directory %s "' % directory
|
||||||
|
|
||||||
|
cmd = ['git', '-C', ROOT, 'commit', msg]
|
||||||
|
run_cmd_and_return_errorcode(cmd)
|
||||||
|
else:
|
||||||
|
if target:
|
||||||
|
logger.info("No changes detected in %s, skipping commit" % target)
|
||||||
|
else:
|
||||||
|
logger.info("No changes detected in %s, skipping commit" %
|
||||||
|
relpath(directory, ROOT))
|
||||||
|
|
||||||
|
def run_cmake_build(configure, cmake_build_dir, bl_supported= None,
|
||||||
|
tfm_target=None, tfm_toolchain=None, debug=False):
|
||||||
|
|
||||||
|
if configure:
|
||||||
|
cmake_cmd = ['cmake', '-GUnix Makefiles']
|
||||||
|
cmake_cmd.append('-DPROJ_CONFIG=' + (join(TF_M_BUILD_DIR,
|
||||||
|
'trusted-firmware-m', 'configs/ConfigCoreIPC.cmake')))
|
||||||
|
cmake_cmd.append('-DTARGET_PLATFORM=' + tfm_target)
|
||||||
|
cmake_cmd.append('-DCOMPILER=' + tfm_toolchain)
|
||||||
|
if debug:
|
||||||
|
cmake_cmd.append('-DCMAKE_BUILD_TYPE=Debug')
|
||||||
|
else:
|
||||||
|
cmake_cmd.append('-DCMAKE_BUILD_TYPE=Release')
|
||||||
|
if not bl_supported:
|
||||||
|
cmake_cmd.append('-DBL2=False')
|
||||||
|
cmake_cmd.append('..')
|
||||||
|
else:
|
||||||
|
cmake_cmd = ['cmake', '--build', '.', '--', 'install']
|
||||||
|
|
||||||
|
proc = subprocess.Popen(cmake_cmd, stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE, cwd=cmake_build_dir)
|
||||||
|
for line in iter(proc.stdout.readline, b''):
|
||||||
|
logger.debug(line.decode("utf-8").strip('\n'))
|
||||||
|
|
||||||
|
std_out, std_err = proc.communicate()
|
||||||
|
|
||||||
|
if proc.returncode:
|
||||||
|
logger.info(std_err.decode("utf-8"))
|
||||||
|
return proc.returncode
|
||||||
|
|
||||||
|
def get_parser():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
parser.add_argument("-m", "--mcu",
|
||||||
|
help="Build for the given MCU",
|
||||||
|
default=None,
|
||||||
|
choices=get_tfm_secure_targets())
|
||||||
|
hmsg = "Build for the given tool chain (default is tfm_default_toolchain)"
|
||||||
|
parser.add_argument("-t", "--toolchain",
|
||||||
|
help=hmsg,
|
||||||
|
default=None,
|
||||||
|
choices=["ARMCLANG", "GNUARM"])
|
||||||
|
|
||||||
|
parser.add_argument("-d", "--debug",
|
||||||
|
help="Set build profile to debug",
|
||||||
|
action="store_true",
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
parser.add_argument('-l', '--list',
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="Print supported TF-M secure targets")
|
||||||
|
|
||||||
|
parser.add_argument("--clone",
|
||||||
|
help="Clone TF-M git repo and its dependencies",
|
||||||
|
action="store_true",
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
parser.add_argument("--commit",
|
||||||
|
help="Create a git commit for each platform",
|
||||||
|
action="store_true",
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
parser.add_argument("--clean-build",
|
||||||
|
help="Remove cmake build directory",
|
||||||
|
action="store_true",
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
parser.add_argument("-v", "--verbose",
|
||||||
|
help="Verbose output",
|
||||||
|
action="store_true",
|
||||||
|
default=False)
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
|
def clean_build_directory():
|
||||||
|
cmake_build_dir = join(TF_M_BUILD_DIR, 'trusted-firmware-m', 'cmake_build')
|
||||||
|
if isdir(cmake_build_dir):
|
||||||
|
logger.info("Removing cmake build directory %s" %
|
||||||
|
relpath(cmake_build_dir))
|
||||||
|
shutil.rmtree(cmake_build_dir)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
"""
|
||||||
Build Trusted Firmware M (TF-M) image for mbed-os supported TF-M targets.
|
Build Trusted Firmware M (TF-M) image for mbed-os supported TF-M targets
|
||||||
Current version of the script only clones TF-M git repo and dependencies
|
|
||||||
and creates a VERSION.txt file under 'features/FEATURE_PSA/FEATURE_TFM'
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
parser = get_parser()
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.clean_build:
|
||||||
|
clean_build_directory()
|
||||||
|
return
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
if args.list:
|
||||||
|
logger.info("Supported TF-M platforms are: {}".format(
|
||||||
|
', '.join([t for t in get_tfm_secure_targets()])))
|
||||||
|
return
|
||||||
|
|
||||||
if not isdir(TF_M_BUILD_DIR):
|
if not isdir(TF_M_BUILD_DIR):
|
||||||
os.mkdir(TF_M_BUILD_DIR)
|
os.mkdir(TF_M_BUILD_DIR)
|
||||||
clone_tfm_repo()
|
|
||||||
|
clone_tfm_repo(args.commit)
|
||||||
|
if args.clone:
|
||||||
|
return
|
||||||
|
|
||||||
|
cmake_build_dir = join(TF_M_BUILD_DIR, 'trusted-firmware-m', 'cmake_build')
|
||||||
|
if not isdir(cmake_build_dir):
|
||||||
|
os.mkdir(cmake_build_dir)
|
||||||
|
|
||||||
|
debug = False
|
||||||
|
if args.mcu:
|
||||||
|
tgt = None
|
||||||
|
if args.toolchain:
|
||||||
|
msg = "Building TF-M for target %s using toolchain %s" % (args.mcu,
|
||||||
|
args.toolchain)
|
||||||
|
logger.info(msg)
|
||||||
|
tgt = get_target_info(args.mcu, args.toolchain)
|
||||||
|
else:
|
||||||
|
tgt = get_target_info(args.mcu)
|
||||||
|
msg = "Building TF-M for target %s using default toolchain %s" % (
|
||||||
|
args.mcu, tgt[2])
|
||||||
|
logger.info(msg)
|
||||||
|
|
||||||
|
if args.debug:
|
||||||
|
debug = True
|
||||||
|
|
||||||
|
retcode = run_cmake_build(True, cmake_build_dir, tgt[4], tgt[1],
|
||||||
|
tgt[2], debug)
|
||||||
|
if retcode:
|
||||||
|
msg = "Cmake configure failed for target %s using toolchain %s" % (
|
||||||
|
tgt[0], tgt[2])
|
||||||
|
logger.critical(msg)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
retcode = run_cmake_build(False, cmake_build_dir)
|
||||||
|
if retcode:
|
||||||
|
msg = "Cmake build failed for target %s using toolchain %s" % (
|
||||||
|
tgt[0], tgt[2])
|
||||||
|
logger.critical(msg)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
output_dir = None
|
||||||
|
if(tgt[3].endswith('/')):
|
||||||
|
output_dir = tgt[3]
|
||||||
|
else:
|
||||||
|
output_dir = tgt[3] + '/'
|
||||||
|
tfm_secure_bin = join(cmake_build_dir, 'install', 'outputs', tgt[1],
|
||||||
|
'tfm_s.bin')
|
||||||
|
logger.info("Copying %s to %s" % (relpath(tfm_secure_bin, ROOT),
|
||||||
|
relpath(output_dir, ROOT)))
|
||||||
|
shutil.copy2(tfm_secure_bin, output_dir)
|
||||||
|
|
||||||
|
if args.commit:
|
||||||
|
commit_changes(tgt[3], tgt[0], tgt[2])
|
||||||
|
else:
|
||||||
|
for tgt in get_mbed_supported_tfm_targets():
|
||||||
|
msg = "Building TF-M for target %s using default toolchain %s" % (
|
||||||
|
tgt[0], tgt[2])
|
||||||
|
logger.info(msg)
|
||||||
|
|
||||||
|
if args.debug:
|
||||||
|
debug = True
|
||||||
|
|
||||||
|
retcode = run_cmake_build(True, cmake_build_dir, tgt[4], tgt[1],
|
||||||
|
tgt[2], debug)
|
||||||
|
if retcode:
|
||||||
|
msg = "Cmake configure failed for target %s with toolchain %s" % (
|
||||||
|
tgt[0], tgt[2])
|
||||||
|
logger.critical(msg)
|
||||||
|
sys.exit(1)
|
||||||
|
retcode = run_cmake_build(False, cmake_build_dir)
|
||||||
|
if retcode:
|
||||||
|
msg = "Cmake build failed for target %s using toolchain %s" % (
|
||||||
|
tgt[0], tgt[2])
|
||||||
|
logger.critical(msg)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
output_dir = None
|
||||||
|
if(tgt[3].endswith('/')):
|
||||||
|
output_dir = tgt[3]
|
||||||
|
else:
|
||||||
|
output_dir = tgt[3] + '/'
|
||||||
|
|
||||||
|
tfm_secure_bin = join(cmake_build_dir, 'install', 'outputs',
|
||||||
|
tgt[1], 'tfm_s.bin')
|
||||||
|
logger.info("Copying %s to %s" % (relpath(tfm_secure_bin, ROOT),
|
||||||
|
relpath(output_dir, ROOT)))
|
||||||
|
shutil.copy2(tfm_secure_bin, output_dir)
|
||||||
|
|
||||||
|
if args.commit:
|
||||||
|
commit_changes(tgt[3], tgt[0], tgt[2])
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if is_git_installed() != 0:
|
if is_git_installed() != 0:
|
||||||
logger.error('"git" is not installed. Exiting...')
|
logger.error('"git" is not installed. Exiting...')
|
||||||
elif is_git_lfs_installed() != 0:
|
elif is_git_lfs_installed() != 0:
|
||||||
logger.error('"git-lfs" is not installed. Exiting...')
|
logger.error('"git-lfs" is not installed. Exiting...')
|
||||||
|
elif is_cmake_installed() != 0:
|
||||||
|
logger.error('"cmake" is not installed. Exiting...')
|
||||||
else:
|
else:
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -418,8 +418,8 @@ class Target(namedtuple(
|
||||||
return 'NSPE_Target' in self.labels
|
return 'NSPE_Target' in self.labels
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_PSA_target(self):
|
def is_TFM_target(self):
|
||||||
return self.is_PSA_secure_target or self.is_PSA_non_secure_target
|
return getattr(self, 'tfm_target_name', False)
|
||||||
|
|
||||||
def get_post_build_hook(self, toolchain_labels):
|
def get_post_build_hook(self, toolchain_labels):
|
||||||
"""Initialize the post-build hooks for a toolchain. For now, this
|
"""Initialize the post-build hooks for a toolchain. For now, this
|
||||||
|
|
Loading…
Reference in New Issue