blob: 35ba2a79b0b574bdfed88d47642b72675a77a714 [file] [log] [blame]
Miklos Balint470919c2018-05-22 17:51:29 +02001#-------------------------------------------------------------------------------
David Hu7f86d7e2025-03-15 00:24:04 +00002# Copyright (c) 2018-2025, Arm Limited. All rights reserved.
Chris Brandf1d6b6f2022-07-22 11:49:01 -07003# Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company)
4# or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
Miklos Balint470919c2018-05-22 17:51:29 +02005#
6# SPDX-License-Identifier: BSD-3-Clause
7#
8#-------------------------------------------------------------------------------
9
10import os
Mate Toth-Pal36f21842018-11-08 16:12:51 +010011import io
Kevin Pengce99e5d2021-11-09 18:06:53 +080012import re
Shawn Shana9ad1e02019-08-07 15:49:48 +080013import sys
14import argparse
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -050015import logging
Ken Liu1f345b02020-05-30 21:11:05 +080016from jinja2 import Environment, BaseLoader, select_autoescape, TemplateNotFound
David Hu7f86d7e2025-03-15 00:24:04 +000017from manifest_helpers import manifest_client_id_validate
Miklos Balint470919c2018-05-22 17:51:29 +020018
19try:
20 import yaml
21except ImportError as e:
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -050022 logging.error (str(e) + " To install it, type:")
23 logging.error ("pip install PyYAML")
Miklos Balint470919c2018-05-22 17:51:29 +020024 exit(1)
25
Edison Ai48b2d9e2019-06-24 14:39:45 +080026donotedit_warning = \
Sherry Zhangf58f2bd2022-01-10 17:21:11 +080027 ' WARNING: This is an auto-generated file. Do not edit! '
Kevin Peng655f2392019-11-27 16:33:02 +080028
Kevin Pengce99e5d2021-11-09 18:06:53 +080029TFM_ROOT_DIR = os.path.join(sys.path[0], '..')
Kevin Peng655f2392019-11-27 16:33:02 +080030OUT_DIR = None # The root directory that files are generated to
Edison Ai48b2d9e2019-06-24 14:39:45 +080031
Sherry Zhang87e6d2e2021-12-27 14:48:59 +080032# PID[0, TFM_PID_BASE - 1] are reserved for TF-M SPM and test usages
Kevin Pengce99e5d2021-11-09 18:06:53 +080033TFM_PID_BASE = 256
34
Ruiqi Jiang71d361c2021-06-23 17:45:55 +010035# variable for checking for duplicated sid
36sid_list = []
chesun012345aa52023-04-18 17:31:53 +080037
Jason Guo8a45a682023-08-23 11:22:37 +080038# Manifest attributes defined by FF-M
39ffm_manifest_attributes = \
40 ['psa_framework_version', 'name', 'type', 'priority', 'model', 'entry_point', 'stack_size', \
41 'description', 'entry_init', 'heap_size', 'mmio_regions', 'services', 'irqs', 'dependencies',\
42 # TF-M extension of PSA attributes for mailbox client support.
43 'client_id_base', 'client_id_limit']
44
45# Manifest attributes defined by FF-M within "service" attribute
46ffm_manifest_services_attributes = \
47 ['name', 'sid', 'non_secure_clients', 'description', 'version', 'version_policy', \
48 'connection_based', 'stateless_handle', 'mm_iovec']
49
50# Manifest attributes defined by FF-M within "mmio_regions" attribute
51ffm_manifest_mmio_regions_attributes = ['name', 'base', 'size', 'permission']
52
53# Manifest attributes defined by FF-M within "irqs" attribute
54ffm_manifest_irqs_attributes = ['source', 'signal', 'name', 'handling', 'description',\
55 # TF-M extension of PSA attributes for mailbox client support.
56 'client_id_base', 'client_id_limit']
chesun012345aa52023-04-18 17:31:53 +080057
Mate Toth-Pal36f21842018-11-08 16:12:51 +010058class TemplateLoader(BaseLoader):
59 """
60 Template loader class.
Miklos Balint470919c2018-05-22 17:51:29 +020061
Mate Toth-Pal36f21842018-11-08 16:12:51 +010062 An instance of this class is passed to the template engine. It is
63 responsible for reading the template file
64 """
65 def __init__(self):
66 pass
Miklos Balint470919c2018-05-22 17:51:29 +020067
Mate Toth-Pal36f21842018-11-08 16:12:51 +010068 def get_source(self, environment, template):
69 """
70 This function reads the template files.
71 For detailed documentation see:
72 http://jinja.pocoo.org/docs/2.10/api/#jinja2.BaseLoader.get_source
73
74 Please note that this function always return 'false' as 'uptodate'
75 value, so the output file will always be generated.
76 """
77 if not os.path.isfile(template):
78 raise TemplateNotFound(template)
79 with open(template) as f:
80 source = f.read()
81 return source, template, False
82
Kevin Pengfb1761b2022-05-12 12:11:31 +080083def parse_configurations(file_paths):
84 """
85 Parses the given config files and return a dict whose key-values are build
86 configurations and their values.
87
88 Valid configurations should be in the format of:
89 "#define VAR [...]" in a single line.
90 The value of the config is optional.
91 """
92 configurations = {}
93
94 lines = []
95 for file in file_paths:
96 with open(file, 'r') as config_file:
97 lines += config_file.readlines()
98
99 for line in lines:
100 if not line.startswith('#define'):
101 continue
102
103 line = line.rstrip('\r\n')
104 line_items = line.split(maxsplit=2)
105 if len(line_items) == 3:
106 configurations[line_items[1]] = line_items[2]
107 elif len(line_items) == 2:
108 configurations[line_items[1]] = ''
109
110 logging.debug(configurations)
111
112 return configurations
113
Kevin Peng5c3fee72022-02-16 22:25:22 +0800114def manifest_validation(manifest, pid):
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800115 """
116 This function validates FF-M compliance for partition manifest, and sets
117 default values for optional attributes.
Kevin Pengce99e5d2021-11-09 18:06:53 +0800118 The validation is skipped for TF-M specific Partitions (PID < TFM_PID_BASE).
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800119 """
Kevin Peng5bc82d22021-10-19 11:18:40 +0800120
Kevin Peng5c3fee72022-02-16 22:25:22 +0800121 service_list = manifest.get('services', [])
122 irq_list = manifest.get('irqs', [])
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800123
Kevin Peng5c3fee72022-02-16 22:25:22 +0800124 # "psa_framework_version" validation
125 if manifest['psa_framework_version'] not in [1.0, 1.1]:
126 raise Exception('Invalid psa_framework_version of {}'.format(manifest['name']))
127
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700128 # "type" validation
Kevin Peng5c3fee72022-02-16 22:25:22 +0800129 if manifest['type'] not in ['PSA-ROT', 'APPLICATION-ROT']:
130 raise Exception('Invalid type of {}'.format(manifest['name']))
131
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700132 # "priority" validation
133 if manifest['priority'] not in ['HIGH', 'NORMAL', 'LOW']:
134 raise Exception('Invalid priority of {}'.format(manifest['name']))
135
Chris Brandc422cdd2022-07-21 13:32:47 -0700136 if 'ns_agent' not in manifest:
137 manifest['ns_agent'] = False
138
Kevin Peng5c3fee72022-02-16 22:25:22 +0800139 # Every PSA Partition must have at least either a secure service or an IRQ
Kevin Pengce99e5d2021-11-09 18:06:53 +0800140 if (pid == None or pid >= TFM_PID_BASE) \
Kevin Peng8849b6a2021-11-09 14:17:35 +0800141 and len(service_list) == 0 and len(irq_list) == 0:
142 raise Exception('{} must declare at least either a secure service or an IRQ!'
Kevin Peng5c3fee72022-02-16 22:25:22 +0800143 .format(manifest['name']))
144
145 if manifest['psa_framework_version'] == 1.0:
146 # For 1.0 Partition, the model is IPC
147 manifest['model'] = 'IPC'
148
149 # "model" validation:
150 model = manifest.get('model', None)
151 if model == None:
152 raise Exception('{} is missing the "model" attribute'.format(manifest['name']))
153
154 # Assign a unified 'entry' for templates
155 if model == 'IPC':
156 # entry_point is mandatory for IPC Partitions
157 if 'entry_point' not in manifest.keys():
158 raise Exception('{} is missing the "entry_point" attribute'.format(manifest['name']))
159 manifest['entry'] = manifest['entry_point']
160 elif model == 'SFN':
161 if 'entry_init' in manifest.keys():
162 manifest['entry'] = manifest['entry_init']
163 else:
164 manifest['entry'] = 0
165 else:
166 raise Exception('Invalid "model" of {}'.format(manifest['name']))
Kevin Peng8849b6a2021-11-09 14:17:35 +0800167
168 # Service FF-M manifest validation
169 for service in service_list:
Kevin Peng5c3fee72022-02-16 22:25:22 +0800170 if manifest['psa_framework_version'] == 1.0:
171 service['connection_based'] = True
172 elif 'connection_based' not in service:
173 raise Exception("'connection_based' is mandatory in FF-M 1.1 service!")
174
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800175 if 'version' not in service.keys():
176 service['version'] = 1
177 if 'version_policy' not in service.keys():
Kevin Peng5bc82d22021-10-19 11:18:40 +0800178 service['version_policy'] = 'STRICT'
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800179
Kevin Peng5bc82d22021-10-19 11:18:40 +0800180 # SID duplication check
181 if service['sid'] in sid_list:
182 raise Exception('Service ID: {} has duplications!'.format(service['sid']))
183 else:
184 sid_list.append(service['sid'])
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100185
Kevin Peng5c3fee72022-02-16 22:25:22 +0800186 return manifest
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800187
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800188def check_circular_dependency(partitions, service_partition_map):
189 """
190 This function detects if there is any circular partition dependency chain.
191 If a circular dependency is detected, the script exits with error.
192
193 Inputs:
194 - partitions: dict of partition manifests
195 - service_partition_map: map between services and their owner Partitions
196 """
197
198 dependency_table = {}
199 for partition in partitions:
200 manifest = partition['manifest']
201 dependencies = manifest['dependencies'].copy() \
202 if 'dependencies' in manifest else []
203 dependencies += manifest['weak_dependencies'].copy() \
204 if 'weak_dependencies' in manifest else []
205 dependency_table[manifest['name']] = {
206 'dependencies': [service_partition_map[dependency]
207 for dependency in dependencies
208 if dependency in service_partition_map],
209 'validated': False
210 }
211
212 for partition in dependency_table.keys():
213 validate_dependency_chain(partition, dependency_table, [])
214
215def validate_dependency_chain(partition,
216 dependency_table,
217 dependency_chain):
218 """
219 Recursively validate if the given partition and its dependencies
220 have a circular dependency with the given dependency_chain.
221 Exit with error code once any circular is detected.
222
223 Inputs:
224 - partition: next partition to be checked
225 - dependency_table: dict of partitions and their dependencies
226 - dependency_chain: list of dependencies in current chain
227 """
228
229 dependency_chain.append(partition)
230 if partition in dependency_chain[:-1]:
231 logging.error(
232 'Circular dependency exists in chain: {}'.format(
233 ', '.join(dependency_chain)))
234 exit(1)
235 for dependency in dependency_table[partition]['dependencies']:
236 if dependency_table[dependency]['validated']:
237 continue
238 validate_dependency_chain(dependency, dependency_table, dependency_chain)
239 dependency_table[partition]['validated'] = True
240
chesun012345aa52023-04-18 17:31:53 +0800241def manifest_attribute_check(manifest, manifest_item):
242 """
Jason Guo8a45a682023-08-23 11:22:37 +0800243 Check whether there is any invalid attribute in manifests.
244 Non-FF-M compliant attributes are allowed provided that they are explicitly registered in
245 manifest lists. And they are only allowed in the top-level attributes.
246
247 Note:
248 This method only checks the existence of invalid attributes.
249 It does not validate the values.
250 Those are done in manifest_validation().
251
252 The main purposes of this method are:
253 1. Make sure developers are aware of using Non-FF-M attributes.
254 2. Detect typos on optional attributes.
chesun012345aa52023-04-18 17:31:53 +0800255
256 Inputs:
257 - manifest: next manifest to be checked
258 - manifest_item: the manifest items in manifest lists
259 """
Jason Guo8a45a682023-08-23 11:22:37 +0800260
261 # Top-level attributes check
chesun012345aa52023-04-18 17:31:53 +0800262 allowed_attributes = ffm_manifest_attributes + manifest_item.get('non_ffm_attributes', [])
263 for keyword in manifest.keys():
264 if keyword not in allowed_attributes:
Jason Guo8a45a682023-08-23 11:22:37 +0800265 logging.error('The Non-FFM attribute "{}" is used by "{}" without registration.'
266 .format(keyword, manifest['name']))
chesun012345aa52023-04-18 17:31:53 +0800267 exit(1)
268
Jason Guo8a45a682023-08-23 11:22:37 +0800269 # "services" attribute check
270 services = manifest.get('services', [])
271 for srv in services:
272 for attr in srv.keys():
273 if attr not in ffm_manifest_services_attributes:
274 logging.error('Invalid attribute "{}" used by "{}" in "services".'
275 .format(attr, manifest['name']))
276 exit(1)
277
278 # "mmio_regions" attribute check
279 mmio_regions = manifest.get('mmio_regions', [])
280 for reg in mmio_regions:
281 for attr in reg.keys():
282 if attr not in ffm_manifest_mmio_regions_attributes:
283 logging.error('Invalid attribute "{}" used by "{}" in "mmio_regions".'
284 .format(attr, manifest['name']))
285 exit(1)
286
287 # "irqs" attribute check
288 irqs = manifest.get('irqs', [])
289 for irq in irqs:
290 for attr in irq.keys():
291 if attr not in ffm_manifest_irqs_attributes:
292 logging.error('Invalid attribute "{}" used by "{}" in "irqs".'
293 .format(attr, manifest['name']))
294 exit(1)
295
Kevin Pengfb1761b2022-05-12 12:11:31 +0800296def process_partition_manifests(manifest_lists, configs):
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100297 """
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800298 Parse the input manifest lists, check if manifest settings are valid,
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700299 generate the data base for generated files
Kevin Peng655f2392019-11-27 16:33:02 +0800300 and generate manifest header files.
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100301
302 Parameters
303 ----------
Kevin Peng65064c52021-10-27 17:12:17 +0800304 manifest_lists:
Kevin Pengfb1761b2022-05-12 12:11:31 +0800305 A list of Secure Partition manifest lists
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100306
307 Returns
308 -------
Kevin Peng5bc82d22021-10-19 11:18:40 +0800309 The manifest data base.
Edison Ai48b2d9e2019-06-24 14:39:45 +0800310 """
Kevin Peng655f2392019-11-27 16:33:02 +0800311
Kevin Peng5bc82d22021-10-19 11:18:40 +0800312 context = {}
313
Ken Liu861b0782021-05-22 13:15:08 +0800314 partition_list = []
Kevin Peng65064c52021-10-27 17:12:17 +0800315 all_manifests = []
Kevin Peng56b0ea62021-10-18 11:32:57 +0800316 pid_list = []
317 no_pid_manifest_idx = []
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800318 service_partition_map = {}
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800319 partition_statistics = {
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800320 'connection_based_srv_num': 0,
Kevin Peng47c26ec2022-03-11 11:49:52 +0800321 'ipc_partitions': [],
Sherry Zhang2ed48fd2022-09-06 11:33:22 +0800322 'mmio_region_num': 0,
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800323 'flih_num': 0,
324 'slih_num': 0
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800325 }
Kevin Peng9f1a7542022-02-07 16:32:27 +0800326 config_impl = {
327 'CONFIG_TFM_SPM_BACKEND_SFN' : '0',
328 'CONFIG_TFM_SPM_BACKEND_IPC' : '0',
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800329 'CONFIG_TFM_CONNECTION_BASED_SERVICE_API' : '0',
Sherry Zhang2ed48fd2022-09-06 11:33:22 +0800330 'CONFIG_TFM_MMIO_REGION_ENABLE' : '0',
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800331 'CONFIG_TFM_FLIH_API' : '0',
332 'CONFIG_TFM_SLIH_API' : '0'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800333 }
chesun0122abf0a2023-10-17 13:42:16 +0800334 priority_map = {
335 'LOWEST' : '00',
336 'LOW' : '01',
337 'NORMAL' : '02',
338 'HIGH' : '03',
339 'HIGHEST' : '04'
340 }
Kevin Peng655f2392019-11-27 16:33:02 +0800341
Kevin Pengfb1761b2022-05-12 12:11:31 +0800342 isolation_level = int(configs['TFM_ISOLATION_LEVEL'], base = 10)
343 backend = configs['CONFIG_TFM_SPM_BACKEND']
344
Kevin Peng65064c52021-10-27 17:12:17 +0800345 # Get all the manifests information as a dictionary
346 for i, item in enumerate(manifest_lists):
Kevin Pengfb1761b2022-05-12 12:11:31 +0800347 if not os.path.isfile(item):
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500348 logging.error('Manifest list item [{}] must be a file'.format(i))
Kevin Peng65064c52021-10-27 17:12:17 +0800349 exit(1)
Kevin Peng655f2392019-11-27 16:33:02 +0800350
Kevin Peng65064c52021-10-27 17:12:17 +0800351 # The manifest list file generated by configure_file()
352 with open(item) as manifest_list_yaml_file:
353 manifest_dic = yaml.safe_load(manifest_list_yaml_file)['manifest_list']
354 for dict in manifest_dic:
Raef Coles052e8712023-11-02 15:29:40 +0000355 # Replace environment variables in the manifest path.
356 expanded_path = os.path.expandvars(dict['manifest']).replace('\\', '/')
357
358 # If the manifest exists relative to the manifest list, then use
359 # that. Else, either interpret it as an absolute path or one
360 # relative to the current working directory
361 path_relative_to_manifest_list = os.path.join(os.path.dirname(item), # path of manifest list
362 expanded_path)
363 if os.path.isfile(path_relative_to_manifest_list):
364 manifest_path = path_relative_to_manifest_list
365 else:
366 manifest_path = expanded_path
Kevin Pengfb1761b2022-05-12 12:11:31 +0800367 dict['manifest'] = manifest_path
Kevin Peng65064c52021-10-27 17:12:17 +0800368 all_manifests.append(dict)
369
Anton Komlev52920712024-05-16 13:45:46 +0100370 logging.info("----------- Secure Partitions ------------------------")
Chris Brand4b69fcf2022-06-06 09:37:49 -0700371
Kevin Peng65064c52021-10-27 17:12:17 +0800372 # Parse the manifests
373 for i, manifest_item in enumerate(all_manifests):
Kevin Pengfb1761b2022-05-12 12:11:31 +0800374 valid_enabled_conditions = ['1', 'on', 'true', 'enabled']
375 valid_disabled_conditions = ['0', 'off', 'false', 'disabled', '']
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800376 is_enabled = ''
377
378 if 'conditional' in manifest_item.keys():
Kevin Pengfb1761b2022-05-12 12:11:31 +0800379 if manifest_item['conditional'] not in configs.keys():
380 logging.error('Configuration "{}" is not defined!'.format(manifest_item['conditional']))
381 exit(1)
382 is_enabled = configs[manifest_item['conditional']].lower()
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800383 else:
Kevin Pengfb1761b2022-05-12 12:11:31 +0800384 # Partitions without 'conditional' is always on
385 is_enabled = '1'
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800386
387 if is_enabled in valid_disabled_conditions:
BohdanHunko6cea95d2022-08-16 15:33:51 +0300388 logging.info(" {:40s} OFF".format(manifest_item['description']))
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800389 continue
Chris Brand4b69fcf2022-06-06 09:37:49 -0700390 elif is_enabled in valid_enabled_conditions:
BohdanHunko6cea95d2022-08-16 15:33:51 +0300391 logging.info(" {:40s} ON".format(manifest_item['description']))
Chris Brand4b69fcf2022-06-06 09:37:49 -0700392 else:
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800393 raise Exception('Invalid "conditional" attribute: "{}" for {}. '
394 'Please set to one of {} or {}, case-insensitive.'\
395 .format(manifest_item['conditional'],
BohdanHunko6cea95d2022-08-16 15:33:51 +0300396 manifest_item['description'],
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800397 valid_enabled_conditions, valid_disabled_conditions))
398
Xinyu Zhangc46ee1f2021-04-01 10:10:43 +0800399 # Check if partition ID is manually set
400 if 'pid' not in manifest_item.keys():
401 no_pid_manifest_idx.append(i)
Kevin Peng8849b6a2021-11-09 14:17:35 +0800402 pid = None
Kevin Peng56b0ea62021-10-18 11:32:57 +0800403 else:
Kevin Peng8849b6a2021-11-09 14:17:35 +0800404 pid = manifest_item['pid']
405
406 # Check if partition ID is duplicated
407 if pid in pid_list:
Antonio de Angelisbaa27642022-05-25 11:07:12 +0100408 raise Exception('PID No. {} has already been used!'.format(pid))
Kevin Peng8849b6a2021-11-09 14:17:35 +0800409 else:
410 pid_list.append(pid)
Xinyu Zhang19504a52021-03-31 16:26:20 +0800411
Kevin Pengfb1761b2022-05-12 12:11:31 +0800412 manifest_path = manifest_item['manifest']
Kevin Peng5bc82d22021-10-19 11:18:40 +0800413 with open(manifest_path) as manifest_file:
Kevin Pengec0e5ce2022-02-17 13:48:51 +0800414 manifest = yaml.safe_load(manifest_file)
chesun0122abf0a2023-10-17 13:42:16 +0800415 # Check manifest attribute validity
chesun012345aa52023-04-18 17:31:53 +0800416 manifest_attribute_check(manifest, manifest_item)
417
Kevin Pengec0e5ce2022-02-17 13:48:51 +0800418 if manifest.get('model', None) == 'dual':
419 # If a Partition supports both models, it can set the "model" to "backend".
420 # The actual model used follows the backend being used.
421 manifest['model'] = backend
422 manifest = manifest_validation(manifest, pid)
Kevin Peng655f2392019-11-27 16:33:02 +0800423
chesun0122abf0a2023-10-17 13:42:16 +0800424 # Priority mapping
425 numbered_priority = priority_map[manifest['priority']]
426
Jamie Foxb15418a2024-01-18 11:10:20 +0000427 if (pid == None or pid >= TFM_PID_BASE) and not manifest['ns_agent']:
428 # Count the number of IPC/SFN partitions (excluding TF-M internal
429 # and agent partitions)
Kevin Peng47c26ec2022-03-11 11:49:52 +0800430 if manifest['model'] == 'IPC':
431 partition_statistics['ipc_partitions'].append(manifest['name'])
Mingyang Suneab7eae2021-09-30 13:06:52 +0800432
Kevin Peng5c3fee72022-02-16 22:25:22 +0800433 # Set initial value to -1 to make (srv_idx + 1) reflect the correct
434 # number (0) when there are no services.
435 srv_idx = -1
436 for srv_idx, service in enumerate(manifest.get('services', [])):
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800437 service_partition_map[service['name']] = manifest['name']
Kevin Peng5c3fee72022-02-16 22:25:22 +0800438 if manifest['model'] == 'IPC':
439 # Assign signal value, the first 4 bits are reserved by FF-M
440 service['signal_value'] = (1 << (srv_idx + 4))
441 else:
442 # Signals of SFN Partitions are SPM internal only, does not
443 # need to reserve 4 bits.
444 service['signal_value'] = (1 << srv_idx)
445 if service['connection_based']:
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800446 partition_statistics['connection_based_srv_num'] += 1
Kevin Peng5c3fee72022-02-16 22:25:22 +0800447 logging.debug('{} has {} services'.format(manifest['name'], srv_idx +1))
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800448
Sherry Zhang2ed48fd2022-09-06 11:33:22 +0800449 # Calculate the number of mmio region
450 mmio_region_list = manifest.get('mmio_regions', [])
451 partition_statistics['mmio_region_num'] += len(mmio_region_list)
452
Kevin Peng5c3fee72022-02-16 22:25:22 +0800453 # Set initial value to -1 to make (irq + 1) reflect the correct
454 # number (0) when there are no irqs.
455 irq_idx = -1
456 for irq_idx, irq in enumerate(manifest.get('irqs', [])):
457 # Assign signal value, from the most significant bit
458 irq['signal_value'] = (1 << (31 - irq_idx))
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800459 if irq.get('handling', None) == 'FLIH':
460 partition_statistics['flih_num'] += 1
461 else:
462 partition_statistics['slih_num'] += 1
Kevin Peng5c3fee72022-02-16 22:25:22 +0800463 logging.debug('{} has {} IRQS'.format(manifest['name'], irq_idx +1))
464
465 if ((srv_idx + 1) + (irq_idx + 1)) > 28:
466 raise Exception('Total number of Services and IRQs of {} exceeds the limit (28)'
467 .format(manifest['name']))
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800468
Kevin Peng65064c52021-10-27 17:12:17 +0800469 manifest_out_basename = os.path.splitext(os.path.basename(manifest_path))[0]
Kevin Peng655f2392019-11-27 16:33:02 +0800470
Kevin Peng4fade072021-10-26 17:57:50 +0800471 if 'output_path' in manifest_item:
Kevin Peng4fade072021-10-26 17:57:50 +0800472 output_path = os.path.expandvars(manifest_item['output_path'])
Kevin Peng4fade072021-10-26 17:57:50 +0800473 else:
Kevin Peng65064c52021-10-27 17:12:17 +0800474 output_path = ''
David Hub2694202021-07-15 14:58:39 +0800475
Kevin Peng5bc82d22021-10-19 11:18:40 +0800476 manifest_head_file = os.path.join(OUT_DIR, output_path, 'psa_manifest',
477 '{}.h'.format(manifest_out_basename))\
478 .replace('\\', '/')
479 intermedia_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
480 'intermedia_{}.c'.format(manifest_out_basename))\
481 .replace('\\', '/')
482 load_info_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
483 'load_info_{}.c'.format(manifest_out_basename))\
484 .replace('\\', '/')
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800485 output_dir = os.path.join(OUT_DIR, output_path).replace('\\', '/')
Kevin Peng655f2392019-11-27 16:33:02 +0800486
Kevin Peng5bc82d22021-10-19 11:18:40 +0800487 partition_list.append({'manifest': manifest, 'attr': manifest_item,
488 'manifest_out_basename': manifest_out_basename,
489 'header_file': manifest_head_file,
490 'intermedia_file': intermedia_file,
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800491 'loadinfo_file': load_info_file,
chesun0122abf0a2023-10-17 13:42:16 +0800492 'output_dir': output_dir,
493 'numbered_priority': numbered_priority})
Ken Liu861b0782021-05-22 13:15:08 +0800494
Anton Komlev52920712024-05-16 13:45:46 +0100495 logging.info("------------------------------------------------------")
Chris Brand4b69fcf2022-06-06 09:37:49 -0700496
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800497 check_circular_dependency(partition_list, service_partition_map)
498
Kevin Peng56b0ea62021-10-18 11:32:57 +0800499 # Automatically assign PIDs for partitions without 'pid' attribute
Kevin Pengce99e5d2021-11-09 18:06:53 +0800500 pid = max(pid_list, default = TFM_PID_BASE - 1)
Kevin Peng56b0ea62021-10-18 11:32:57 +0800501 for idx in no_pid_manifest_idx:
Kevin Pengc424eec2021-06-25 17:26:11 +0800502 pid += 1
Kevin Peng65064c52021-10-27 17:12:17 +0800503 all_manifests[idx]['pid'] = pid
Kevin Peng56b0ea62021-10-18 11:32:57 +0800504 pid_list.append(pid)
505
Kevin Peng9f1a7542022-02-07 16:32:27 +0800506 # Set up configurations
Kevin Peng76c0c162022-02-09 22:49:06 +0800507 if backend == 'SFN':
Kevin Peng47c26ec2022-03-11 11:49:52 +0800508 if len(partition_statistics['ipc_partitions']) > 0:
509 logging.error('SFN backend does not support IPC Partitions:')
510 logging.error(partition_statistics['ipc_partitions'])
Kevin Peng9f1a7542022-02-07 16:32:27 +0800511 exit(1)
Kevin Peng76c0c162022-02-09 22:49:06 +0800512
513 if isolation_level > 1:
514 logging.error('SFN backend does not support high isolation levels.')
515 exit(1)
516
Kevin Peng9f1a7542022-02-07 16:32:27 +0800517 config_impl['CONFIG_TFM_SPM_BACKEND_SFN'] = '1'
Kevin Peng76c0c162022-02-09 22:49:06 +0800518 elif backend == 'IPC':
Kevin Peng9f1a7542022-02-07 16:32:27 +0800519 config_impl['CONFIG_TFM_SPM_BACKEND_IPC'] = '1'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800520
521 if partition_statistics['connection_based_srv_num'] > 0:
522 config_impl['CONFIG_TFM_CONNECTION_BASED_SERVICE_API'] = 1
523
Sherry Zhang2ed48fd2022-09-06 11:33:22 +0800524 if partition_statistics['mmio_region_num'] > 0:
525 config_impl['CONFIG_TFM_MMIO_REGION_ENABLE'] = 1
526
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800527 if partition_statistics['flih_num'] > 0:
528 config_impl['CONFIG_TFM_FLIH_API'] = 1
Joakim Anderssoneec5cd32022-06-10 12:02:07 +0200529 if partition_statistics['slih_num'] > 0:
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800530 config_impl['CONFIG_TFM_SLIH_API'] = 1
531
Kevin Peng5bc82d22021-10-19 11:18:40 +0800532 context['partitions'] = partition_list
Kevin Peng9f1a7542022-02-07 16:32:27 +0800533 context['config_impl'] = config_impl
Kevin Pengce99e5d2021-11-09 18:06:53 +0800534 context['stateless_services'] = process_stateless_services(partition_list)
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100535
Kevin Peng5bc82d22021-10-19 11:18:40 +0800536 return context
Ken Liu861b0782021-05-22 13:15:08 +0800537
538def gen_per_partition_files(context):
539 """
540 Generate per-partition files
541
542 Parameters
543 ----------
544 context:
545 context contains partition infos
546 """
547
Kevin Peng5bc82d22021-10-19 11:18:40 +0800548 partition_context = {}
Sherry Zhangf58f2bd2022-01-10 17:21:11 +0800549 partition_context['utilities'] = context['utilities']
Sherry Zhangf865c4e2022-03-23 13:53:38 +0800550 partition_context['config_impl'] = context['config_impl']
Ken Liu861b0782021-05-22 13:15:08 +0800551
Kevin Peng5bc82d22021-10-19 11:18:40 +0800552 manifesttemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/manifestfilename.template'))
553 memorytemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_intermedia.template'))
554 infotemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_load_info.template'))
Ken Liu861b0782021-05-22 13:15:08 +0800555
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500556 logging.info ("Start to generate partition files:")
Ken Liu861b0782021-05-22 13:15:08 +0800557
558 for one_partition in context['partitions']:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800559 partition_context['manifest'] = one_partition['manifest']
560 partition_context['attr'] = one_partition['attr']
561 partition_context['manifest_out_basename'] = one_partition['manifest_out_basename']
chesun0122abf0a2023-10-17 13:42:16 +0800562 partition_context['numbered_priority'] = one_partition['numbered_priority']
Ken Liu861b0782021-05-22 13:15:08 +0800563
BohdanHunko6cea95d2022-08-16 15:33:51 +0300564 logging.info ('Generating {} in {}'.format(one_partition['attr']['description'],
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800565 one_partition['output_dir']))
Ken Liu861b0782021-05-22 13:15:08 +0800566 outfile_path = os.path.dirname(one_partition['header_file'])
Kevin Peng655f2392019-11-27 16:33:02 +0800567 if not os.path.exists(outfile_path):
568 os.makedirs(outfile_path)
569
Kevin Peng5bc82d22021-10-19 11:18:40 +0800570 headerfile = io.open(one_partition['header_file'], 'w', newline=None)
571 headerfile.write(manifesttemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800572 headerfile.close()
Kevin Peng655f2392019-11-27 16:33:02 +0800573
Ken Liu861b0782021-05-22 13:15:08 +0800574 intermediafile_path = os.path.dirname(one_partition['intermedia_file'])
Mingyang Sund20999f2020-10-15 14:53:12 +0800575 if not os.path.exists(intermediafile_path):
576 os.makedirs(intermediafile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800577 intermediafile = io.open(one_partition['intermedia_file'], 'w', newline=None)
578 intermediafile.write(memorytemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800579 intermediafile.close()
Mingyang Sund20999f2020-10-15 14:53:12 +0800580
Ken Liu861b0782021-05-22 13:15:08 +0800581 infofile_path = os.path.dirname(one_partition['loadinfo_file'])
Mingyang Sunf6a78572021-04-02 16:51:05 +0800582 if not os.path.exists(infofile_path):
583 os.makedirs(infofile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800584 infooutfile = io.open(one_partition['loadinfo_file'], 'w', newline=None)
585 infooutfile.write(infotemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800586 infooutfile.close()
Mingyang Sunf6a78572021-04-02 16:51:05 +0800587
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500588 logging.info ("Per-partition files done:")
Mingyang Sunf6a78572021-04-02 16:51:05 +0800589
Ken Liu861b0782021-05-22 13:15:08 +0800590def gen_summary_files(context, gen_file_lists):
Kevin Peng655f2392019-11-27 16:33:02 +0800591 """
592 Generate files according to the gen_file_list
Edison Ai48b2d9e2019-06-24 14:39:45 +0800593
594 Parameters
595 ----------
Raef Colesf42f0882020-07-10 10:01:58 +0100596 gen_file_lists:
597 The lists of files to generate
Edison Ai48b2d9e2019-06-24 14:39:45 +0800598 """
Kevin Peng655f2392019-11-27 16:33:02 +0800599 file_list = []
Shawn Shana9ad1e02019-08-07 15:49:48 +0800600
Raef Colesf42f0882020-07-10 10:01:58 +0100601 for f in gen_file_lists:
602 with open(f) as file_list_yaml_file:
Kevin Peng655f2392019-11-27 16:33:02 +0800603 file_list_yaml = yaml.safe_load(file_list_yaml_file)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800604 file_list.extend(file_list_yaml['file_list'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800605
Kevin Peng655f2392019-11-27 16:33:02 +0800606 for file in file_list:
Raef Coles558487a2020-10-29 13:09:44 +0000607 # Replace environment variables in the output filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800608 manifest_out_file = os.path.expandvars(file['output'])
Raef Coles558487a2020-10-29 13:09:44 +0000609 # Replace environment variables in the template filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800610 templatefile_name = os.path.expandvars(file['template'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800611
Kevin Peng4fade072021-10-26 17:57:50 +0800612 manifest_out_file = os.path.join(OUT_DIR, manifest_out_file)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800613
Ken Liu861b0782021-05-22 13:15:08 +0800614 outfile_path = os.path.dirname(manifest_out_file)
Kevin Peng655f2392019-11-27 16:33:02 +0800615 if not os.path.exists(outfile_path):
616 os.makedirs(outfile_path)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800617
Kevin Peng655f2392019-11-27 16:33:02 +0800618 template = ENV.get_template(templatefile_name)
Edison Ai6e3f2a32019-06-11 15:29:05 +0800619
Kevin Peng5bc82d22021-10-19 11:18:40 +0800620 outfile = io.open(manifest_out_file, 'w', newline=None)
Kevin Peng655f2392019-11-27 16:33:02 +0800621 outfile.write(template.render(context))
622 outfile.close()
Edison Ai48b2d9e2019-06-24 14:39:45 +0800623
Kevin Pengce99e5d2021-11-09 18:06:53 +0800624def process_stateless_services(partitions):
Mingyang Suna1ca6112021-01-11 11:34:59 +0800625 """
626 This function collects all stateless services together, and allocates
Mingyang Sun4ecea992021-03-30 17:56:26 +0800627 stateless handles for them.
Kevin Pengc05319d2021-04-22 22:59:35 +0800628 Valid stateless handle in service will be converted to an index. If the
629 stateless handle is set as "auto", or not set, framework will allocate a
630 valid index for the service.
631 Framework puts each service into a reordered stateless service list at
632 position of "index". Other unused positions are left None.
Ken Liu50948382022-10-27 12:45:53 +0800633
634 Keep the variable names start with upper case 'STATIC_HANDLE_' the same
635 as the preprocessors in C sources. This could easier the upcomping
636 modification when developer searches these definitions for modification.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800637 """
Kevin Pengce99e5d2021-11-09 18:06:53 +0800638
Kevin Pengc05319d2021-04-22 22:59:35 +0800639 collected_stateless_services = []
Ken Liu50948382022-10-27 12:45:53 +0800640 STATIC_HANDLE_NUM_LIMIT = 32
Mingyang Suna1ca6112021-01-11 11:34:59 +0800641
642 # Collect all stateless services first.
643 for partition in partitions:
644 # Skip the FF-M 1.0 partitions
645 if partition['manifest']['psa_framework_version'] < 1.1:
646 continue
Kevin Peng8849b6a2021-11-09 14:17:35 +0800647
648 service_list = partition['manifest'].get('services', [])
649
650 for service in service_list:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800651 if service['connection_based'] is False:
Kevin Pengc05319d2021-04-22 22:59:35 +0800652 collected_stateless_services.append(service)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800653
Kevin Pengc05319d2021-04-22 22:59:35 +0800654 if len(collected_stateless_services) == 0:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800655 return []
656
Ken Liu50948382022-10-27 12:45:53 +0800657 if len(collected_stateless_services) > STATIC_HANDLE_NUM_LIMIT:
658 raise Exception('Stateless service numbers range exceed {number}.'.format(number=STATIC_HANDLE_NUM_LIMIT))
Mingyang Suna1ca6112021-01-11 11:34:59 +0800659
660 """
Kevin Pengc05319d2021-04-22 22:59:35 +0800661 Allocate an empty stateless service list to store services.
662 Use "handle - 1" as the index for service, since handle value starts from
663 1 and list index starts from 0.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800664 """
Ken Liu50948382022-10-27 12:45:53 +0800665 reordered_stateless_services = [None] * STATIC_HANDLE_NUM_LIMIT
Kevin Pengc05319d2021-04-22 22:59:35 +0800666 auto_alloc_services = []
Mingyang Suna1ca6112021-01-11 11:34:59 +0800667
Kevin Pengc05319d2021-04-22 22:59:35 +0800668 for service in collected_stateless_services:
669 # If not set, it is "auto" by default
670 if 'stateless_handle' not in service:
671 auto_alloc_services.append(service)
672 continue
673
Mingyang Sun4ecea992021-03-30 17:56:26 +0800674 service_handle = service['stateless_handle']
Mingyang Suna1ca6112021-01-11 11:34:59 +0800675
Mingyang Sun4ecea992021-03-30 17:56:26 +0800676 # Fill in service list with specified stateless handle, otherwise skip
677 if isinstance(service_handle, int):
Ken Liu50948382022-10-27 12:45:53 +0800678 if service_handle < 1 or service_handle > STATIC_HANDLE_NUM_LIMIT:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800679 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800680 # Convert handle index to reordered service list index
681 service_handle = service_handle - 1
682
683 if reordered_stateless_services[service_handle] is not None:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800684 raise Exception('Duplicated stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800685 reordered_stateless_services[service_handle] = service
Kevin Pengc05319d2021-04-22 22:59:35 +0800686 elif service_handle == 'auto':
687 auto_alloc_services.append(service)
688 else:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800689 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800690
Xinyu Zhangb2d4ed42023-02-14 11:43:16 +0800691 STATIC_HANDLE_IDX_BIT_WIDTH = 5
Kevin Pengce99e5d2021-11-09 18:06:53 +0800692 STATIC_HANDLE_IDX_MASK = (1 << STATIC_HANDLE_IDX_BIT_WIDTH) - 1
Ken Liu50948382022-10-27 12:45:53 +0800693 STATIC_HANDLE_INDICATOR_OFFSET = 30
694 STATIC_HANDLE_VER_OFFSET = 8
695 STATIC_HANDLE_VER_BIT_WIDTH = 8
Kevin Pengce99e5d2021-11-09 18:06:53 +0800696 STATIC_HANDLE_VER_MASK = (1 << STATIC_HANDLE_VER_BIT_WIDTH) - 1
697
Mingyang Sun4ecea992021-03-30 17:56:26 +0800698 # Auto-allocate stateless handle and encode the stateless handle
Ken Liu50948382022-10-27 12:45:53 +0800699 for i in range(0, STATIC_HANDLE_NUM_LIMIT):
Mingyang Sun4ecea992021-03-30 17:56:26 +0800700 service = reordered_stateless_services[i]
701
Kevin Pengc05319d2021-04-22 22:59:35 +0800702 if service == None and len(auto_alloc_services) > 0:
703 service = auto_alloc_services.pop(0)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800704
Mingyang Sun453ad402021-03-17 17:58:33 +0800705 """
706 Encode stateless flag and version into stateless handle
Mingyang Sun453ad402021-03-17 17:58:33 +0800707 """
Mingyang Sun4ecea992021-03-30 17:56:26 +0800708 stateless_handle_value = 0
709 if service != None:
Kevin Pengce99e5d2021-11-09 18:06:53 +0800710 stateless_index = (i & STATIC_HANDLE_IDX_MASK)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800711 stateless_handle_value |= stateless_index
Kevin Pengce99e5d2021-11-09 18:06:53 +0800712 stateless_handle_value |= (1 << STATIC_HANDLE_INDICATOR_OFFSET)
713 stateless_version = (service['version'] & STATIC_HANDLE_VER_MASK) << STATIC_HANDLE_VER_OFFSET
Mingyang Sun453ad402021-03-17 17:58:33 +0800714 stateless_handle_value |= stateless_version
Mingyang Sun4ecea992021-03-30 17:56:26 +0800715 service['stateless_handle_value'] = '0x{0:08x}'.format(stateless_handle_value)
Ken Liu861b0782021-05-22 13:15:08 +0800716 service['stateless_handle_index'] = stateless_index
Mingyang Suna1ca6112021-01-11 11:34:59 +0800717
Mingyang Sun4ecea992021-03-30 17:56:26 +0800718 reordered_stateless_services[i] = service
719
720 return reordered_stateless_services
Mingyang Suna1ca6112021-01-11 11:34:59 +0800721
Kevin Peng655f2392019-11-27 16:33:02 +0800722def parse_args():
Raef Coles558487a2020-10-29 13:09:44 +0000723 parser = argparse.ArgumentParser(description='Parse secure partition manifest list and generate files listed by the file list',
Juha Ylinenbc261272024-06-19 13:00:00 +0300724 epilog='Note that environment variables in template files will be replaced with their values',
725 allow_abbrev=False)
Raef Coles558487a2020-10-29 13:09:44 +0000726
Kevin Peng655f2392019-11-27 16:33:02 +0800727 parser.add_argument('-o', '--outdir'
728 , dest='outdir'
Kevin Peng4fade072021-10-26 17:57:50 +0800729 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800730 , metavar='out_dir'
Kevin Peng4fade072021-10-26 17:57:50 +0800731 , help='The root directory for generated files')
Shawn Shana9ad1e02019-08-07 15:49:48 +0800732
Kevin Peng5bc82d22021-10-19 11:18:40 +0800733 parser.add_argument('-m', '--manifest-lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100734 , nargs='+'
Kevin Peng5bc82d22021-10-19 11:18:40 +0800735 , dest='manifest_lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100736 , required=True
Kevin Peng65064c52021-10-27 17:12:17 +0800737 , metavar='manifest list'
738 , help='A list of Secure Partition manifest lists and their original paths.\n\
739 The manifest lists might be processed by CMake and\n\
740 the path might be different to the original one\n\
741 The format must be [list A, orignal path A, list B, orignal path B, ...]')
Kevin Peng655f2392019-11-27 16:33:02 +0800742
743 parser.add_argument('-f', '--file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100744 , nargs='+'
Kevin Peng655f2392019-11-27 16:33:02 +0800745 , dest='gen_file_args'
Raef Colesf42f0882020-07-10 10:01:58 +0100746 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800747 , metavar='file-list'
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700748 , help='These files describe the file list to generate')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800749
Kevin Pengfb1761b2022-05-12 12:11:31 +0800750 parser.add_argument('-c', '--config-files'
751 , nargs='+'
752 , dest='config_files'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800753 , required=True
Kevin Pengfb1761b2022-05-12 12:11:31 +0800754 , metavar='config-files'
755 , help='A header file contains build configurations')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800756
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500757 parser.add_argument('-q', '--quiet'
758 , dest='quiet'
759 , required=False
760 , default=False
761 , action='store_true'
762 , help='Reduce log messages')
Kevin Peng655f2392019-11-27 16:33:02 +0800763
764 args = parser.parse_args()
Kevin Peng655f2392019-11-27 16:33:02 +0800765
Kevin Peng655f2392019-11-27 16:33:02 +0800766 return args
767
David Hu7f86d7e2025-03-15 00:24:04 +0000768def register_helpers():
769 """
770 Register helper functions to enable templates to call those helpers.
771 """
772
773 ENV.globals["manifest_ns_agent_client_id_validate"] = manifest_client_id_validate.ns_agent_client_id_validate
774 ENV.globals["manifest_irq_client_id_validate"] = manifest_client_id_validate.irq_client_id_validate
775
Kevin Peng655f2392019-11-27 16:33:02 +0800776ENV = Environment(
777 loader = TemplateLoader(),
778 autoescape = select_autoescape(['html', 'xml']),
779 lstrip_blocks = True,
780 trim_blocks = True,
781 keep_trailing_newline = True
782 )
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100783
Miklos Balint470919c2018-05-22 17:51:29 +0200784def main():
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100785 """
786 The entry point of the script.
787
788 Generates the output files based on the templates and the manifests.
789 """
Shawn Shana9ad1e02019-08-07 15:49:48 +0800790
Kevin Peng655f2392019-11-27 16:33:02 +0800791 global OUT_DIR
Shawn Shana9ad1e02019-08-07 15:49:48 +0800792
Kevin Peng655f2392019-11-27 16:33:02 +0800793 args = parse_args()
Shawn Shana9ad1e02019-08-07 15:49:48 +0800794
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500795 logging.basicConfig(format='%(message)s'
796 , level=logging.WARNING if args.quiet else logging.INFO)
797
Kevin Peng5bc82d22021-10-19 11:18:40 +0800798 OUT_DIR = os.path.abspath(args.outdir)
Kevin Peng655f2392019-11-27 16:33:02 +0800799
David Hu7f86d7e2025-03-15 00:24:04 +0000800 register_helpers()
801
Kevin Peng5bc82d22021-10-19 11:18:40 +0800802 manifest_lists = [os.path.abspath(x) for x in args.manifest_lists]
803 gen_file_lists = [os.path.abspath(x) for x in args.gen_file_args]
Shawn Shana9ad1e02019-08-07 15:49:48 +0800804
Shawn Shana9ad1e02019-08-07 15:49:48 +0800805 """
Kevin Peng655f2392019-11-27 16:33:02 +0800806 Relative path to TF-M root folder is supported in the manifests
807 and default value of manifest list and generated file list are relative to TF-M root folder as well,
808 so first change directory to TF-M root folder.
Shawn Shana9ad1e02019-08-07 15:49:48 +0800809 By doing this, the script can be executed anywhere
Kevin Peng655f2392019-11-27 16:33:02 +0800810 The script is located in <TF-M root folder>/tools, so sys.path[0]<location of the script>/.. is TF-M root folder.
Shawn Shana9ad1e02019-08-07 15:49:48 +0800811 """
Kevin Peng5bc82d22021-10-19 11:18:40 +0800812 os.chdir(os.path.join(sys.path[0], '..'))
Shawn Shana9ad1e02019-08-07 15:49:48 +0800813
Kevin Peng76c0c162022-02-09 22:49:06 +0800814 context = process_partition_manifests(manifest_lists,
Kevin Pengfb1761b2022-05-12 12:11:31 +0800815 parse_configurations(args.config_files))
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100816
Edison Ai6e3f2a32019-06-11 15:29:05 +0800817 utilities = {}
Mingyang Suna1ca6112021-01-11 11:34:59 +0800818 utilities['donotedit_warning'] = donotedit_warning
Miklos Balint470919c2018-05-22 17:51:29 +0200819
Kevin Peng655f2392019-11-27 16:33:02 +0800820 context['utilities'] = utilities
Mingyang Suneab7eae2021-09-30 13:06:52 +0800821
Ken Liu861b0782021-05-22 13:15:08 +0800822 gen_per_partition_files(context)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800823 gen_summary_files(context, gen_file_lists)
Miklos Balint470919c2018-05-22 17:51:29 +0200824
Kevin Peng5bc82d22021-10-19 11:18:40 +0800825if __name__ == '__main__':
Miklos Balint470919c2018-05-22 17:51:29 +0200826 main()