blob: 5cc25ce756d073bd7afdd5ca9a187162fe530b85 [file] [log] [blame]
Miklos Balint470919c2018-05-22 17:51:29 +02001#-------------------------------------------------------------------------------
Xinyu Zhang90f08dc2022-01-12 15:55:17 +08002# Copyright (c) 2018-2022, 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
Miklos Balint470919c2018-05-22 17:51:29 +020017
18try:
19 import yaml
20except ImportError as e:
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -050021 logging.error (str(e) + " To install it, type:")
22 logging.error ("pip install PyYAML")
Miklos Balint470919c2018-05-22 17:51:29 +020023 exit(1)
24
Edison Ai48b2d9e2019-06-24 14:39:45 +080025donotedit_warning = \
Sherry Zhangf58f2bd2022-01-10 17:21:11 +080026 ' WARNING: This is an auto-generated file. Do not edit! '
Kevin Peng655f2392019-11-27 16:33:02 +080027
Kevin Pengce99e5d2021-11-09 18:06:53 +080028TFM_ROOT_DIR = os.path.join(sys.path[0], '..')
Kevin Peng655f2392019-11-27 16:33:02 +080029OUT_DIR = None # The root directory that files are generated to
Edison Ai48b2d9e2019-06-24 14:39:45 +080030
Sherry Zhang87e6d2e2021-12-27 14:48:59 +080031# PID[0, TFM_PID_BASE - 1] are reserved for TF-M SPM and test usages
Kevin Pengce99e5d2021-11-09 18:06:53 +080032TFM_PID_BASE = 256
33
Ruiqi Jiang71d361c2021-06-23 17:45:55 +010034# variable for checking for duplicated sid
35sid_list = []
Mate Toth-Pal36f21842018-11-08 16:12:51 +010036class TemplateLoader(BaseLoader):
37 """
38 Template loader class.
Miklos Balint470919c2018-05-22 17:51:29 +020039
Mate Toth-Pal36f21842018-11-08 16:12:51 +010040 An instance of this class is passed to the template engine. It is
41 responsible for reading the template file
42 """
43 def __init__(self):
44 pass
Miklos Balint470919c2018-05-22 17:51:29 +020045
Mate Toth-Pal36f21842018-11-08 16:12:51 +010046 def get_source(self, environment, template):
47 """
48 This function reads the template files.
49 For detailed documentation see:
50 http://jinja.pocoo.org/docs/2.10/api/#jinja2.BaseLoader.get_source
51
52 Please note that this function always return 'false' as 'uptodate'
53 value, so the output file will always be generated.
54 """
55 if not os.path.isfile(template):
56 raise TemplateNotFound(template)
57 with open(template) as f:
58 source = f.read()
59 return source, template, False
60
Kevin Pengce99e5d2021-11-09 18:06:53 +080061def get_single_macro_def_from_file(file_name, macro_name):
62 """
63 This function parses the given file_name to get the definition of the given
64 C Macro (macro_name).
65
66 It assumes that the target Macro has no multiple definitions in different
67 build configurations.
68
69 It supports Macros defined in multi-line, for example:
70 #define SOME_MACRO \
71 the_macro_value
72
73 Inputs:
74 - file_name: the file to get the Macro from
75 - macro_name: the name of the Macro to get
76 Returns:
77 - The Macro definition with '()' stripped, or Exception if not found
78 """
79
80 with open(file_name, 'r') as f:
81 pattern = re.compile(r'#define\s+{}[\\\s]+.*'.format(macro_name))
82 result = pattern.findall(f.read())
83
84 if len(result) != 1:
85 raise Exception('{} not defined or has multiple definitions'.format(macro_name))
86
87 macro_def = result[0].split()[-1].strip('()')
88
89 return macro_def
90
Kevin Peng5c3fee72022-02-16 22:25:22 +080091def manifest_validation(manifest, pid):
Mingyang Sun294ce2e2021-06-11 11:58:24 +080092 """
93 This function validates FF-M compliance for partition manifest, and sets
94 default values for optional attributes.
Kevin Pengce99e5d2021-11-09 18:06:53 +080095 The validation is skipped for TF-M specific Partitions (PID < TFM_PID_BASE).
Mingyang Sun294ce2e2021-06-11 11:58:24 +080096 """
Kevin Peng5bc82d22021-10-19 11:18:40 +080097
Kevin Peng5c3fee72022-02-16 22:25:22 +080098 service_list = manifest.get('services', [])
99 irq_list = manifest.get('irqs', [])
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800100
Kevin Peng5c3fee72022-02-16 22:25:22 +0800101 # "psa_framework_version" validation
102 if manifest['psa_framework_version'] not in [1.0, 1.1]:
103 raise Exception('Invalid psa_framework_version of {}'.format(manifest['name']))
104
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700105 # "type" validation
Kevin Peng5c3fee72022-02-16 22:25:22 +0800106 if manifest['type'] not in ['PSA-ROT', 'APPLICATION-ROT']:
107 raise Exception('Invalid type of {}'.format(manifest['name']))
108
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700109 # "priority" validation
110 if manifest['priority'] not in ['HIGH', 'NORMAL', 'LOW']:
111 raise Exception('Invalid priority of {}'.format(manifest['name']))
112
Kevin Peng5c3fee72022-02-16 22:25:22 +0800113 # Every PSA Partition must have at least either a secure service or an IRQ
Kevin Pengce99e5d2021-11-09 18:06:53 +0800114 if (pid == None or pid >= TFM_PID_BASE) \
Kevin Peng8849b6a2021-11-09 14:17:35 +0800115 and len(service_list) == 0 and len(irq_list) == 0:
116 raise Exception('{} must declare at least either a secure service or an IRQ!'
Kevin Peng5c3fee72022-02-16 22:25:22 +0800117 .format(manifest['name']))
118
119 if manifest['psa_framework_version'] == 1.0:
120 # For 1.0 Partition, the model is IPC
121 manifest['model'] = 'IPC'
122
123 # "model" validation:
124 model = manifest.get('model', None)
125 if model == None:
126 raise Exception('{} is missing the "model" attribute'.format(manifest['name']))
127
128 # Assign a unified 'entry' for templates
129 if model == 'IPC':
130 # entry_point is mandatory for IPC Partitions
131 if 'entry_point' not in manifest.keys():
132 raise Exception('{} is missing the "entry_point" attribute'.format(manifest['name']))
133 manifest['entry'] = manifest['entry_point']
134 elif model == 'SFN':
135 if 'entry_init' in manifest.keys():
136 manifest['entry'] = manifest['entry_init']
137 else:
138 manifest['entry'] = 0
139 else:
140 raise Exception('Invalid "model" of {}'.format(manifest['name']))
Kevin Peng8849b6a2021-11-09 14:17:35 +0800141
142 # Service FF-M manifest validation
143 for service in service_list:
Kevin Peng5c3fee72022-02-16 22:25:22 +0800144 if manifest['psa_framework_version'] == 1.0:
145 service['connection_based'] = True
146 elif 'connection_based' not in service:
147 raise Exception("'connection_based' is mandatory in FF-M 1.1 service!")
148
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800149 if 'version' not in service.keys():
150 service['version'] = 1
151 if 'version_policy' not in service.keys():
Kevin Peng5bc82d22021-10-19 11:18:40 +0800152 service['version_policy'] = 'STRICT'
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800153
Kevin Peng5bc82d22021-10-19 11:18:40 +0800154 # SID duplication check
155 if service['sid'] in sid_list:
156 raise Exception('Service ID: {} has duplications!'.format(service['sid']))
157 else:
158 sid_list.append(service['sid'])
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100159
Kevin Peng5c3fee72022-02-16 22:25:22 +0800160 return manifest
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800161
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800162def check_circular_dependency(partitions, service_partition_map):
163 """
164 This function detects if there is any circular partition dependency chain.
165 If a circular dependency is detected, the script exits with error.
166
167 Inputs:
168 - partitions: dict of partition manifests
169 - service_partition_map: map between services and their owner Partitions
170 """
171
172 dependency_table = {}
173 for partition in partitions:
174 manifest = partition['manifest']
175 dependencies = manifest['dependencies'].copy() \
176 if 'dependencies' in manifest else []
177 dependencies += manifest['weak_dependencies'].copy() \
178 if 'weak_dependencies' in manifest else []
179 dependency_table[manifest['name']] = {
180 'dependencies': [service_partition_map[dependency]
181 for dependency in dependencies
182 if dependency in service_partition_map],
183 'validated': False
184 }
185
186 for partition in dependency_table.keys():
187 validate_dependency_chain(partition, dependency_table, [])
188
189def validate_dependency_chain(partition,
190 dependency_table,
191 dependency_chain):
192 """
193 Recursively validate if the given partition and its dependencies
194 have a circular dependency with the given dependency_chain.
195 Exit with error code once any circular is detected.
196
197 Inputs:
198 - partition: next partition to be checked
199 - dependency_table: dict of partitions and their dependencies
200 - dependency_chain: list of dependencies in current chain
201 """
202
203 dependency_chain.append(partition)
204 if partition in dependency_chain[:-1]:
205 logging.error(
206 'Circular dependency exists in chain: {}'.format(
207 ', '.join(dependency_chain)))
208 exit(1)
209 for dependency in dependency_table[partition]['dependencies']:
210 if dependency_table[dependency]['validated']:
211 continue
212 validate_dependency_chain(dependency, dependency_table, dependency_chain)
213 dependency_table[partition]['validated'] = True
214
Kevin Peng76c0c162022-02-09 22:49:06 +0800215def process_partition_manifests(manifest_lists, isolation_level, backend):
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100216 """
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800217 Parse the input manifest lists, check if manifest settings are valid,
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700218 generate the data base for generated files
Kevin Peng655f2392019-11-27 16:33:02 +0800219 and generate manifest header files.
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100220
221 Parameters
222 ----------
Kevin Peng65064c52021-10-27 17:12:17 +0800223 manifest_lists:
224 A list of Secure Partition manifest lists and their original paths.
225 The manifest lists might be processed by CMake and the paths might be
226 different to the original ones. Original paths are needed to handle
227 relative paths in the lists.
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700228 The format must be [list A, original path A, list B, orignal path B, ...]
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100229
230 Returns
231 -------
Kevin Peng5bc82d22021-10-19 11:18:40 +0800232 The manifest data base.
Edison Ai48b2d9e2019-06-24 14:39:45 +0800233 """
Kevin Peng655f2392019-11-27 16:33:02 +0800234
Kevin Peng5bc82d22021-10-19 11:18:40 +0800235 context = {}
236
Ken Liu861b0782021-05-22 13:15:08 +0800237 partition_list = []
Kevin Peng65064c52021-10-27 17:12:17 +0800238 all_manifests = []
Kevin Peng56b0ea62021-10-18 11:32:57 +0800239 pid_list = []
240 no_pid_manifest_idx = []
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800241 service_partition_map = {}
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800242 partition_statistics = {
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800243 'connection_based_srv_num': 0,
Kevin Peng47c26ec2022-03-11 11:49:52 +0800244 'ipc_partitions': [],
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800245 'flih_num': 0,
246 'slih_num': 0
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800247 }
Kevin Peng9f1a7542022-02-07 16:32:27 +0800248 config_impl = {
249 'CONFIG_TFM_SPM_BACKEND_SFN' : '0',
250 'CONFIG_TFM_SPM_BACKEND_IPC' : '0',
251 'CONFIG_TFM_PSA_API_SFN_CALL' : '0',
252 'CONFIG_TFM_PSA_API_CROSS_CALL' : '0',
253 'CONFIG_TFM_PSA_API_SUPERVISOR_CALL' : '0',
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800254 'CONFIG_TFM_CONNECTION_BASED_SERVICE_API' : '0',
255 'CONFIG_TFM_FLIH_API' : '0',
256 'CONFIG_TFM_SLIH_API' : '0'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800257 }
Kevin Peng655f2392019-11-27 16:33:02 +0800258
Kevin Peng65064c52021-10-27 17:12:17 +0800259 # Get all the manifests information as a dictionary
260 for i, item in enumerate(manifest_lists):
261 if i % 2 == 0 and not os.path.isfile(item):
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500262 logging.error('Manifest list item [{}] must be a file'.format(i))
Kevin Peng65064c52021-10-27 17:12:17 +0800263 exit(1)
Kevin Peng655f2392019-11-27 16:33:02 +0800264
Kevin Peng65064c52021-10-27 17:12:17 +0800265 if i % 2 == 1:
266 if not os.path.isdir(item):
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500267 logging.error('Manifest list item [{}] must be a directory'.format(i))
Kevin Peng65064c52021-10-27 17:12:17 +0800268 exit(1)
David Hub2694202021-07-15 14:58:39 +0800269
Kevin Peng65064c52021-10-27 17:12:17 +0800270 # Skip original manifest paths
271 continue
David Hub2694202021-07-15 14:58:39 +0800272
Kevin Peng65064c52021-10-27 17:12:17 +0800273 # The manifest list file generated by configure_file()
274 with open(item) as manifest_list_yaml_file:
275 manifest_dic = yaml.safe_load(manifest_list_yaml_file)['manifest_list']
276 for dict in manifest_dic:
277 # Add original path of manifest list.
278 # The validation will be done in the next loop.
279 dict['list_path'] = manifest_lists[i + 1]
280 all_manifests.append(dict)
281
Chris Brand4b69fcf2022-06-06 09:37:49 -0700282 logging.info("------------ Display partition configuration - start ------------")
283
Kevin Peng65064c52021-10-27 17:12:17 +0800284 # Parse the manifests
285 for i, manifest_item in enumerate(all_manifests):
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800286 valid_enabled_conditions = ['on', 'true', 'enabled']
Kevin Peng50f413c2021-11-12 10:31:45 +0800287 valid_disabled_conditions = ['off', 'false', 'disabled', '']
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800288 is_enabled = ''
289
290 if 'conditional' in manifest_item.keys():
Kevin Peng50f413c2021-11-12 10:31:45 +0800291 is_enabled = str(manifest_item['conditional']).lower()
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800292 else:
Chris Brand4b69fcf2022-06-06 09:37:49 -0700293 # Partitions without 'conditional' are always on
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800294 is_enabled = 'on'
295
296 if is_enabled in valid_disabled_conditions:
Anton Komlev58dde462022-07-07 13:50:02 +0100297 logging.info(" {:40s} OFF".format(manifest_item['name']))
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800298 continue
Chris Brand4b69fcf2022-06-06 09:37:49 -0700299 elif is_enabled in valid_enabled_conditions:
Anton Komlev58dde462022-07-07 13:50:02 +0100300 logging.info(" {:40s} ON".format(manifest_item['name']))
Chris Brand4b69fcf2022-06-06 09:37:49 -0700301 else:
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800302 raise Exception('Invalid "conditional" attribute: "{}" for {}. '
303 'Please set to one of {} or {}, case-insensitive.'\
304 .format(manifest_item['conditional'],
305 manifest_item['name'],
306 valid_enabled_conditions, valid_disabled_conditions))
307
Xinyu Zhangc46ee1f2021-04-01 10:10:43 +0800308 # Check if partition ID is manually set
309 if 'pid' not in manifest_item.keys():
310 no_pid_manifest_idx.append(i)
Kevin Peng8849b6a2021-11-09 14:17:35 +0800311 pid = None
Kevin Peng56b0ea62021-10-18 11:32:57 +0800312 else:
Kevin Peng8849b6a2021-11-09 14:17:35 +0800313 pid = manifest_item['pid']
314
315 # Check if partition ID is duplicated
316 if pid in pid_list:
Antonio de Angelisbaa27642022-05-25 11:07:12 +0100317 raise Exception('PID No. {} has already been used!'.format(pid))
Kevin Peng8849b6a2021-11-09 14:17:35 +0800318 else:
319 pid_list.append(pid)
Xinyu Zhang19504a52021-03-31 16:26:20 +0800320
Raef Coles558487a2020-10-29 13:09:44 +0000321 # Replace environment variables in the manifest path
Kevin Peng655f2392019-11-27 16:33:02 +0800322 manifest_path = os.path.expandvars(manifest_item['manifest'])
Kevin Peng65064c52021-10-27 17:12:17 +0800323 # Convert to absolute path. If it's already abspath, the path will not be changed.
324 manifest_path = os.path.join(manifest_item['list_path'], manifest_path).replace('\\', '/')
David Hub2694202021-07-15 14:58:39 +0800325
Kevin Peng5bc82d22021-10-19 11:18:40 +0800326 with open(manifest_path) as manifest_file:
Kevin Pengec0e5ce2022-02-17 13:48:51 +0800327 manifest = yaml.safe_load(manifest_file)
328 if manifest.get('model', None) == 'dual':
329 # If a Partition supports both models, it can set the "model" to "backend".
330 # The actual model used follows the backend being used.
331 manifest['model'] = backend
332 manifest = manifest_validation(manifest, pid)
Kevin Peng655f2392019-11-27 16:33:02 +0800333
Kevin Pengce99e5d2021-11-09 18:06:53 +0800334 if pid == None or pid >= TFM_PID_BASE:
Kevin Pengd08f3ba2021-11-18 15:18:56 +0800335 # Count the number of IPC/SFN partitions
Kevin Peng47c26ec2022-03-11 11:49:52 +0800336 if manifest['model'] == 'IPC':
337 partition_statistics['ipc_partitions'].append(manifest['name'])
Mingyang Suneab7eae2021-09-30 13:06:52 +0800338
Kevin Peng5c3fee72022-02-16 22:25:22 +0800339 # Set initial value to -1 to make (srv_idx + 1) reflect the correct
340 # number (0) when there are no services.
341 srv_idx = -1
342 for srv_idx, service in enumerate(manifest.get('services', [])):
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800343 service_partition_map[service['name']] = manifest['name']
Kevin Peng5c3fee72022-02-16 22:25:22 +0800344 if manifest['model'] == 'IPC':
345 # Assign signal value, the first 4 bits are reserved by FF-M
346 service['signal_value'] = (1 << (srv_idx + 4))
347 else:
348 # Signals of SFN Partitions are SPM internal only, does not
349 # need to reserve 4 bits.
350 service['signal_value'] = (1 << srv_idx)
351 if service['connection_based']:
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800352 partition_statistics['connection_based_srv_num'] += 1
Kevin Peng5c3fee72022-02-16 22:25:22 +0800353 logging.debug('{} has {} services'.format(manifest['name'], srv_idx +1))
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800354
Kevin Peng5c3fee72022-02-16 22:25:22 +0800355 # Set initial value to -1 to make (irq + 1) reflect the correct
356 # number (0) when there are no irqs.
357 irq_idx = -1
358 for irq_idx, irq in enumerate(manifest.get('irqs', [])):
359 # Assign signal value, from the most significant bit
360 irq['signal_value'] = (1 << (31 - irq_idx))
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800361 if irq.get('handling', None) == 'FLIH':
362 partition_statistics['flih_num'] += 1
363 else:
364 partition_statistics['slih_num'] += 1
Kevin Peng5c3fee72022-02-16 22:25:22 +0800365 logging.debug('{} has {} IRQS'.format(manifest['name'], irq_idx +1))
366
367 if ((srv_idx + 1) + (irq_idx + 1)) > 28:
368 raise Exception('Total number of Services and IRQs of {} exceeds the limit (28)'
369 .format(manifest['name']))
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800370
Kevin Peng65064c52021-10-27 17:12:17 +0800371 manifest_out_basename = os.path.splitext(os.path.basename(manifest_path))[0]
Kevin Peng655f2392019-11-27 16:33:02 +0800372
Kevin Peng4fade072021-10-26 17:57:50 +0800373 if 'output_path' in manifest_item:
Kevin Peng4fade072021-10-26 17:57:50 +0800374 output_path = os.path.expandvars(manifest_item['output_path'])
Kevin Peng4fade072021-10-26 17:57:50 +0800375 else:
Kevin Peng65064c52021-10-27 17:12:17 +0800376 output_path = ''
David Hub2694202021-07-15 14:58:39 +0800377
Kevin Peng5bc82d22021-10-19 11:18:40 +0800378 manifest_head_file = os.path.join(OUT_DIR, output_path, 'psa_manifest',
379 '{}.h'.format(manifest_out_basename))\
380 .replace('\\', '/')
381 intermedia_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
382 'intermedia_{}.c'.format(manifest_out_basename))\
383 .replace('\\', '/')
384 load_info_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
385 'load_info_{}.c'.format(manifest_out_basename))\
386 .replace('\\', '/')
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800387 output_dir = os.path.join(OUT_DIR, output_path).replace('\\', '/')
Kevin Peng655f2392019-11-27 16:33:02 +0800388
Kevin Peng5bc82d22021-10-19 11:18:40 +0800389 partition_list.append({'manifest': manifest, 'attr': manifest_item,
390 'manifest_out_basename': manifest_out_basename,
391 'header_file': manifest_head_file,
392 'intermedia_file': intermedia_file,
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800393 'loadinfo_file': load_info_file,
394 'output_dir':output_dir})
Ken Liu861b0782021-05-22 13:15:08 +0800395
Chris Brand4b69fcf2022-06-06 09:37:49 -0700396 logging.info("------------ Display partition configuration - end ------------")
397
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800398 check_circular_dependency(partition_list, service_partition_map)
399
Kevin Peng56b0ea62021-10-18 11:32:57 +0800400 # Automatically assign PIDs for partitions without 'pid' attribute
Kevin Pengce99e5d2021-11-09 18:06:53 +0800401 pid = max(pid_list, default = TFM_PID_BASE - 1)
Kevin Peng56b0ea62021-10-18 11:32:57 +0800402 for idx in no_pid_manifest_idx:
Kevin Pengc424eec2021-06-25 17:26:11 +0800403 pid += 1
Kevin Peng65064c52021-10-27 17:12:17 +0800404 all_manifests[idx]['pid'] = pid
Kevin Peng56b0ea62021-10-18 11:32:57 +0800405 pid_list.append(pid)
406
Kevin Peng9f1a7542022-02-07 16:32:27 +0800407 # Set up configurations
Kevin Peng76c0c162022-02-09 22:49:06 +0800408 if backend == 'SFN':
Kevin Peng47c26ec2022-03-11 11:49:52 +0800409 if len(partition_statistics['ipc_partitions']) > 0:
410 logging.error('SFN backend does not support IPC Partitions:')
411 logging.error(partition_statistics['ipc_partitions'])
Kevin Peng9f1a7542022-02-07 16:32:27 +0800412 exit(1)
Kevin Peng76c0c162022-02-09 22:49:06 +0800413
414 if isolation_level > 1:
415 logging.error('SFN backend does not support high isolation levels.')
416 exit(1)
417
Kevin Peng9f1a7542022-02-07 16:32:27 +0800418 config_impl['CONFIG_TFM_SPM_BACKEND_SFN'] = '1'
419 config_impl['CONFIG_TFM_PSA_API_SFN_CALL'] = '1'
Kevin Peng76c0c162022-02-09 22:49:06 +0800420 elif backend == 'IPC':
Kevin Peng9f1a7542022-02-07 16:32:27 +0800421 config_impl['CONFIG_TFM_SPM_BACKEND_IPC'] = '1'
422 if isolation_level > 1:
423 config_impl['CONFIG_TFM_PSA_API_SUPERVISOR_CALL'] = '1'
424 else:
425 config_impl['CONFIG_TFM_PSA_API_CROSS_CALL'] = '1'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800426
427 if partition_statistics['connection_based_srv_num'] > 0:
428 config_impl['CONFIG_TFM_CONNECTION_BASED_SERVICE_API'] = 1
429
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800430 if partition_statistics['flih_num'] > 0:
431 config_impl['CONFIG_TFM_FLIH_API'] = 1
Joakim Anderssoneec5cd32022-06-10 12:02:07 +0200432 if partition_statistics['slih_num'] > 0:
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800433 config_impl['CONFIG_TFM_SLIH_API'] = 1
434
Kevin Peng5bc82d22021-10-19 11:18:40 +0800435 context['partitions'] = partition_list
Kevin Peng9f1a7542022-02-07 16:32:27 +0800436 context['config_impl'] = config_impl
Kevin Pengce99e5d2021-11-09 18:06:53 +0800437 context['stateless_services'] = process_stateless_services(partition_list)
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100438
Kevin Peng5bc82d22021-10-19 11:18:40 +0800439 return context
Ken Liu861b0782021-05-22 13:15:08 +0800440
441def gen_per_partition_files(context):
442 """
443 Generate per-partition files
444
445 Parameters
446 ----------
447 context:
448 context contains partition infos
449 """
450
Kevin Peng5bc82d22021-10-19 11:18:40 +0800451 partition_context = {}
Sherry Zhangf58f2bd2022-01-10 17:21:11 +0800452 partition_context['utilities'] = context['utilities']
Sherry Zhangf865c4e2022-03-23 13:53:38 +0800453 partition_context['config_impl'] = context['config_impl']
Ken Liu861b0782021-05-22 13:15:08 +0800454
Kevin Peng5bc82d22021-10-19 11:18:40 +0800455 manifesttemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/manifestfilename.template'))
456 memorytemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_intermedia.template'))
457 infotemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_load_info.template'))
Ken Liu861b0782021-05-22 13:15:08 +0800458
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500459 logging.info ("Start to generate partition files:")
Ken Liu861b0782021-05-22 13:15:08 +0800460
461 for one_partition in context['partitions']:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800462 partition_context['manifest'] = one_partition['manifest']
463 partition_context['attr'] = one_partition['attr']
464 partition_context['manifest_out_basename'] = one_partition['manifest_out_basename']
Ken Liu861b0782021-05-22 13:15:08 +0800465
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800466 logging.info ('Generating {} in {}'.format(one_partition['attr']['name'],
467 one_partition['output_dir']))
Ken Liu861b0782021-05-22 13:15:08 +0800468 outfile_path = os.path.dirname(one_partition['header_file'])
Kevin Peng655f2392019-11-27 16:33:02 +0800469 if not os.path.exists(outfile_path):
470 os.makedirs(outfile_path)
471
Kevin Peng5bc82d22021-10-19 11:18:40 +0800472 headerfile = io.open(one_partition['header_file'], 'w', newline=None)
473 headerfile.write(manifesttemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800474 headerfile.close()
Kevin Peng655f2392019-11-27 16:33:02 +0800475
Ken Liu861b0782021-05-22 13:15:08 +0800476 intermediafile_path = os.path.dirname(one_partition['intermedia_file'])
Mingyang Sund20999f2020-10-15 14:53:12 +0800477 if not os.path.exists(intermediafile_path):
478 os.makedirs(intermediafile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800479 intermediafile = io.open(one_partition['intermedia_file'], 'w', newline=None)
480 intermediafile.write(memorytemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800481 intermediafile.close()
Mingyang Sund20999f2020-10-15 14:53:12 +0800482
Ken Liu861b0782021-05-22 13:15:08 +0800483 infofile_path = os.path.dirname(one_partition['loadinfo_file'])
Mingyang Sunf6a78572021-04-02 16:51:05 +0800484 if not os.path.exists(infofile_path):
485 os.makedirs(infofile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800486 infooutfile = io.open(one_partition['loadinfo_file'], 'w', newline=None)
487 infooutfile.write(infotemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800488 infooutfile.close()
Mingyang Sunf6a78572021-04-02 16:51:05 +0800489
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500490 logging.info ("Per-partition files done:")
Mingyang Sunf6a78572021-04-02 16:51:05 +0800491
Ken Liu861b0782021-05-22 13:15:08 +0800492def gen_summary_files(context, gen_file_lists):
Kevin Peng655f2392019-11-27 16:33:02 +0800493 """
494 Generate files according to the gen_file_list
Edison Ai48b2d9e2019-06-24 14:39:45 +0800495
496 Parameters
497 ----------
Raef Colesf42f0882020-07-10 10:01:58 +0100498 gen_file_lists:
499 The lists of files to generate
Edison Ai48b2d9e2019-06-24 14:39:45 +0800500 """
Kevin Peng655f2392019-11-27 16:33:02 +0800501 file_list = []
Shawn Shana9ad1e02019-08-07 15:49:48 +0800502
Raef Colesf42f0882020-07-10 10:01:58 +0100503 for f in gen_file_lists:
504 with open(f) as file_list_yaml_file:
Kevin Peng655f2392019-11-27 16:33:02 +0800505 file_list_yaml = yaml.safe_load(file_list_yaml_file)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800506 file_list.extend(file_list_yaml['file_list'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800507
Kevin Peng655f2392019-11-27 16:33:02 +0800508 for file in file_list:
Raef Coles558487a2020-10-29 13:09:44 +0000509 # Replace environment variables in the output filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800510 manifest_out_file = os.path.expandvars(file['output'])
Raef Coles558487a2020-10-29 13:09:44 +0000511 # Replace environment variables in the template filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800512 templatefile_name = os.path.expandvars(file['template'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800513
Kevin Peng4fade072021-10-26 17:57:50 +0800514 manifest_out_file = os.path.join(OUT_DIR, manifest_out_file)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800515
Ken Liu861b0782021-05-22 13:15:08 +0800516 outfile_path = os.path.dirname(manifest_out_file)
Kevin Peng655f2392019-11-27 16:33:02 +0800517 if not os.path.exists(outfile_path):
518 os.makedirs(outfile_path)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800519
Kevin Peng655f2392019-11-27 16:33:02 +0800520 template = ENV.get_template(templatefile_name)
Edison Ai6e3f2a32019-06-11 15:29:05 +0800521
Kevin Peng5bc82d22021-10-19 11:18:40 +0800522 outfile = io.open(manifest_out_file, 'w', newline=None)
Kevin Peng655f2392019-11-27 16:33:02 +0800523 outfile.write(template.render(context))
524 outfile.close()
Edison Ai48b2d9e2019-06-24 14:39:45 +0800525
Kevin Pengce99e5d2021-11-09 18:06:53 +0800526def process_stateless_services(partitions):
Mingyang Suna1ca6112021-01-11 11:34:59 +0800527 """
528 This function collects all stateless services together, and allocates
Mingyang Sun4ecea992021-03-30 17:56:26 +0800529 stateless handles for them.
Kevin Pengc05319d2021-04-22 22:59:35 +0800530 Valid stateless handle in service will be converted to an index. If the
531 stateless handle is set as "auto", or not set, framework will allocate a
532 valid index for the service.
533 Framework puts each service into a reordered stateless service list at
534 position of "index". Other unused positions are left None.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800535 """
Kevin Pengce99e5d2021-11-09 18:06:53 +0800536
537 STATIC_HANDLE_CONFIG_FILE = 'secure_fw/spm/cmsis_psa/spm_ipc.h'
538
Kevin Pengc05319d2021-04-22 22:59:35 +0800539 collected_stateless_services = []
Kevin Pengce99e5d2021-11-09 18:06:53 +0800540 stateless_index_max_num = \
541 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_NUM_LIMIT'), base = 10)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800542
543 # Collect all stateless services first.
544 for partition in partitions:
545 # Skip the FF-M 1.0 partitions
546 if partition['manifest']['psa_framework_version'] < 1.1:
547 continue
Kevin Peng8849b6a2021-11-09 14:17:35 +0800548
549 service_list = partition['manifest'].get('services', [])
550
551 for service in service_list:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800552 if service['connection_based'] is False:
Kevin Pengc05319d2021-04-22 22:59:35 +0800553 collected_stateless_services.append(service)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800554
Kevin Pengc05319d2021-04-22 22:59:35 +0800555 if len(collected_stateless_services) == 0:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800556 return []
557
Ken Liu861b0782021-05-22 13:15:08 +0800558 if len(collected_stateless_services) > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800559 raise Exception('Stateless service numbers range exceed {number}.'.format(number=stateless_index_max_num))
Mingyang Suna1ca6112021-01-11 11:34:59 +0800560
561 """
Kevin Pengc05319d2021-04-22 22:59:35 +0800562 Allocate an empty stateless service list to store services.
563 Use "handle - 1" as the index for service, since handle value starts from
564 1 and list index starts from 0.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800565 """
Ken Liu861b0782021-05-22 13:15:08 +0800566 reordered_stateless_services = [None] * stateless_index_max_num
Kevin Pengc05319d2021-04-22 22:59:35 +0800567 auto_alloc_services = []
Mingyang Suna1ca6112021-01-11 11:34:59 +0800568
Kevin Pengc05319d2021-04-22 22:59:35 +0800569 for service in collected_stateless_services:
570 # If not set, it is "auto" by default
571 if 'stateless_handle' not in service:
572 auto_alloc_services.append(service)
573 continue
574
Mingyang Sun4ecea992021-03-30 17:56:26 +0800575 service_handle = service['stateless_handle']
Mingyang Suna1ca6112021-01-11 11:34:59 +0800576
Mingyang Sun4ecea992021-03-30 17:56:26 +0800577 # Fill in service list with specified stateless handle, otherwise skip
578 if isinstance(service_handle, int):
Ken Liu861b0782021-05-22 13:15:08 +0800579 if service_handle < 1 or service_handle > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800580 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800581 # Convert handle index to reordered service list index
582 service_handle = service_handle - 1
583
584 if reordered_stateless_services[service_handle] is not None:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800585 raise Exception('Duplicated stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800586 reordered_stateless_services[service_handle] = service
Kevin Pengc05319d2021-04-22 22:59:35 +0800587 elif service_handle == 'auto':
588 auto_alloc_services.append(service)
589 else:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800590 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800591
Kevin Pengce99e5d2021-11-09 18:06:53 +0800592 STATIC_HANDLE_IDX_BIT_WIDTH = \
593 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_IDX_BIT_WIDTH'), base = 10)
594 STATIC_HANDLE_IDX_MASK = (1 << STATIC_HANDLE_IDX_BIT_WIDTH) - 1
595
596 STATIC_HANDLE_INDICATOR_OFFSET = \
597 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_INDICATOR_OFFSET'), base = 10)
598
599 STATIC_HANDLE_VER_OFFSET = \
600 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_OFFSET'), base = 10)
601
602 STATIC_HANDLE_VER_BIT_WIDTH = \
603 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_BIT_WIDTH'), base = 10)
604 STATIC_HANDLE_VER_MASK = (1 << STATIC_HANDLE_VER_BIT_WIDTH) - 1
605
Mingyang Sun4ecea992021-03-30 17:56:26 +0800606 # Auto-allocate stateless handle and encode the stateless handle
Ken Liu861b0782021-05-22 13:15:08 +0800607 for i in range(0, stateless_index_max_num):
Mingyang Sun4ecea992021-03-30 17:56:26 +0800608 service = reordered_stateless_services[i]
609
Kevin Pengc05319d2021-04-22 22:59:35 +0800610 if service == None and len(auto_alloc_services) > 0:
611 service = auto_alloc_services.pop(0)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800612
Mingyang Sun453ad402021-03-17 17:58:33 +0800613 """
614 Encode stateless flag and version into stateless handle
Kevin Pengce99e5d2021-11-09 18:06:53 +0800615 Check STATIC_HANDLE_CONFIG_FILE for details
Mingyang Sun453ad402021-03-17 17:58:33 +0800616 """
Mingyang Sun4ecea992021-03-30 17:56:26 +0800617 stateless_handle_value = 0
618 if service != None:
Kevin Pengce99e5d2021-11-09 18:06:53 +0800619 stateless_index = (i & STATIC_HANDLE_IDX_MASK)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800620 stateless_handle_value |= stateless_index
Kevin Pengce99e5d2021-11-09 18:06:53 +0800621 stateless_handle_value |= (1 << STATIC_HANDLE_INDICATOR_OFFSET)
622 stateless_version = (service['version'] & STATIC_HANDLE_VER_MASK) << STATIC_HANDLE_VER_OFFSET
Mingyang Sun453ad402021-03-17 17:58:33 +0800623 stateless_handle_value |= stateless_version
Mingyang Sun4ecea992021-03-30 17:56:26 +0800624 service['stateless_handle_value'] = '0x{0:08x}'.format(stateless_handle_value)
Ken Liu861b0782021-05-22 13:15:08 +0800625 service['stateless_handle_index'] = stateless_index
Mingyang Suna1ca6112021-01-11 11:34:59 +0800626
Mingyang Sun4ecea992021-03-30 17:56:26 +0800627 reordered_stateless_services[i] = service
628
629 return reordered_stateless_services
Mingyang Suna1ca6112021-01-11 11:34:59 +0800630
Kevin Peng655f2392019-11-27 16:33:02 +0800631def parse_args():
Raef Coles558487a2020-10-29 13:09:44 +0000632 parser = argparse.ArgumentParser(description='Parse secure partition manifest list and generate files listed by the file list',
633 epilog='Note that environment variables in template files will be replaced with their values')
634
Kevin Peng655f2392019-11-27 16:33:02 +0800635 parser.add_argument('-o', '--outdir'
636 , dest='outdir'
Kevin Peng4fade072021-10-26 17:57:50 +0800637 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800638 , metavar='out_dir'
Kevin Peng4fade072021-10-26 17:57:50 +0800639 , help='The root directory for generated files')
Shawn Shana9ad1e02019-08-07 15:49:48 +0800640
Kevin Peng5bc82d22021-10-19 11:18:40 +0800641 parser.add_argument('-m', '--manifest-lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100642 , nargs='+'
Kevin Peng5bc82d22021-10-19 11:18:40 +0800643 , dest='manifest_lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100644 , required=True
Kevin Peng65064c52021-10-27 17:12:17 +0800645 , metavar='manifest list'
646 , help='A list of Secure Partition manifest lists and their original paths.\n\
647 The manifest lists might be processed by CMake and\n\
648 the path might be different to the original one\n\
649 The format must be [list A, orignal path A, list B, orignal path B, ...]')
Kevin Peng655f2392019-11-27 16:33:02 +0800650
651 parser.add_argument('-f', '--file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100652 , nargs='+'
Kevin Peng655f2392019-11-27 16:33:02 +0800653 , dest='gen_file_args'
Raef Colesf42f0882020-07-10 10:01:58 +0100654 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800655 , metavar='file-list'
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700656 , help='These files describe the file list to generate')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800657
658 parser.add_argument('-l', '--isolation-level'
659 , dest='isolation_level'
660 , required=True
661 , choices=['1', '2', '3']
Kevin Peng76c0c162022-02-09 22:49:06 +0800662 , metavar='isolation-level')
663
664 parser.add_argument('-b', '--backend'
665 , dest='backend'
666 , required=True
667 , choices=['IPC', 'SFN']
668 , metavar='spm-backend'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800669 , help='The isolation level')
670
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500671 parser.add_argument('-q', '--quiet'
672 , dest='quiet'
673 , required=False
674 , default=False
675 , action='store_true'
676 , help='Reduce log messages')
Kevin Peng655f2392019-11-27 16:33:02 +0800677
678 args = parser.parse_args()
Kevin Peng655f2392019-11-27 16:33:02 +0800679
Kevin Peng65064c52021-10-27 17:12:17 +0800680 if len(args.manifest_lists) % 2 != 0:
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500681 logging.error('Invalid structure in manifest lists.\n'
Kevin Peng65064c52021-10-27 17:12:17 +0800682 'Each element shall consist of a manifest list and its original path')
683 exit(1)
684
Kevin Peng655f2392019-11-27 16:33:02 +0800685 return args
686
687ENV = Environment(
688 loader = TemplateLoader(),
689 autoescape = select_autoescape(['html', 'xml']),
690 lstrip_blocks = True,
691 trim_blocks = True,
692 keep_trailing_newline = True
693 )
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100694
Miklos Balint470919c2018-05-22 17:51:29 +0200695def main():
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100696 """
697 The entry point of the script.
698
699 Generates the output files based on the templates and the manifests.
700 """
Shawn Shana9ad1e02019-08-07 15:49:48 +0800701
Kevin Peng655f2392019-11-27 16:33:02 +0800702 global OUT_DIR
Shawn Shana9ad1e02019-08-07 15:49:48 +0800703
Kevin Peng655f2392019-11-27 16:33:02 +0800704 args = parse_args()
Shawn Shana9ad1e02019-08-07 15:49:48 +0800705
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500706 logging.basicConfig(format='%(message)s'
707 , level=logging.WARNING if args.quiet else logging.INFO)
708
Kevin Peng5bc82d22021-10-19 11:18:40 +0800709 OUT_DIR = os.path.abspath(args.outdir)
Kevin Peng655f2392019-11-27 16:33:02 +0800710
Kevin Peng5bc82d22021-10-19 11:18:40 +0800711 manifest_lists = [os.path.abspath(x) for x in args.manifest_lists]
712 gen_file_lists = [os.path.abspath(x) for x in args.gen_file_args]
Shawn Shana9ad1e02019-08-07 15:49:48 +0800713
Shawn Shana9ad1e02019-08-07 15:49:48 +0800714 """
Kevin Peng655f2392019-11-27 16:33:02 +0800715 Relative path to TF-M root folder is supported in the manifests
716 and default value of manifest list and generated file list are relative to TF-M root folder as well,
717 so first change directory to TF-M root folder.
Shawn Shana9ad1e02019-08-07 15:49:48 +0800718 By doing this, the script can be executed anywhere
Kevin Peng655f2392019-11-27 16:33:02 +0800719 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 +0800720 """
Kevin Peng5bc82d22021-10-19 11:18:40 +0800721 os.chdir(os.path.join(sys.path[0], '..'))
Shawn Shana9ad1e02019-08-07 15:49:48 +0800722
Kevin Peng76c0c162022-02-09 22:49:06 +0800723 context = process_partition_manifests(manifest_lists,
724 int(args.isolation_level),
725 args.backend)
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100726
Edison Ai6e3f2a32019-06-11 15:29:05 +0800727 utilities = {}
Mingyang Suna1ca6112021-01-11 11:34:59 +0800728 utilities['donotedit_warning'] = donotedit_warning
Miklos Balint470919c2018-05-22 17:51:29 +0200729
Kevin Peng655f2392019-11-27 16:33:02 +0800730 context['utilities'] = utilities
Mingyang Suneab7eae2021-09-30 13:06:52 +0800731
Ken Liu861b0782021-05-22 13:15:08 +0800732 gen_per_partition_files(context)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800733 gen_summary_files(context, gen_file_lists)
Miklos Balint470919c2018-05-22 17:51:29 +0200734
Kevin Peng5bc82d22021-10-19 11:18:40 +0800735if __name__ == '__main__':
Miklos Balint470919c2018-05-22 17:51:29 +0200736 main()