Skip to content

Commit 516af50

Browse files
author
Michael Schwarcz
committed
Consolidating tools/tfm and tools/spm into tools/psa
1 parent 0ba963a commit 516af50

20 files changed

+357
-1147
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,5 +324,5 @@ matrix:
324324
- NAME=psa-autogen
325325
script:
326326
# Run SPM code generator and check that changes are not needed
327-
- python tools/spm/generate_partition_code.py
327+
- python tools/psa/generate_mbed_spm_partition_code.py
328328
- git diff --exit-code

tools/psa/__init__.py

Whitespace-only changes.
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
#!/usr/bin/python
2+
# Copyright (c) 2017-2018 ARM Limited
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
18+
import itertools
19+
import os
20+
import sys
21+
from os.path import join as path_join
22+
from jinja2 import Environment, FileSystemLoader, StrictUndefined
23+
24+
# Be sure that the tools directory is in the search path
25+
ROOT = os.path.abspath(path_join(os.path.dirname(__file__), os.pardir, os.pardir))
26+
sys.path.insert(0, ROOT)
27+
28+
from tools.psa.mbed_spm_tfm_common import Manifest, validate_partition_manifests, manifests_discovery
29+
30+
__version__ = '1.0'
31+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
32+
TEMPLATES_DIR = path_join(SCRIPT_DIR, 'mbed_spm', 'templates')
33+
MANIFEST_TEMPLATES = [filename for filename in
34+
[os.path.join(dp, f) for dp, dn, fn in
35+
os.walk(TEMPLATES_DIR) for f in fn if f.endswith('.tpl')]
36+
if '_NAME_' in filename]
37+
COMMON_TEMPLATES = [filename for filename in
38+
[os.path.join(dp, f) for dp, dn, fn in
39+
os.walk(TEMPLATES_DIR) for f in fn if f.endswith('.tpl')]
40+
if '_NAME_' not in filename]
41+
MANIFEST_FILE_PATTERN = '*_psa.json'
42+
MBED_OS_ROOT = os.path.abspath(path_join(SCRIPT_DIR, os.pardir, os.pardir))
43+
SPM_CORE_ROOT = path_join(MBED_OS_ROOT, 'components', 'TARGET_PSA', 'TARGET_MBED_SPM')
44+
SPM_TESTS_ROOT = path_join(MBED_OS_ROOT, 'TESTS', 'psa')
45+
46+
47+
def generate_source_files(
48+
templates,
49+
render_args,
50+
output_folder,
51+
extra_filters=None
52+
):
53+
"""
54+
Generate SPM common C code from manifests using given templates
55+
56+
:param templates: Dictionary of template and their auto-generated products
57+
:param render_args: Dictionary of arguments that should be passed to render
58+
:param output_folder: Output directory for file generation
59+
:param extra_filters: Dictionary of extra filters to use in the rendering
60+
process
61+
:return: Path to generated folder containing common generated files
62+
"""
63+
64+
rendered_files = []
65+
templates_dirs = list(
66+
set([os.path.dirname(path) for path in templates])
67+
)
68+
template_files = {os.path.basename(t): t for t in templates}
69+
70+
# Load templates for the code generation.
71+
env = Environment(
72+
loader=FileSystemLoader(templates_dirs),
73+
lstrip_blocks=True,
74+
trim_blocks=True,
75+
undefined=StrictUndefined
76+
)
77+
if extra_filters:
78+
env.filters.update(extra_filters)
79+
80+
for tf in template_files:
81+
template = env.get_template(tf)
82+
rendered_files.append(
83+
(templates[template_files[tf]], template.render(**render_args)))
84+
rendered_file_dir = os.path.dirname(templates[template_files[tf]])
85+
if not os.path.exists(rendered_file_dir):
86+
os.makedirs(rendered_file_dir)
87+
88+
if not os.path.exists(output_folder):
89+
os.makedirs(output_folder)
90+
91+
for fname, data in rendered_files:
92+
with open(fname, 'wt') as fh:
93+
fh.write(data)
94+
95+
return output_folder
96+
97+
98+
def generate_partitions_sources(manifest_files, extra_filters=None):
99+
"""
100+
Process all the given manifest files and generate C code from them
101+
102+
:param manifest_files: List of manifest files
103+
:param extra_filters: Dictionary of extra filters to use in the rendering
104+
process
105+
:return: List of paths to the generated files
106+
"""
107+
108+
# Construct a list of all the manifests and sids.
109+
manifests = []
110+
for manifest_file in manifest_files:
111+
manifest = Manifest.from_json(manifest_file)
112+
manifests.append(manifest)
113+
114+
generated_folders = set()
115+
for manifest in manifests:
116+
manifest_output_folder = manifest.autogen_folder
117+
118+
render_args = {
119+
'partition': manifest,
120+
'dependent_partitions': manifest.find_dependencies(manifests),
121+
'script_ver': __version__
122+
}
123+
manifest_output_folder = generate_source_files(
124+
manifest.templates_to_files(MANIFEST_TEMPLATES,
125+
TEMPLATES_DIR,
126+
manifest_output_folder),
127+
render_args,
128+
manifest_output_folder,
129+
extra_filters=extra_filters
130+
)
131+
generated_folders.add(manifest_output_folder)
132+
133+
return list(generated_folders)
134+
135+
136+
def generate_psa_setup(manifest_files, output_dir, weak_setup,
137+
extra_filters=None):
138+
"""
139+
Process all the given manifest files and generate C setup code from them
140+
:param manifest_files: List of manifest files
141+
:param output_dir: Output directory for the generated files
142+
:param weak_setup: Is the functions/data in the setup file weak
143+
(can be overridden by another setup file)
144+
:param extra_filters: Dictionary of extra filters to use in the rendering
145+
process
146+
:return: path to the setup generated files
147+
"""
148+
autogen_folder = output_dir
149+
templates_dict = {
150+
t: path_join(autogen_folder,
151+
os.path.relpath(os.path.splitext(t)[0], TEMPLATES_DIR))
152+
for t in COMMON_TEMPLATES
153+
}
154+
155+
complete_source_list = list(templates_dict.values())
156+
157+
# Construct lists of all the manifests and mmio_regions.
158+
region_list = []
159+
manifests = []
160+
for manifest_file in manifest_files:
161+
manifest_obj = Manifest.from_json(manifest_file)
162+
manifests.append(manifest_obj)
163+
for region in manifest_obj.mmio_regions:
164+
region_list.append(region)
165+
complete_source_list.extend(
166+
list(manifest_obj.templates_to_files(
167+
MANIFEST_TEMPLATES,
168+
TEMPLATES_DIR,
169+
manifest_obj.autogen_folder).values())
170+
)
171+
172+
# Validate the correctness of the manifest collection.
173+
validate_partition_manifests(manifests)
174+
175+
render_args = {
176+
'partitions': manifests,
177+
'regions': region_list,
178+
'region_pair_list': list(itertools.combinations(region_list, 2)),
179+
'weak': weak_setup,
180+
'script_ver': __version__
181+
}
182+
183+
return generate_source_files(
184+
templates_dict,
185+
render_args,
186+
autogen_folder,
187+
extra_filters=extra_filters
188+
)
189+
190+
191+
def generate_psa_code():
192+
# Find all manifest files in the mbed-os tree
193+
manifest_files = manifests_discovery(MBED_OS_ROOT)
194+
195+
# Generate partition code for each manifest file
196+
generate_partitions_sources(manifest_files)
197+
198+
test_manifest_files = sorted(
199+
[path for path in manifest_files if 'TESTS' in path])
200+
system_manifest_files = sorted(
201+
list(set(manifest_files) - set(test_manifest_files)))
202+
203+
# Generate default system psa setup file (only system partitions)
204+
generate_psa_setup(system_manifest_files, SPM_CORE_ROOT, weak_setup=True)
205+
206+
tests_dir_content = [path_join(SPM_TESTS_ROOT, f) for f in
207+
os.listdir(SPM_TESTS_ROOT)]
208+
spm_tests = [path for path in tests_dir_content if os.path.isdir(path)]
209+
210+
# Build a dictionary for test partition in the form of:
211+
# { test_root: manifest_list }
212+
# For each test generate specific psa setup file (system + test partitions)
213+
tests_dict = {test_root: [] for test_root in spm_tests}
214+
for test_root in spm_tests:
215+
tests_dict[test_root] = [manifest_path for manifest_path in
216+
test_manifest_files if
217+
test_root in manifest_path]
218+
219+
if not tests_dict[test_root]:
220+
continue
221+
tests_dict[test_root] += system_manifest_files
222+
generate_psa_setup(sorted(tests_dict[test_root]), test_root,
223+
weak_setup=False)
224+
225+
226+
if __name__ == '__main__':
227+
generate_psa_code()
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/bin/python
2+
# Copyright (c) 2017-2018 ARM Limited
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
18+
import json
19+
import os
20+
import sys
21+
from os.path import join as path_join
22+
from jinja2 import Environment, FileSystemLoader, StrictUndefined
23+
24+
# Be sure that the tools directory is in the search path
25+
ROOT = os.path.abspath(path_join(os.path.dirname(__file__), os.pardir, os.pardir))
26+
sys.path.insert(0, ROOT)
27+
28+
from tools.psa.mbed_spm_tfm_common import Manifest, validate_partition_manifests
29+
30+
__version__ = '1.0'
31+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
32+
MBED_OS_ROOT = os.path.abspath(path_join(SCRIPT_DIR, os.pardir, os.pardir))
33+
TEMPLATES_LIST_FILE = path_join(SCRIPT_DIR, 'tfm', 'tfm_generated_file_list.json')
34+
SERVICES_DIR = os.path.join(MBED_OS_ROOT, "components", "TARGET_PSA", "services")
35+
36+
SERVICES_MANIFESTS = [
37+
path_join(SERVICES_DIR, 'psa_prot_internal_storage', 'pits_psa.json'),
38+
path_join(SERVICES_DIR, 'platform', 'platform_psa.json'),
39+
path_join(SERVICES_DIR, 'crypto', 'crypto_partition_psa.json')
40+
]
41+
42+
43+
def generate_partition_source_files(manifest_files, extra_filters=None):
44+
"""
45+
Process all the given manifest files and generate C code from them.
46+
47+
:param manifest_files: List of manifest files
48+
:param extra_filters: Dictionary of extra filters to use in the rendering
49+
process
50+
:return: path to the setup generated files
51+
"""
52+
53+
# Construct lists of all the manifests and mmio_regions.
54+
region_list = []
55+
manifests = []
56+
for manifest_file in manifest_files:
57+
manifest_obj = Manifest.from_json(manifest_file, psa_type='TFM')
58+
manifests.append(manifest_obj)
59+
for region in manifest_obj.mmio_regions:
60+
region_list.append(region)
61+
62+
# Validate the correctness of the manifest collection.
63+
validate_partition_manifests(manifests)
64+
65+
render_args = {
66+
'partitions': manifests,
67+
}
68+
69+
# Load templates for the code generation.
70+
with open(TEMPLATES_LIST_FILE, 'r') as fh:
71+
templates_data = json.load(fh)
72+
73+
env = Environment(
74+
loader=FileSystemLoader(MBED_OS_ROOT),
75+
lstrip_blocks=True,
76+
trim_blocks=True,
77+
undefined=StrictUndefined
78+
)
79+
80+
if extra_filters:
81+
env.filters.update(extra_filters)
82+
83+
# Generate code for each template
84+
for tpl in templates_data:
85+
template = env.get_template(tpl['template'])
86+
data = template.render(**render_args)
87+
output_path = os.path.join(MBED_OS_ROOT, tpl['output'])
88+
output_folder = os.path.dirname(output_path)
89+
90+
if not os.path.exists(output_folder):
91+
os.makedirs(output_folder)
92+
93+
with open(output_path, 'wt') as fh:
94+
fh.write(data)
95+
96+
97+
def generate_tfm_code():
98+
generate_partition_source_files(SERVICES_MANIFESTS)
99+
100+
101+
if __name__ == '__main__':
102+
generate_tfm_code()

0 commit comments

Comments
 (0)