diff --git a/.travis.yml b/.travis.yml index 23c3ab8c63..36e6e1de66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -195,8 +195,8 @@ matrix: ### Extended Tests ### - &extended-vm stage: "Extended" - name: "psa autogen" - env: NAME=psa-autogen + name: "events" + env: NAME=events EVENTS=events language: python python: 3.7 install: @@ -208,13 +208,6 @@ matrix: - python -m pip install --upgrade setuptools==40.4.3 - pip install -r requirements.txt - pip list --verbose - script: - - python tools/psa/generate_partition_code.py - - git diff --exit-code - - - <<: *extended-vm - name: "events" - env: NAME=events EVENTS=events script: # Check that example compiles - sed -n '/``` cpp/,/```/{/```$/Q;/```/d;p;}' ${EVENTS}/README.md > main.cpp diff --git a/tools/build.py b/tools/build.py index bde4561050..027b6ffcca 100644 --- a/tools/build.py +++ b/tools/build.py @@ -44,8 +44,6 @@ from tools.utils import argparse_filestring_type, args_error, argparse_many from tools.utils import argparse_dir_not_parent from tools.utils import NoValidToolchainException from tools.utils import print_end_warnings -from tools.psa import generate_psa_sources -from tools.resources import OsAndSpeResourceFilter def main(): start = time() @@ -189,12 +187,6 @@ def main(): if options.source_dir: resource_filter = None - if target.is_PSA_secure_target: - generate_psa_sources( - source_dirs=options.source_dir, - ignore_paths=[options.build_dir] - ) - resource_filter = OsAndSpeResourceFilter() lib_build_res = build_library( options.source_dir, options.build_dir, target, toolchain_name, diff --git a/tools/build_api.py b/tools/build_api.py index 8f877e224b..7a5be525e1 100755 --- a/tools/build_api.py +++ b/tools/build_api.py @@ -41,7 +41,7 @@ from .paths import (MBED_CMSIS_PATH, MBED_TARGETS_PATH, MBED_LIBRARIES, MBED_CONFIG_FILE, MBED_LIBRARIES_DRIVERS, MBED_LIBRARIES_PLATFORM, MBED_LIBRARIES_HAL, BUILD_DIR) -from .resources import Resources, FileType, FileRef, PsaManifestResourceFilter +from .resources import Resources, FileType, FileRef from .notifier.mock import MockNotifier from .targets import TARGET_NAMES, TARGET_MAP, CORE_ARCH, Target from .libraries import Library @@ -753,7 +753,6 @@ def build_library(src_paths, build_path, target, toolchain_name, res = Resources(notify).scan_with_toolchain( src_paths, toolchain, dependencies_paths, inc_dirs=inc_dirs) res.filter(resource_filter) - res.filter(PsaManifestResourceFilter()) # Copy headers, objects and static libraries - all files needed for # static lib diff --git a/tools/make.py b/tools/make.py index fe3f6584f7..f01e22eb52 100644 --- a/tools/make.py +++ b/tools/make.py @@ -55,8 +55,6 @@ from tools.utils import print_end_warnings from tools.utils import print_large_string from tools.settings import ROOT from tools.targets import Target -from tools.psa import generate_psa_sources -from tools.resources import OsAndSpeResourceFilter def default_args_dict(options): return dict( @@ -336,13 +334,6 @@ def main(): if options.source_dir is not None: resource_filter = None - if target.is_PSA_secure_target: - generate_psa_sources( - source_dirs=options.source_dir, - ignore_paths=[options.build_dir] - ) - resource_filter = OsAndSpeResourceFilter() - wrapped_build_project( options.source_dir, options.build_dir, diff --git a/tools/project.py b/tools/project.py index 76cc051bd4..a943d3dfcc 100644 --- a/tools/project.py +++ b/tools/project.py @@ -53,8 +53,6 @@ from tools.utils import print_large_string from tools.utils import NotSupportedException from tools.options import extract_profile, list_profiles, extract_mcus from tools.notifier.term import TerminalNotifier -from tools.psa import generate_psa_sources -from tools.resources import OsAndSpeResourceFilter """ The CLI entry point for exporting projects from the mbed tools to any of the supported IDEs or project structures. @@ -389,14 +387,7 @@ def main(): args_error(parser, "%s not supported by %s" % (mcu, ide)) try: - target = Target.get_target(mcu) resource_filter = None - if target.is_PSA_secure_target: - generate_psa_sources(source_dirs=options.source_dir, - ignore_paths=[] - ) - resource_filter = OsAndSpeResourceFilter() - export( mcu, ide, diff --git a/tools/psa/README.md b/tools/psa/README.md deleted file mode 100644 index 047a3992ee..0000000000 --- a/tools/psa/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# PSA tools - -## Code generation script - -Mbed-OS contains two implementations of PSA Firmware Framework: - -* Mbed-SPM - Implementation for dual-core v7 targets. -* TF-M - Implementation for v8 targets. - -Both PSA Firmware Framework implementation impose the following requirements: - -* PSA manifests must be valid according to the JSON schema file provided by PSA FF spec. -* There are no conflicts between various PSA manifests (duplicate SIDs and PIDs, dependencies, etc.) -* Secure partition initialization code to be present at mbed-os core compile time. - -To satisfy the requirement listed above, Mbed-OS build system invokes `generate_partition_code.py` script -during the build process for PSA targets. - -PSA code generation step has the following effects: -* Scan the whole source tree for PSA manifest files, including application (in case invoked from application directory) and all the `TESTS` directories. -* All found PSA manifest files get parsed and validated. -* Source and header files for initializing SPM are generated. Test related partitions and SIDs are disabled by default by `#ifndef` guards. - To enable them following defines must be passed to build command (typically done automatically via [release.py](#secure-image-generation)): - * `-DUSE_PSA_TEST_PARTITIONS` - * `-DUSE_` where `` corresponds to the name in PSA manifest file (`"name"` property). - -## Secure image generation - -`release.py` is the script assigned with compiling the default secure images. - -For an application with custom secure portions, the secure image should be generated by invoking `mbed-cli` directly. - -> **Note**: when building targets utilizing TF-M PSA implementations, add the following arguments to a build command for the secure image: - `--app-config /tools/psa/tfm/mbed_app.json` - -### Usage -```text -usage: release.py [-h] [-m MCU] [-t TC] [-d] [-q] [-l] [--commit] - [--skip-tests] [-x ...] - -optional arguments: - -h, --help show this help message and exit - -m MCU, --mcu MCU build for the given MCU - -t TC, --tc TC build for the given tool chain (default is - default_toolchain) - -d, --debug set build profile to debug - -q, --quiet No Build log will be printed - -l, --list Print supported PSA secure targets - --commit create a git commit for each platform - --skip-tests skip the test build phase - -x ..., --extra ... additional build parameters -``` - -* The script must be run from the mbed-os folder via `tools/psa/release.py`, - otherwise the list of available tests will not be accurate and the test - partitions will not be properly generated. -* When `MCU ` is not specified, the script compiles all the images for all the targets. -* When `-t/--tc` is not specified, the script compiles with the default_toolchain speciified in targets.json. -* When `-d/--debug` is not specified, the script compiles the images using the release profile. -* When `--commit` is not specified, the script will not commit the images to git and - any auto-generated PSA related components and services. -* A user can specify additional commands that will be passed on to the build commands (Ex. -D for compilation defines). - -This script should be run in following scenarios: - -* Release. -* Update to files originating in the secure side. -* Drivers update. -* PSA updates. diff --git a/tools/psa/__init__.py b/tools/psa/__init__.py deleted file mode 100644 index 21e25ba464..0000000000 --- a/tools/psa/__init__.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2019 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 shutil - -from tools.resources import FileType -from tools.settings import ROOT -from .generate_partition_code import manifests_discovery, generate_spm_code - - - -def find_secure_image(notify, resources, ns_image_path, - configured_s_image_filename, image_type): - """ Find secure image. """ - if configured_s_image_filename is None: - return None - - assert ns_image_path and configured_s_image_filename, \ - 'ns_image_path and configured_s_image_path are mandatory' - assert image_type in [FileType.BIN, FileType.HEX], \ - 'image_type must be of type BIN or HEX' - - image_files = resources.get_file_paths(image_type) - assert image_files, 'No image files found for this target' - - secure_image = next( - (f for f in image_files if - os.path.basename(f) == configured_s_image_filename), None) - secure_image = next( - (f for f in image_files if - os.path.splitext(os.path.basename(f))[0] == - os.path.splitext(os.path.basename(ns_image_path))[0]), - secure_image - ) - - if secure_image: - notify.debug("Secure image file found: %s." % secure_image) - else: - notify.debug("Secure image file %s not found. Aborting." - % configured_s_image_filename) - raise Exception("Required secure image not found.") - - return secure_image - -def generate_psa_sources(source_dirs, ignore_paths): - services, apps = manifests_discovery(root_dirs=source_dirs, - ignore_paths=ignore_paths + ['.git']) - assert len(services + apps), 'PSA manifest discovery failed' - psa_out_dir = os.path.join(ROOT, 'components', 'TARGET_PSA') - - generate_spm_code(services, apps, psa_out_dir) - return psa_out_dir diff --git a/tools/psa/generate_partition_code.py b/tools/psa/generate_partition_code.py deleted file mode 100644 index 1567c98840..0000000000 --- a/tools/psa/generate_partition_code.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2017-2019 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 argparse -import itertools -import json -import os -import sys -from os.path import join as path_join - -# Be sure that the tools directory is in the search path -ROOT = os.path.abspath(path_join(os.path.dirname(__file__), os.pardir, os.pardir)) -sys.path.insert(0, ROOT) - -from tools.psa.mbed_spm_tfm_common import validate_partition_manifests, \ - manifests_discovery, parse_manifests, generate_source_files, \ - MBED_OS_ROOT - -__version__ = '1.1' -SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) -MANIFEST_FILE_PATTERN = '*_psa.json' -PSA_CORE_ROOT = path_join(MBED_OS_ROOT, 'components', 'TARGET_PSA') -TEMPLATES_DESC = path_join(SCRIPT_DIR, 'spm_template_file_list.json') - - -def _get_timestamp(f): - return os.path.getmtime(f) if os.path.isfile(f) else 0 - - -def is_up_to_date(manifest_files, out_files): - manifest_timestamp = max(_get_timestamp(f) for f in manifest_files) - out_timestamps = min(_get_timestamp(f) for f in out_files) - return manifest_timestamp <= out_timestamps - - -def generate_spm_code(service_files, app_files, output_dir): - with open(TEMPLATES_DESC, 'r') as fh: - templates_data = json.load(fh) - templates_dict = { - path_join(MBED_OS_ROOT, t['template']): - path_join(output_dir, t['output']) for t in templates_data - } - - if is_up_to_date(service_files + app_files, list(templates_dict.values())): - return - - # Construct lists of all the manifests and mmio_regions. - service_manifests, service_region_list = parse_manifests(service_files) - test_manifests, test_region_list = parse_manifests(app_files) - - # Validate the correctness of the manifest collection. - validate_partition_manifests(service_manifests + test_manifests) - - region_list = service_region_list + test_region_list - - render_args = { - 'service_partitions': service_manifests, - 'test_partitions': test_manifests, - 'script_ver': __version__, - 'regions': region_list, - 'region_pair_list': list(itertools.combinations(region_list, 2)), - } - - generate_source_files(templates_dict, render_args) - - -class AppendReadableDir(argparse.Action): - def __call__(self, parser, namespace, values, option_string=None): - prosp_dir = os.path.abspath(values) - if not os.path.isdir(prosp_dir): - raise argparse.ArgumentTypeError("{} is missing".format(prosp_dir)) - if not os.access(prosp_dir, os.R_OK): - raise argparse.ArgumentTypeError( - "{} is not a accessible for read".format(prosp_dir)) - if not getattr(namespace, self.dest): - setattr(namespace, self.dest, []) - getattr(namespace, self.dest).append(prosp_dir) - - -def get_parser(): - parser = argparse.ArgumentParser( - description='PSA SPM code generator', - formatter_class=argparse.ArgumentDefaultsHelpFormatter - ) - parser.add_argument( - '-u', '--user-app', - action=AppendReadableDir, - default=[ROOT], - help='Root directory for recursive PSA manifest scan. Use for adding ' - 'application specific secure partitions. Can be supplied more ' - 'than once', - metavar='DIR' - ) - - parser.add_argument( - '-o', '--output-dir', - default=ROOT, - help='Root directory for generating the sources', - metavar='DIR' - ) - - return parser - - -def main(): - parser = get_parser() - args = parser.parse_args() - - services, apps = manifests_discovery(root_dirs=args.user_app, - ignore_paths=['BUILD', '.git']) - - generate_spm_code(services, apps, args.output_dir) - - -if __name__ == '__main__': - main() diff --git a/tools/psa/mbed_spm_tfm_common.py b/tools/psa/mbed_spm_tfm_common.py deleted file mode 100644 index eb1f407191..0000000000 --- a/tools/psa/mbed_spm_tfm_common.py +++ /dev/null @@ -1,678 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2017-2018 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 -from os.path import join as path_join -import json -from jsonschema import validate -import fnmatch -from six import integer_types, string_types -from jinja2 import Environment, FileSystemLoader, StrictUndefined - -SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) -MBED_OS_ROOT = os.path.abspath(path_join(SCRIPT_DIR, os.pardir, os.pardir)) -SERVICES_DIR = path_join(MBED_OS_ROOT, "components", "TARGET_PSA", "services") -TESTS_DIR = path_join(MBED_OS_ROOT, "TESTS", "psa") -MANIFEST_FILE_PATTERN = '*_psa.json' - - -def _assert_int(num): - """ - Tries to parse an integer num from a given string - - :param num: Number in int/string type - :return: Numeric value - """ - if isinstance(num, int): - return num - num_str = str(num) - radix = 16 if num_str.lower().startswith('0x') else 10 - res = int(num_str, radix) - # Python converts str to int as a signed integer - if res > 0x7FFFFFFF: - res -= 0x100000000 - return res - - -class RotService(object): - MINOR_POLICIES = ['STRICT', 'RELAXED'] - - def __init__( - self, - name, - identifier, - signal, - non_secure_clients, - minor_version=1, - minor_policy='STRICT' - ): - """ - Root of Trust Service C'tor (Aligned with json schema) - - :param name: Root of Trust Service identifier (available to user) - :param identifier: Root of Trust Service numeric enumeration. - :param signal: Root of Trust Service identifier inside the partition - :param non_secure_clients: True to allow connections from non-secure - partitions - :param minor_version: Root of Trust Service version - :param minor_policy: Enforcement level of minor version - """ - self.name = name - self.id = identifier - self.signal = signal - - assert _assert_int(identifier) - - assert isinstance(non_secure_clients, bool), \ - 'non_secure_clients parameter must be of boolean type' - self.nspe_callable = non_secure_clients - - self.minor_version = _assert_int(minor_version) - assert self.minor_version > 0, 'minor_version parameter is invalid' - - assert minor_policy in self.MINOR_POLICIES, \ - 'minor_policy parameter is invalid' - self.minor_policy = minor_policy - - @property - def numeric_id(self): - return _assert_int(self.id) - - def __eq__(self, other): - return ( - (self.name == other.name) and - (self.id == other.id) and - (self.signal == other.signal) and - (self.nspe_callable == other.nspe_callable) and - (self.minor_version == other.minor_version) and - (self.minor_policy == other.minor_policy) - ) - - -class MmioRegion(object): - MMIO_PERMISSIONS = { - 'READ-ONLY': 'PSA_MMIO_PERM_READ_ONLY', - 'READ-WRITE': 'PSA_MMIO_PERM_READ_WRITE' - } - - def __init__(self, **kwargs): - """ - MMIO Region C'tor (Aligned with json schema) - - Supports both named and numeric regions - In case of named region the acceptable params are name and permission - In case of numeric region the acceptable params are name, size and - permission - - :param name: C definition name of the region (size will be - auto-generated) - :param base: C hex string defining a memory address (must be 32bit) - :param size: size of a region (Applicable only for numbered regions) - :param permission: Access permissions to the described region (R/RW) - - """ - assert 'permission' in kwargs - self.permission = self.MMIO_PERMISSIONS[kwargs['permission']] - if 'name' in kwargs: - self.base = kwargs['name'] - self.size = '(sizeof(*({})))'.format(kwargs['name']) - if 'base' in kwargs: - self.base = kwargs['base'] - self.size = _assert_int(kwargs['size']) - - assert 'partition_id' in kwargs - self.partition_id = _assert_int(kwargs['partition_id']) - - assert hasattr(self, 'base') - assert hasattr(self, 'size') - assert hasattr(self, 'permission') - assert hasattr(self, 'partition_id') - - def __eq__(self, other): - return ( - (self.base == other.base) and - (self.size == other.size) and - (self.permission == other.permission) - ) - - -class Irq(object): - def __init__(self, line_num, signal): - """ - IRQ line C'tor (Aligned with json schema) - - :param line_num: number of interrupt used by the partition - :param signal: IRQ line identifier inside the partition - """ - self.line_num = _assert_int(line_num) - assert isinstance(signal, string_types) - self.signal = signal - - def __eq__(self, other): - return (self.line_num == other.line_num) and \ - (self.signal == other.signal) - - -class Manifest(object): - PRIORITY = { - 'LOW': 'osPriorityLow', - 'NORMAL': 'osPriorityNormal', - 'HIGH': 'osPriorityHigh' - } - PARTITION_TYPES = ['APPLICATION-ROT', 'PSA-ROT'] - # The following signal bits cannot be used: - # bit[0-2] | Reserved - # bit[3] | PSA Doorbell - # bit[31] | RTX error bit - RESERVED_SIGNALS = 5 - - def __init__( - self, - manifest_file, - name, - partition_id, - partition_type, - priority, - entry_point, - heap_size, - stack_size, - source_files, - mmio_regions=None, - rot_services=None, - extern_sids=None, - irqs=None - ): - """ - Manifest C'tor (Aligned with json schema) - - :param manifest_file: Path to json manifest - :param name: Partition unique name - :param partition_id: Partition identifier - :param partition_type: Whether the partition is unprivileged or part - of the trusted computing base - :param priority: Priority of the partition's thread - :param entry_point: C symbol name of the partition's main function - :param heap_size: Size of heap required for the partition - :param stack_size: Size of stack required for the partition - :param source_files: List of files assembling the partition - (relative paths) - :param mmio_regions: List of MMIO regions used by the partition - :param rot_services: List of Root of Trust Services declared by the - partition - :param extern_sids: List of Root of Trust Services the partition can call - :param irqs: List of interrupts the partition can handle - """ - assert manifest_file is not None - assert name is not None - assert partition_id is not None - assert partition_type is not None - assert entry_point is not None - assert priority is not None - assert heap_size is not None - assert stack_size is not None - assert source_files is not None - - mmio_regions = [] if mmio_regions is None else mmio_regions - rot_services = [] if rot_services is None else rot_services - extern_sids = [] if extern_sids is None else extern_sids - irqs = [] if irqs is None else irqs - - assert os.path.isfile(manifest_file) - assert isinstance(partition_id, integer_types) - assert isinstance(heap_size, int) - assert isinstance(stack_size, int) - assert isinstance(entry_point, string_types) - assert partition_type in self.PARTITION_TYPES - assert partition_id > 0 - - self.file = manifest_file - self.name = name - self.id = partition_id - self.type = partition_type - - self.priority_tfm = priority - self.priority_mbed = self.PRIORITY[priority] - self.heap_size = heap_size - self.stack_size = stack_size - self.entry_point = entry_point - if isinstance(source_files, list): - self.source_files = source_files - else: - self.source_files = [source_files] - - self.mmio_regions = mmio_regions - self.rot_services = rot_services - self.extern_sids = extern_sids - self.irqs = irqs - - for src_file in self.source_files: - assert os.path.isfile(src_file), \ - "The source file {} mentioned in {} doesn't exist.".format( - src_file, self.file - ) - - for rot_srv in self.rot_services: - assert isinstance(rot_srv, RotService) - - for extern_sid in self.extern_sids: - assert isinstance(extern_sid, string_types) - - assert len(self.extern_sids) == len(set(self.extern_sids)), \ - 'Detected duplicates external SIDs in {}'.format(self.file) - - for irq in self.irqs: - assert isinstance(irq, Irq) - - total_signals = len(self.rot_services) + len(self.irqs) - assert total_signals <= 32 - self.RESERVED_SIGNALS, \ - 'Manifest {} - {} exceeds limit of RoT services and IRQs allowed ' \ - '({}).'.format( - self.name, self.file, 32 - self.RESERVED_SIGNALS - ) - - def __eq__(self, other): - return ( - (self.file == other.file) and - (self.name == other.name) and - (self.id == other.id) and - (self.type == other.type) and - (self.priority_mbed == other.priority_mbed) and - (self.priority_tfm == other.priority_tfm) and - (self.heap_size == other.heap_size) and - (self.stack_size == other.stack_size) and - (self.entry_point == other.entry_point) and - (self.source_files == other.source_files) and - (self.mmio_regions == other.mmio_regions) and - (self.rot_services == other.rot_services) and - (self.extern_sids == other.extern_sids) and - (self.irqs == other.irqs) - ) - - @classmethod - def from_json(cls, manifest_file, skip_src=False): - """ - Load a partition manifest file - - :param manifest_file: Manifest file path - :param skip_src: Ignore the `source_files` entry - :return: Manifest object - """ - - partition_schema_path = path_join( - SCRIPT_DIR, - 'partition_description_schema.json' - ) - with open(partition_schema_path) as schema_fh: - partition_schema = json.load(schema_fh) - - # Load partition manifest file. - with open(manifest_file) as fh: - manifest = json.load(fh) - - validate(manifest, partition_schema) - manifest_dir = os.path.dirname(manifest_file) - - source_files = [] - if not skip_src: - for src_file in manifest['source_files']: - source_files.append( - os.path.normpath(path_join(manifest_dir, src_file))) - - mmio_regions = [] - for mmio_region in manifest.get('mmio_regions', []): - mmio_regions.append( - MmioRegion(partition_id=manifest['id'], **mmio_region)) - - rot_services = [] - for rot_srv in manifest.get('services', []): - rot_services.append(RotService(**rot_srv)) - - irqs = [] - for irq in manifest.get('irqs', []): - irqs.append(Irq(**irq)) - - return Manifest( - manifest_file=manifest_file, - name=manifest['name'], - partition_id=_assert_int(manifest['id']), - partition_type=manifest['type'], - priority=manifest['priority'], - heap_size=_assert_int(manifest['heap_size']), - stack_size=_assert_int(manifest['stack_size']), - entry_point=manifest['entry_point'], - source_files=source_files, - mmio_regions=mmio_regions, - rot_services=rot_services, - extern_sids=manifest.get('extern_sids', []), - irqs=irqs - ) - - @property - def sids(self): - return [rot_srv.name for rot_srv in self.rot_services] - - @property - def autogen_folder(self): - return os.path.abspath(os.path.dirname(self.file)) - - def find_dependencies(self, manifests): - """ - Find other manifests which holds Root of Trust Services that - are declared as extern in this manifest - - :param manifests: list of manifests to filter - :return: list of manifest's names that holds current - extern Root of Trust Services - """ - - manifests = [man for man in manifests if man != self] - extern_sids_set = set(self.extern_sids) - return [manifest.name for manifest in manifests - if extern_sids_set.intersection(set(manifest.sids))] - - def templates_to_files(self, templates, templates_base, output_dir): - """ - Translates a list of partition templates to file names - - :param templates: List of partition templates - :param templates_base: Base directory of the templates - :param output_dir: Output directory (Default is autogen folder property) - :return: Dictionary of template to output file translation - """ - - generated_files = {} - for t in templates: - fname = os.path.relpath(t, templates_base) - _tpl = fname.replace('NAME', self.name.lower()) - full_path = path_join( - output_dir, - os.path.splitext(_tpl)[0] - ) - generated_files[t] = full_path - - return generated_files - - -def check_circular_call_dependencies(manifests): - """ - Check if there is a circular dependency between the partitions - described by the manifests. - A circular dependency might happen if there is a scenario in which a - partition calls a Root of Trust Service in another partition which than - calls another Root of Trust Service which resides in the - originating partition. - For example: Partition A has a Root of Trust Service A1 and extern sid B1, - partition B has a Root of Trust Service B1 and extern sid A1. - - :param manifests: List of the partition manifests. - :return: True if a circular dependency exists, false otherwise. - """ - - # Construct a call graph. - call_graph = {} - for manifest in manifests: - call_graph[manifest.name] = { - 'calls': manifest.find_dependencies(manifests), - 'called_by': set() - } - for manifest_name in call_graph: - for called in call_graph[manifest_name]['calls']: - call_graph[called]['called_by'].add(manifest_name) - - # Run topological sort on the call graph. - while len(call_graph) > 0: - # Find all the nodes that aren't called by anyone and - # therefore can be removed. - nodes_to_remove = [x for x in list(call_graph.keys()) if - len(call_graph[x]['called_by']) == 0] - - # If no node can be removed we have a circle. - if not nodes_to_remove: - return True - - # Remove the nodes. - for node in nodes_to_remove: - for called in call_graph[node]['calls']: - call_graph[called]['called_by'].remove(node) - call_graph.pop(node) - - return False - - -def validate_partition_manifests(manifests): - """ - Check the correctness of the manifests list - (no conflicts, no missing elements, etc.) - - :param manifests: List of the partition manifests - """ - for manifest in manifests: - assert isinstance(manifest, Manifest) - - partitions_names = {} - partitions_ids = {} - rot_service_ids = {} - rot_service_names = {} - rot_service_signals = {} - irq_signals = {} - irq_numbers = {} - all_extern_sids = set() - spe_contained_manifests = [] - - for manifest in manifests: - # Make sure the partition names are unique. - if manifest.name in partitions_names: - raise ValueError( - 'Partition name {} is not unique, ' - 'found in both {} and {}.'.format( - manifest.name, - partitions_names[manifest.name], - manifest.file - ) - ) - partitions_names[manifest.name] = manifest.file - - # Make sure the partition ID's are unique. - if manifest.id in partitions_ids: - raise ValueError( - 'Partition id {} is not unique, ' - 'found in both {} and {}.'.format( - manifest.id, - partitions_ids[manifest.id], - manifest.file - ) - ) - partitions_ids[manifest.id] = manifest.file - - is_nspe_callabale = False - - # Make sure all the Root of Trust Service IDs and signals are unique. - for rot_service in manifest.rot_services: - if rot_service.name in rot_service_names: - raise ValueError( - 'Root of Trust Service name {} is found ' - 'in both {} and {}.'.format( - rot_service.name, - rot_service_names[rot_service.name], - manifest.file - ) - ) - rot_service_names[rot_service.name] = manifest.file - - if rot_service.signal in rot_service_signals: - raise ValueError( - 'Root of Trust Service signal {} is found ' - 'in both {} and {}.'.format( - rot_service.signal, - rot_service_signals[rot_service.signal], - manifest.file - ) - ) - rot_service_signals[rot_service.signal] = manifest.file - - if rot_service.numeric_id in rot_service_ids: - raise ValueError( - 'Root of Trust Service identifier {} is found ' - 'in both {} and {}.'.format( - rot_service.numeric_id, - rot_service_ids[rot_service.numeric_id], - manifest.file - ) - ) - rot_service_ids[rot_service.numeric_id] = manifest.file - is_nspe_callabale |= rot_service.nspe_callable - - if not is_nspe_callabale: - spe_contained_manifests.append(manifest) - - # Make sure all the IRQ signals and line-numbers are unique. - for irq in manifest.irqs: - if irq.signal in irq_signals: - raise ValueError( - 'IRQ signal {} is found in both {} and {}.'.format( - irq.signal, - irq_signals[irq.signal], - manifest.file - ) - ) - irq_signals[irq.signal] = manifest.file - - if irq.line_num in irq_numbers: - raise ValueError( - 'IRQ line number {} is found in both {} and {}.'.format( - irq.line_num, - irq_numbers[irq.line_num], - manifest.file - ) - ) - irq_numbers[irq.line_num] = manifest.file - - all_extern_sids.update(manifest.extern_sids) - - # Check that all the external SIDs can be found. - declared_sids = set(rot_service_names.keys()) - for manifest in manifests: - extern_sids = set(manifest.extern_sids) - if not extern_sids.issubset(declared_sids): - missing_sids = extern_sids.difference(declared_sids) - raise ValueError( - "External SID(s) {} required by {} can't be found in " - "any partition manifest.".format( - ', '.join(missing_sids), manifest.file) - ) - - if check_circular_call_dependencies(manifests): - raise ValueError( - "Detected a circular call dependency between the partitions.") - - for manifest in spe_contained_manifests: - rot_services = set([service.name for service in manifest.rot_services]) - if not rot_services.intersection(all_extern_sids) and len( - manifest.irqs) == 0: - raise ValueError( - 'Partition {} (defined by {}) is not accessible from NSPE ' - 'and not referenced by any other partition.'.format( - manifest.name, - manifest.file - ) - ) - - -def is_test_manifest(manifest): - return 'TESTS' in manifest - - -def is_service_manifest(manifest): - return not is_test_manifest(manifest) - - -def manifests_discovery(root_dirs, ignore_paths): - service_manifest_files = set() - test_manifest_files = set() - for root_dir in root_dirs: - for root, dirs, files in os.walk(root_dir, followlinks=True): - # Filters paths if they are inside one of the ignore paths - if next((True for igp in ignore_paths if igp in root), False): - continue - - to_add = [path_join(root, f) for f in - fnmatch.filter(files, MANIFEST_FILE_PATTERN)] - service_manifest_files.update(filter(is_service_manifest, to_add)) - test_manifest_files.update(filter(is_test_manifest, to_add)) - - service_manifest_files = sorted(list(service_manifest_files)) - test_manifest_files = sorted(list(test_manifest_files)) - return service_manifest_files, test_manifest_files - - -def parse_manifests(manifests_files): - region_list = [] - manifests = [] - for manifest_file in manifests_files: - manifest_obj = Manifest.from_json(manifest_file) - manifests.append(manifest_obj) - for region in manifest_obj.mmio_regions: - region_list.append(region) - - return manifests, region_list - - -def generate_source_files( - templates, - render_args, - extra_filters=None -): - """ - Generate SPM common C code from manifests using given templates - - :param templates: Dictionary of template and their auto-generated products - :param render_args: Dictionary of arguments that should be passed to render - :param extra_filters: Dictionary of extra filters to use in the rendering - process - :return: Path to generated folder containing common generated files - """ - - rendered_files = [] - templates_dirs = list( - set([os.path.dirname(path) for path in templates]) - ) - template_files = {os.path.basename(t): t for t in templates} - - # Load templates for the code generation. - env = Environment( - loader=FileSystemLoader(templates_dirs), - lstrip_blocks=True, - trim_blocks=True, - undefined=StrictUndefined - ) - if extra_filters: - env.filters.update(extra_filters) - - for tf in template_files: - template = env.get_template(tf) - rendered_files.append( - (templates[template_files[tf]], template.render(**render_args))) - rendered_file_dir = os.path.dirname(templates[template_files[tf]]) - if not os.path.exists(rendered_file_dir): - os.makedirs(rendered_file_dir) - - for fname, data in rendered_files: - output_folder = os.path.dirname(fname) - if not os.path.isdir(output_folder): - os.makedirs(output_folder) - with open(fname, 'wt') as fh: - fh.write(data) diff --git a/tools/psa/partition_description_schema.json b/tools/psa/partition_description_schema.json deleted file mode 100644 index 1089c8dca6..0000000000 --- a/tools/psa/partition_description_schema.json +++ /dev/null @@ -1,196 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "schema for a partition description.", - "type": "object", - "required": ["name", "type", "priority", "id", "entry_point", "stack_size", "heap_size", "source_files"], - "anyOf": [ - {"required" : ["services"]}, - {"required" : ["irqs"]} - ], - "properties": { - "name": { - "description": "Alphanumeric C macro for referring to a partition. (all capital)", - "$ref": "#/definitions/c_macro" - }, - "type": { - "description": "Whether the partition is unprivileged or part of the trusted computing base.", - "enum": ["APPLICATION-ROT", "PSA-ROT"] - }, - "priority": { - "description": "Partition task priority.", - "enum": ["LOW", "NORMAL", "HIGH"] - }, - "id": { - "description": "Partition numeric unique positive identifier. (must be a positive 8 bytes hex string)", - "type": "string", - "pattern": "^0x[0-7][0-9a-fA-F]{7}$" - }, - "entry_point": { - "description": "C symbol name of the partition's entry point. (unmangled, use extern C if needed)", - "$ref": "#/definitions/c_symbol" - }, - "stack_size": { - "description": "Partition's task stack size in bytes.", - "$ref": "#/definitions/positive_integer_or_hex_string" - }, - "heap_size": { - "description": "Partition's task heap size in bytes.", - "$ref": "#/definitions/positive_integer_or_hex_string" - }, - "mmio_regions": { - "description": "List of Memory-Mapped IO region objects which the partition has access to.", - "type": "array", - "items": { - "anyOf": [{ - "$ref": "#/definitions/named_region" - }, - { - "$ref": "#/definitions/numbered_region" - } - ] - }, - "uniqueItems": true - }, - "services": { - "description": "List of RoT Service objects which the partition implements.", - "type": "array", - "items": { - "$ref": "#/definitions/service" - }, - "uniqueItems": true - }, - "extern_sids": { - "description": "List of SID which the partition code depends on and allowed to access.", - "type": "array", - "items": { - "$ref": "#/definitions/c_macro" - }, - "uniqueItems": true - }, - "source_files": { - "description": "List of source files relative to PSA Manifest file. A Secure Partition is built from explicit file list.", - "type": "array", - "items": { - "type": "string", - "pattern": "^[a-zA-Z0-9-_./]+$" - }, - "minItems": 1, - "uniqueItems": true - }, - "irqs": { - "description": "List of IRQ objects which the partition implements.", - "type": "array", - "items": { - "$ref": "#/definitions/irq" - }, - "uniqueItems": true - } - }, - "definitions": { - "c_macro": { - "type": "string", - "pattern": "^[A-Z_][A-Z0-9_]*$" - }, - "c_symbol": { - "type": "string", - "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$" - }, - "hex_string": { - "type": "string", - "pattern": "^0x(0*[1-9a-fA-F][0-9a-fA-F]*)$", - "minLength": 3, - "maxLength": 10 - }, - "positive_integer": { - "type": "integer", - "exclusiveMinimum": true, - "minimum": 0 - }, - "positive_integer_or_hex_string": { - "oneOf": [{ - "$ref": "#/definitions/positive_integer" - }, - { - "$ref": "#/definitions/hex_string" - } - ] - }, - "named_region": { - "description": "MMIO region which is described by it's C macro name and access permissions.", - "required": ["name", "permission"], - "properties": { - "name": { - "description": "Alphanumeric C macro for referring to the region.", - "$ref": "#/definitions/c_macro" - }, - "permission": { - "description": "Access permissions for the region.", - "enum": ["READ-ONLY", "READ-WRITE"] - } - } - }, - "numbered_region": { - "description": "MMIO region which is described by it's base address, size and access permissions.", - "required": ["base", "size", "permission"], - "properties": { - "base": { - "description": "The base address of the region.", - "$ref": "#/definitions/hex_string" - }, - "size": { - "description": "Size in bytes of the region.", - "$ref": "#/definitions/positive_integer_or_hex_string" - }, - "permission": { - "description": "Access permissions for the region.", - "enum": ["READ-ONLY", "READ-WRITE"] - } - } - }, - "service": { - "required": ["name", "identifier", "non_secure_clients", "signal"], - "properties": { - "name": { - "description": "Alphanumeric C macro for referring to a RoT Service from source code (all capital)", - "$ref": "#/definitions/c_macro" - }, - "identifier": { - "description": "The integer value of the NAME field", - "$ref": "#/definitions/positive_integer_or_hex_string" - }, - "non_secure_clients": { - "description": "Denote whether the RoT Service is exposed to non-secure clients.", - "type": "boolean" - }, - "signal": { - "description": "Alphanumeric C macro for referring to the RoT Service's signal value. (all capital)", - "$ref": "#/definitions/c_macro" - }, - "minor_version": { - "description": "Optional: Minor version number of the RoT Service's interface.", - "$ref": "#/definitions/positive_integer", - "default": 1 - }, - "minor_policy": { - "description": "Optional: Minor version policy to apply on connections to the RoT Service.", - "enum": ["STRICT", "RELAXED"], - "default": "STRICT" - } - } - }, - "irq": { - "required": ["line_num", "signal"], - "properties": { - "line_num": { - "description": "Interrupt line number for registering to ISR table entry and enable/disable the specific IRQ once received.", - "type": "integer", - "minimum": 0 - }, - "signal": { - "description": "Alphanumeric C macro for referring to the IRQ's signal value. (all capital)", - "$ref": "#/definitions/c_macro" - } - } - } - } -} diff --git a/tools/psa/release.py b/tools/psa/release.py deleted file mode 100644 index 8034df81f4..0000000000 --- a/tools/psa/release.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/python -# Copyright (c) 2017-2018 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 subprocess -import sys -import shutil -import logging -import argparse - -FNULL = open(os.devnull, 'w') -ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), - os.pardir, os.pardir)) -sys.path.insert(0, ROOT) -from tools.toolchains import TOOLCHAIN_CLASSES -from tools.targets import Target, TARGET_MAP, TARGET_NAMES - - -logging.basicConfig(level=logging.DEBUG, - format='[%(name)s] %(asctime)s: %(message)s.', - datefmt='%H:%M:%S') -logger = logging.getLogger('PSA release tool') -subprocess_output = None -subprocess_err = None - -MAKE_PY_LOCATTION = os.path.join(ROOT, 'tools', 'make.py') -TEST_PY_LOCATTION = os.path.join(ROOT, 'tools', 'test.py') -TFM_MBED_APP = os.path.join(ROOT, 'tools', 'psa', 'tfm', 'mbed_app.json') -PSA_TESTS = { - '*psa-spm_smoke': ['USE_PSA_TEST_PARTITIONS', 'USE_SMOKE_TESTS_PART1'], - '*psa-spm_client': ['USE_PSA_TEST_PARTITIONS', 'USE_CLIENT_TESTS_PART1'], - '*psa-spm_server': ['USE_PSA_TEST_PARTITIONS', 'USE_SERVER_TESTS_PART1', - 'USE_SERVER_TESTS_PART2'], - '*psa-crypto_access_control': ['USE_PSA_TEST_PARTITIONS', - 'USE_CRYPTO_ACL_TEST'] -} -PSA_AUTOGEN_LOCATION = os.path.join(ROOT, 'components', 'TARGET_PSA') - -def _psa_backend(target): - """ - Returns a target PSA backend. - - :param target: Target name as in targets.json - :return: PSA backend as string (TFM/MBED_SPM) - """ - return 'TFM' if 'TFM' in Target.get_target(target).labels else 'MBED_SPM' - - -def _get_target_info(target, toolchain): - """ - Creates a PSA target tuple with default toolchain and - artifact delivery directory. - - :param target: Target name. - :return: tuple (target, toolchain, delivery directory). - """ - delivery_dir = os.path.join(ROOT, 'targets', - TARGET_MAP[target].delivery_dir) - - if not os.path.exists(delivery_dir): - raise Exception("{} does not have delivery_dir".format(target)) - - if toolchain: - if toolchain not in TARGET_MAP[target].supported_toolchains: - raise Exception("Toolchain {} is not supported by {}".format(toolchain, TARGET_MAP[target].name)) - return tuple([TARGET_MAP[target].name, - toolchain, - delivery_dir]) - else: - return tuple([TARGET_MAP[target].name, - TARGET_MAP[target].default_toolchain, - delivery_dir]) - - -def _get_psa_secure_targets_list(): - """ - Creates a list of PSA secure targets. - - :return: List of PSA secure targets. - """ - return [str(t) for t in TARGET_NAMES if - Target.get_target(t).is_PSA_secure_target] - - -def verbose_check_call(cmd, check_call=True): - """ - Calls a shell command and logs the call. - - :param cmd: command to run as a list - :param check_call: choose subprocess method (call/check_call) - :return: return code of the executed command - """ - logger.info('Running: {}'.format(' '.join(cmd))) - if check_call: - return subprocess.check_call(cmd, stdout=subprocess_output, - stderr=subprocess_err) - - return subprocess.call(cmd, stdout=subprocess_output, stderr=subprocess_err) - - -def get_mbed_official_psa_release(target=None, toolchain=None): - """ - Creates a list of PSA targets with default toolchain and - artifact delivery directory. - - :param target: Ask for specific target, None for all targets. - :return: List of tuples (target, toolchain, delivery directory). - """ - psa_secure_targets = _get_psa_secure_targets_list() - logger.debug("Found the following PSA targets: {}".format( - ', '.join(psa_secure_targets))) - if target is not None: - return [_get_target_info(target, toolchain)] - - return [_get_target_info(t, toolchain) for t in psa_secure_targets] - - -def create_mbed_ignore(build_dir): - """ - Creates a .mbedignore file in a given directory. - - :param build_dir: Directory to create .mbedignore file. - """ - logger.debug('Created .mbedignore in {}'.format(build_dir)) - with open(os.path.join(build_dir, '.mbedignore'), 'w') as f: - f.write('*\n') - - -def build_tests(target, toolchain, profile, args): - """ - Builds secure images for tests. - - :param target: target to be built. - :param toolchain: toolchain to be used. - :param profile: build profile. - :param args: list of extra arguments. - """ - build_dir = os.path.join(ROOT, 'BUILD', 'tests', target) - if os.path.exists(build_dir): - logger.info("BUILD directory deleted: {}".format(build_dir)) - shutil.rmtree(build_dir) - - for test in PSA_TESTS.keys(): - logger.info( - "Building tests image({}) for {} using {} with {} profile".format( - test, target, toolchain, profile)) - - test_defines = ['-D{}'.format(define) for define in PSA_TESTS[test]] - cmd = [ - sys.executable, TEST_PY_LOCATTION, - '--greentea', - '--profile', profile, - '-t', toolchain, - '-m', target, - '--source', ROOT, - '--build', build_dir, - '--test-spec', os.path.join(build_dir, 'test_spec.json'), - '--build-data', os.path.join(build_dir, 'build_data.json'), - '-n', test] + test_defines + args - - if _psa_backend(target) is 'TFM': - cmd += ['--app-config', TFM_MBED_APP] - - verbose_check_call(cmd) - logger.info( - "Finished Building tests image({}) for {}".format(test, target)) - - -def build_default_image(target, toolchain, profile, args): - """ - Builds the default secure image. - - :param target: target to be built. - :param toolchain: toolchain to be used. - :param profile: build profile. - :param args: list of extra arguments. - """ - logger.info("Building default image for {} using {} with {} profile".format( - target, toolchain, profile)) - - build_dir = os.path.join(ROOT, 'BUILD', target) - if os.path.exists(build_dir): - logger.info("BUILD directory deleted: {}".format(build_dir)) - shutil.rmtree(build_dir) - - cmd = [ - sys.executable, MAKE_PY_LOCATTION, - '-t', toolchain, - '-m', target, - '--profile', profile, - '--source', ROOT, - '--build', build_dir] + args - - if _psa_backend(target) is 'TFM': - cmd += ['--app-config', TFM_MBED_APP] - else: - cmd += ['--artifact-name', 'psa_release_1.0'] - - verbose_check_call(cmd) - logger.info( - "Finished building default image for {} successfully".format(target)) - - -def commit_binaries(target, delivery_dir, toolchain): - """ - Commits changes in secure binaries. - - :param target: Target name. - :param delivery_dir: Secure images should be moved to this folder - by the build system. - """ - changes_made = verbose_check_call([ - 'git', - '-C', ROOT, - 'diff', '--exit-code', '--quiet', - delivery_dir], check_call=False) - - if changes_made: - logger.info("Change in images for {} has been detected".format(target)) - verbose_check_call([ - 'git', - '-C', ROOT, - 'add', os.path.relpath(delivery_dir, ROOT)]) - - logger.info("Committing images for {}".format(target)) - commit_message = '--message="Update secure binaries for %s (%s)"' % ( - target, toolchain) - verbose_check_call([ - 'git', - '-C', ROOT, - 'commit', - commit_message]) - else: - logger.info("No changes detected in {}, Skipping commit".format(target)) - -def commit_psa_autogen(): - """ - Commit changes related to auto-generated PSA components and services - """ - changes_made = verbose_check_call([ - 'git', - '-C', ROOT, - 'diff', '--exit-code', '--quiet', - PSA_AUTOGEN_LOCATION], check_call=False) - - if changes_made: - logger.info("Change in PSA auto-generated files has been detected") - verbose_check_call([ - 'git', - '-C', ROOT, - 'add', PSA_AUTOGEN_LOCATION]) - - logger.info("Committing changes...") - commit_message = ('--message=Update PSA auto-generated components and ' - 'services') - verbose_check_call([ - 'git', - '-C', ROOT, - 'commit', - commit_message]) - else: - logger.info("No changes has been detected for PSA autogen, " - "Skipping commit") - -def build_psa_platform(target, toolchain, delivery_dir, debug, git_commit, - skip_tests, args): - """ - Calls the correct build function and commits if requested. - - :param target: Target name. - :param toolchain: Toolchain to be used. - :param delivery_dir: Artifact directory, where images should be placed. - :param debug: Build with debug profile. - :param git_commit: Commit the changes. - :param skip_tests: skip the test images build phase. - :param args: list of extra arguments. - """ - profile = 'debug' if debug else 'release' - if not skip_tests: - build_tests(target, toolchain, profile, args) - - build_default_image(target, toolchain, profile, args) - if git_commit: - commit_binaries(target, delivery_dir, toolchain) - commit_psa_autogen() - - -def get_parser(): - parser = argparse.ArgumentParser() - parser.add_argument("-m", "--mcu", - help="build for the given MCU", - default=None, - choices=_get_psa_secure_targets_list(), - metavar="MCU") - - parser.add_argument("-t", "--tc", - help="build for the given tool chain (default is default_toolchain)", - default=None) - - parser.add_argument("-d", "--debug", - help="set build profile to debug", - action="store_true", - default=False) - - parser.add_argument('-q', '--quiet', - action="store_true", - default=False, - help="No Build log will be printed") - - parser.add_argument('-l', '--list', - action="store_true", - default=False, - help="Print supported PSA secure targets") - - parser.add_argument("--commit", - help="create a git commit for each platform", - action="store_true", - default=False) - - parser.add_argument('--skip-tests', - action="store_true", - default=False, - help="skip the test build phase") - - parser.add_argument('-x', '--extra', - dest='extra_args', - default=[], - nargs=argparse.REMAINDER, - help="additional build parameters") - - return parser - - -def prep_build_dir(): - build_dir = os.path.join(ROOT, 'BUILD') - if not os.path.exists(build_dir): - logger.info("BUILD directory created in {}".format(build_dir)) - os.makedirs(build_dir) - create_mbed_ignore(build_dir) - - -def main(): - parser = get_parser() - options = parser.parse_args() - if options.quiet: - logger.setLevel(logging.INFO) - global subprocess_output, subprocess_err - subprocess_output = FNULL - subprocess_err = subprocess.STDOUT - - if options.list: - logger.info("Available platforms are: {}".format( - ', '.join([t for t in _get_psa_secure_targets_list()]))) - return - - prep_build_dir() - psa_platforms_list = get_mbed_official_psa_release(options.mcu, options.tc) - logger.info("Building the following platforms: {}".format( - ', '.join([t[0] for t in psa_platforms_list]))) - - toolchains_set = set([t[1] for t in psa_platforms_list]) - for tc in toolchains_set: - if not TOOLCHAIN_CLASSES[tc].check_executable(): - raise Exception("Toolchain {} was not found in PATH".format(tc)) - - for target, tc, directory in psa_platforms_list: - build_psa_platform(target, tc, directory, options.debug, - options.commit, options.skip_tests, - options.extra_args) - - logger.info("Finished Updating PSA images") - - -if __name__ == '__main__': - main() diff --git a/tools/psa/spm_template_file_list.json b/tools/psa/spm_template_file_list.json deleted file mode 100644 index 2c4125114e..0000000000 --- a/tools/psa/spm_template_file_list.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "name": "Secure Partition ID definitions", - "template": "tools/psa/templates/tfm_partition_defs.inc.tpl", - "output": "TARGET_TFM/COMPONENT_SPE/inc/tfm_partition_defs.inc" - }, - { - "name": "Secure Partition declarations", - "template": "tools/psa/templates/tfm_partition_list.inc.tpl", - "output": "TARGET_TFM/COMPONENT_SPE/inc/tfm_partition_list.inc" - }, - { - "name": "Secure Service list", - "template": "tools/psa/templates/tfm_service_list.inc.tpl", - "output": "TARGET_TFM/COMPONENT_SPE/inc/tfm_service_list.inc" - }, - { - "name": "Secure Service signals list", - "template": "tools/psa/templates/tfm_spm_signal_defs.h.tpl", - "output": "TARGET_TFM/COMPONENT_SPE/inc/tfm_spm_signal_defs.h" - }, - { - "name": "mbed-SPM database", - "template": "tools/psa/templates/psa_setup.c.tpl", - "output": "TARGET_MBED_SPM/COMPONENT_SPE/psa_setup.c" - }, - { - "name": "Mappings from RoT Service names to SIDs", - "template": "tools/psa/templates/sid.h.tpl", - "output": "services/inc/autogen_sid.h" - }, - { - "name": "Details partition defines and structures", - "template": "tools/psa/templates/mbed_spm_partitions.h.tpl", - "output": "services/inc/mbed_spm_partitions.h" - } -] diff --git a/tools/psa/templates/mbed_spm_partitions.h.tpl b/tools/psa/templates/mbed_spm_partitions.h.tpl deleted file mode 100644 index 01b3af4d25..0000000000 --- a/tools/psa/templates/mbed_spm_partitions.h.tpl +++ /dev/null @@ -1,104 +0,0 @@ -/* Copyright (c) 2017-2019 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. - */ - -/******************************************************************************* - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT. - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * Template Version 1.0 - * Generated by tools/psa/generate_partition_code.py Version {{script_ver}} - ******************************************************************************/ - -#ifndef __MBED_SPM_PARTITIONS_H___ -#define __MBED_SPM_PARTITIONS_H___ - -{% macro do_parition(partition) -%} - -/* ----------------------------------------------------------------------------- - * {{partition.name|upper}} defines - * -------------------------------------------------------------------------- */ -#define {{partition.name|upper}}_ID {{partition.id}} - -{% if partition.rot_services|count > 0 %} -#define {{partition.name|upper}}_ROT_SRV_COUNT ({{partition.rot_services|count}}UL) -{% endif %} -#define {{partition.name|upper}}_EXT_ROT_SRV_COUNT ({{partition.extern_sids|count}}UL) - -{% for irq in partition.irqs %} -#define {{irq.signal|upper}}_POS ({{loop.index + 3 }}UL) -#define {{irq.signal|upper}} (1UL << {{irq.signal|upper}}_POS) -{% endfor %} - -{% if partition.irqs|count > 0 %} -#define {{partition.name|upper}}_WAIT_ANY_IRQ_MSK (\ -{% for irq in partition.irqs %} - {{irq.signal|upper}}{{")" if loop.last else " | \\"}} -{% endfor %} -{% else %} -#define {{partition.name|upper}}_WAIT_ANY_IRQ_MSK (0) -{% endif %} - -{% for rot_srv in partition.rot_services %} -#define {{rot_srv.signal|upper}}_POS ({{loop.index + 3 + partition.irqs|count}}UL) -#define {{rot_srv.signal|upper}} (1UL << {{rot_srv.signal|upper}}_POS) -{% endfor %} - -{% if partition.rot_services|count > 0 %} -#define {{partition.name|upper}}_WAIT_ANY_SID_MSK (\ -{% for rot_srv in partition.rot_services %} - {{rot_srv.signal|upper}}{{")" if loop.last else " | \\"}} -{% endfor %} -{% else %} -#define {{partition.name|upper}}_WAIT_ANY_SID_MSK (0) -{% endif %} - -{% if partition.irqs|count > 0 %} -uint32_t spm_{{partition.name|lower}}_signal_to_irq_mapper(uint32_t signal); -{% endif %} -{%- endmacro %} -{# ------------------ macro do_parition(partition) -------------------------- #} - -/****************** Common definitions ****************************************/ - -/* PSA reserved event flags */ -#define PSA_RESERVED1_POS (1UL) -#define PSA_RESERVED1_MSK (1UL << PSA_RESERVED1_POS) - -#define PSA_RESERVED2_POS (2UL) -#define PSA_RESERVED2_MSK (1UL << PSA_RESERVED2_POS) - -/****************** Service Partitions ****************************************/ - -{% for partition in service_partitions %} -{{ do_parition(partition) }} -{% endfor %} - -/****************** Test Partitions *******************************************/ - -#ifdef USE_PSA_TEST_PARTITIONS - -{% for test_partition in test_partitions %} -#ifdef USE_{{test_partition.name|upper}} -{{ do_parition(test_partition) }} -#endif // USE_{{test_partition.name|upper}} - -{% endfor %} - -#endif // USE_PSA_TEST_PARTITIONS - -#endif // __MBED_SPM_PARTITIONS_H___ -{# End of file #} diff --git a/tools/psa/templates/psa_setup.c.tpl b/tools/psa/templates/psa_setup.c.tpl deleted file mode 100644 index 54e8ec994f..0000000000 --- a/tools/psa/templates/psa_setup.c.tpl +++ /dev/null @@ -1,281 +0,0 @@ -/* Copyright (c) 2017-2019 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. - */ - -/******************************************************************************* - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT. - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * Template Version 1.0 - * Generated by tools/psa/generate_partition_code.py Version {{script_ver}} - ******************************************************************************/ - -#include "cmsis.h" -#include "rtx_os.h" - -#include "mbed_toolchain.h" /* For using MBED_ALIGN macro */ - -#include "spm_panic.h" -#include "spm_internal.h" -#include "handles_manager.h" -#include "mbed_spm_partitions.h" - -#include "psa_manifest/sid.h" - -extern spm_db_t g_spm; - -{% macro do_parition(partition) -%} - -/* ----------------------------------------------------------------------------- - * {{partition.name|upper}} declarations - * -------------------------------------------------------------------------- */ -MBED_ALIGN(8) static uint8_t {{partition.name|lower}}_thread_stack[{{partition.stack_size}}] = {0}; - -static osRtxThread_t {{partition.name|lower}}_thread_cb = {0}; -static const osThreadAttr_t {{partition.name|lower}}_thread_attr = { - .name = "{{partition.name|lower}}", - .attr_bits = 0, - .cb_mem = &{{partition.name|lower}}_thread_cb, - .cb_size = sizeof({{partition.name|lower}}_thread_cb), - .stack_mem = {{partition.name|lower}}_thread_stack, - .stack_size = {{partition.stack_size}}, - .priority = {{partition.priority_mbed}}, - .tz_module = 0, - .reserved = 0 -}; - -static osRtxMutex_t {{partition.name|lower}}_mutex = {0}; -static const osMutexAttr_t {{partition.name|lower}}_mutex_attr = { - .name = "{{partition.name|lower}}_mutex", - .attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust, - .cb_mem = &{{partition.name|lower}}_mutex, - .cb_size = sizeof({{partition.name|lower}}_mutex), -}; - -{% if partition.rot_services|count > 0 %} -spm_rot_service_t {{partition.name|lower}}_rot_services[] = { -{% for rot_srv in partition.rot_services %} - { - .sid = {{rot_srv.name|upper}}, - .mask = {{rot_srv.signal|upper}}, - .partition = NULL, - .min_version = {{rot_srv.minor_version}}, - .min_version_policy = PSA_MINOR_VERSION_POLICY_{{rot_srv.minor_policy|upper}}, -{% if rot_srv.nspe_callable %} - .allow_nspe = true, -{% else %} - .allow_nspe = false, -{% endif %} - .queue = { - .head = NULL, - .tail = NULL - } - }, -{% endfor %} -}; - -{% endif %} -{% if partition.extern_sids|count > 0 %} -/* External SIDs used by {{partition.name}} */ -const uint32_t {{partition.name|lower}}_external_sids[{{partition.extern_sids|count}}] = { -{% for sid in partition.extern_sids %} - {{sid|upper}}, -{% endfor %} -}; - -{% endif %} -{% if partition.irqs|count > 0 %} -// Mapper function from irq signal to interupts number -IRQn_Type spm_{{partition.name|lower}}_signal_to_irq_mapper(uint32_t signal) -{ - SPM_ASSERT({{partition.name|upper}}_WAIT_ANY_IRQ_MSK & signal); - switch(signal){ - {% for irq in partition.irqs %} - case {{ irq.signal }}: - return (IRQn_Type){{irq.line_num}}; - break; - {% endfor %} - default: - break; - } - - SPM_PANIC("Unknown signal number %lu", signal); - return 0; -} - -{% for irq in partition.irqs %} -// ISR handler for interrupt {irq.line_num} -void spm_irq_{{irq.signal}}_{{partition.name|lower}}(void) -{ - spm_partition_t *partition = NULL; - for (uint32_t i = 0; i < g_spm.partition_count; ++i) { - if (g_spm.partitions[i].partition_id == {{partition.name|upper}}_ID) { - partition = &(g_spm.partitions[i]); - } - } - SPM_ASSERT(partition); - - NVIC_DisableIRQ((IRQn_Type){{irq.line_num}}); // will be enabled by psa_eoi() - osThreadFlagsSet(partition->thread_id, {{irq.signal|upper}}); // notify partition -} - -{% endfor %} -{% endif %} -extern void {{partition.entry_point}}(void *ptr); - -void {{partition.name|lower}}_init(spm_partition_t *partition) -{ - if (NULL == partition) { - SPM_PANIC("partition is NULL!\n"); - } - - partition->mutex = osMutexNew(&{{partition.name|lower}}_mutex_attr); - if (NULL == partition->mutex) { - SPM_PANIC("Failed to create mutex for secure partition {{partition.name|lower}}!\n"); - } - - {% if partition.rot_services|count > 0 %} - for (uint32_t i = 0; i < {{partition.name|upper}}_ROT_SRV_COUNT; ++i) { - {{partition.name|lower}}_rot_services[i].partition = partition; - } - partition->rot_services = {{partition.name|lower}}_rot_services; - {% else %} - partition->rot_services = NULL; - {% endif %} - - partition->thread_id = osThreadNew({{partition.entry_point}}, NULL, &{{partition.name|lower}}_thread_attr); - if (NULL == partition->thread_id) { - SPM_PANIC("Failed to create start main thread of partition {{partition.name|lower}}!\n"); - } -} - -{%- endmacro %} -{# -------------- macro do_parition(partition) ----------------------------- #} -/****************** Service Partitions ****************************************/ - -{% for partition in service_partitions %} -{{do_parition(partition)}} - -{% endfor %} - -/****************** Test Partitions *******************************************/ -#ifdef USE_PSA_TEST_PARTITIONS - -{% for test_partition in test_partitions %} -#ifdef USE_{{test_partition.name|upper}} -{{ do_parition(test_partition) }} - -#endif // USE_{{test_partition.name|upper}} - -{% endfor %} -#endif // USE_PSA_TEST_PARTITIONS - -{# -------------- spm_db_entry(partition) ----------------------------------- #} -{% macro spm_db_entry(partition) -%} - - /* {{partition.name|upper}} */ - { - .partition_id = {{partition.name|upper}}_ID, - .thread_id = 0, - .flags = {{partition.name|upper}}_WAIT_ANY_SID_MSK | {{partition.name|upper}}_WAIT_ANY_IRQ_MSK, - .rot_services = NULL, - {% if partition.rot_services|count > 0 %} - .rot_services_count = {{partition.name|upper}}_ROT_SRV_COUNT, - {% else %} - .rot_services_count = 0, - {% endif %} - {% if partition.extern_sids|count > 0 %} - .extern_sids = {{partition.name|lower}}_external_sids, - {% else %} - .extern_sids = NULL, - {% endif %} - .extern_sids_count = {{partition.name|upper}}_EXT_ROT_SRV_COUNT, - {% if partition.irqs|count > 0 %} - .irq_mapper = spm_{{partition.name|lower}}_signal_to_irq_mapper, - {% else %} - .irq_mapper = NULL, - {% endif %} - }, -{%- endmacro %} -{# -------------- spm_db_entry(partition) ----------------------------------- #} -/****************** SPM DB initialization *************************************/ -spm_partition_t g_partitions[] = { -{% for partition in service_partitions %} - {{spm_db_entry(partition)}} - -{% endfor %} -#ifdef USE_PSA_TEST_PARTITIONS - -{% for test_partition in test_partitions %} -#ifdef USE_{{test_partition.name|upper}} {{ spm_db_entry(test_partition) }} -#endif // USE_{{test_partition.name|upper}} - -{% endfor %} -#endif // USE_PSA_TEST_PARTITIONS - -}; - -/****************** MMIO regions **********************************************/ -{% if regions|count > 0 %} -/****************** Sanity checks *********************************************/ -/* Check all the defined memory regions for overlapping. */ -{% for region_pair in region_pair_list %} -MBED_STATIC_ASSERT( - ((uintptr_t)({{region_pair[0].base}}) + {{region_pair[0].size}} - 1 < (uintptr_t)({{region_pair[1].base}})) || - ((uintptr_t)({{region_pair[1].base}}) + {{region_pair[1].size}} - 1 < (uintptr_t)({{region_pair[0].base}})), - "The region with base {{region_pair[0].base}} and size {{region_pair[0].size}} overlaps with the region with base {{region_pair[1].base}} and size {{region_pair[1].size}}!"); - -{% endfor %} -/****************** MMIO regions definition ***********************************/ -/* A list of all the memory regions. */ -const mem_region_t mem_regions[] = { -{% for region in regions %} - { (uint32_t)({{region.base}}), {{region.size}}, {{region.permission}}, {{region.partition_id}} }, -{% endfor %} -}; -{% else %} -const mem_region_t *mem_regions = NULL; -{% endif %} -const uint32_t mem_region_count = {{regions|count}}; - -/****************** Partitions init function *********************************/ -uint32_t init_partitions(spm_partition_t **partitions) -{ - uint32_t partition_idx = 0; - - if (NULL == partitions) { - SPM_PANIC("partitions is NULL!\n"); - } - -{% for partition in service_partitions %} - {{partition.name|lower}}_init(&(g_partitions[partition_idx++])); -{% endfor %} - -#ifdef USE_PSA_TEST_PARTITIONS - -{% for test_partition in test_partitions %} -#ifdef USE_{{test_partition.name|upper}} - {{test_partition.name|lower}}_init(&(g_partitions[partition_idx++])); -#endif // USE_{{test_partition.name|upper}} - -{% endfor %} -#endif // USE_PSA_TEST_PARTITIONS - - *partitions = g_partitions; - return partition_idx; -} - -{# End of file #} diff --git a/tools/psa/templates/sid.h.tpl b/tools/psa/templates/sid.h.tpl deleted file mode 100644 index 7cc6e1202d..0000000000 --- a/tools/psa/templates/sid.h.tpl +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (c) 2019 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. - */ - -/******************************************************************************* - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT. - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * Template Version 1.0 - * Generated by tools/psa/generate_partition_code.py Version {{script_ver}} - ******************************************************************************/ -{% macro parition_sid(partition) -%} -/* ----------------------------------------------------------------------------- - * {{partition.name|upper}} Service IDs - * -------------------------------------------------------------------------- */ - -{% for rot_srv in partition.rot_services %} -#define {{rot_srv.name|upper}} {{rot_srv.id}} -{% endfor %} - -{%- endmacro %} -{# -------------- macro parition_sid(partition) ---------------------------- #} - -/****************** Service Partitions ****************************************/ - -{% for partition in service_partitions %} -{{parition_sid(partition)}} -{% endfor %} -/****************** Test Partitions *******************************************/ - -{% for partition in test_partitions %} -{{parition_sid(partition)}} -{% endfor %} -{# End of file #} diff --git a/tools/psa/templates/tfm_partition_defs.inc.tpl b/tools/psa/templates/tfm_partition_defs.inc.tpl deleted file mode 100644 index d462164a26..0000000000 --- a/tools/psa/templates/tfm_partition_defs.inc.tpl +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (c) 2017-2019 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. - */ - -/******************************************************************************* - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT. - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * Template Version 1.0 - * Generated by tools/psa/generate_partition_code.py Version {{script_ver}} - ******************************************************************************/ - -#ifndef __TFM_PARTITION_DEFS_INC__ -#define __TFM_PARTITION_DEFS_INC__ - -/*************************** Service Partitions *******************************/ - -{% for partition in service_partitions %} -{% set partition_loop = loop %} -#define {{partition.name|upper}}_ID (TFM_SP_BASE + {{ partition_loop.index0 }}) -{% endfor %} - -/*************************** Test Partitions **********************************/ - -#ifdef USE_PSA_TEST_PARTITIONS - -{% for partition in test_partitions %} -{% set partition_loop = loop %} -#ifdef USE_{{partition.name|upper}} -#define {{partition.name|upper}}_ID (TFM_SP_BASE + {{service_partitions|count}} + {{ partition_loop.index0 }}) -#endif - -{% endfor %} -#endif // USE_PSA_TEST_PARTITIONS - -#ifdef USE_PSA_TEST_PARTITIONS -#define TFM_MAX_USER_PARTITIONS ({{service_partitions|count}} + {{test_partitions|count}}) -#else -#define TFM_MAX_USER_PARTITIONS ({{service_partitions|count}}) -#endif - -#endif // __TFM_PARTITION_DEFS_INC__ -{# End of file #} diff --git a/tools/psa/templates/tfm_partition_list.inc.tpl b/tools/psa/templates/tfm_partition_list.inc.tpl deleted file mode 100644 index e05a639307..0000000000 --- a/tools/psa/templates/tfm_partition_list.inc.tpl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -/******************************************************************************* - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT. - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * Template Version 1.0 - * Generated by tools/psa/generate_partition_code.py Version {{script_ver}} - ******************************************************************************/ - -#ifndef __TFM_PARTITION_LIST_INC__ -#define __TFM_PARTITION_LIST_INC__ - -/*************************** Service Partitions *******************************/ -{% for partition in service_partitions %} -/* ----------------------------------------------------------------------------- - * {{partition.name|upper}} - * -------------------------------------------------------------------------- */ -PARTITION_DECLARE({{partition.name|upper}}, 0 - | SPM_PART_FLAG_IPC - , "{{partition.type}}", {{partition.id}}, {{partition.priority_tfm}}, {{partition.stack_size}}); -PARTITION_ADD_INIT_FUNC({{partition.name|upper}}, {{partition.entry_point}}); - -{% endfor %} -/*************************** Test Partitions **********************************/ -#ifdef USE_PSA_TEST_PARTITIONS - -{% for partition in test_partitions %} -#ifdef USE_{{partition.name|upper}} -/* ----------------------------------------------------------------------------- - * {{partition.name|upper}} - * -------------------------------------------------------------------------- */ -PARTITION_DECLARE({{partition.name|upper}}, 0 - | SPM_PART_FLAG_IPC - , "{{partition.type}}", {{partition.id}}, {{partition.priority_tfm}}, {{partition.stack_size}}); -PARTITION_ADD_INIT_FUNC({{partition.name|upper}}, {{partition.entry_point}}); -#endif // USE_{{partition.name|upper}} - -{% endfor %} -#endif // USE_PSA_TEST_PARTITIONS - -#endif // __TFM_PARTITION_LIST_INC__ -{# End of file #} diff --git a/tools/psa/templates/tfm_service_list.inc.tpl b/tools/psa/templates/tfm_service_list.inc.tpl deleted file mode 100644 index 3f0a83c66a..0000000000 --- a/tools/psa/templates/tfm_service_list.inc.tpl +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -/******************************************************************************* - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT. - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * Template Version 1.0 - * Generated by tools/psa/generate_partition_code.py Version {{script_ver}} - ******************************************************************************/ - -#ifndef __TFM_SERVICE_LIST_INC__ -#define __TFM_SERVICE_LIST_INC__ - -/*************************** Service Partitions *******************************/ -{% for partition in service_partitions %} -/* ----------------------------------------------------------------------------- - * {{partition.name|upper}} Services - * -------------------------------------------------------------------------- */ -{% for rot_srv in partition.rot_services %} -{"{{rot_srv.name|upper}}", {{partition.name|upper}}_ID, {{rot_srv.signal|upper}}, {{rot_srv.id}}, {% if rot_srv.nspe_callable %}true{% else %}false{% endif %}, {{rot_srv.minor_version}}, TFM_VERSION_POLICY_{{rot_srv.minor_policy|upper}}}, -{% endfor %} - -{% endfor %} -/*************************** Test Partitions **********************************/ -#ifdef USE_PSA_TEST_PARTITIONS - -{% for partition in test_partitions %} -#ifdef USE_{{partition.name|upper}} -/* ----------------------------------------------------------------------------- - * {{partition.name|upper}} Services - * -------------------------------------------------------------------------- */ -{% for rot_srv in partition.rot_services %} -{"{{rot_srv.name|upper}}", {{partition.name|upper}}_ID, {{rot_srv.signal|upper}}, {{rot_srv.id}}, {% if rot_srv.nspe_callable %}true{% else %}false{% endif %}, {{rot_srv.minor_version}}, TFM_VERSION_POLICY_{{rot_srv.minor_policy|upper}}}, -{% endfor %} -#endif // USE_{{partition.name|upper}} - -{% endfor %} -#endif // USE_PSA_TEST_PARTITIONS - -#endif // __TFM_SERVICE_LIST_INC__ -{# End of file #} diff --git a/tools/psa/templates/tfm_spm_signal_defs.h.tpl b/tools/psa/templates/tfm_spm_signal_defs.h.tpl deleted file mode 100644 index cf37eab490..0000000000 --- a/tools/psa/templates/tfm_spm_signal_defs.h.tpl +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2018-2019, Arm Limited. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -/******************************************************************************* - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * THIS FILE IS AN AUTO-GENERATED FILE - DO NOT MODIFY IT. - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * Template Version 1.0 - * Generated by tools/psa/generate_partition_code.py Version {{script_ver}} - ******************************************************************************/ - -#ifndef __TFM_SPM_SIGNAL_DEFS_H__ -#define __TFM_SPM_SIGNAL_DEFS_H__ - -/*************************** Service Partitions *******************************/ -{% for partition in service_partitions %} -/* ----------------------------------------------------------------------------- - * {{partition.name|upper}} Signals - * -------------------------------------------------------------------------- */ -{% for rot_srv in partition.rot_services %} -#define {{rot_srv.signal|upper}}_POS ({{loop.index + 3}}UL) -#define {{rot_srv.signal|upper}} (1UL << {{rot_srv.signal|upper}}_POS) -{% endfor %} - -{% endfor %} -/*************************** Test Partitions **********************************/ -#ifdef USE_PSA_TEST_PARTITIONS - -{% for partition in test_partitions %} -#ifdef USE_{{partition.name|upper}} -/* ----------------------------------------------------------------------------- - * {{partition.name|upper}} Signals - * -------------------------------------------------------------------------- */ -{% for rot_srv in partition.rot_services %} -#define {{rot_srv.signal|upper}}_POS ({{loop.index + 3}}UL) -#define {{rot_srv.signal|upper}} (1UL << {{rot_srv.signal|upper}}_POS) -{% endfor %} -#endif // USE_{{partition.name|upper}} - -{% endfor %} -#endif // USE_PSA_TEST_PARTITIONS - -#endif // __TFM_SPM_SIGNAL_DEFS_H__ -{# End of file #} diff --git a/tools/psa/tfm/__init__.py b/tools/psa/tfm/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/psa/tfm/bin_utils/__init__.py b/tools/psa/tfm/bin_utils/__init__.py deleted file mode 100644 index 3aaffc4847..0000000000 --- a/tools/psa/tfm/bin_utils/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright (c) 2017-2018 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. - -from .assemble import Assembly - -__all__ = [ - 'Assembly' -] diff --git a/tools/psa/tfm/bin_utils/assemble.py b/tools/psa/tfm/bin_utils/assemble.py deleted file mode 100644 index 0bb41f122e..0000000000 --- a/tools/psa/tfm/bin_utils/assemble.py +++ /dev/null @@ -1,105 +0,0 @@ -#! /usr/bin/env python3 -# -# Copyright 2017 Linaro Limited -# Copyright (c) 2017-2018, Arm Limited. -# -# 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. - -""" -Assemble multiple images into a single image that can be flashed on the device. -""" - -import argparse -import errno -import io -import re -import os -import shutil - -offset_re = re.compile(r"^#define ([0-9A-Z_]+)_IMAGE_OFFSET\s+((0x)?[0-9a-fA-F]+)") -size_re = re.compile(r"^#define ([0-9A-Z_]+)_IMAGE_MAX_SIZE\s+((0x)?[0-9a-fA-F]+)") - -class Assembly(): - def __init__(self, layout_path, output): - self.output = output - self.layout_path = layout_path - self.find_slots() - try: - os.unlink(output) - except OSError as e: - if e.errno != errno.ENOENT: - raise - - def find_slots(self): - offsets = {} - sizes = {} - - if os.path.isabs(self.layout_path): - configFile = self.layout_path - else: - scriptsDir = os.path.dirname(os.path.abspath(__file__)) - configFile = os.path.join(scriptsDir, self.layout_path) - - with open(configFile, 'r') as fd: - for line in fd: - m = offset_re.match(line) - if m is not None: - offsets[m.group(1)] = int(m.group(2), 0) - m = size_re.match(line) - if m is not None: - sizes[m.group(1)] = int(m.group(2), 0) - - if 'SECURE' not in offsets: - raise Exception("Image config does not have secure partition") - - if 'NON_SECURE' not in offsets: - raise Exception("Image config does not have non-secure partition") - - self.offsets = offsets - self.sizes = sizes - - def add_image(self, source, partition): - with open(self.output, 'ab') as ofd: - ofd.seek(0, os.SEEK_END) - pos = ofd.tell() - if pos > self.offsets[partition]: - raise Exception("Partitions not in order, unsupported") - if pos < self.offsets[partition]: - ofd.write(b'\xFF' * (self.offsets[partition] - pos)) - statinfo = os.stat(source) - if statinfo.st_size > self.sizes[partition]: - raise Exception("Image {} is too large for partition".format(source)) - with open(source, 'rb') as rfd: - shutil.copyfileobj(rfd, ofd, 0x10000) - -def main(): - parser = argparse.ArgumentParser() - - parser.add_argument('-l', '--layout', required=True, - help='Location of the memory layout file') - parser.add_argument('-s', '--secure', required=True, - help='Unsigned secure image') - parser.add_argument('-n', '--non_secure', - help='Unsigned non-secure image') - parser.add_argument('-o', '--output', required=True, - help='Filename to write full image to') - - args = parser.parse_args() - output = Assembly(args.layout, args.output) - - - output.add_image(args.secure, "SECURE") - output.add_image(args.non_secure, "NON_SECURE") - -if __name__ == '__main__': - main() diff --git a/tools/psa/tfm/bin_utils/imgtool.py b/tools/psa/tfm/bin_utils/imgtool.py deleted file mode 100644 index 0440f88fd7..0000000000 --- a/tools/psa/tfm/bin_utils/imgtool.py +++ /dev/null @@ -1,177 +0,0 @@ -#! /usr/bin/env python3 -# -# Copyright 2017 Linaro Limited -# Copyright (c) 2018, Arm Limited. -# -# 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. - -from __future__ import print_function -import os -import re -import argparse -from .imgtool_lib import keys -from .imgtool_lib import image -from .imgtool_lib import version -import sys - -def find_load_address(args): - load_address_re = re.compile(r"^#define\sIMAGE_LOAD_ADDRESS\s+(0x[0-9a-fA-F]+)") - - if os.path.isabs(args.layout): - configFile = args.layout - else: - scriptsDir = os.path.dirname(os.path.abspath(__file__)) - configFile = os.path.join(scriptsDir, args.layout) - - ramLoadAddress = None - with open(configFile, 'r') as flash_layout_file: - for line in flash_layout_file: - m = load_address_re.match(line) - if m is not None: - ramLoadAddress = int(m.group(1), 0) - print("**[INFO]** Writing load address from the macro in " - "flash_layout.h to the image header.. " - + hex(ramLoadAddress) - + " (dec. " + str(ramLoadAddress) + ")") - break - return ramLoadAddress - -# Returns the last version number if present, or None if not -def get_last_version(path): - if (os.path.isfile(path) == False): # Version file not present - return None - else: # Version file is present, check it has a valid number inside it - with open(path, "r") as oldFile: - fileContents = oldFile.read() - if version.version_re.match(fileContents): # number is valid - return version.decode_version(fileContents) - else: - return None - -def next_version_number(args, defaultVersion, path): - newVersion = None - if (version.compare(args.version, defaultVersion) == 0): # Default version - lastVersion = get_last_version(path) - if (lastVersion is not None): - newVersion = version.increment_build_num(lastVersion) - else: - newVersion = version.increment_build_num(defaultVersion) - else: # Version number has been explicitly provided (not using the default) - newVersion = args.version - versionString = "{a}.{b}.{c}+{d}".format( - a=str(newVersion.major), - b=str(newVersion.minor), - c=str(newVersion.revision), - d=str(newVersion.build) - ) - with open(path, "w") as newFile: - newFile.write(versionString) - print("**[INFO]** Image version number set to " + versionString) - return newVersion - -def gen_rsa2048(args): - keys.RSA2048.generate().export_private(args.key) - -keygens = { - 'rsa-2048': gen_rsa2048, } - -def do_keygen(args): - if args.type not in keygens: - msg = "Unexpected key type: {}".format(args.type) - raise argparse.ArgumentTypeError(msg) - keygens[args.type](args) - -def do_getpub(args): - key = keys.load(args.key) - if args.lang == 'c': - key.emit_c() - else: - msg = "Unsupported language, valid are: c" - raise argparse.ArgumentTypeError(msg) - -def do_sign(args): - if args.rsa_pkcs1_15: - keys.sign_rsa_pss = False - img = image.Image.load(args.infile, - version=next_version_number(args, - version.decode_version("0"), - "lastVerNum.txt"), - header_size=args.header_size, - included_header=args.included_header, - pad=args.pad) - key = keys.load(args.key) if args.key else None - img.sign(key, find_load_address(args)) - - if args.pad: - img.pad_to(args.pad, args.align) - - img.save(args.outfile) - -subcmds = { - 'keygen': do_keygen, - 'getpub': do_getpub, - 'sign': do_sign, } - -def alignment_value(text): - value = int(text) - if value not in [1, 2, 4, 8]: - msg = "{} must be one of 1, 2, 4 or 8".format(value) - raise argparse.ArgumentTypeError(msg) - return value - -def intparse(text): - """Parse a command line argument as an integer. - - Accepts 0x and other prefixes to allow other bases to be used.""" - return int(text, 0) - -def args(): - parser = argparse.ArgumentParser() - subs = parser.add_subparsers(help='subcommand help', dest='subcmd') - - keygenp = subs.add_parser('keygen', help='Generate pub/private keypair') - keygenp.add_argument('-k', '--key', metavar='filename', required=True) - keygenp.add_argument('-t', '--type', metavar='type', - choices=keygens.keys(), required=True) - - getpub = subs.add_parser('getpub', help='Get public key from keypair') - getpub.add_argument('-k', '--key', metavar='filename', required=True) - getpub.add_argument('-l', '--lang', metavar='lang', default='c') - - sign = subs.add_parser('sign', help='Sign an image with a private key') - sign.add_argument('--layout', required=True, - help='Location of the memory layout file') - sign.add_argument('-k', '--key', metavar='filename') - sign.add_argument("--align", type=alignment_value, required=True) - sign.add_argument("-v", "--version", type=version.decode_version, - default="0.0.0+0") - sign.add_argument("-H", "--header-size", type=intparse, required=True) - sign.add_argument("--included-header", default=False, action='store_true', - help='Image has gap for header') - sign.add_argument("--pad", type=intparse, - help='Pad image to this many bytes, adding trailer magic') - sign.add_argument("--rsa-pkcs1-15", - help='Use old PKCS#1 v1.5 signature algorithm', - default=False, action='store_true') - sign.add_argument("infile") - sign.add_argument("outfile") - - args = parser.parse_args() - if args.subcmd is None: - print('Must specify a subcommand', file=sys.stderr) - sys.exit(1) - - subcmds[args.subcmd](args) - -if __name__ == '__main__': - args() \ No newline at end of file diff --git a/tools/psa/tfm/bin_utils/imgtool_lib/__init__.py b/tools/psa/tfm/bin_utils/imgtool_lib/__init__.py deleted file mode 100644 index fd240440dc..0000000000 --- a/tools/psa/tfm/bin_utils/imgtool_lib/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2017 Linaro Limited -# -# 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. - -# This file is intentionally empty. -# -# The __init__.py files are required to make Python treat the directories as -# containing packages. \ No newline at end of file diff --git a/tools/psa/tfm/bin_utils/imgtool_lib/image.py b/tools/psa/tfm/bin_utils/imgtool_lib/image.py deleted file mode 100644 index 67425d4ba3..0000000000 --- a/tools/psa/tfm/bin_utils/imgtool_lib/image.py +++ /dev/null @@ -1,179 +0,0 @@ -# Copyright 2017 Linaro Limited -# Copyright (c) 2018, Arm Limited. -# -# 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. - -""" -Image signing and management. -""" - -from . import version as versmod -import hashlib -import struct - -IMAGE_MAGIC = 0x96f3b83d -IMAGE_HEADER_SIZE = 32 - -# Image header flags. -IMAGE_F = { - 'PIC': 0x0000001, - 'NON_BOOTABLE': 0x0000010, - 'RAM_LOAD': 0x0000020, } -TLV_VALUES = { - 'KEYHASH': 0x01, - 'SHA256' : 0x10, - 'RSA2048': 0x20, } - -TLV_INFO_SIZE = 4 -TLV_INFO_MAGIC = 0x6907 - -# Sizes of the image trailer, depending on flash write size. -trailer_sizes = { - write_size: 128 * 3 * write_size + 8 * 2 + 16 - for write_size in [1, 2, 4, 8] -} - -boot_magic = bytearray([ - 0x77, 0xc2, 0x95, 0xf3, - 0x60, 0xd2, 0xef, 0x7f, - 0x35, 0x52, 0x50, 0x0f, - 0x2c, 0xb6, 0x79, 0x80, ]) - -class TLV(): - def __init__(self): - self.buf = bytearray() - - def add(self, kind, payload): - """Add a TLV record. Kind should be a string found in TLV_VALUES above.""" - buf = struct.pack(' 0: - obj.payload = (b'\000' * obj.header_size) + obj.payload - - obj.check() - return obj - - def __init__(self, version, header_size=IMAGE_HEADER_SIZE, pad=0): - self.version = version - self.header_size = header_size or IMAGE_HEADER_SIZE - self.pad = pad - - def __repr__(self): - return "".format( - self.version, - self.header_size, - self.pad, - len(self.payload)) - - def save(self, path): - with open(path, 'wb') as f: - f.write(self.payload) - - def check(self): - """Perform some sanity checking of the image.""" - # If there is a header requested, make sure that the image - # starts with all zeros. - if self.header_size > 0: - if any(v != 0 and v != b'\000' for v in self.payload[0:self.header_size]): - raise Exception("Padding requested, but image does not start with zeros") - - def sign(self, key, ramLoadAddress): - self.add_header(key, ramLoadAddress) - - tlv = TLV() - - sha = hashlib.sha256() - sha.update(self.payload) - digest = sha.digest() - - tlv.add('SHA256', digest) - - if key is not None: - pub = key.get_public_bytes() - sha = hashlib.sha256() - sha.update(pub) - pubbytes = sha.digest() - tlv.add('KEYHASH', pubbytes) - - sig = key.sign(self.payload) - tlv.add(key.sig_tlv(), sig) - - self.payload += tlv.get() - - def add_header(self, key, ramLoadAddress): - """Install the image header. - - The key is needed to know the type of signature, and - approximate the size of the signature.""" - - flags = 0 - if ramLoadAddress is not None: - # add the load address flag to the header to indicate that an SRAM - # load address macro has been defined - flags |= IMAGE_F["RAM_LOAD"] - - fmt = ('<' + - # type ImageHdr struct { - 'I' + # Magic uint32 - 'I' + # LoadAddr uint32 - 'H' + # HdrSz uint16 - 'H' + # Pad1 uint16 - 'I' + # ImgSz uint32 - 'I' + # Flags uint32 - 'BBHI' + # Vers ImageVersion - 'I' # Pad2 uint32 - ) # } - assert struct.calcsize(fmt) == IMAGE_HEADER_SIZE - header = struct.pack(fmt, - IMAGE_MAGIC, - 0 if (ramLoadAddress is None) else ramLoadAddress, # LoadAddr - self.header_size, - 0, # Pad1 - len(self.payload) - self.header_size, # ImageSz - flags, # Flags - self.version.major, - self.version.minor or 0, - self.version.revision or 0, - self.version.build or 0, - 0) # Pad2 - self.payload = bytearray(self.payload) - self.payload[:len(header)] = header - - def pad_to(self, size, align): - """Pad the image to the given size, with the given flash alignment.""" - tsize = trailer_sizes[align] - padding = size - (len(self.payload) + tsize) - if padding < 0: - msg = "Image size (0x{:x}) + trailer (0x{:x}) exceeds requested size 0x{:x}".format( - len(self.payload), tsize, size) - raise Exception(msg) - pbytes = b'\xff' * padding - pbytes += b'\xff' * (tsize - len(boot_magic)) - pbytes += boot_magic - self.payload += pbytes \ No newline at end of file diff --git a/tools/psa/tfm/bin_utils/imgtool_lib/keys.py b/tools/psa/tfm/bin_utils/imgtool_lib/keys.py deleted file mode 100644 index fda3ed6710..0000000000 --- a/tools/psa/tfm/bin_utils/imgtool_lib/keys.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2017 Linaro Limited -# Copyright (c) 2017-2018, Arm Limited. -# -# 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. - -""" -Cryptographic key management for imgtool. -""" - -from __future__ import print_function -from Crypto.Hash import SHA256 -from Crypto.PublicKey import RSA -from Crypto.Signature import PKCS1_v1_5, PKCS1_PSS -import hashlib -from pyasn1.type import namedtype, univ -from pyasn1.codec.der.encoder import encode - -# By default, we use RSA-PSS (PKCS 2.1). That can be overridden on -# the command line to support the older (less secure) PKCS1.5 -sign_rsa_pss = True - -AUTOGEN_MESSAGE = "/* Autogenerated by imgtool.py, do not edit. */" - -class RSAPublicKey(univ.Sequence): - componentType = namedtype.NamedTypes( - namedtype.NamedType('modulus', univ.Integer()), - namedtype.NamedType('publicExponent', univ.Integer())) - -class RSA2048(): - def __init__(self, key): - """Construct an RSA2048 key with the given key data""" - self.key = key - - @staticmethod - def generate(): - return RSA2048(RSA.generate(2048)) - - def export_private(self, path): - with open(path, 'wb') as f: - f.write(self.key.exportKey('PEM')) - - def get_public_bytes(self): - node = RSAPublicKey() - node['modulus'] = self.key.n - node['publicExponent'] = self.key.e - return bytearray(encode(node)) - - def emit_c(self): - print(AUTOGEN_MESSAGE) - print("const unsigned char rsa_pub_key[] = {", end='') - encoded = self.get_public_bytes() - for count, b in enumerate(encoded): - if count % 8 == 0: - print("\n\t", end='') - else: - print(" ", end='') - print("0x{:02x},".format(b), end='') - print("\n};") - print("const unsigned int rsa_pub_key_len = {};".format(len(encoded))) - - def sig_type(self): - """Return the type of this signature (as a string)""" - if sign_rsa_pss: - return "PKCS1_PSS_RSA2048_SHA256" - else: - return "PKCS15_RSA2048_SHA256" - - def sig_len(self): - return 256 - - def sig_tlv(self): - return "RSA2048" - - def sign(self, payload): - converted_payload = bytes(payload) - sha = SHA256.new(converted_payload) - if sign_rsa_pss: - signer = PKCS1_PSS.new(self.key) - else: - signer = PKCS1_v1_5.new(self.key) - signature = signer.sign(sha) - assert len(signature) == self.sig_len() - return signature - -def load(path): - with open(path, 'rb') as f: - pem = f.read() - try: - key = RSA.importKey(pem) - if key.n.bit_length() != 2048: - raise Exception("Unsupported RSA bit length, only 2048 supported") - return RSA2048(key) - except ValueError: - raise Exception("Unsupported RSA key file") diff --git a/tools/psa/tfm/bin_utils/imgtool_lib/version.py b/tools/psa/tfm/bin_utils/imgtool_lib/version.py deleted file mode 100644 index d1d45f0385..0000000000 --- a/tools/psa/tfm/bin_utils/imgtool_lib/version.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2017 Linaro Limited -# Copyright (c) 2018, Arm Limited. -# -# 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. - -""" -Semi Semantic Versioning - -Implements a subset of semantic versioning that is supportable by the image header. -""" - -import argparse -from collections import namedtuple -import re - -SemiSemVersion = namedtuple('SemiSemVersion', ['major', 'minor', 'revision', 'build']) - -def increment_build_num(lastVer): - newVer = SemiSemVersion(lastVer.major, lastVer.minor, lastVer.revision, lastVer.build + 1) - return newVer - -# -1 if a is older than b; 0 if they're the same version; 1 if a is newer than b -def compare(a, b): - if (a.major > b.major): return 1 - elif (a.major < b.major): return -1 - else: - if (a.minor > b.minor): return 1 - elif (a.minor < b.minor): return -1 - else: - if (a.revision > b.revision): return 1 - elif (a.revision < b.revision): return -1 - else: - if (a.build > b.build): return 1 - elif (a.build < b.build): return -1 - else: return 0 - -version_re = re.compile(r"""^([1-9]\d*|0)(\.([1-9]\d*|0)(\.([1-9]\d*|0)(\+([1-9]\d*|0))?)?)?$""") -def decode_version(text): - """Decode the version string, which should be of the form maj.min.rev+build""" - m = version_re.match(text) - if m: - result = SemiSemVersion( - int(m.group(1)) if m.group(1) else 0, - int(m.group(3)) if m.group(3) else 0, - int(m.group(5)) if m.group(5) else 0, - int(m.group(7)) if m.group(7) else 0) - return result - else: - msg = "Invalid version number, should be maj.min.rev+build with later parts optional" - raise argparse.ArgumentTypeError(msg) - -if __name__ == '__main__': - print(decode_version("1.2")) - print(decode_version("1.0")) - print(decode_version("0.0.2+75")) - print(decode_version("0.0.0+00")) diff --git a/tools/psa/tfm/mbed_app.json b/tools/psa/tfm/mbed_app.json deleted file mode 100644 index b98452dfde..0000000000 --- a/tools/psa/tfm/mbed_app.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "tfm_build", - "requires" : ["psa-services", "tfm", "tfm-s", "psa"], - "macros": ["MBEDTLS_CIPHER_MODE_CTR", "MBEDTLS_CMAC_C"], - "artifact_name": "tfm" -} diff --git a/tools/resources/__init__.py b/tools/resources/__init__.py index 45339c1c30..102309c9fb 100644 --- a/tools/resources/__init__.py +++ b/tools/resources/__init__.py @@ -604,38 +604,3 @@ class Resources(object): for t in res_filter.file_types: self._file_refs[t] = set(filter( res_filter.predicate, self._file_refs[t])) - - -class ResourceFilter(object): - def __init__(self, file_types): - self.file_types = file_types - - def predicate(self, ref): - raise NotImplemented - - -class SpeOnlyResourceFilter(ResourceFilter): - def __init__(self): - ResourceFilter.__init__( - self, [FileType.ASM_SRC, FileType.C_SRC, FileType.CPP_SRC]) - - def predicate(self, ref): - return 'COMPONENT_SPE' in ref.name - - -class OsAndSpeResourceFilter(ResourceFilter): - def __init__(self): - ResourceFilter.__init__( - self, [FileType.ASM_SRC, FileType.C_SRC, FileType.CPP_SRC]) - - def predicate(self, ref): - return ROOT in abspath(ref.name) or 'COMPONENT_SPE' in ref.name - - -class PsaManifestResourceFilter(ResourceFilter): - def __init__(self): - ResourceFilter.__init__( - self, [FileType.JSON]) - - def predicate(self, ref): - return not ref.name.endswith('_psa.json') diff --git a/tools/targets/__init__.py b/tools/targets/__init__.py index eb6ebac7d9..66dd070951 100644 --- a/tools/targets/__init__.py +++ b/tools/targets/__init__.py @@ -30,7 +30,6 @@ from tools.settings import ROOT from tools.targets.LPC import patch from tools.paths import TOOLS_BOOTLOADERS from tools.utils import json_file_to_dict, NotSupportedException -from tools.psa import find_secure_image __all__ = ["target", "TARGETS", "TARGET_MAP", "TARGET_NAMES", "CORE_LABELS", diff --git a/tools/test.py b/tools/test.py index 9e6a0fc2f6..8dcc93961d 100644 --- a/tools/test.py +++ b/tools/test.py @@ -43,8 +43,6 @@ from tools.utils import argparse_dir_not_parent from tools.utils import print_end_warnings from tools.settings import ROOT from tools.targets import Target -from tools.psa import generate_psa_sources -from tools.resources import OsAndSpeResourceFilter, SpeOnlyResourceFilter def main(): error = False @@ -237,12 +235,6 @@ def main(): profile = extract_profile(parser, options, internal_tc_name) try: resource_filter = None - if target.is_PSA_secure_target: - resource_filter = OsAndSpeResourceFilter() - generate_psa_sources( - source_dirs=base_source_paths, - ignore_paths=[options.build_dir] - ) # Build sources notify = TerminalNotifier(options.verbose, options.silent) @@ -277,10 +269,7 @@ def main(): if not library_build_success: print("Failed to build library") else: - if target.is_PSA_secure_target: - resource_filter = SpeOnlyResourceFilter() - else: - resource_filter = None + resource_filter = None # Build all the tests notify = TerminalNotifier(options.verbose, options.silent) diff --git a/tools/test/psa/__init__.py b/tools/test/psa/__init__.py deleted file mode 100644 index 982d7317e5..0000000000 --- a/tools/test/psa/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -Copyright (c) 2019 ARM Limited. All rights reserved. - -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 -""" diff --git a/tools/test/psa/test_data.py b/tools/test/psa/test_data.py deleted file mode 100644 index 3b8a3150aa..0000000000 --- a/tools/test/psa/test_data.py +++ /dev/null @@ -1,732 +0,0 @@ -# Copyright (c) 2017-2018 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. - -manifests = [ - { - 'name': 'TEST_PARTITION', - 'id': "0x7FFFFFFF", - "type": "APPLICATION-ROT", - 'priority': 'NORMAL', - 'entry_point': 'test_main', - 'stack_size': 512, # 512 == 0x200 - 'heap_size': 2048, - 'mmio_regions': [ - { - 'name': 'PERIPH1', - 'permission': 'READ-ONLY' - }, - { - 'name': 'PERIPH2', - 'permission': 'READ-ONLY' - }, - { - 'base': '0xCCCCCCCC', - 'size': 4096, 'permission': 'READ-ONLY' - }, - { - 'base': '0xDDDDDDDD', - 'size': 33554432, 'permission': 'READ-WRITE' - } - ], - 'services': [ - { - 'name': 'SID1', - 'identifier': '0x00000001', - 'signal': 'SID1', - 'minor_version': 1, - 'minor_policy': 'RELAXED', - 'non_secure_clients': True - }, - { - 'name': 'SID2', - 'identifier': '0x00000002', - 'signal': 'SID2', - 'minor_version': 2, - 'minor_policy': 'STRICT', - 'non_secure_clients': False - }, - ], - 'source_files': ['src1.cpp', 'src2.cpp'], - 'irqs': [ - {"line_num": 20, "signal": "ISR20"}, - {"line_num": 21, "signal": "ISR21"} - ], - 'extern_sids': ['SID3', 'SID4'] - }, - { - 'name': 'TEST_PARTITION2', - 'id': "0x7FFFFFFE", - "type": "APPLICATION-ROT", - 'priority': 'NORMAL', - 'entry_point': 'test2_main', - 'stack_size': 512, # 512 == 0x200 - 'heap_size': 2048, - 'mmio_regions': [ - { - 'name': 'PERIPH1', - 'permission': 'READ-ONLY' - }, - { - 'name': 'PERIPH3', - 'permission': 'READ-ONLY' - }, - { - 'base': '0xAAAAAAAA', - 'size': 4096, 'permission': 'READ-ONLY' - }, - { - 'base': '0xBBBBBBBB', - 'size': 33554432, 'permission': 'READ-WRITE' - } - ], - 'services': [ - { - 'name': 'SID3', - 'identifier': '0x00000003', - 'signal': 'SID3', - 'minor_version': 5, - 'minor_policy': 'RELAXED', - 'non_secure_clients': True - }, - { - 'name': 'SID4', - 'identifier': '0x00000004', - 'signal': 'SID4', - 'minor_version': 12, - 'minor_policy': 'STRICT', - 'non_secure_clients': False - }, - ], - 'source_files': ['src3.cpp', 'src4.cpp'], - 'irqs': [ - {"line_num": 22, "signal": "ISR22"}, - {"line_num": 23, "signal": "ISR23"} - ] - } -] - -manifests_for_circular_call_dependency_checks = [ - { - 'name': 'PARTITION1', - 'id': '0x7FFFFFFF', - 'type': 'APPLICATION-ROT', - 'priority': 'NORMAL', - 'entry_point': 'test_main', - 'stack_size': 512, - 'heap_size': 2048, - 'source_files': ['src1.cpp'], - 'services': [ - { - 'name': 'SID1', - 'identifier': '0x00000001', - 'signal': 'SID1', - 'non_secure_clients': False - }, - { - 'name': 'SID2', - 'identifier': '0x00000002', - 'signal': 'SID2', - 'non_secure_clients': False - } - ], - 'extern_sids': ['SID3', 'SID4'] - }, - { - 'name': 'PARTITION2', - 'id': '0x7FFFFFFE', - 'type': 'APPLICATION-ROT', - 'priority': 'NORMAL', - 'entry_point': 'test_main', - 'stack_size': 512, - 'heap_size': 2048, - 'source_files': ['src2.cpp'], - 'services': [ - { - 'name': 'SID3', - 'identifier': '0x00000003', - 'signal': 'SID3', - 'non_secure_clients': False - }, - { - 'name': 'SID4', - 'identifier': '0x00000004', - 'signal': 'SID4', - 'non_secure_clients': False - } - ], - 'extern_sids': ['SID1', 'SID2'] - }, - { - 'name': 'PARTITION3', - 'id': '0x7FFFFFFD', - 'type': 'APPLICATION-ROT', - 'priority': 'NORMAL', - 'entry_point': 'test_main', - 'stack_size': 512, - 'heap_size': 2048, - 'source_files': ['src3.cpp'], - 'services': [ - { - 'name': 'SID5', - 'identifier': '0x00000005', - 'signal': 'SID5', - 'non_secure_clients': False - } - ], - 'extern_sids': ['SID7'] - }, - { - 'name': 'PARTITION4', - 'id': '0x7FFFFFFC', - 'type': 'APPLICATION-ROT', - 'priority': 'NORMAL', - 'entry_point': 'test_main', - 'stack_size': 512, - 'heap_size': 2048, - 'source_files': ['src4.cpp'], - 'services': [ - { - 'name': 'SID6', - 'identifier': '0x00000006', - 'signal': 'SID6', - 'non_secure_clients': False - }, - { - 'name': 'SID7', - 'identifier': '0x00000007', - 'signal': 'SID7', - 'non_secure_clients': False - }, - ], - 'extern_sids': ['SID9'] - }, - { - 'name': 'PARTITION5', - 'id': '0x7FFFFFFB', - 'type': 'APPLICATION-ROT', - 'priority': 'NORMAL', - 'entry_point': 'test_main', - 'stack_size': 512, - 'heap_size': 2048, - 'source_files': ['src5.cpp'], - 'services': [ - { - 'name': 'SID8', - 'identifier': '0x00000008', - 'signal': 'SID8', - 'non_secure_clients': False - }, - { - 'name': 'SID9', - 'identifier': '0x00000009', - 'signal': 'SID9', - 'non_secure_clients': False - } - ], - 'extern_sids': ['SID5'] - }, - { - 'name': 'PARTITION6', - 'id': '0x7FFFFFFA', - 'type': 'APPLICATION-ROT', - 'priority': 'NORMAL', - 'entry_point': 'test_main', - 'stack_size': 512, - 'heap_size': 2048, - 'source_files': ['src6.cpp'], - 'services': [ - { - 'name': 'SID10', - 'identifier': '0x0000000A', - 'signal': 'SID10', - 'non_secure_clients': False - }, - { - 'name': 'SID11', - 'identifier': '0x0000000B', - 'signal': 'SID11', - 'non_secure_clients': False - } - ], - 'extern_sids': ['SID7', 'SID5'] - }, - { - 'name': 'PARTITION7', - 'id': '0x7FFFFFF9', - 'type': 'APPLICATION-ROT', - 'priority': 'NORMAL', - 'entry_point': 'test_main', - 'stack_size': 512, - 'heap_size': 2048, - 'source_files': ['src6.cpp'], - 'services': [ - { - 'name': 'SID12', - 'identifier': '0x0000000C', - 'signal': 'SID12', - 'non_secure_clients': False - } - ] - } -] - -invalid_minor_version_policy_rot_srv = [ - { - 'name': 'SID1', - 'identifier': '0x00000001', - 'signal': 'SID1', - 'minor_version': 1, - 'minor_policy': 'invalid_policy', - 'non_secure_clients': True - } -] - -invalid_nspe_callable_rot_srv = [ - { - 'name': 'SID1', - 'identifier': '0x00000001', - 'signal': 'SID1', - 'minor_version': 1, - 'minor_policy': 'STRICT', - 'non_secure_clients': 'invalid_value' - } -] - -missing_nspe_callable_rot_srv = [ - { - 'name': 'SID1', - 'identifier': '0x00000001', - 'signal': 'SID1', - 'minor_version': 1, - 'minor_policy': 'STRICT' - } -] - -duplicate_signal_rot_services = [ - { - 'name': 'SID3', - 'identifier': '0x00000001', - 'signal': 'SID1', - 'minor_version': 5, - 'minor_policy': 'RELAXED', - 'non_secure_clients': True - }, - { - 'name': 'SID4', - 'identifier': '0x00000002', - 'signal': 'SID2', - 'minor_version': 12, - 'minor_policy': 'STRICT', - 'non_secure_clients': True - }, -] - -duplicate_identifier_rot_services = [ - { - 'name': 'SID3', - 'identifier': '0x00000003', - 'signal': 'SID3', - 'minor_version': 5, - 'minor_policy': 'RELAXED', - 'non_secure_clients': True - }, - { - 'name': 'SID4', - 'identifier': '0x00000002', - 'signal': 'SID4', - 'minor_version': 12, - 'minor_policy': 'STRICT', - 'non_secure_clients': True - }, -] - -spe_contained_rot_services = [ - { - 'name': 'SID5', - 'identifier': '0x00000005', - 'signal': 'SID5', - 'minor_version': 5, - 'minor_policy': 'RELAXED', - 'non_secure_clients': False - }, - { - 'name': 'SID6', - 'identifier': '0x00000006', - 'signal': 'SID6', - 'minor_version': 12, - 'minor_policy': 'STRICT', - 'non_secure_clients': False - } -] - -missing_minor_version_rot_srv = [ - { - 'name': 'SID1', - 'identifier': '0x00000001', - 'signal': 'SID1', - 'minor_policy': 'RELAXED', - 'non_secure_clients': True - } -] - -missing_minor_version_policy_rot_srv = [ - { - 'name': 'SID2', - 'identifier': '0x00000002', - 'signal': 'SID2', - 'minor_version': 1, - 'non_secure_clients': True - } -] - -missing_minor_completley_rot_srv = [ - {'name': 'SID2', 'identifier': '0x00000002', 'signal': 'SID2', - 'non_secure_clients': True} -] - -duplicate_signal_irqs = [ - {"line_num": 22, "signal": "ISR20"} -] - -duplicate_line_num_irqs = [ - {"line_num": 21, "signal": "ISR22"} -] - -invalid_mmioregion_base = { - 'base': 'str', - 'size': 4096, - 'permission': 'READ-ONLY' -} - -invalid_mmioregion_size = { - 'base': '0xEEEEEEEE', - 'size': 'str', - 'permission': 'READ-ONLY' -} - -test_mock_files = { - 'manifest1': 1, - 'manifest2': 2, - 'template_common1': 3, - 'template_common2': 4, - 'template_NAME_3': 5, - 'template_NAME_4': 6, - 'gen1': 7, - 'gen2': 8, - 'gen3': 9, - 'gen4': 10, - 'gen5': 11, - 'gen6': 12 -} - -test_common_template = '''{ - "num_of_partitions": {{partitions|count}}, - "partition_names": [ -{% for partition in partitions %} - "{{partition.name}}"{{"" if loop.last else ","}} -{% endfor %} - ], - "num_of_region_pairs": {{region_pair_list|count}} -} -''' - -test_common_expected = '''{ - "num_of_partitions": 2, - "partition_names": [ - "TEST_PARTITION", - "TEST_PARTITION2" - ], - "num_of_region_pairs": 28 -} -''' - -test_partition_template = '''{ - "name": "{{partition.name}}", - "id": "0x{{"%0x"|format(partition.id|int)|upper}}", - "type": "{{partition.type}}", - "priority": "{{partition.priority_mbed|find_priority_key}}", - "entry_point": "{{partition.entry_point}}", - "stack_size": {{partition.stack_size}}, - "heap_size": {{partition.heap_size}}, - "mmio_regions": [ -{% for mmio in partition.mmio_regions %} - { - {% if mmio.size|int %} - "base": "{{mmio.base}}", - "size": {{mmio.size}}, - {% else %} - "name": "{{mmio.base}}", - {% endif %} - "permission": "{{mmio.permission|find_permission_key}}" - {{"}" if loop.last else "},"}} -{% endfor %} - ], - "services": [ -{% for rot_srv in partition.rot_services %} - { - "name": "{{rot_srv.name}}", - "identifier": "{{rot_srv.id}}", - "signal": "{{rot_srv.signal}}", - "minor_version": {{rot_srv.minor_version}}, - "minor_policy": "{{rot_srv.minor_policy}}", - "non_secure_clients": {{rot_srv.nspe_callable|lower}} - {{"}" if loop.last else "},"}} -{% endfor %} - ], -{% if partition.extern_sids %} - "extern_sids": [ -{% for ext_sid in partition.extern_sids %} - "{{ext_sid}}"{{"" if loop.last else ","}} -{% endfor %} - ], -{% endif %} - "source_files": [ -{% for src in partition.source_files %} - "{{src|basename}}"{{"" if loop.last else ","}} -{% endfor %} - ], - "irqs": [ -{% for irq in partition.irqs %} - { - "line_num": {{irq.line_num}}, - "signal": "{{irq.signal}}" - {{"}" if loop.last else "},"}} -{% endfor %} - ] -} -''' - -exceeding_services = [ - { - "name": "XSID1", - "signal": "XSID1", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000009" - }, - { - "name": "XSID2", - "signal": "XSID2", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000000a" - }, { - "name": "XSID3", - "signal": "XSID3", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000000b" - }, { - "name": "XSID4", - "signal": "XSID4", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000000c" - }, { - "name": "XSID5", - "signal": "XSID5", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000000d" - }, { - "name": "XSID6", - "signal": "XSID6", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000000e" - }, { - "name": "XSID7", - "signal": "XSID7", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000000f" - }, { - "name": "XSID8", - "signal": "XSID8", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000010" - }, { - "name": "XSID9", - "signal": "XSID9", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000011" - }, { - "name": "XSID10", - "signal": "XSID10", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000012" - }, { - "name": "XSID11", - "signal": "XSID11", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000013" - }, { - "name": "XSID12", - "signal": "XSID12", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000014" - }, { - "name": "XSID13", - "signal": "XSID13", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000015" - }, { - "name": "XSID14", - "signal": "XSID14", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000016" - }, { - "name": "XSID15", - "signal": "XSID15", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000017" - }, { - "name": "XSID16", - "signal": "XSID16", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000018" - }, { - "name": "XSID17", - "signal": "XSID17", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000019" - }, { - "name": "XSID18", - "signal": "XSID18", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000001a" - }, { - "name": "XSID19", - "signal": "XSID19", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000001b" - }, { - "name": "XSID20", - "signal": "XSID20", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000001c" - }, { - "name": "XSID21", - "signal": "XSID21", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000001d" - }, { - "name": "XSID22", - "signal": "XSID22", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000001e" - }, { - "name": "XSID23", - "signal": "XSID23", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x0000001f" - }, { - "name": "XSID24", - "signal": "XSID24", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000020" - }, { - "name": "XSID25", - "signal": "XSID25", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000021" - }, { - "name": "XSID26", - "signal": "XSID26", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000022" - }, { - "name": "XSID27", - "signal": "XSID27", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000023" - }, { - "name": "XSID28", - "signal": "XSID28", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000024" - }, { - "name": "XSID29", - "signal": "XSID29", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000025" - }, { - "name": "XSID30", - "signal": "XSID30", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000026" - }, { - "name": "XSID31", - "signal": "XSID31", - "non_secure_clients": True, - "minor_version": 5, - "minor_policy": "RELAXED", - "identifier": "0x00000027" - } -] diff --git a/tools/test/psa/test_find_secure_image.py b/tools/test/psa/test_find_secure_image.py deleted file mode 100644 index d303a4a665..0000000000 --- a/tools/test/psa/test_find_secure_image.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (c) 2019 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 pytest -import os -from tools.notifier.mock import MockNotifier -from tools.resources import Resources, FileType -from tools.psa import find_secure_image - - -def test_find_secure_image(): - mock_notifier = MockNotifier() - mock_resources = Resources(mock_notifier) - ns_image_path = os.path.join('BUILD', 'TARGET_NS', 'app.bin') - ns_test_path = os.path.join('BUILD', 'TARGET_NS', 'test.bin') - config_s_image_name = 'target_config.bin' - default_bin = os.path.join('prebuilt', config_s_image_name) - test_bin = os.path.join('prebuilt', 'test.bin') - - with pytest.raises(Exception, match='ns_image_path and configured_s_image_path are mandatory'): - find_secure_image(mock_notifier, mock_resources, None, None, FileType.BIN) - find_secure_image(mock_notifier, mock_resources, ns_image_path, None, FileType.BIN) - find_secure_image(mock_notifier, mock_resources, None, config_s_image_name, FileType.BIN) - - with pytest.raises(Exception, match='image_type must be of type BIN or HEX'): - find_secure_image(mock_notifier, mock_resources, ns_image_path, config_s_image_name, None) - find_secure_image(mock_notifier, mock_resources, ns_image_path, config_s_image_name, FileType.C_SRC) - - with pytest.raises(Exception, match='No image files found for this target'): - find_secure_image(mock_notifier, mock_resources, ns_image_path, config_s_image_name, FileType.BIN) - - dummy_bin = os.path.join('path', 'to', 'dummy.bin') - mock_resources.add_file_ref(FileType.BIN, dummy_bin, dummy_bin) - - with pytest.raises(Exception, match='Required secure image not found'): - find_secure_image(mock_notifier, mock_resources, ns_image_path, config_s_image_name, FileType.BIN) - - mock_resources.add_file_ref(FileType.BIN, default_bin, default_bin) - mock_resources.add_file_ref(FileType.BIN, test_bin, test_bin) - secure_image = find_secure_image(mock_notifier, mock_resources, ns_image_path, config_s_image_name, FileType.BIN) - assert secure_image == default_bin - - secure_image = find_secure_image(mock_notifier, mock_resources, ns_test_path, config_s_image_name, FileType.BIN) - assert secure_image == test_bin diff --git a/tools/test/psa/test_generate_partition_code.py b/tools/test/psa/test_generate_partition_code.py deleted file mode 100644 index a45fb03b28..0000000000 --- a/tools/test/psa/test_generate_partition_code.py +++ /dev/null @@ -1,683 +0,0 @@ -# Copyright (c) 2017-2018 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 filecmp -import re -import shutil -import tempfile -import pytest -import jsonschema.exceptions as jexcep -from jinja2.defaults import DEFAULT_FILTERS -from tools.psa.mbed_spm_tfm_common import * -from tools.psa.generate_partition_code import * -from .test_data import * - - -SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) - - -def extract_test_name(line): - return re.search(r'.*\[(.*)\]', line).group(1) - - -def dump_manifest_to_json(manifest, test_name, test_dir, create_files=True): - """ - Create a JSON manifest file from a dictionary. - - :param manifest: The manifest dictionary. - :param test_name: Name of the test. - :param test_dir: Directory to contain the JSON file. - :param create_files: Whether to create the source files listed in the - manifest 'source_files' entry. - :return: Path of the JSON file. - """ - test_file_name = test_dir.join('{}.json'.format(test_name)) - with open(test_file_name.strpath, 'wt') as fh: - json.dump(manifest, fh, indent=2) - - # Create all the partition source files - if create_files: - [test_dir.join(name).write(name) for name in - manifest.get('source_files', [])] - - return test_file_name.strpath - - -def find_priority_key(value): - """ - Finds the key in 'Manifest.PRIORITY' of a given value. - - :param value: The value. - :return: The key of the given value. - """ - return next( - (key for key, val in Manifest.PRIORITY.items() if val == value), - None - ) - - -def find_permission_key(value): - """ - Finds the key in 'MmioRegion.MMIO_PERMISIONS' of a given value. - - :param value: The value. - :return: The key of the given value. - """ - return next( - (key for key, val in MmioRegion.MMIO_PERMISSIONS.items() if - val == value), - None - ) - - -@pytest.fixture(scope="session") -def temp_test_data(tmpdir_factory): - """ - Fixture (https://docs.pytest.org/en/latest/fixture.html) function to be - used by the tests. - This fixture function Creates a valid JSON manifest file in a temporary - directory. The scope of this fixture is the entire test session. - - :param tmpdir_factory: Fixture used to create temporary directories. - see: https://docs.pytest.org/en/latest/tmpdir.html#the-tmpdir-factory-fixture - :return: A dictionary containing these keys: - 'dir': The temporary directory object created by this fixture. - 'json': The created valid manifest JSON file. - 'manifest': The manifest object read from the JSON file. - """ - test_dir = tmpdir_factory.mktemp('test_data') - fname = dump_manifest_to_json(manifests[0], 'valid_partition', test_dir) - valid_manifest = Manifest.from_json(fname) - return {'dir': test_dir, 'json': fname, 'manifest': valid_manifest} - - -""" -'modified_json_params' contain the parameters to be used in the -'modified_json' fixture. -Each key in the dictionary represents a different parameter to be used by -'modified_json', so for each test which uses -the 'modified_json' fixture, the test will run len(modified_json_params) times, - each time with different parameters. -Each parameter is a dictionary which contains these keys: - 'partition': A modified partition dictionary. - 'assert': The expected assertion which must occur when running with this - parameter. -""" -modified_json_params = { - 'missing_partition_name': { - 'partition': {k: manifests[0][k] for k in manifests[0] if k != 'name'}, - 'assert': jexcep.ValidationError - }, - 'missing_partition_id': { - 'partition': {k: manifests[0][k] for k in manifests[0] if k != 'id'}, - 'assert': jexcep.ValidationError - }, - 'missing_partition_priority': { - 'partition': {k: manifests[0][k] for k in manifests[0] if - k != 'priority'}, - 'assert': jexcep.ValidationError - }, - 'missing_entry_point': { - 'partition': {k: manifests[0][k] for k in manifests[0] if - k != 'entry_point'}, - 'assert': jexcep.ValidationError - }, - 'missing_stack_size': { - 'partition': {k: manifests[0][k] for k in manifests[0] if - k != 'stack_size'}, - 'assert': jexcep.ValidationError - }, - 'missing_heap_size': { - 'partition': {k: manifests[0][k] for k in manifests[0] if - k != 'heap_size'}, - 'assert': jexcep.ValidationError - }, - 'missing_source_files': { - 'partition': {k: manifests[0][k] for k in manifests[0] if - k != 'source_files'}, - 'assert': jexcep.ValidationError - }, - 'missing_irqs_and_sids': { - 'partition': {k: manifests[0][k] for k in manifests[0] if - k not in ['services', 'irqs']}, - 'assert': jexcep.ValidationError - }, - 'empty_source_files': { - 'partition': dict(manifests[0], source_files=[]), - 'assert': jexcep.ValidationError - }, - 'invalid_minor_policy': { - 'partition': dict(manifests[0], - services=invalid_minor_version_policy_rot_srv), - 'assert': jexcep.ValidationError - }, - 'invalid_nspe_callable': { - 'partition': dict(manifests[0], - services=invalid_nspe_callable_rot_srv), - 'assert': jexcep.ValidationError - }, - 'missing_nspe_callable': { - 'partition': dict(manifests[0], - services=missing_nspe_callable_rot_srv), - 'assert': jexcep.ValidationError - }, - 'invalid_stack_size': { - 'partition': dict(manifests[0], stack_size='str'), - 'assert': jexcep.ValidationError - }, - 'invalid_heap_size': { - 'partition': dict(manifests[0], heap_size='str'), - 'assert': jexcep.ValidationError - }, - 'invalid_priority': { - 'partition': dict(manifests[0], priority='invalid_priority'), - 'assert': jexcep.ValidationError - }, - 'invalid_mmioregion_base': { - 'partition': dict(manifests[0], - mmio_regions=[invalid_mmioregion_base]), - 'assert': jexcep.ValidationError - }, - 'invalid_mmioregion_size': { - 'partition': dict(manifests[0], - mmio_regions=[invalid_mmioregion_size]), - 'assert': jexcep.ValidationError - }, - 'invalid_irq_num': { - 'partition': dict(manifests[0], - irqs=[{"line_num": "str", "signal": "ISR22"}]), - 'assert': jexcep.ValidationError - }, - 'not_exist_src_filename': { - 'partition': dict(manifests[0], source_files=['missing.cpp']), - 'assert': AssertionError - }, - 'invalid_partition_id_decimal': { - 'partition': dict(manifests[0], id=-1), - 'assert': jexcep.ValidationError - }, - 'invalid_partition_id_hex': { - 'partition': dict(manifests[0], id='0xFFFFFFFF'), - 'assert': jexcep.ValidationError - }, - 'duplicates_extern_sids': { - 'partition': dict(manifests[0], extern_sids=['SID66', 'SID66']), - 'assert': jexcep.ValidationError - }, - 'exceeding_services': { - 'partition': dict(manifests[1], services=exceeding_services), - 'assert': AssertionError - } -} - - -@pytest.fixture(params=modified_json_params.values(), - ids=modified_json_params.keys()) -def modified_json(request, temp_test_data): - """ - Fixture (https://docs.pytest.org/en/latest/fixture.html) function to be - used by the tests. - This fixture function Creates a JSON manifest file from a given partition - dictionary and save it - to a temporary directory. - This fixture uses the 'temp_test_data' fixture. - This fixture is a parametrized fixture - (https://docs.pytest.org/en/latest/fixture.html#parametrizing-fixtures). - The scope of this fixture is a specific test. - - :param request: Request object which contain the current parameter from - 'modified_json_params'. - :param temp_test_data: The 'temp_test_data' fixture. - :return: A list containing these values: - - The created manifest JSON file for the current parameter. - - The expected assertion for the current parameter. - """ - testname = extract_test_name(request.node.name) - test_file = dump_manifest_to_json(request.param['partition'], testname, - temp_test_data['dir'], False) - return test_file, request.param['assert'] - - -def test_invalid_json(modified_json): - """ - Test which gets an invalid JSON manifest file (from the - 'modified_json' fixture) and tries to create a - Manifest object from it. - The test expects an assertion to happen. - - :param modified_json: The 'modified_json' fixture. - :return: - """ - with pytest.raises(modified_json[1]): - Manifest.from_json(modified_json[0]) - - -def test_valid_json(temp_test_data): - """ - Test which gets a valid JSON manifest file (from the 'temp_test_data' - fixture) and tries to create a Manifest object from it. - The test expects the Manifest to be same as the Manifest created by the - 'temp_test_data' fixture. - - :param temp_test_data: The 'temp_test_data' fixture. - :return: - """ - manifest = Manifest.from_json(temp_test_data['json']) - assert manifest == temp_test_data['manifest'] - - -# Test parametrization decorator -# See https://docs.pytest.org/en/latest/parametrize.html#pytest-mark-parametrize-parametrizing-test-functions -# Contain the parameters to be used in the 'test_validate_partition_manifest' -# test. It defines a list of (manifest, assertion) tuples which each entry -# will be the input of the 'test_validate_partition_manifest' test, the test -# will run len(LIST_OF_TUPPLES) times, each time with different (manifest, -# assertion) tuple. -# The tuple fields are: -# 'manifest': A modified partition dictionary. -# 'assertion': A tuple containing the expected assertion and assertion -# string which must occur when running with this parameter. -@pytest.mark.parametrize( - 'manifests, assertion', - [ - pytest.param( - [manifests[0], dict(manifests[1], name=manifests[0]['name'])], - (ValueError, r'Partition name .* is not unique, .*'), - id='duplicate_partition_name' - ), - pytest.param( - [manifests[0], dict(manifests[1], id=manifests[0]['id'])], - (ValueError, r'Partition id .* is not unique, .*'), - id='duplicate_partition_id' - ), - pytest.param( - [manifests[0], dict(manifests[1], services=manifests[0]['services'])], - (ValueError, r'Root of Trust Service name .* is found in both .*'), - id='duplicate_rot_srv_name' - ), - pytest.param( - [manifests[0], dict(manifests[1], services=duplicate_signal_rot_services)], - (ValueError, r'Root of Trust Service signal .* is found in both .*'), - id='duplicate_rot_srv_signal' - ), - pytest.param( - [manifests[0], dict(manifests[1], services=duplicate_identifier_rot_services)], - (ValueError, r'Root of Trust Service identifier .* is found in both .*'), - id='duplicate_rot_srv_identifier' - ), - pytest.param( - [manifests[0], dict(manifests[1], irqs=duplicate_signal_irqs)], - (ValueError, r'IRQ signal .* is found in both .*'), - id='duplicate_irq_signal' - ), - pytest.param( - [manifests[0], dict(manifests[1], irqs=duplicate_line_num_irqs)], - (ValueError, r'IRQ line number .* is found in both .*'), - id='duplicate_irq_line_num' - ), - pytest.param( - [manifests[0], dict(manifests[1], extern_sids=['SID66', 'SID999'])], - (ValueError, r'External SID\(s\) .* can\'t be found in any partition manifest.'), - id='orphan_extern_ids' - ), - pytest.param( - [manifests[0], dict(manifests[1], extern_sids=[manifests[0]['services'][0]['name']])], - (ValueError, r'Detected a circular call dependency between the partitions.'), - id='circular_call_dependency' - ), - pytest.param( - [{k: manifests[0][k] for k in manifests[0] if k != 'extern_sids'}, - dict({k: manifests[1][k] for k in manifests[1] if k != 'services' - and k != 'irqs'}, services=spe_contained_rot_services)], - (ValueError, r'Partition .* is not accessible from NSPE ' - 'and not referenced by any other partition.'), - id='dead_partition' - ) - ] -) -def test_validate_partition_manifest(request, temp_test_data, manifests, assertion): - """ - Test which creates an invalid manifest object (after passing JSON schema - validation) and call - validate_partition_manifests() with it and with a valid manifest object. - The test expects an assertion to happen. - - :param request: Request object. - :param temp_test_data: The 'temp_test_data' fixture. - :param manifest: The manifest value from the (manifest, assertion) tuple - for the current parameter. - :param assertion: The assertion value from the (manifest, assertion) tuple - for the current parameter. - :return: - """ - test_name = extract_test_name(request.node.name) - jsons = [dump_manifest_to_json(m, '%s_%d' % (test_name, i), temp_test_data['dir']) for i, m in enumerate(manifests)] - created_manifests, _ = parse_manifests(jsons) - - with pytest.raises(assertion[0], match=assertion[1]): - validate_partition_manifests(created_manifests) - - -""" -'verify_json_params' contain the parameters to be used in the 'verify_json' -fixture. Each key in the dictionary represents a different parameter to be used -by 'verify_json', so for each test which uses the 'verify_json' fixture, the -test will run len(verify_json_params) times, each time with different -parameters. -Each parameter is a dictionary which contains these keys: - 'partition': A modified partition dictionary. - 'field': The modified field name. - 'expected': The expected field object. -""" -verify_json_params = { - 'missing_minor_version_rot_services': { - 'partition': dict(manifests[0], - services=missing_minor_version_rot_srv), - 'field': 'rot_services', - 'expected': [ - RotService( - name='SID1', identifier='0x00000001',signal='SID1', - minor_policy='RELAXED', non_secure_clients=True, minor_version=1 - ) - ] - }, - 'missing_minor_version_policy_rot_services': { - 'partition': dict(manifests[0], - services=missing_minor_version_policy_rot_srv), - 'field': 'rot_services', - 'expected': [ - RotService( - name='SID2', identifier='0x00000002', signal='SID2', - minor_policy='STRICT', non_secure_clients=True, minor_version=1 - ) - ] - }, - 'missing_minor_completley_rot_services': { - 'partition': dict(manifests[0], - services=missing_minor_completley_rot_srv), - 'field': 'rot_services', - 'expected': [ - RotService( - name='SID2', identifier='0x00000002', signal='SID2', - minor_policy='STRICT', non_secure_clients=True, minor_version=1 - ) - ] - } -} - - -@pytest.fixture(params=verify_json_params.values(), - ids=verify_json_params.keys()) -def verify_json(request, tmpdir_factory): - """ - Fixture (https://docs.pytest.org/en/latest/fixture.html) function to be - used by the tests. - This fixture function Creates 2 JSON manifest files (The 1st from - 'verify_json_params', the 2nd from manifests[1]) and saves them to a - temporary directory. This fixture is a parametrized fixture - (https://docs.pytest.org/en/latest/fixture.html#parametrizing-fixtures). - The scope of this fixture is a specific test. - - :param request: Request object which contain the current parameter from - 'verify_json_params'. - :param tmpdir_factory: The 'tmpdir_factory' fixture. - :return: A dictionary containing these keys: - 'files_list': A list of the created manifest JSON files. - 'field': The changed field in the 1st manifest. - 'expected': The expected 'field' object. - """ - test_dir = tmpdir_factory.mktemp('test_data') - test_name = extract_test_name(request.node.name) - files_list = [ - dump_manifest_to_json(request.param['partition'], '%s1' % test_name, - test_dir), - dump_manifest_to_json(dict(manifests[1], extern_sids=[]), - '%s2' % test_name, test_dir) - ] - return {'files_list': files_list, 'field': request.param['field'], - 'expected': request.param['expected']} - - -def test_verify_json(verify_json): - """ - Test which gets 2 JSON manifest files (from the 'verify_json' fixture), - create Manifest objects from them, call validate_partition_manifests() on - the manifest objects and check that the 1st Manifest object is as expected. - - :param verify_json: The 'verify_json' fixture. - :return: - """ - test_manifests, _ = parse_manifests(verify_json['files_list']) - validate_partition_manifests(test_manifests) - assert getattr(test_manifests[0], verify_json['field']) == verify_json['expected'] - - -@pytest.fixture(scope="function") -def test_template_setup(tmpdir_factory): - """ - Fixture (https://docs.pytest.org/en/latest/fixture.html) function to be - used by the tests. This fixture function Creates JSON manifest files, - Manifest objects from 'manifest' and template files in a temporary - directory. The scope of this fixture is the entire test session. - - :param tmpdir_factory: Fixture used to create temporary directories. - see: https://docs.pytest.org/en/latest/tmpdir.html#the-tmpdir-factory-fixture - :return: A dictionary containing these keys: - 'dir': The temporary directory object created by this fixture. - 'template_files': List of the created template files. - 'manifest_files': List of the created manifest JSON files. - 'manifests': List of the created Manifest objects. - 'filters': Dictionary with additional filters for - generate_source_files() - """ - - def find_priority_key(value): - """ - Finds the key in 'Manifest.PRIORITY' of a given value. - - :param value: The value. - :return: The key of the given value. - """ - return next( - (key for key, val in Manifest.PRIORITY.items() if val == value), - None) - - def find_permission_key(value): - """ - Finds the key in 'MmioRegion.MMIO_PERMISIONS' of a given value. - - :param value: The value. - :return: The key of the given value. - """ - return next((key for key, val in MmioRegion.MMIO_PERMISSIONS.items() if - val == value), None) - - test_dir = tmpdir_factory.mktemp('test_data') - manifest_files = [ - dump_manifest_to_json(manifest, manifest['name'], test_dir) for - manifest in manifests] - manifest_objects, regions = parse_manifests(manifest_files) - filters = { - 'basename': os.path.basename, - 'find_priority_key': find_priority_key, - 'find_permission_key': find_permission_key - } - template_files = [test_dir.join('_NAME_data.json.tpl'), - test_dir.join('common.json.tpl')] - for template, _file in [(test_partition_template, template_files[0]), - (test_common_template, template_files[1])]: - _file.write(template) - template_files = [_file.strpath for _file in template_files] - - expected_common_files = [test_dir.join('common.json')] - for output, _file in [(test_common_expected, expected_common_files[0])]: - _file.write(output) - expected_common_files = [_file.strpath for _file in expected_common_files] - - return { - 'dir': test_dir.strpath, - 'template_files': template_files, - 'manifest_files': manifest_files, - 'common_files': expected_common_files, - 'manifests': manifest_objects, - 'region_list': regions, - 'filters': filters - } - - -def test_generate_source_files(test_template_setup): - """ - Test which calls generate_source_files() with the data from - 'test_template_setup' fixture and checks normal output. - - :param test_template_setup: The 'test_template_setup' fixture. - :return: - """ - - before_file_list = set(os.listdir(test_template_setup['dir'])) - partition_templates = filter(lambda filename: '_NAME_' in filename, test_template_setup['template_files']) - common_templates = filter(lambda filename: '_NAME_' not in filename, test_template_setup['template_files']) - common_templates = { - t: path_join(test_template_setup['dir'], os.path.basename(os.path.splitext(t)[0])) for t in common_templates - } - - region_pair_list = list(itertools.combinations(test_template_setup['region_list'], 2)) - for manifest in test_template_setup['manifests']: - generate_source_files( - templates=manifest.templates_to_files(partition_templates, test_template_setup['dir'], test_template_setup['dir']), - render_args={ - 'partition': manifest, - 'dependent_partitions': manifest.find_dependencies(test_template_setup['manifests']) - }, - extra_filters=test_template_setup['filters'] - ) - - generate_source_files( - common_templates, - render_args={ - 'partitions': test_template_setup['manifests'], - 'region_pair_list': region_pair_list - }, - extra_filters=test_template_setup['filters'] - ) - - after_file_list = set(os.listdir(test_template_setup['dir'])) - generated_files = list(after_file_list.difference(before_file_list)) - - for gen_file in [os.path.join(test_template_setup['dir'], f) for f in generated_files]: - """ - For each generated json file in 'autogen_dir': - 1. Load the json file to a dictionary named 'generated'. - 2. If it was generated from a partition template ('generated' has a 'name' key): - a) Read the original manifest json from the test temp dir. - b) Load the manifest json file to a dictionary named 'expected'. - Else (generated from a common template): - a) Calculate 'region_list'. - b) Build the 'expected' dictionary with values from the original manifest objects. - 3. Compare 'generated' with 'expected'. - """ - with open(gen_file) as fh: - generated = json.load(fh) - - if 'name' in generated: - input_file = os.path.join(test_template_setup['dir'], - generated['name'] + '.json') - assert os.path.isfile(input_file) - assert input_file in test_template_setup['manifest_files'] - with open(input_file) as fh: - expected = json.load(fh) - else: - expected = { - 'num_of_partitions': len(test_template_setup['manifests']), - 'partition_names': [manifest.name for manifest in - test_template_setup['manifests']], - 'num_of_region_pairs': len(region_pair_list) - } - assert generated == expected - - -circular_call_dependency_params = { - 'no manifests': { - 'manifests': [], - 'result': False - }, - 'one manifest': { - 'manifests': ['PARTITION1'], - 'result': False - }, - '2 manifests with dependency': { - 'manifests': ['PARTITION1', 'PARTITION2'], - 'result': True - }, - '2 manifests without dependency': { - 'manifests': ['PARTITION1', 'PARTITION3'], - 'result': False - }, - '5 manifests with dependency': { - 'manifests': ['PARTITION1', 'PARTITION3', 'PARTITION4', 'PARTITION5', 'PARTITION6'], - 'result': True - }, - '5 manifests without dependency': { - 'manifests': ['PARTITION1', 'PARTITION3', 'PARTITION4', 'PARTITION6', 'PARTITION7'], - 'result': False - } -} - - -@pytest.fixture(params=circular_call_dependency_params.values(), - ids=circular_call_dependency_params.keys()) -def circular_dependencies(request, tmpdir_factory): - """ - Fixture (https://docs.pytest.org/en/latest/fixture.html) function to be - used by the tests. - This fixture function Creates a JSON manifest file from a given partition - dictionary and save it - to a temporary directory. - This fixture uses the 'temp_test_data' fixture. - This fixture is a parametrized fixture - (https://docs.pytest.org/en/latest/fixture.html#parametrizing-fixtures). - The scope of this fixture is a specific test. - - :param request: Request object which contain the current parameter from - 'circular_call_dependency_params'. - :param temp_test_data: The 'temp_test_data' fixture. - :return: A Dictionary containing these values: - - files - list of manifest filesgenerated - - The expected result from check_circular_call_dependencies - """ - test_dir = tmpdir_factory.mktemp('test_data') - - test_manifests = filter(lambda x: x['name'] in request.param['manifests'], - manifests_for_circular_call_dependency_checks) - manifest_files = [ - dump_manifest_to_json(manifest, manifest['name'], test_dir) for - manifest in test_manifests] - - return {'files': manifest_files, 'result': request.param['result']} - - -def test_check_circular_call_dependencies(circular_dependencies): - """ - Test detection of circular call dependencies between the partitions. - The test performs the circular call dependency check in a few - predefined partition topologies and compares the result with the expected value. - - :param circular_dependencies: the 'circular_dependencies' fixture - :return: - """ - objects, _ = parse_manifests(circular_dependencies['files']) - assert check_circular_call_dependencies(objects) == circular_dependencies[ - 'result']