blob: 3f76a855846fec66d8d6d7f89bc613c065a5227c [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 Pengfb1761b2022-05-12 12:11:31 +080091def parse_configurations(file_paths):
92 """
93 Parses the given config files and return a dict whose key-values are build
94 configurations and their values.
95
96 Valid configurations should be in the format of:
97 "#define VAR [...]" in a single line.
98 The value of the config is optional.
99 """
100 configurations = {}
101
102 lines = []
103 for file in file_paths:
104 with open(file, 'r') as config_file:
105 lines += config_file.readlines()
106
107 for line in lines:
108 if not line.startswith('#define'):
109 continue
110
111 line = line.rstrip('\r\n')
112 line_items = line.split(maxsplit=2)
113 if len(line_items) == 3:
114 configurations[line_items[1]] = line_items[2]
115 elif len(line_items) == 2:
116 configurations[line_items[1]] = ''
117
118 logging.debug(configurations)
119
120 return configurations
121
Kevin Peng5c3fee72022-02-16 22:25:22 +0800122def manifest_validation(manifest, pid):
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800123 """
124 This function validates FF-M compliance for partition manifest, and sets
125 default values for optional attributes.
Kevin Pengce99e5d2021-11-09 18:06:53 +0800126 The validation is skipped for TF-M specific Partitions (PID < TFM_PID_BASE).
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800127 """
Kevin Peng5bc82d22021-10-19 11:18:40 +0800128
Kevin Peng5c3fee72022-02-16 22:25:22 +0800129 service_list = manifest.get('services', [])
130 irq_list = manifest.get('irqs', [])
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800131
Kevin Peng5c3fee72022-02-16 22:25:22 +0800132 # "psa_framework_version" validation
133 if manifest['psa_framework_version'] not in [1.0, 1.1]:
134 raise Exception('Invalid psa_framework_version of {}'.format(manifest['name']))
135
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700136 # "type" validation
Kevin Peng5c3fee72022-02-16 22:25:22 +0800137 if manifest['type'] not in ['PSA-ROT', 'APPLICATION-ROT']:
138 raise Exception('Invalid type of {}'.format(manifest['name']))
139
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700140 # "priority" validation
141 if manifest['priority'] not in ['HIGH', 'NORMAL', 'LOW']:
142 raise Exception('Invalid priority of {}'.format(manifest['name']))
143
Kevin Peng5c3fee72022-02-16 22:25:22 +0800144 # Every PSA Partition must have at least either a secure service or an IRQ
Kevin Pengce99e5d2021-11-09 18:06:53 +0800145 if (pid == None or pid >= TFM_PID_BASE) \
Kevin Peng8849b6a2021-11-09 14:17:35 +0800146 and len(service_list) == 0 and len(irq_list) == 0:
147 raise Exception('{} must declare at least either a secure service or an IRQ!'
Kevin Peng5c3fee72022-02-16 22:25:22 +0800148 .format(manifest['name']))
149
150 if manifest['psa_framework_version'] == 1.0:
151 # For 1.0 Partition, the model is IPC
152 manifest['model'] = 'IPC'
153
154 # "model" validation:
155 model = manifest.get('model', None)
156 if model == None:
157 raise Exception('{} is missing the "model" attribute'.format(manifest['name']))
158
159 # Assign a unified 'entry' for templates
160 if model == 'IPC':
161 # entry_point is mandatory for IPC Partitions
162 if 'entry_point' not in manifest.keys():
163 raise Exception('{} is missing the "entry_point" attribute'.format(manifest['name']))
164 manifest['entry'] = manifest['entry_point']
165 elif model == 'SFN':
166 if 'entry_init' in manifest.keys():
167 manifest['entry'] = manifest['entry_init']
168 else:
169 manifest['entry'] = 0
170 else:
171 raise Exception('Invalid "model" of {}'.format(manifest['name']))
Kevin Peng8849b6a2021-11-09 14:17:35 +0800172
173 # Service FF-M manifest validation
174 for service in service_list:
Kevin Peng5c3fee72022-02-16 22:25:22 +0800175 if manifest['psa_framework_version'] == 1.0:
176 service['connection_based'] = True
177 elif 'connection_based' not in service:
178 raise Exception("'connection_based' is mandatory in FF-M 1.1 service!")
179
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800180 if 'version' not in service.keys():
181 service['version'] = 1
182 if 'version_policy' not in service.keys():
Kevin Peng5bc82d22021-10-19 11:18:40 +0800183 service['version_policy'] = 'STRICT'
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800184
Kevin Peng5bc82d22021-10-19 11:18:40 +0800185 # SID duplication check
186 if service['sid'] in sid_list:
187 raise Exception('Service ID: {} has duplications!'.format(service['sid']))
188 else:
189 sid_list.append(service['sid'])
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100190
Kevin Peng5c3fee72022-02-16 22:25:22 +0800191 return manifest
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800192
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800193def check_circular_dependency(partitions, service_partition_map):
194 """
195 This function detects if there is any circular partition dependency chain.
196 If a circular dependency is detected, the script exits with error.
197
198 Inputs:
199 - partitions: dict of partition manifests
200 - service_partition_map: map between services and their owner Partitions
201 """
202
203 dependency_table = {}
204 for partition in partitions:
205 manifest = partition['manifest']
206 dependencies = manifest['dependencies'].copy() \
207 if 'dependencies' in manifest else []
208 dependencies += manifest['weak_dependencies'].copy() \
209 if 'weak_dependencies' in manifest else []
210 dependency_table[manifest['name']] = {
211 'dependencies': [service_partition_map[dependency]
212 for dependency in dependencies
213 if dependency in service_partition_map],
214 'validated': False
215 }
216
217 for partition in dependency_table.keys():
218 validate_dependency_chain(partition, dependency_table, [])
219
220def validate_dependency_chain(partition,
221 dependency_table,
222 dependency_chain):
223 """
224 Recursively validate if the given partition and its dependencies
225 have a circular dependency with the given dependency_chain.
226 Exit with error code once any circular is detected.
227
228 Inputs:
229 - partition: next partition to be checked
230 - dependency_table: dict of partitions and their dependencies
231 - dependency_chain: list of dependencies in current chain
232 """
233
234 dependency_chain.append(partition)
235 if partition in dependency_chain[:-1]:
236 logging.error(
237 'Circular dependency exists in chain: {}'.format(
238 ', '.join(dependency_chain)))
239 exit(1)
240 for dependency in dependency_table[partition]['dependencies']:
241 if dependency_table[dependency]['validated']:
242 continue
243 validate_dependency_chain(dependency, dependency_table, dependency_chain)
244 dependency_table[partition]['validated'] = True
245
Kevin Pengfb1761b2022-05-12 12:11:31 +0800246def process_partition_manifests(manifest_lists, configs):
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100247 """
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800248 Parse the input manifest lists, check if manifest settings are valid,
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700249 generate the data base for generated files
Kevin Peng655f2392019-11-27 16:33:02 +0800250 and generate manifest header files.
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100251
252 Parameters
253 ----------
Kevin Peng65064c52021-10-27 17:12:17 +0800254 manifest_lists:
Kevin Pengfb1761b2022-05-12 12:11:31 +0800255 A list of Secure Partition manifest lists
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100256
257 Returns
258 -------
Kevin Peng5bc82d22021-10-19 11:18:40 +0800259 The manifest data base.
Edison Ai48b2d9e2019-06-24 14:39:45 +0800260 """
Kevin Peng655f2392019-11-27 16:33:02 +0800261
Kevin Peng5bc82d22021-10-19 11:18:40 +0800262 context = {}
263
Ken Liu861b0782021-05-22 13:15:08 +0800264 partition_list = []
Kevin Peng65064c52021-10-27 17:12:17 +0800265 all_manifests = []
Kevin Peng56b0ea62021-10-18 11:32:57 +0800266 pid_list = []
267 no_pid_manifest_idx = []
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800268 service_partition_map = {}
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800269 partition_statistics = {
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800270 'connection_based_srv_num': 0,
Kevin Peng47c26ec2022-03-11 11:49:52 +0800271 'ipc_partitions': [],
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800272 'flih_num': 0,
273 'slih_num': 0
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800274 }
Kevin Peng9f1a7542022-02-07 16:32:27 +0800275 config_impl = {
276 'CONFIG_TFM_SPM_BACKEND_SFN' : '0',
277 'CONFIG_TFM_SPM_BACKEND_IPC' : '0',
278 'CONFIG_TFM_PSA_API_SFN_CALL' : '0',
279 'CONFIG_TFM_PSA_API_CROSS_CALL' : '0',
280 'CONFIG_TFM_PSA_API_SUPERVISOR_CALL' : '0',
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800281 'CONFIG_TFM_CONNECTION_BASED_SERVICE_API' : '0',
282 'CONFIG_TFM_FLIH_API' : '0',
283 'CONFIG_TFM_SLIH_API' : '0'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800284 }
Kevin Peng655f2392019-11-27 16:33:02 +0800285
Kevin Pengfb1761b2022-05-12 12:11:31 +0800286 isolation_level = int(configs['TFM_ISOLATION_LEVEL'], base = 10)
287 backend = configs['CONFIG_TFM_SPM_BACKEND']
288
Kevin Peng65064c52021-10-27 17:12:17 +0800289 # Get all the manifests information as a dictionary
290 for i, item in enumerate(manifest_lists):
Kevin Pengfb1761b2022-05-12 12:11:31 +0800291 if not os.path.isfile(item):
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500292 logging.error('Manifest list item [{}] must be a file'.format(i))
Kevin Peng65064c52021-10-27 17:12:17 +0800293 exit(1)
Kevin Peng655f2392019-11-27 16:33:02 +0800294
Kevin Peng65064c52021-10-27 17:12:17 +0800295 # The manifest list file generated by configure_file()
296 with open(item) as manifest_list_yaml_file:
297 manifest_dic = yaml.safe_load(manifest_list_yaml_file)['manifest_list']
298 for dict in manifest_dic:
Kevin Pengfb1761b2022-05-12 12:11:31 +0800299 # Replace environment variables in the manifest path and convert to absolute path.
300 # If it's already abspath, the path will not be changed.
301 manifest_path = os.path.join(os.path.dirname(item), # path of manifest list
302 os.path.expandvars(dict['manifest']))\
303 .replace('\\', '/')
304 dict['manifest'] = manifest_path
Kevin Peng65064c52021-10-27 17:12:17 +0800305 all_manifests.append(dict)
306
Chris Brand4b69fcf2022-06-06 09:37:49 -0700307 logging.info("------------ Display partition configuration - start ------------")
308
Kevin Peng65064c52021-10-27 17:12:17 +0800309 # Parse the manifests
310 for i, manifest_item in enumerate(all_manifests):
Kevin Pengfb1761b2022-05-12 12:11:31 +0800311 valid_enabled_conditions = ['1', 'on', 'true', 'enabled']
312 valid_disabled_conditions = ['0', 'off', 'false', 'disabled', '']
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800313 is_enabled = ''
314
315 if 'conditional' in manifest_item.keys():
Kevin Pengfb1761b2022-05-12 12:11:31 +0800316 if manifest_item['conditional'] not in configs.keys():
317 logging.error('Configuration "{}" is not defined!'.format(manifest_item['conditional']))
318 exit(1)
319 is_enabled = configs[manifest_item['conditional']].lower()
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800320 else:
Kevin Pengfb1761b2022-05-12 12:11:31 +0800321 # Partitions without 'conditional' is always on
322 is_enabled = '1'
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800323
324 if is_enabled in valid_disabled_conditions:
Anton Komlev58dde462022-07-07 13:50:02 +0100325 logging.info(" {:40s} OFF".format(manifest_item['name']))
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800326 continue
Chris Brand4b69fcf2022-06-06 09:37:49 -0700327 elif is_enabled in valid_enabled_conditions:
Anton Komlev58dde462022-07-07 13:50:02 +0100328 logging.info(" {:40s} ON".format(manifest_item['name']))
Chris Brand4b69fcf2022-06-06 09:37:49 -0700329 else:
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800330 raise Exception('Invalid "conditional" attribute: "{}" for {}. '
331 'Please set to one of {} or {}, case-insensitive.'\
332 .format(manifest_item['conditional'],
333 manifest_item['name'],
334 valid_enabled_conditions, valid_disabled_conditions))
335
Xinyu Zhangc46ee1f2021-04-01 10:10:43 +0800336 # Check if partition ID is manually set
337 if 'pid' not in manifest_item.keys():
338 no_pid_manifest_idx.append(i)
Kevin Peng8849b6a2021-11-09 14:17:35 +0800339 pid = None
Kevin Peng56b0ea62021-10-18 11:32:57 +0800340 else:
Kevin Peng8849b6a2021-11-09 14:17:35 +0800341 pid = manifest_item['pid']
342
343 # Check if partition ID is duplicated
344 if pid in pid_list:
Antonio de Angelisbaa27642022-05-25 11:07:12 +0100345 raise Exception('PID No. {} has already been used!'.format(pid))
Kevin Peng8849b6a2021-11-09 14:17:35 +0800346 else:
347 pid_list.append(pid)
Xinyu Zhang19504a52021-03-31 16:26:20 +0800348
Kevin Pengfb1761b2022-05-12 12:11:31 +0800349 manifest_path = manifest_item['manifest']
Kevin Peng5bc82d22021-10-19 11:18:40 +0800350 with open(manifest_path) as manifest_file:
Kevin Pengec0e5ce2022-02-17 13:48:51 +0800351 manifest = yaml.safe_load(manifest_file)
352 if manifest.get('model', None) == 'dual':
353 # If a Partition supports both models, it can set the "model" to "backend".
354 # The actual model used follows the backend being used.
355 manifest['model'] = backend
356 manifest = manifest_validation(manifest, pid)
Kevin Peng655f2392019-11-27 16:33:02 +0800357
Kevin Pengce99e5d2021-11-09 18:06:53 +0800358 if pid == None or pid >= TFM_PID_BASE:
Kevin Pengd08f3ba2021-11-18 15:18:56 +0800359 # Count the number of IPC/SFN partitions
Kevin Peng47c26ec2022-03-11 11:49:52 +0800360 if manifest['model'] == 'IPC':
361 partition_statistics['ipc_partitions'].append(manifest['name'])
Mingyang Suneab7eae2021-09-30 13:06:52 +0800362
Kevin Peng5c3fee72022-02-16 22:25:22 +0800363 # Set initial value to -1 to make (srv_idx + 1) reflect the correct
364 # number (0) when there are no services.
365 srv_idx = -1
366 for srv_idx, service in enumerate(manifest.get('services', [])):
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800367 service_partition_map[service['name']] = manifest['name']
Kevin Peng5c3fee72022-02-16 22:25:22 +0800368 if manifest['model'] == 'IPC':
369 # Assign signal value, the first 4 bits are reserved by FF-M
370 service['signal_value'] = (1 << (srv_idx + 4))
371 else:
372 # Signals of SFN Partitions are SPM internal only, does not
373 # need to reserve 4 bits.
374 service['signal_value'] = (1 << srv_idx)
375 if service['connection_based']:
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800376 partition_statistics['connection_based_srv_num'] += 1
Kevin Peng5c3fee72022-02-16 22:25:22 +0800377 logging.debug('{} has {} services'.format(manifest['name'], srv_idx +1))
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800378
Kevin Peng5c3fee72022-02-16 22:25:22 +0800379 # Set initial value to -1 to make (irq + 1) reflect the correct
380 # number (0) when there are no irqs.
381 irq_idx = -1
382 for irq_idx, irq in enumerate(manifest.get('irqs', [])):
383 # Assign signal value, from the most significant bit
384 irq['signal_value'] = (1 << (31 - irq_idx))
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800385 if irq.get('handling', None) == 'FLIH':
386 partition_statistics['flih_num'] += 1
387 else:
388 partition_statistics['slih_num'] += 1
Kevin Peng5c3fee72022-02-16 22:25:22 +0800389 logging.debug('{} has {} IRQS'.format(manifest['name'], irq_idx +1))
390
391 if ((srv_idx + 1) + (irq_idx + 1)) > 28:
392 raise Exception('Total number of Services and IRQs of {} exceeds the limit (28)'
393 .format(manifest['name']))
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800394
Kevin Peng65064c52021-10-27 17:12:17 +0800395 manifest_out_basename = os.path.splitext(os.path.basename(manifest_path))[0]
Kevin Peng655f2392019-11-27 16:33:02 +0800396
Kevin Peng4fade072021-10-26 17:57:50 +0800397 if 'output_path' in manifest_item:
Kevin Peng4fade072021-10-26 17:57:50 +0800398 output_path = os.path.expandvars(manifest_item['output_path'])
Kevin Peng4fade072021-10-26 17:57:50 +0800399 else:
Kevin Peng65064c52021-10-27 17:12:17 +0800400 output_path = ''
David Hub2694202021-07-15 14:58:39 +0800401
Kevin Peng5bc82d22021-10-19 11:18:40 +0800402 manifest_head_file = os.path.join(OUT_DIR, output_path, 'psa_manifest',
403 '{}.h'.format(manifest_out_basename))\
404 .replace('\\', '/')
405 intermedia_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
406 'intermedia_{}.c'.format(manifest_out_basename))\
407 .replace('\\', '/')
408 load_info_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
409 'load_info_{}.c'.format(manifest_out_basename))\
410 .replace('\\', '/')
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800411 output_dir = os.path.join(OUT_DIR, output_path).replace('\\', '/')
Kevin Peng655f2392019-11-27 16:33:02 +0800412
Kevin Peng5bc82d22021-10-19 11:18:40 +0800413 partition_list.append({'manifest': manifest, 'attr': manifest_item,
414 'manifest_out_basename': manifest_out_basename,
415 'header_file': manifest_head_file,
416 'intermedia_file': intermedia_file,
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800417 'loadinfo_file': load_info_file,
418 'output_dir':output_dir})
Ken Liu861b0782021-05-22 13:15:08 +0800419
Chris Brand4b69fcf2022-06-06 09:37:49 -0700420 logging.info("------------ Display partition configuration - end ------------")
421
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800422 check_circular_dependency(partition_list, service_partition_map)
423
Kevin Peng56b0ea62021-10-18 11:32:57 +0800424 # Automatically assign PIDs for partitions without 'pid' attribute
Kevin Pengce99e5d2021-11-09 18:06:53 +0800425 pid = max(pid_list, default = TFM_PID_BASE - 1)
Kevin Peng56b0ea62021-10-18 11:32:57 +0800426 for idx in no_pid_manifest_idx:
Kevin Pengc424eec2021-06-25 17:26:11 +0800427 pid += 1
Kevin Peng65064c52021-10-27 17:12:17 +0800428 all_manifests[idx]['pid'] = pid
Kevin Peng56b0ea62021-10-18 11:32:57 +0800429 pid_list.append(pid)
430
Kevin Peng9f1a7542022-02-07 16:32:27 +0800431 # Set up configurations
Kevin Peng76c0c162022-02-09 22:49:06 +0800432 if backend == 'SFN':
Kevin Peng47c26ec2022-03-11 11:49:52 +0800433 if len(partition_statistics['ipc_partitions']) > 0:
434 logging.error('SFN backend does not support IPC Partitions:')
435 logging.error(partition_statistics['ipc_partitions'])
Kevin Peng9f1a7542022-02-07 16:32:27 +0800436 exit(1)
Kevin Peng76c0c162022-02-09 22:49:06 +0800437
438 if isolation_level > 1:
439 logging.error('SFN backend does not support high isolation levels.')
440 exit(1)
441
Kevin Peng9f1a7542022-02-07 16:32:27 +0800442 config_impl['CONFIG_TFM_SPM_BACKEND_SFN'] = '1'
443 config_impl['CONFIG_TFM_PSA_API_SFN_CALL'] = '1'
Kevin Peng76c0c162022-02-09 22:49:06 +0800444 elif backend == 'IPC':
Kevin Peng9f1a7542022-02-07 16:32:27 +0800445 config_impl['CONFIG_TFM_SPM_BACKEND_IPC'] = '1'
446 if isolation_level > 1:
447 config_impl['CONFIG_TFM_PSA_API_SUPERVISOR_CALL'] = '1'
448 else:
449 config_impl['CONFIG_TFM_PSA_API_CROSS_CALL'] = '1'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800450
451 if partition_statistics['connection_based_srv_num'] > 0:
452 config_impl['CONFIG_TFM_CONNECTION_BASED_SERVICE_API'] = 1
453
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800454 if partition_statistics['flih_num'] > 0:
455 config_impl['CONFIG_TFM_FLIH_API'] = 1
Joakim Anderssoneec5cd32022-06-10 12:02:07 +0200456 if partition_statistics['slih_num'] > 0:
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800457 config_impl['CONFIG_TFM_SLIH_API'] = 1
458
Kevin Peng5bc82d22021-10-19 11:18:40 +0800459 context['partitions'] = partition_list
Kevin Peng9f1a7542022-02-07 16:32:27 +0800460 context['config_impl'] = config_impl
Kevin Pengce99e5d2021-11-09 18:06:53 +0800461 context['stateless_services'] = process_stateless_services(partition_list)
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100462
Kevin Peng5bc82d22021-10-19 11:18:40 +0800463 return context
Ken Liu861b0782021-05-22 13:15:08 +0800464
465def gen_per_partition_files(context):
466 """
467 Generate per-partition files
468
469 Parameters
470 ----------
471 context:
472 context contains partition infos
473 """
474
Kevin Peng5bc82d22021-10-19 11:18:40 +0800475 partition_context = {}
Sherry Zhangf58f2bd2022-01-10 17:21:11 +0800476 partition_context['utilities'] = context['utilities']
Sherry Zhangf865c4e2022-03-23 13:53:38 +0800477 partition_context['config_impl'] = context['config_impl']
Ken Liu861b0782021-05-22 13:15:08 +0800478
Kevin Peng5bc82d22021-10-19 11:18:40 +0800479 manifesttemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/manifestfilename.template'))
480 memorytemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_intermedia.template'))
481 infotemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_load_info.template'))
Ken Liu861b0782021-05-22 13:15:08 +0800482
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500483 logging.info ("Start to generate partition files:")
Ken Liu861b0782021-05-22 13:15:08 +0800484
485 for one_partition in context['partitions']:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800486 partition_context['manifest'] = one_partition['manifest']
487 partition_context['attr'] = one_partition['attr']
488 partition_context['manifest_out_basename'] = one_partition['manifest_out_basename']
Ken Liu861b0782021-05-22 13:15:08 +0800489
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800490 logging.info ('Generating {} in {}'.format(one_partition['attr']['name'],
491 one_partition['output_dir']))
Ken Liu861b0782021-05-22 13:15:08 +0800492 outfile_path = os.path.dirname(one_partition['header_file'])
Kevin Peng655f2392019-11-27 16:33:02 +0800493 if not os.path.exists(outfile_path):
494 os.makedirs(outfile_path)
495
Kevin Peng5bc82d22021-10-19 11:18:40 +0800496 headerfile = io.open(one_partition['header_file'], 'w', newline=None)
497 headerfile.write(manifesttemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800498 headerfile.close()
Kevin Peng655f2392019-11-27 16:33:02 +0800499
Ken Liu861b0782021-05-22 13:15:08 +0800500 intermediafile_path = os.path.dirname(one_partition['intermedia_file'])
Mingyang Sund20999f2020-10-15 14:53:12 +0800501 if not os.path.exists(intermediafile_path):
502 os.makedirs(intermediafile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800503 intermediafile = io.open(one_partition['intermedia_file'], 'w', newline=None)
504 intermediafile.write(memorytemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800505 intermediafile.close()
Mingyang Sund20999f2020-10-15 14:53:12 +0800506
Ken Liu861b0782021-05-22 13:15:08 +0800507 infofile_path = os.path.dirname(one_partition['loadinfo_file'])
Mingyang Sunf6a78572021-04-02 16:51:05 +0800508 if not os.path.exists(infofile_path):
509 os.makedirs(infofile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800510 infooutfile = io.open(one_partition['loadinfo_file'], 'w', newline=None)
511 infooutfile.write(infotemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800512 infooutfile.close()
Mingyang Sunf6a78572021-04-02 16:51:05 +0800513
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500514 logging.info ("Per-partition files done:")
Mingyang Sunf6a78572021-04-02 16:51:05 +0800515
Ken Liu861b0782021-05-22 13:15:08 +0800516def gen_summary_files(context, gen_file_lists):
Kevin Peng655f2392019-11-27 16:33:02 +0800517 """
518 Generate files according to the gen_file_list
Edison Ai48b2d9e2019-06-24 14:39:45 +0800519
520 Parameters
521 ----------
Raef Colesf42f0882020-07-10 10:01:58 +0100522 gen_file_lists:
523 The lists of files to generate
Edison Ai48b2d9e2019-06-24 14:39:45 +0800524 """
Kevin Peng655f2392019-11-27 16:33:02 +0800525 file_list = []
Shawn Shana9ad1e02019-08-07 15:49:48 +0800526
Raef Colesf42f0882020-07-10 10:01:58 +0100527 for f in gen_file_lists:
528 with open(f) as file_list_yaml_file:
Kevin Peng655f2392019-11-27 16:33:02 +0800529 file_list_yaml = yaml.safe_load(file_list_yaml_file)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800530 file_list.extend(file_list_yaml['file_list'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800531
Kevin Peng655f2392019-11-27 16:33:02 +0800532 for file in file_list:
Raef Coles558487a2020-10-29 13:09:44 +0000533 # Replace environment variables in the output filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800534 manifest_out_file = os.path.expandvars(file['output'])
Raef Coles558487a2020-10-29 13:09:44 +0000535 # Replace environment variables in the template filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800536 templatefile_name = os.path.expandvars(file['template'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800537
Kevin Peng4fade072021-10-26 17:57:50 +0800538 manifest_out_file = os.path.join(OUT_DIR, manifest_out_file)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800539
Ken Liu861b0782021-05-22 13:15:08 +0800540 outfile_path = os.path.dirname(manifest_out_file)
Kevin Peng655f2392019-11-27 16:33:02 +0800541 if not os.path.exists(outfile_path):
542 os.makedirs(outfile_path)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800543
Kevin Peng655f2392019-11-27 16:33:02 +0800544 template = ENV.get_template(templatefile_name)
Edison Ai6e3f2a32019-06-11 15:29:05 +0800545
Kevin Peng5bc82d22021-10-19 11:18:40 +0800546 outfile = io.open(manifest_out_file, 'w', newline=None)
Kevin Peng655f2392019-11-27 16:33:02 +0800547 outfile.write(template.render(context))
548 outfile.close()
Edison Ai48b2d9e2019-06-24 14:39:45 +0800549
Kevin Pengce99e5d2021-11-09 18:06:53 +0800550def process_stateless_services(partitions):
Mingyang Suna1ca6112021-01-11 11:34:59 +0800551 """
552 This function collects all stateless services together, and allocates
Mingyang Sun4ecea992021-03-30 17:56:26 +0800553 stateless handles for them.
Kevin Pengc05319d2021-04-22 22:59:35 +0800554 Valid stateless handle in service will be converted to an index. If the
555 stateless handle is set as "auto", or not set, framework will allocate a
556 valid index for the service.
557 Framework puts each service into a reordered stateless service list at
558 position of "index". Other unused positions are left None.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800559 """
Kevin Pengce99e5d2021-11-09 18:06:53 +0800560
561 STATIC_HANDLE_CONFIG_FILE = 'secure_fw/spm/cmsis_psa/spm_ipc.h'
562
Kevin Pengc05319d2021-04-22 22:59:35 +0800563 collected_stateless_services = []
Kevin Pengce99e5d2021-11-09 18:06:53 +0800564 stateless_index_max_num = \
565 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_NUM_LIMIT'), base = 10)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800566
567 # Collect all stateless services first.
568 for partition in partitions:
569 # Skip the FF-M 1.0 partitions
570 if partition['manifest']['psa_framework_version'] < 1.1:
571 continue
Kevin Peng8849b6a2021-11-09 14:17:35 +0800572
573 service_list = partition['manifest'].get('services', [])
574
575 for service in service_list:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800576 if service['connection_based'] is False:
Kevin Pengc05319d2021-04-22 22:59:35 +0800577 collected_stateless_services.append(service)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800578
Kevin Pengc05319d2021-04-22 22:59:35 +0800579 if len(collected_stateless_services) == 0:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800580 return []
581
Ken Liu861b0782021-05-22 13:15:08 +0800582 if len(collected_stateless_services) > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800583 raise Exception('Stateless service numbers range exceed {number}.'.format(number=stateless_index_max_num))
Mingyang Suna1ca6112021-01-11 11:34:59 +0800584
585 """
Kevin Pengc05319d2021-04-22 22:59:35 +0800586 Allocate an empty stateless service list to store services.
587 Use "handle - 1" as the index for service, since handle value starts from
588 1 and list index starts from 0.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800589 """
Ken Liu861b0782021-05-22 13:15:08 +0800590 reordered_stateless_services = [None] * stateless_index_max_num
Kevin Pengc05319d2021-04-22 22:59:35 +0800591 auto_alloc_services = []
Mingyang Suna1ca6112021-01-11 11:34:59 +0800592
Kevin Pengc05319d2021-04-22 22:59:35 +0800593 for service in collected_stateless_services:
594 # If not set, it is "auto" by default
595 if 'stateless_handle' not in service:
596 auto_alloc_services.append(service)
597 continue
598
Mingyang Sun4ecea992021-03-30 17:56:26 +0800599 service_handle = service['stateless_handle']
Mingyang Suna1ca6112021-01-11 11:34:59 +0800600
Mingyang Sun4ecea992021-03-30 17:56:26 +0800601 # Fill in service list with specified stateless handle, otherwise skip
602 if isinstance(service_handle, int):
Ken Liu861b0782021-05-22 13:15:08 +0800603 if service_handle < 1 or service_handle > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800604 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800605 # Convert handle index to reordered service list index
606 service_handle = service_handle - 1
607
608 if reordered_stateless_services[service_handle] is not None:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800609 raise Exception('Duplicated stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800610 reordered_stateless_services[service_handle] = service
Kevin Pengc05319d2021-04-22 22:59:35 +0800611 elif service_handle == 'auto':
612 auto_alloc_services.append(service)
613 else:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800614 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800615
Kevin Pengce99e5d2021-11-09 18:06:53 +0800616 STATIC_HANDLE_IDX_BIT_WIDTH = \
617 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_IDX_BIT_WIDTH'), base = 10)
618 STATIC_HANDLE_IDX_MASK = (1 << STATIC_HANDLE_IDX_BIT_WIDTH) - 1
619
620 STATIC_HANDLE_INDICATOR_OFFSET = \
621 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_INDICATOR_OFFSET'), base = 10)
622
623 STATIC_HANDLE_VER_OFFSET = \
624 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_OFFSET'), base = 10)
625
626 STATIC_HANDLE_VER_BIT_WIDTH = \
627 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_BIT_WIDTH'), base = 10)
628 STATIC_HANDLE_VER_MASK = (1 << STATIC_HANDLE_VER_BIT_WIDTH) - 1
629
Mingyang Sun4ecea992021-03-30 17:56:26 +0800630 # Auto-allocate stateless handle and encode the stateless handle
Ken Liu861b0782021-05-22 13:15:08 +0800631 for i in range(0, stateless_index_max_num):
Mingyang Sun4ecea992021-03-30 17:56:26 +0800632 service = reordered_stateless_services[i]
633
Kevin Pengc05319d2021-04-22 22:59:35 +0800634 if service == None and len(auto_alloc_services) > 0:
635 service = auto_alloc_services.pop(0)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800636
Mingyang Sun453ad402021-03-17 17:58:33 +0800637 """
638 Encode stateless flag and version into stateless handle
Kevin Pengce99e5d2021-11-09 18:06:53 +0800639 Check STATIC_HANDLE_CONFIG_FILE for details
Mingyang Sun453ad402021-03-17 17:58:33 +0800640 """
Mingyang Sun4ecea992021-03-30 17:56:26 +0800641 stateless_handle_value = 0
642 if service != None:
Kevin Pengce99e5d2021-11-09 18:06:53 +0800643 stateless_index = (i & STATIC_HANDLE_IDX_MASK)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800644 stateless_handle_value |= stateless_index
Kevin Pengce99e5d2021-11-09 18:06:53 +0800645 stateless_handle_value |= (1 << STATIC_HANDLE_INDICATOR_OFFSET)
646 stateless_version = (service['version'] & STATIC_HANDLE_VER_MASK) << STATIC_HANDLE_VER_OFFSET
Mingyang Sun453ad402021-03-17 17:58:33 +0800647 stateless_handle_value |= stateless_version
Mingyang Sun4ecea992021-03-30 17:56:26 +0800648 service['stateless_handle_value'] = '0x{0:08x}'.format(stateless_handle_value)
Ken Liu861b0782021-05-22 13:15:08 +0800649 service['stateless_handle_index'] = stateless_index
Mingyang Suna1ca6112021-01-11 11:34:59 +0800650
Mingyang Sun4ecea992021-03-30 17:56:26 +0800651 reordered_stateless_services[i] = service
652
653 return reordered_stateless_services
Mingyang Suna1ca6112021-01-11 11:34:59 +0800654
Kevin Peng655f2392019-11-27 16:33:02 +0800655def parse_args():
Raef Coles558487a2020-10-29 13:09:44 +0000656 parser = argparse.ArgumentParser(description='Parse secure partition manifest list and generate files listed by the file list',
657 epilog='Note that environment variables in template files will be replaced with their values')
658
Kevin Peng655f2392019-11-27 16:33:02 +0800659 parser.add_argument('-o', '--outdir'
660 , dest='outdir'
Kevin Peng4fade072021-10-26 17:57:50 +0800661 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800662 , metavar='out_dir'
Kevin Peng4fade072021-10-26 17:57:50 +0800663 , help='The root directory for generated files')
Shawn Shana9ad1e02019-08-07 15:49:48 +0800664
Kevin Peng5bc82d22021-10-19 11:18:40 +0800665 parser.add_argument('-m', '--manifest-lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100666 , nargs='+'
Kevin Peng5bc82d22021-10-19 11:18:40 +0800667 , dest='manifest_lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100668 , required=True
Kevin Peng65064c52021-10-27 17:12:17 +0800669 , metavar='manifest list'
670 , help='A list of Secure Partition manifest lists and their original paths.\n\
671 The manifest lists might be processed by CMake and\n\
672 the path might be different to the original one\n\
673 The format must be [list A, orignal path A, list B, orignal path B, ...]')
Kevin Peng655f2392019-11-27 16:33:02 +0800674
675 parser.add_argument('-f', '--file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100676 , nargs='+'
Kevin Peng655f2392019-11-27 16:33:02 +0800677 , dest='gen_file_args'
Raef Colesf42f0882020-07-10 10:01:58 +0100678 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800679 , metavar='file-list'
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700680 , help='These files describe the file list to generate')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800681
Kevin Pengfb1761b2022-05-12 12:11:31 +0800682 parser.add_argument('-c', '--config-files'
683 , nargs='+'
684 , dest='config_files'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800685 , required=True
Kevin Pengfb1761b2022-05-12 12:11:31 +0800686 , metavar='config-files'
687 , help='A header file contains build configurations')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800688
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500689 parser.add_argument('-q', '--quiet'
690 , dest='quiet'
691 , required=False
692 , default=False
693 , action='store_true'
694 , help='Reduce log messages')
Kevin Peng655f2392019-11-27 16:33:02 +0800695
696 args = parser.parse_args()
Kevin Peng655f2392019-11-27 16:33:02 +0800697
Kevin Peng655f2392019-11-27 16:33:02 +0800698 return args
699
700ENV = Environment(
701 loader = TemplateLoader(),
702 autoescape = select_autoescape(['html', 'xml']),
703 lstrip_blocks = True,
704 trim_blocks = True,
705 keep_trailing_newline = True
706 )
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100707
Miklos Balint470919c2018-05-22 17:51:29 +0200708def main():
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100709 """
710 The entry point of the script.
711
712 Generates the output files based on the templates and the manifests.
713 """
Shawn Shana9ad1e02019-08-07 15:49:48 +0800714
Kevin Peng655f2392019-11-27 16:33:02 +0800715 global OUT_DIR
Shawn Shana9ad1e02019-08-07 15:49:48 +0800716
Kevin Peng655f2392019-11-27 16:33:02 +0800717 args = parse_args()
Shawn Shana9ad1e02019-08-07 15:49:48 +0800718
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500719 logging.basicConfig(format='%(message)s'
720 , level=logging.WARNING if args.quiet else logging.INFO)
721
Kevin Peng5bc82d22021-10-19 11:18:40 +0800722 OUT_DIR = os.path.abspath(args.outdir)
Kevin Peng655f2392019-11-27 16:33:02 +0800723
Kevin Peng5bc82d22021-10-19 11:18:40 +0800724 manifest_lists = [os.path.abspath(x) for x in args.manifest_lists]
725 gen_file_lists = [os.path.abspath(x) for x in args.gen_file_args]
Shawn Shana9ad1e02019-08-07 15:49:48 +0800726
Shawn Shana9ad1e02019-08-07 15:49:48 +0800727 """
Kevin Peng655f2392019-11-27 16:33:02 +0800728 Relative path to TF-M root folder is supported in the manifests
729 and default value of manifest list and generated file list are relative to TF-M root folder as well,
730 so first change directory to TF-M root folder.
Shawn Shana9ad1e02019-08-07 15:49:48 +0800731 By doing this, the script can be executed anywhere
Kevin Peng655f2392019-11-27 16:33:02 +0800732 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 +0800733 """
Kevin Peng5bc82d22021-10-19 11:18:40 +0800734 os.chdir(os.path.join(sys.path[0], '..'))
Shawn Shana9ad1e02019-08-07 15:49:48 +0800735
Kevin Peng76c0c162022-02-09 22:49:06 +0800736 context = process_partition_manifests(manifest_lists,
Kevin Pengfb1761b2022-05-12 12:11:31 +0800737 parse_configurations(args.config_files))
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100738
Edison Ai6e3f2a32019-06-11 15:29:05 +0800739 utilities = {}
Mingyang Suna1ca6112021-01-11 11:34:59 +0800740 utilities['donotedit_warning'] = donotedit_warning
Miklos Balint470919c2018-05-22 17:51:29 +0200741
Kevin Peng655f2392019-11-27 16:33:02 +0800742 context['utilities'] = utilities
Mingyang Suneab7eae2021-09-30 13:06:52 +0800743
Ken Liu861b0782021-05-22 13:15:08 +0800744 gen_per_partition_files(context)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800745 gen_summary_files(context, gen_file_lists)
Miklos Balint470919c2018-05-22 17:51:29 +0200746
Kevin Peng5bc82d22021-10-19 11:18:40 +0800747if __name__ == '__main__':
Miklos Balint470919c2018-05-22 17:51:29 +0200748 main()