Newer
Older
mbed-os / platform / FEATURE_EXPERIMENTAL_API / FEATURE_PSA / TARGET_TFM / TARGET_TFM_LATEST / scripts / generate_mbed_image.py
@Jamie Smith Jamie Smith on 14 Sep 2022 5 KB Fix PSA and MUSCA build
#!/usr/bin/python
# Copyright (c) 2017-2021 Arm Limited
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import sys
from os.path import abspath, basename, dirname, splitext, isdir
from os.path import join as path_join
import re
import subprocess
import argparse

SCRIPT_DIR = dirname(abspath(__file__))
MBED_OS_ROOT = abspath(path_join(SCRIPT_DIR, os.pardir, os.pardir, os.pardir, os.pardir, os.pardir, os.pardir))

def sign_and_merge_tfm_bin(target_name, target_path, non_secure_bin, secure_bin):

    assert os.path.isdir(target_path)
    assert os.path.isfile(secure_bin)
    assert os.path.isfile(non_secure_bin)

    build_dir = dirname(non_secure_bin)
    tempdir = path_join(build_dir, 'temp')
    if not isdir(tempdir):
        os.makedirs(tempdir)
    flash_layout = path_join(target_path, 'partition', 'flash_layout.h')
    mcuboot_bin = path_join(target_path, 'bl2.bin')
    image_macros_s = path_join(target_path, 'partition', 'signing_layout_s.c')
    image_macros_ns = path_join(target_path, 'partition', 'signing_layout_ns.c')
    s_bin_name, s_bin_ext = splitext(basename(secure_bin))
    s_signed_bin = abspath(path_join(tempdir, s_bin_name + '_signed' + s_bin_ext))
    ns_bin_name, ns_bin_ext = splitext(basename(non_secure_bin))
    ns_signed_bin = abspath(path_join(tempdir, 'tfm_' + ns_bin_name + '_signed' + ns_bin_ext))
    concatenated_bin = abspath(path_join(tempdir, s_bin_name + '_' + ns_bin_name + '_concat' + ns_bin_ext))

    assert os.path.isfile(image_macros_s)
    assert os.path.isfile(image_macros_ns)

    #1. Run wrapper to sign the TF-M secure binary
    cmd = [
        sys.executable,
        path_join(MBED_OS_ROOT, "tools", "psa","tfm", "bin_utils","wrapper.py"),
        "-v",
        '1.2.0',
        "-k",
        path_join(target_path, (target_name + '-root-rsa-3072.pem')),
        "--layout",
        image_macros_s,
        "--public-key-format",
        'full',
        "--align",
        '1',
        "--pad",
        "--pad-header",
        "-H",
        '0x400',
        "--overwrite-only",
        "-s",
        'auto',
        "-d",
        '(0,0.0.0+0)',
        abspath(secure_bin),
        s_signed_bin,
    ]

    retcode = run_cmd(cmd, MBED_OS_ROOT)
    if retcode:
        raise Exception("Unable to sign " + target_name +
                            " secure binary, Error code: " + str(retcode))

    #2. Run wrapper to sign the non-secure mbed binary
    cmd = [
        sys.executable,
        path_join(MBED_OS_ROOT, "tools", "psa","tfm", "bin_utils","wrapper.py"),
        "-v",
        '1.2.0',
        "-k",
        path_join(target_path, (target_name + '-root-rsa-3072_1.pem')),
        "--layout",
        image_macros_ns,
        "--public-key-format",
        'full',
        "--align",
        '1',
        "--pad",
        "--pad-header",
        "-H",
        '0x400',
        "--overwrite-only",
        "-s",
        'auto',
        "-d",
        '(1,0.0.0+0)',
        abspath(non_secure_bin),
        ns_signed_bin,
    ]

    retcode = run_cmd(cmd, MBED_OS_ROOT)
    if retcode:
        raise Exception("Unable to sign " + target_name +
                            " non-secure binary, Error code: " + str(retcode))

    #3. Concatenate signed secure TFM and non-secure mbed binaries
    cmd = [
        sys.executable,
        path_join(MBED_OS_ROOT, "tools", "psa","tfm", "bin_utils","assemble.py"),
        "--layout",
        image_macros_s,
        "-s",
        s_signed_bin,
        "-n",
        ns_signed_bin,
        "-o",
        concatenated_bin,
    ]

    retcode = run_cmd(cmd, MBED_OS_ROOT)
    if retcode:
        raise Exception("Unable to concatenate " + target_name +
                            " binaries, Error code: " + str(retcode))

    #4. Concatenate mcuboot and signed binary and overwrite mbed built binary file
    mcuboot_image_size = find_bl2_size(flash_layout)
    with open(mcuboot_bin, "rb") as mcuboot_fh, open(concatenated_bin, "rb") as concat_fh:
        with open(non_secure_bin, "w+b") as out_fh:
            out_fh.write(mcuboot_fh.read())
            out_fh.seek(mcuboot_image_size)
            out_fh.write(concat_fh.read())


def find_bl2_size(configFile):
    bl2_size_re = re.compile(r"^#define\s+FLASH_AREA_BL2_SIZE\s+\({0,1}(0x[0-9a-fA-F]+)\){0,1}")
    bl2_size = None
    with open(configFile, 'r') as flash_layout_file:
        for line in flash_layout_file:
            m = bl2_size_re.match(line)
            if m is not None:
                bl2_size = int(m.group(1), 0)
                break
    return bl2_size

def run_cmd(cmd, directory):
    popen_instance = subprocess.Popen(
        cmd,
        stderr=subprocess.STDOUT,
        cwd=directory,
    )
    popen_instance.communicate()
    return popen_instance.returncode

def parse_args():
    parser = argparse.ArgumentParser()

    parser.add_argument(
        "--tfm-target",
        help="Name of the TF-M target",
        required=True
    )

    parser.add_argument(
        "--target-path",
        help="Path containing the target's bootloader, layouts and signing keys",
        required=True
    )

    parser.add_argument(
        "--non-secure-bin",
        help="Path to the non-secure binary",
        required=True
    )

    parser.add_argument(
        "--secure-bin",
        help="Path to the secure binary",
        required=True
    )

    return parser.parse_args()

if __name__ == "__main__":
    args = parse_args()
    sign_and_merge_tfm_bin(args.tfm_target, args.target_path, args.non_secure_bin, args.secure_bin)