|
14 | 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15 | 15 | # See the License for the specific language governing permissions and
|
16 | 16 | # limitations under the License.
|
17 |
| - |
| 17 | +import argparse |
18 | 18 | import itertools
|
19 | 19 | import json
|
20 | 20 | import os
|
|
27 | 27 |
|
28 | 28 | from tools.psa.mbed_spm_tfm_common import validate_partition_manifests, \
|
29 | 29 | manifests_discovery, parse_manifests, generate_source_files, \
|
30 |
| - MBED_OS_ROOT, SERVICES_DIR, TESTS_DIR |
| 30 | + MBED_OS_ROOT |
31 | 31 |
|
32 |
| -__version__ = '1.0' |
| 32 | +__version__ = '1.1' |
33 | 33 | SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
34 | 34 | MANIFEST_FILE_PATTERN = '*_psa.json'
|
35 | 35 | PSA_CORE_ROOT = path_join(MBED_OS_ROOT, 'components', 'TARGET_PSA')
|
36 |
| -TFM_TEMPLATES_DESC = path_join(SCRIPT_DIR, 'tfm', 'tfm_generated_file_list.json') |
37 |
| -MBED_SPM_TEMPLATES_DESC = path_join(SCRIPT_DIR, 'mbed_spm', 'mbed_spm_generated_file_list.json') |
38 |
| -MBED_SPM_TEMPLATES_DIR = path_join(SCRIPT_DIR, 'mbed_spm', 'templates') |
39 |
| - |
40 |
| - |
41 |
| -def generate_partitions_sources(manifest_files, extra_filters=None): |
42 |
| - """ |
43 |
| - Process all the given manifest files and generate C code from them |
44 |
| -
|
45 |
| - :param manifest_files: List of manifest files |
46 |
| - :param extra_filters: Dictionary of extra filters to use in the rendering |
47 |
| - process |
48 |
| - :return: List of paths to the generated files |
49 |
| - """ |
50 |
| - |
51 |
| - # Construct a list of all the manifests and sids. |
52 |
| - manifests, _ = parse_manifests(manifest_files, 'MBED_SPM') |
53 |
| - |
54 |
| - with open(MBED_SPM_TEMPLATES_DESC, 'r') as fh: |
55 |
| - template_data = json.load(fh) |
56 |
| - manifest_template_list = [path_join(MBED_OS_ROOT, t['template']) |
57 |
| - for t in template_data['partition']] |
58 |
| - |
59 |
| - generated_folders = set() |
60 |
| - for manifest in manifests: |
61 |
| - manifest_output_folder = manifest.autogen_folder |
62 |
| - render_args = { |
63 |
| - 'partition': manifest, |
64 |
| - 'dependent_partitions': manifest.find_dependencies(manifests), |
65 |
| - 'script_ver': __version__ |
66 |
| - } |
| 36 | +TEMPLATES_DESC = path_join(SCRIPT_DIR, 'spm_template_file_list.json') |
| 37 | + |
| 38 | + |
| 39 | +def _get_timestamp(f): |
| 40 | + return os.path.getmtime(f) if os.path.isfile(f) else 0 |
67 | 41 |
|
68 |
| - manifest_output_folder = generate_source_files( |
69 |
| - manifest.templates_to_files(manifest_template_list, |
70 |
| - MBED_SPM_TEMPLATES_DIR, |
71 |
| - manifest_output_folder), |
72 |
| - render_args, |
73 |
| - manifest_output_folder, |
74 |
| - extra_filters=extra_filters |
75 |
| - ) |
76 |
| - |
77 |
| - generated_folders.add(manifest_output_folder) |
78 |
| - |
79 |
| - return list(generated_folders) |
80 |
| - |
81 |
| - |
82 |
| -def generate_psa_setup(manifest_files, output_dir, weak_setup, extra_filters=None): |
83 |
| - """ |
84 |
| -Process all the given manifest files and generate C setup code from them |
85 |
| - :param manifest_files: List of manifest files |
86 |
| - :param output_dir: Output directory for the generated files |
87 |
| - :param weak_setup: Is the functions/data in the setup file weak |
88 |
| - (can be overridden by another setup file) |
89 |
| - :param extra_filters: Dictionary of extra filters to use in the rendering |
90 |
| - process |
91 |
| - :return: path to the setup generated files |
92 |
| - """ |
93 |
| - with open(MBED_SPM_TEMPLATES_DESC, 'r') as fh: |
94 |
| - template_data = json.load(fh) |
| 42 | + |
| 43 | +def is_up_to_date(manifest_files, out_files): |
| 44 | + manifest_timestamp = max(_get_timestamp(f) for f in manifest_files) |
| 45 | + out_timestamps = min(_get_timestamp(f) for f in out_files) |
| 46 | + return manifest_timestamp <= out_timestamps |
| 47 | + |
| 48 | + |
| 49 | +def generate_spm_code(service_files, app_files, output_dir): |
| 50 | + with open(TEMPLATES_DESC, 'r') as fh: |
| 51 | + templates_data = json.load(fh) |
95 | 52 | templates_dict = {
|
96 | 53 | path_join(MBED_OS_ROOT, t['template']):
|
97 |
| - path_join(output_dir, t['target']) |
98 |
| - for t in template_data['common'] |
| 54 | + path_join(output_dir, t['output']) for t in templates_data |
99 | 55 | }
|
100 | 56 |
|
| 57 | + if is_up_to_date(service_files + app_files, list(templates_dict.values())): |
| 58 | + return |
| 59 | + |
101 | 60 | # Construct lists of all the manifests and mmio_regions.
|
102 |
| - manifests, region_list = parse_manifests(manifest_files, 'MBED_SPM') |
| 61 | + service_manifests, service_region_list = parse_manifests(service_files) |
| 62 | + test_manifests, test_region_list = parse_manifests(app_files) |
103 | 63 |
|
104 | 64 | # Validate the correctness of the manifest collection.
|
105 |
| - validate_partition_manifests(manifests) |
| 65 | + validate_partition_manifests(service_manifests + test_manifests) |
| 66 | + |
| 67 | + region_list = service_region_list + test_region_list |
106 | 68 |
|
107 | 69 | render_args = {
|
108 |
| - 'partitions': manifests, |
| 70 | + 'service_partitions': service_manifests, |
| 71 | + 'test_partitions': test_manifests, |
| 72 | + 'script_ver': __version__, |
109 | 73 | 'regions': region_list,
|
110 | 74 | 'region_pair_list': list(itertools.combinations(region_list, 2)),
|
111 |
| - 'weak': weak_setup, |
112 |
| - 'script_ver': __version__ |
113 | 75 | }
|
114 | 76 |
|
115 |
| - return generate_source_files( |
116 |
| - templates_dict, |
117 |
| - render_args, |
118 |
| - output_dir, |
119 |
| - extra_filters=extra_filters |
120 |
| - ) |
121 |
| - |
122 |
| - |
123 |
| -def generate_psa_code(service_files, test_files): |
124 |
| - # Generate partition code for each manifest file |
125 |
| - generate_partitions_sources(service_files + test_files) |
126 |
| - |
127 |
| - # Generate default system psa setup file (only system partitions) |
128 |
| - generate_psa_setup(service_files, PSA_CORE_ROOT, weak_setup=True) |
| 77 | + generate_source_files(templates_dict, render_args) |
129 | 78 |
|
130 |
| - tests_dict = {} |
131 |
| - for test_manifest in test_files: |
132 |
| - test_dir = os.path.dirname(test_manifest) |
133 |
| - if test_dir not in tests_dict: |
134 |
| - tests_dict[test_dir] = [test_manifest] |
135 |
| - else: |
136 |
| - tests_dict[test_dir].append(test_manifest) |
137 | 79 |
|
138 |
| - for test_dir in tests_dict: |
139 |
| - generate_psa_setup(service_files + tests_dict[test_dir], |
140 |
| - test_dir, weak_setup=False) |
| 80 | +class AppendReadableDir(argparse.Action): |
| 81 | + def __call__(self, parser, namespace, values, option_string=None): |
| 82 | + prosp_dir = os.path.abspath(values) |
| 83 | + if not os.path.isdir(prosp_dir): |
| 84 | + raise argparse.ArgumentTypeError("{} is missing".format(prosp_dir)) |
| 85 | + if not os.access(prosp_dir, os.R_OK): |
| 86 | + raise argparse.ArgumentTypeError( |
| 87 | + "{} is not a accessible for read".format(prosp_dir)) |
| 88 | + if not getattr(namespace, self.dest): |
| 89 | + setattr(namespace, self.dest, []) |
| 90 | + getattr(namespace, self.dest).append(prosp_dir) |
141 | 91 |
|
142 | 92 |
|
143 |
| -def generate_tfm_code(service_files, test_files): |
144 |
| - # Construct lists of all the manifests and mmio_regions. |
145 |
| - service_manifests, service_region_list = parse_manifests( |
146 |
| - service_files, 'TFM') |
147 |
| - test_manifests, test_region_list = parse_manifests( |
148 |
| - test_files, 'TFM') |
| 93 | +def get_parser(): |
| 94 | + parser = argparse.ArgumentParser( |
| 95 | + description='PSA SPM code generator', |
| 96 | + formatter_class=argparse.ArgumentDefaultsHelpFormatter |
| 97 | + ) |
| 98 | + parser.add_argument( |
| 99 | + '-u', '--user-app', |
| 100 | + action=AppendReadableDir, |
| 101 | + default=[ROOT], |
| 102 | + help='Root directory for recursive PSA manifest scan. Use for adding ' |
| 103 | + 'application specific secure partitions. Can be supplied more ' |
| 104 | + 'than once', |
| 105 | + metavar='DIR' |
| 106 | + ) |
149 | 107 |
|
150 |
| - # Validate the correctness of the manifest collection. |
151 |
| - validate_partition_manifests(service_manifests + test_manifests) |
| 108 | + parser.add_argument( |
| 109 | + '-o', '--output-dir', |
| 110 | + default=ROOT, |
| 111 | + help='Root directory for generating the sources', |
| 112 | + metavar='DIR' |
| 113 | + ) |
152 | 114 |
|
153 |
| - render_args = { |
154 |
| - 'service_partitions': service_manifests, |
155 |
| - 'test_partitions': test_manifests |
156 |
| - } |
| 115 | + return parser |
157 | 116 |
|
158 |
| - with open(TFM_TEMPLATES_DESC, 'r') as fh: |
159 |
| - templates_data = json.load(fh) |
160 |
| - templates_dict = { |
161 |
| - path_join(MBED_OS_ROOT, t['template']): |
162 |
| - path_join(MBED_OS_ROOT, t['output']) for t in templates_data |
163 |
| - } |
164 | 117 |
|
165 |
| - generate_source_files(templates_dict, render_args, MBED_OS_ROOT) |
| 118 | +def main(): |
| 119 | + parser = get_parser() |
| 120 | + args = parser.parse_args() |
166 | 121 |
|
| 122 | + services, apps = manifests_discovery(root_dirs=args.user_app, |
| 123 | + ignore_paths=['BUILD', '.git']) |
167 | 124 |
|
168 |
| -def main(): |
169 |
| - services, _ = manifests_discovery(root_dir=SERVICES_DIR) |
170 |
| - _, tests = manifests_discovery(root_dir=TESTS_DIR) |
171 |
| - generate_psa_code(services, tests) |
172 |
| - generate_tfm_code(services, tests) |
| 125 | + generate_spm_code(services, apps, args.output_dir) |
173 | 126 |
|
174 | 127 |
|
175 | 128 | if __name__ == '__main__':
|
|
0 commit comments