mbed-os/tools/psa/generate_mbed_spm_partition...

228 lines
8.0 KiB
Python

#!/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 itertools
import os
import sys
from os.path import join as path_join
from jinja2 import Environment, FileSystemLoader, StrictUndefined
# 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 Manifest, validate_partition_manifests, manifests_discovery
__version__ = '1.0'
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
TEMPLATES_DIR = path_join(SCRIPT_DIR, 'mbed_spm', 'templates')
MANIFEST_TEMPLATES = [filename for filename in
[os.path.join(dp, f) for dp, dn, fn in
os.walk(TEMPLATES_DIR) for f in fn if f.endswith('.tpl')]
if '_NAME_' in filename]
COMMON_TEMPLATES = [filename for filename in
[os.path.join(dp, f) for dp, dn, fn in
os.walk(TEMPLATES_DIR) for f in fn if f.endswith('.tpl')]
if '_NAME_' not in filename]
MANIFEST_FILE_PATTERN = '*_psa.json'
MBED_OS_ROOT = os.path.abspath(path_join(SCRIPT_DIR, os.pardir, os.pardir))
SPM_CORE_ROOT = path_join(MBED_OS_ROOT, 'components', 'TARGET_PSA', 'TARGET_MBED_SPM')
SPM_TESTS_ROOT = path_join(MBED_OS_ROOT, 'TESTS', 'psa')
def generate_source_files(
templates,
render_args,
output_folder,
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 output_folder: Output directory for file generation
: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)
if not os.path.exists(output_folder):
os.makedirs(output_folder)
for fname, data in rendered_files:
with open(fname, 'wt') as fh:
fh.write(data)
return output_folder
def generate_partitions_sources(manifest_files, extra_filters=None):
"""
Process all the given manifest files and generate C code from them
:param manifest_files: List of manifest files
:param extra_filters: Dictionary of extra filters to use in the rendering
process
:return: List of paths to the generated files
"""
# Construct a list of all the manifests and sids.
manifests = []
for manifest_file in manifest_files:
manifest = Manifest.from_json(manifest_file)
manifests.append(manifest)
generated_folders = set()
for manifest in manifests:
manifest_output_folder = manifest.autogen_folder
render_args = {
'partition': manifest,
'dependent_partitions': manifest.find_dependencies(manifests),
'script_ver': __version__
}
manifest_output_folder = generate_source_files(
manifest.templates_to_files(MANIFEST_TEMPLATES,
TEMPLATES_DIR,
manifest_output_folder),
render_args,
manifest_output_folder,
extra_filters=extra_filters
)
generated_folders.add(manifest_output_folder)
return list(generated_folders)
def generate_psa_setup(manifest_files, output_dir, weak_setup,
extra_filters=None):
"""
Process all the given manifest files and generate C setup code from them
:param manifest_files: List of manifest files
:param output_dir: Output directory for the generated files
:param weak_setup: Is the functions/data in the setup file weak
(can be overridden by another setup file)
:param extra_filters: Dictionary of extra filters to use in the rendering
process
:return: path to the setup generated files
"""
autogen_folder = output_dir
templates_dict = {
t: path_join(autogen_folder,
os.path.relpath(os.path.splitext(t)[0], TEMPLATES_DIR))
for t in COMMON_TEMPLATES
}
complete_source_list = list(templates_dict.values())
# Construct lists of all the manifests and mmio_regions.
region_list = []
manifests = []
for manifest_file in manifest_files:
manifest_obj = Manifest.from_json(manifest_file)
manifests.append(manifest_obj)
for region in manifest_obj.mmio_regions:
region_list.append(region)
complete_source_list.extend(
list(manifest_obj.templates_to_files(
MANIFEST_TEMPLATES,
TEMPLATES_DIR,
manifest_obj.autogen_folder).values())
)
# Validate the correctness of the manifest collection.
validate_partition_manifests(manifests)
render_args = {
'partitions': manifests,
'regions': region_list,
'region_pair_list': list(itertools.combinations(region_list, 2)),
'weak': weak_setup,
'script_ver': __version__
}
return generate_source_files(
templates_dict,
render_args,
autogen_folder,
extra_filters=extra_filters
)
def generate_psa_code():
# Find all manifest files in the mbed-os tree
manifest_files = manifests_discovery(MBED_OS_ROOT)
# Generate partition code for each manifest file
generate_partitions_sources(manifest_files)
test_manifest_files = sorted(
[path for path in manifest_files if 'TESTS' in path])
system_manifest_files = sorted(
list(set(manifest_files) - set(test_manifest_files)))
# Generate default system psa setup file (only system partitions)
generate_psa_setup(system_manifest_files, SPM_CORE_ROOT, weak_setup=True)
tests_dir_content = [path_join(SPM_TESTS_ROOT, f) for f in
os.listdir(SPM_TESTS_ROOT)]
spm_tests = [path for path in tests_dir_content if os.path.isdir(path)]
# Build a dictionary for test partition in the form of:
# { test_root: manifest_list }
# For each test generate specific psa setup file (system + test partitions)
tests_dict = {test_root: [] for test_root in spm_tests}
for test_root in spm_tests:
tests_dict[test_root] = [manifest_path for manifest_path in
test_manifest_files if
test_root in manifest_path]
if not tests_dict[test_root]:
continue
tests_dict[test_root] += system_manifest_files
generate_psa_setup(sorted(tests_dict[test_root]), test_root,
weak_setup=False)
if __name__ == '__main__':
generate_psa_code()