blob: 9cbe3c159e580f5e57e744e26ab72525173d3e9e [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
Chris Brandc422cdd2022-07-21 13:32:47 -0700144 if 'ns_agent' not in manifest:
145 manifest['ns_agent'] = False
146
Kevin Peng5c3fee72022-02-16 22:25:22 +0800147 # Every PSA Partition must have at least either a secure service or an IRQ
Kevin Pengce99e5d2021-11-09 18:06:53 +0800148 if (pid == None or pid >= TFM_PID_BASE) \
Kevin Peng8849b6a2021-11-09 14:17:35 +0800149 and len(service_list) == 0 and len(irq_list) == 0:
150 raise Exception('{} must declare at least either a secure service or an IRQ!'
Kevin Peng5c3fee72022-02-16 22:25:22 +0800151 .format(manifest['name']))
152
153 if manifest['psa_framework_version'] == 1.0:
154 # For 1.0 Partition, the model is IPC
155 manifest['model'] = 'IPC'
156
157 # "model" validation:
158 model = manifest.get('model', None)
159 if model == None:
160 raise Exception('{} is missing the "model" attribute'.format(manifest['name']))
161
162 # Assign a unified 'entry' for templates
163 if model == 'IPC':
164 # entry_point is mandatory for IPC Partitions
165 if 'entry_point' not in manifest.keys():
166 raise Exception('{} is missing the "entry_point" attribute'.format(manifest['name']))
167 manifest['entry'] = manifest['entry_point']
168 elif model == 'SFN':
169 if 'entry_init' in manifest.keys():
170 manifest['entry'] = manifest['entry_init']
171 else:
172 manifest['entry'] = 0
173 else:
174 raise Exception('Invalid "model" of {}'.format(manifest['name']))
Kevin Peng8849b6a2021-11-09 14:17:35 +0800175
176 # Service FF-M manifest validation
177 for service in service_list:
Kevin Peng5c3fee72022-02-16 22:25:22 +0800178 if manifest['psa_framework_version'] == 1.0:
179 service['connection_based'] = True
180 elif 'connection_based' not in service:
181 raise Exception("'connection_based' is mandatory in FF-M 1.1 service!")
182
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800183 if 'version' not in service.keys():
184 service['version'] = 1
185 if 'version_policy' not in service.keys():
Kevin Peng5bc82d22021-10-19 11:18:40 +0800186 service['version_policy'] = 'STRICT'
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800187
Kevin Peng5bc82d22021-10-19 11:18:40 +0800188 # SID duplication check
189 if service['sid'] in sid_list:
190 raise Exception('Service ID: {} has duplications!'.format(service['sid']))
191 else:
192 sid_list.append(service['sid'])
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100193
Kevin Peng5c3fee72022-02-16 22:25:22 +0800194 return manifest
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800195
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800196def check_circular_dependency(partitions, service_partition_map):
197 """
198 This function detects if there is any circular partition dependency chain.
199 If a circular dependency is detected, the script exits with error.
200
201 Inputs:
202 - partitions: dict of partition manifests
203 - service_partition_map: map between services and their owner Partitions
204 """
205
206 dependency_table = {}
207 for partition in partitions:
208 manifest = partition['manifest']
209 dependencies = manifest['dependencies'].copy() \
210 if 'dependencies' in manifest else []
211 dependencies += manifest['weak_dependencies'].copy() \
212 if 'weak_dependencies' in manifest else []
213 dependency_table[manifest['name']] = {
214 'dependencies': [service_partition_map[dependency]
215 for dependency in dependencies
216 if dependency in service_partition_map],
217 'validated': False
218 }
219
220 for partition in dependency_table.keys():
221 validate_dependency_chain(partition, dependency_table, [])
222
223def validate_dependency_chain(partition,
224 dependency_table,
225 dependency_chain):
226 """
227 Recursively validate if the given partition and its dependencies
228 have a circular dependency with the given dependency_chain.
229 Exit with error code once any circular is detected.
230
231 Inputs:
232 - partition: next partition to be checked
233 - dependency_table: dict of partitions and their dependencies
234 - dependency_chain: list of dependencies in current chain
235 """
236
237 dependency_chain.append(partition)
238 if partition in dependency_chain[:-1]:
239 logging.error(
240 'Circular dependency exists in chain: {}'.format(
241 ', '.join(dependency_chain)))
242 exit(1)
243 for dependency in dependency_table[partition]['dependencies']:
244 if dependency_table[dependency]['validated']:
245 continue
246 validate_dependency_chain(dependency, dependency_table, dependency_chain)
247 dependency_table[partition]['validated'] = True
248
Kevin Pengfb1761b2022-05-12 12:11:31 +0800249def process_partition_manifests(manifest_lists, configs):
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100250 """
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800251 Parse the input manifest lists, check if manifest settings are valid,
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700252 generate the data base for generated files
Kevin Peng655f2392019-11-27 16:33:02 +0800253 and generate manifest header files.
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100254
255 Parameters
256 ----------
Kevin Peng65064c52021-10-27 17:12:17 +0800257 manifest_lists:
Kevin Pengfb1761b2022-05-12 12:11:31 +0800258 A list of Secure Partition manifest lists
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100259
260 Returns
261 -------
Kevin Peng5bc82d22021-10-19 11:18:40 +0800262 The manifest data base.
Edison Ai48b2d9e2019-06-24 14:39:45 +0800263 """
Kevin Peng655f2392019-11-27 16:33:02 +0800264
Kevin Peng5bc82d22021-10-19 11:18:40 +0800265 context = {}
266
Ken Liu861b0782021-05-22 13:15:08 +0800267 partition_list = []
Kevin Peng65064c52021-10-27 17:12:17 +0800268 all_manifests = []
Kevin Peng56b0ea62021-10-18 11:32:57 +0800269 pid_list = []
270 no_pid_manifest_idx = []
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800271 service_partition_map = {}
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800272 partition_statistics = {
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800273 'connection_based_srv_num': 0,
Kevin Peng47c26ec2022-03-11 11:49:52 +0800274 'ipc_partitions': [],
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800275 'flih_num': 0,
276 'slih_num': 0
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800277 }
Kevin Peng9f1a7542022-02-07 16:32:27 +0800278 config_impl = {
279 'CONFIG_TFM_SPM_BACKEND_SFN' : '0',
280 'CONFIG_TFM_SPM_BACKEND_IPC' : '0',
281 'CONFIG_TFM_PSA_API_SFN_CALL' : '0',
282 'CONFIG_TFM_PSA_API_CROSS_CALL' : '0',
283 'CONFIG_TFM_PSA_API_SUPERVISOR_CALL' : '0',
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800284 'CONFIG_TFM_CONNECTION_BASED_SERVICE_API' : '0',
285 'CONFIG_TFM_FLIH_API' : '0',
286 'CONFIG_TFM_SLIH_API' : '0'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800287 }
Kevin Peng655f2392019-11-27 16:33:02 +0800288
Kevin Pengfb1761b2022-05-12 12:11:31 +0800289 isolation_level = int(configs['TFM_ISOLATION_LEVEL'], base = 10)
290 backend = configs['CONFIG_TFM_SPM_BACKEND']
291
Kevin Peng65064c52021-10-27 17:12:17 +0800292 # Get all the manifests information as a dictionary
293 for i, item in enumerate(manifest_lists):
Kevin Pengfb1761b2022-05-12 12:11:31 +0800294 if not os.path.isfile(item):
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500295 logging.error('Manifest list item [{}] must be a file'.format(i))
Kevin Peng65064c52021-10-27 17:12:17 +0800296 exit(1)
Kevin Peng655f2392019-11-27 16:33:02 +0800297
Kevin Peng65064c52021-10-27 17:12:17 +0800298 # The manifest list file generated by configure_file()
299 with open(item) as manifest_list_yaml_file:
300 manifest_dic = yaml.safe_load(manifest_list_yaml_file)['manifest_list']
301 for dict in manifest_dic:
Kevin Pengfb1761b2022-05-12 12:11:31 +0800302 # Replace environment variables in the manifest path and convert to absolute path.
303 # If it's already abspath, the path will not be changed.
304 manifest_path = os.path.join(os.path.dirname(item), # path of manifest list
305 os.path.expandvars(dict['manifest']))\
306 .replace('\\', '/')
307 dict['manifest'] = manifest_path
Kevin Peng65064c52021-10-27 17:12:17 +0800308 all_manifests.append(dict)
309
Chris Brand4b69fcf2022-06-06 09:37:49 -0700310 logging.info("------------ Display partition configuration - start ------------")
311
Kevin Peng65064c52021-10-27 17:12:17 +0800312 # Parse the manifests
313 for i, manifest_item in enumerate(all_manifests):
Kevin Pengfb1761b2022-05-12 12:11:31 +0800314 valid_enabled_conditions = ['1', 'on', 'true', 'enabled']
315 valid_disabled_conditions = ['0', 'off', 'false', 'disabled', '']
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800316 is_enabled = ''
317
318 if 'conditional' in manifest_item.keys():
Kevin Pengfb1761b2022-05-12 12:11:31 +0800319 if manifest_item['conditional'] not in configs.keys():
320 logging.error('Configuration "{}" is not defined!'.format(manifest_item['conditional']))
321 exit(1)
322 is_enabled = configs[manifest_item['conditional']].lower()
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800323 else:
Kevin Pengfb1761b2022-05-12 12:11:31 +0800324 # Partitions without 'conditional' is always on
325 is_enabled = '1'
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800326
327 if is_enabled in valid_disabled_conditions:
Anton Komlev58dde462022-07-07 13:50:02 +0100328 logging.info(" {:40s} OFF".format(manifest_item['name']))
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800329 continue
Chris Brand4b69fcf2022-06-06 09:37:49 -0700330 elif is_enabled in valid_enabled_conditions:
Anton Komlev58dde462022-07-07 13:50:02 +0100331 logging.info(" {:40s} ON".format(manifest_item['name']))
Chris Brand4b69fcf2022-06-06 09:37:49 -0700332 else:
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800333 raise Exception('Invalid "conditional" attribute: "{}" for {}. '
334 'Please set to one of {} or {}, case-insensitive.'\
335 .format(manifest_item['conditional'],
336 manifest_item['name'],
337 valid_enabled_conditions, valid_disabled_conditions))
338
Xinyu Zhangc46ee1f2021-04-01 10:10:43 +0800339 # Check if partition ID is manually set
340 if 'pid' not in manifest_item.keys():
341 no_pid_manifest_idx.append(i)
Kevin Peng8849b6a2021-11-09 14:17:35 +0800342 pid = None
Kevin Peng56b0ea62021-10-18 11:32:57 +0800343 else:
Kevin Peng8849b6a2021-11-09 14:17:35 +0800344 pid = manifest_item['pid']
345
346 # Check if partition ID is duplicated
347 if pid in pid_list:
Antonio de Angelisbaa27642022-05-25 11:07:12 +0100348 raise Exception('PID No. {} has already been used!'.format(pid))
Kevin Peng8849b6a2021-11-09 14:17:35 +0800349 else:
350 pid_list.append(pid)
Xinyu Zhang19504a52021-03-31 16:26:20 +0800351
Kevin Pengfb1761b2022-05-12 12:11:31 +0800352 manifest_path = manifest_item['manifest']
Kevin Peng5bc82d22021-10-19 11:18:40 +0800353 with open(manifest_path) as manifest_file:
Kevin Pengec0e5ce2022-02-17 13:48:51 +0800354 manifest = yaml.safe_load(manifest_file)
355 if manifest.get('model', None) == 'dual':
356 # If a Partition supports both models, it can set the "model" to "backend".
357 # The actual model used follows the backend being used.
358 manifest['model'] = backend
359 manifest = manifest_validation(manifest, pid)
Kevin Peng655f2392019-11-27 16:33:02 +0800360
Kevin Pengce99e5d2021-11-09 18:06:53 +0800361 if pid == None or pid >= TFM_PID_BASE:
Kevin Pengd08f3ba2021-11-18 15:18:56 +0800362 # Count the number of IPC/SFN partitions
Kevin Peng47c26ec2022-03-11 11:49:52 +0800363 if manifest['model'] == 'IPC':
364 partition_statistics['ipc_partitions'].append(manifest['name'])
Mingyang Suneab7eae2021-09-30 13:06:52 +0800365
Kevin Peng5c3fee72022-02-16 22:25:22 +0800366 # Set initial value to -1 to make (srv_idx + 1) reflect the correct
367 # number (0) when there are no services.
368 srv_idx = -1
369 for srv_idx, service in enumerate(manifest.get('services', [])):
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800370 service_partition_map[service['name']] = manifest['name']
Kevin Peng5c3fee72022-02-16 22:25:22 +0800371 if manifest['model'] == 'IPC':
372 # Assign signal value, the first 4 bits are reserved by FF-M
373 service['signal_value'] = (1 << (srv_idx + 4))
374 else:
375 # Signals of SFN Partitions are SPM internal only, does not
376 # need to reserve 4 bits.
377 service['signal_value'] = (1 << srv_idx)
378 if service['connection_based']:
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800379 partition_statistics['connection_based_srv_num'] += 1
Kevin Peng5c3fee72022-02-16 22:25:22 +0800380 logging.debug('{} has {} services'.format(manifest['name'], srv_idx +1))
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800381
Kevin Peng5c3fee72022-02-16 22:25:22 +0800382 # Set initial value to -1 to make (irq + 1) reflect the correct
383 # number (0) when there are no irqs.
384 irq_idx = -1
385 for irq_idx, irq in enumerate(manifest.get('irqs', [])):
386 # Assign signal value, from the most significant bit
387 irq['signal_value'] = (1 << (31 - irq_idx))
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800388 if irq.get('handling', None) == 'FLIH':
389 partition_statistics['flih_num'] += 1
390 else:
391 partition_statistics['slih_num'] += 1
Kevin Peng5c3fee72022-02-16 22:25:22 +0800392 logging.debug('{} has {} IRQS'.format(manifest['name'], irq_idx +1))
393
394 if ((srv_idx + 1) + (irq_idx + 1)) > 28:
395 raise Exception('Total number of Services and IRQs of {} exceeds the limit (28)'
396 .format(manifest['name']))
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800397
Kevin Peng65064c52021-10-27 17:12:17 +0800398 manifest_out_basename = os.path.splitext(os.path.basename(manifest_path))[0]
Kevin Peng655f2392019-11-27 16:33:02 +0800399
Kevin Peng4fade072021-10-26 17:57:50 +0800400 if 'output_path' in manifest_item:
Kevin Peng4fade072021-10-26 17:57:50 +0800401 output_path = os.path.expandvars(manifest_item['output_path'])
Kevin Peng4fade072021-10-26 17:57:50 +0800402 else:
Kevin Peng65064c52021-10-27 17:12:17 +0800403 output_path = ''
David Hub2694202021-07-15 14:58:39 +0800404
Kevin Peng5bc82d22021-10-19 11:18:40 +0800405 manifest_head_file = os.path.join(OUT_DIR, output_path, 'psa_manifest',
406 '{}.h'.format(manifest_out_basename))\
407 .replace('\\', '/')
408 intermedia_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
409 'intermedia_{}.c'.format(manifest_out_basename))\
410 .replace('\\', '/')
411 load_info_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
412 'load_info_{}.c'.format(manifest_out_basename))\
413 .replace('\\', '/')
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800414 output_dir = os.path.join(OUT_DIR, output_path).replace('\\', '/')
Kevin Peng655f2392019-11-27 16:33:02 +0800415
Kevin Peng5bc82d22021-10-19 11:18:40 +0800416 partition_list.append({'manifest': manifest, 'attr': manifest_item,
417 'manifest_out_basename': manifest_out_basename,
418 'header_file': manifest_head_file,
419 'intermedia_file': intermedia_file,
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800420 'loadinfo_file': load_info_file,
421 'output_dir':output_dir})
Ken Liu861b0782021-05-22 13:15:08 +0800422
Chris Brand4b69fcf2022-06-06 09:37:49 -0700423 logging.info("------------ Display partition configuration - end ------------")
424
Xinyu Zhang7d0a5c82022-05-16 18:15:11 +0800425 check_circular_dependency(partition_list, service_partition_map)
426
Kevin Peng56b0ea62021-10-18 11:32:57 +0800427 # Automatically assign PIDs for partitions without 'pid' attribute
Kevin Pengce99e5d2021-11-09 18:06:53 +0800428 pid = max(pid_list, default = TFM_PID_BASE - 1)
Kevin Peng56b0ea62021-10-18 11:32:57 +0800429 for idx in no_pid_manifest_idx:
Kevin Pengc424eec2021-06-25 17:26:11 +0800430 pid += 1
Kevin Peng65064c52021-10-27 17:12:17 +0800431 all_manifests[idx]['pid'] = pid
Kevin Peng56b0ea62021-10-18 11:32:57 +0800432 pid_list.append(pid)
433
Kevin Peng9f1a7542022-02-07 16:32:27 +0800434 # Set up configurations
Kevin Peng76c0c162022-02-09 22:49:06 +0800435 if backend == 'SFN':
Kevin Peng47c26ec2022-03-11 11:49:52 +0800436 if len(partition_statistics['ipc_partitions']) > 0:
437 logging.error('SFN backend does not support IPC Partitions:')
438 logging.error(partition_statistics['ipc_partitions'])
Kevin Peng9f1a7542022-02-07 16:32:27 +0800439 exit(1)
Kevin Peng76c0c162022-02-09 22:49:06 +0800440
441 if isolation_level > 1:
442 logging.error('SFN backend does not support high isolation levels.')
443 exit(1)
444
Kevin Peng9f1a7542022-02-07 16:32:27 +0800445 config_impl['CONFIG_TFM_SPM_BACKEND_SFN'] = '1'
446 config_impl['CONFIG_TFM_PSA_API_SFN_CALL'] = '1'
Kevin Peng76c0c162022-02-09 22:49:06 +0800447 elif backend == 'IPC':
Kevin Peng9f1a7542022-02-07 16:32:27 +0800448 config_impl['CONFIG_TFM_SPM_BACKEND_IPC'] = '1'
449 if isolation_level > 1:
450 config_impl['CONFIG_TFM_PSA_API_SUPERVISOR_CALL'] = '1'
451 else:
452 config_impl['CONFIG_TFM_PSA_API_CROSS_CALL'] = '1'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800453
454 if partition_statistics['connection_based_srv_num'] > 0:
455 config_impl['CONFIG_TFM_CONNECTION_BASED_SERVICE_API'] = 1
456
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800457 if partition_statistics['flih_num'] > 0:
458 config_impl['CONFIG_TFM_FLIH_API'] = 1
Joakim Anderssoneec5cd32022-06-10 12:02:07 +0200459 if partition_statistics['slih_num'] > 0:
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800460 config_impl['CONFIG_TFM_SLIH_API'] = 1
461
Kevin Peng5bc82d22021-10-19 11:18:40 +0800462 context['partitions'] = partition_list
Kevin Peng9f1a7542022-02-07 16:32:27 +0800463 context['config_impl'] = config_impl
Kevin Pengce99e5d2021-11-09 18:06:53 +0800464 context['stateless_services'] = process_stateless_services(partition_list)
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100465
Kevin Peng5bc82d22021-10-19 11:18:40 +0800466 return context
Ken Liu861b0782021-05-22 13:15:08 +0800467
468def gen_per_partition_files(context):
469 """
470 Generate per-partition files
471
472 Parameters
473 ----------
474 context:
475 context contains partition infos
476 """
477
Kevin Peng5bc82d22021-10-19 11:18:40 +0800478 partition_context = {}
Sherry Zhangf58f2bd2022-01-10 17:21:11 +0800479 partition_context['utilities'] = context['utilities']
Sherry Zhangf865c4e2022-03-23 13:53:38 +0800480 partition_context['config_impl'] = context['config_impl']
Ken Liu861b0782021-05-22 13:15:08 +0800481
Kevin Peng5bc82d22021-10-19 11:18:40 +0800482 manifesttemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/manifestfilename.template'))
483 memorytemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_intermedia.template'))
484 infotemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_load_info.template'))
Ken Liu861b0782021-05-22 13:15:08 +0800485
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500486 logging.info ("Start to generate partition files:")
Ken Liu861b0782021-05-22 13:15:08 +0800487
488 for one_partition in context['partitions']:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800489 partition_context['manifest'] = one_partition['manifest']
490 partition_context['attr'] = one_partition['attr']
491 partition_context['manifest_out_basename'] = one_partition['manifest_out_basename']
Ken Liu861b0782021-05-22 13:15:08 +0800492
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800493 logging.info ('Generating {} in {}'.format(one_partition['attr']['name'],
494 one_partition['output_dir']))
Ken Liu861b0782021-05-22 13:15:08 +0800495 outfile_path = os.path.dirname(one_partition['header_file'])
Kevin Peng655f2392019-11-27 16:33:02 +0800496 if not os.path.exists(outfile_path):
497 os.makedirs(outfile_path)
498
Kevin Peng5bc82d22021-10-19 11:18:40 +0800499 headerfile = io.open(one_partition['header_file'], 'w', newline=None)
500 headerfile.write(manifesttemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800501 headerfile.close()
Kevin Peng655f2392019-11-27 16:33:02 +0800502
Ken Liu861b0782021-05-22 13:15:08 +0800503 intermediafile_path = os.path.dirname(one_partition['intermedia_file'])
Mingyang Sund20999f2020-10-15 14:53:12 +0800504 if not os.path.exists(intermediafile_path):
505 os.makedirs(intermediafile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800506 intermediafile = io.open(one_partition['intermedia_file'], 'w', newline=None)
507 intermediafile.write(memorytemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800508 intermediafile.close()
Mingyang Sund20999f2020-10-15 14:53:12 +0800509
Ken Liu861b0782021-05-22 13:15:08 +0800510 infofile_path = os.path.dirname(one_partition['loadinfo_file'])
Mingyang Sunf6a78572021-04-02 16:51:05 +0800511 if not os.path.exists(infofile_path):
512 os.makedirs(infofile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800513 infooutfile = io.open(one_partition['loadinfo_file'], 'w', newline=None)
514 infooutfile.write(infotemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800515 infooutfile.close()
Mingyang Sunf6a78572021-04-02 16:51:05 +0800516
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500517 logging.info ("Per-partition files done:")
Mingyang Sunf6a78572021-04-02 16:51:05 +0800518
Ken Liu861b0782021-05-22 13:15:08 +0800519def gen_summary_files(context, gen_file_lists):
Kevin Peng655f2392019-11-27 16:33:02 +0800520 """
521 Generate files according to the gen_file_list
Edison Ai48b2d9e2019-06-24 14:39:45 +0800522
523 Parameters
524 ----------
Raef Colesf42f0882020-07-10 10:01:58 +0100525 gen_file_lists:
526 The lists of files to generate
Edison Ai48b2d9e2019-06-24 14:39:45 +0800527 """
Kevin Peng655f2392019-11-27 16:33:02 +0800528 file_list = []
Shawn Shana9ad1e02019-08-07 15:49:48 +0800529
Raef Colesf42f0882020-07-10 10:01:58 +0100530 for f in gen_file_lists:
531 with open(f) as file_list_yaml_file:
Kevin Peng655f2392019-11-27 16:33:02 +0800532 file_list_yaml = yaml.safe_load(file_list_yaml_file)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800533 file_list.extend(file_list_yaml['file_list'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800534
Kevin Peng655f2392019-11-27 16:33:02 +0800535 for file in file_list:
Raef Coles558487a2020-10-29 13:09:44 +0000536 # Replace environment variables in the output filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800537 manifest_out_file = os.path.expandvars(file['output'])
Raef Coles558487a2020-10-29 13:09:44 +0000538 # Replace environment variables in the template filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800539 templatefile_name = os.path.expandvars(file['template'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800540
Kevin Peng4fade072021-10-26 17:57:50 +0800541 manifest_out_file = os.path.join(OUT_DIR, manifest_out_file)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800542
Ken Liu861b0782021-05-22 13:15:08 +0800543 outfile_path = os.path.dirname(manifest_out_file)
Kevin Peng655f2392019-11-27 16:33:02 +0800544 if not os.path.exists(outfile_path):
545 os.makedirs(outfile_path)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800546
Kevin Peng655f2392019-11-27 16:33:02 +0800547 template = ENV.get_template(templatefile_name)
Edison Ai6e3f2a32019-06-11 15:29:05 +0800548
Kevin Peng5bc82d22021-10-19 11:18:40 +0800549 outfile = io.open(manifest_out_file, 'w', newline=None)
Kevin Peng655f2392019-11-27 16:33:02 +0800550 outfile.write(template.render(context))
551 outfile.close()
Edison Ai48b2d9e2019-06-24 14:39:45 +0800552
Kevin Pengce99e5d2021-11-09 18:06:53 +0800553def process_stateless_services(partitions):
Mingyang Suna1ca6112021-01-11 11:34:59 +0800554 """
555 This function collects all stateless services together, and allocates
Mingyang Sun4ecea992021-03-30 17:56:26 +0800556 stateless handles for them.
Kevin Pengc05319d2021-04-22 22:59:35 +0800557 Valid stateless handle in service will be converted to an index. If the
558 stateless handle is set as "auto", or not set, framework will allocate a
559 valid index for the service.
560 Framework puts each service into a reordered stateless service list at
561 position of "index". Other unused positions are left None.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800562 """
Kevin Pengce99e5d2021-11-09 18:06:53 +0800563
564 STATIC_HANDLE_CONFIG_FILE = 'secure_fw/spm/cmsis_psa/spm_ipc.h'
565
Kevin Pengc05319d2021-04-22 22:59:35 +0800566 collected_stateless_services = []
Kevin Pengce99e5d2021-11-09 18:06:53 +0800567 stateless_index_max_num = \
568 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_NUM_LIMIT'), base = 10)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800569
570 # Collect all stateless services first.
571 for partition in partitions:
572 # Skip the FF-M 1.0 partitions
573 if partition['manifest']['psa_framework_version'] < 1.1:
574 continue
Kevin Peng8849b6a2021-11-09 14:17:35 +0800575
576 service_list = partition['manifest'].get('services', [])
577
578 for service in service_list:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800579 if service['connection_based'] is False:
Kevin Pengc05319d2021-04-22 22:59:35 +0800580 collected_stateless_services.append(service)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800581
Kevin Pengc05319d2021-04-22 22:59:35 +0800582 if len(collected_stateless_services) == 0:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800583 return []
584
Ken Liu861b0782021-05-22 13:15:08 +0800585 if len(collected_stateless_services) > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800586 raise Exception('Stateless service numbers range exceed {number}.'.format(number=stateless_index_max_num))
Mingyang Suna1ca6112021-01-11 11:34:59 +0800587
588 """
Kevin Pengc05319d2021-04-22 22:59:35 +0800589 Allocate an empty stateless service list to store services.
590 Use "handle - 1" as the index for service, since handle value starts from
591 1 and list index starts from 0.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800592 """
Ken Liu861b0782021-05-22 13:15:08 +0800593 reordered_stateless_services = [None] * stateless_index_max_num
Kevin Pengc05319d2021-04-22 22:59:35 +0800594 auto_alloc_services = []
Mingyang Suna1ca6112021-01-11 11:34:59 +0800595
Kevin Pengc05319d2021-04-22 22:59:35 +0800596 for service in collected_stateless_services:
597 # If not set, it is "auto" by default
598 if 'stateless_handle' not in service:
599 auto_alloc_services.append(service)
600 continue
601
Mingyang Sun4ecea992021-03-30 17:56:26 +0800602 service_handle = service['stateless_handle']
Mingyang Suna1ca6112021-01-11 11:34:59 +0800603
Mingyang Sun4ecea992021-03-30 17:56:26 +0800604 # Fill in service list with specified stateless handle, otherwise skip
605 if isinstance(service_handle, int):
Ken Liu861b0782021-05-22 13:15:08 +0800606 if service_handle < 1 or service_handle > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800607 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800608 # Convert handle index to reordered service list index
609 service_handle = service_handle - 1
610
611 if reordered_stateless_services[service_handle] is not None:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800612 raise Exception('Duplicated stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800613 reordered_stateless_services[service_handle] = service
Kevin Pengc05319d2021-04-22 22:59:35 +0800614 elif service_handle == 'auto':
615 auto_alloc_services.append(service)
616 else:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800617 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800618
Kevin Pengce99e5d2021-11-09 18:06:53 +0800619 STATIC_HANDLE_IDX_BIT_WIDTH = \
620 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_IDX_BIT_WIDTH'), base = 10)
621 STATIC_HANDLE_IDX_MASK = (1 << STATIC_HANDLE_IDX_BIT_WIDTH) - 1
622
623 STATIC_HANDLE_INDICATOR_OFFSET = \
624 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_INDICATOR_OFFSET'), base = 10)
625
626 STATIC_HANDLE_VER_OFFSET = \
627 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_OFFSET'), base = 10)
628
629 STATIC_HANDLE_VER_BIT_WIDTH = \
630 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_BIT_WIDTH'), base = 10)
631 STATIC_HANDLE_VER_MASK = (1 << STATIC_HANDLE_VER_BIT_WIDTH) - 1
632
Mingyang Sun4ecea992021-03-30 17:56:26 +0800633 # Auto-allocate stateless handle and encode the stateless handle
Ken Liu861b0782021-05-22 13:15:08 +0800634 for i in range(0, stateless_index_max_num):
Mingyang Sun4ecea992021-03-30 17:56:26 +0800635 service = reordered_stateless_services[i]
636
Kevin Pengc05319d2021-04-22 22:59:35 +0800637 if service == None and len(auto_alloc_services) > 0:
638 service = auto_alloc_services.pop(0)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800639
Mingyang Sun453ad402021-03-17 17:58:33 +0800640 """
641 Encode stateless flag and version into stateless handle
Kevin Pengce99e5d2021-11-09 18:06:53 +0800642 Check STATIC_HANDLE_CONFIG_FILE for details
Mingyang Sun453ad402021-03-17 17:58:33 +0800643 """
Mingyang Sun4ecea992021-03-30 17:56:26 +0800644 stateless_handle_value = 0
645 if service != None:
Kevin Pengce99e5d2021-11-09 18:06:53 +0800646 stateless_index = (i & STATIC_HANDLE_IDX_MASK)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800647 stateless_handle_value |= stateless_index
Kevin Pengce99e5d2021-11-09 18:06:53 +0800648 stateless_handle_value |= (1 << STATIC_HANDLE_INDICATOR_OFFSET)
649 stateless_version = (service['version'] & STATIC_HANDLE_VER_MASK) << STATIC_HANDLE_VER_OFFSET
Mingyang Sun453ad402021-03-17 17:58:33 +0800650 stateless_handle_value |= stateless_version
Mingyang Sun4ecea992021-03-30 17:56:26 +0800651 service['stateless_handle_value'] = '0x{0:08x}'.format(stateless_handle_value)
Ken Liu861b0782021-05-22 13:15:08 +0800652 service['stateless_handle_index'] = stateless_index
Mingyang Suna1ca6112021-01-11 11:34:59 +0800653
Mingyang Sun4ecea992021-03-30 17:56:26 +0800654 reordered_stateless_services[i] = service
655
656 return reordered_stateless_services
Mingyang Suna1ca6112021-01-11 11:34:59 +0800657
Kevin Peng655f2392019-11-27 16:33:02 +0800658def parse_args():
Raef Coles558487a2020-10-29 13:09:44 +0000659 parser = argparse.ArgumentParser(description='Parse secure partition manifest list and generate files listed by the file list',
660 epilog='Note that environment variables in template files will be replaced with their values')
661
Kevin Peng655f2392019-11-27 16:33:02 +0800662 parser.add_argument('-o', '--outdir'
663 , dest='outdir'
Kevin Peng4fade072021-10-26 17:57:50 +0800664 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800665 , metavar='out_dir'
Kevin Peng4fade072021-10-26 17:57:50 +0800666 , help='The root directory for generated files')
Shawn Shana9ad1e02019-08-07 15:49:48 +0800667
Kevin Peng5bc82d22021-10-19 11:18:40 +0800668 parser.add_argument('-m', '--manifest-lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100669 , nargs='+'
Kevin Peng5bc82d22021-10-19 11:18:40 +0800670 , dest='manifest_lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100671 , required=True
Kevin Peng65064c52021-10-27 17:12:17 +0800672 , metavar='manifest list'
673 , help='A list of Secure Partition manifest lists and their original paths.\n\
674 The manifest lists might be processed by CMake and\n\
675 the path might be different to the original one\n\
676 The format must be [list A, orignal path A, list B, orignal path B, ...]')
Kevin Peng655f2392019-11-27 16:33:02 +0800677
678 parser.add_argument('-f', '--file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100679 , nargs='+'
Kevin Peng655f2392019-11-27 16:33:02 +0800680 , dest='gen_file_args'
Raef Colesf42f0882020-07-10 10:01:58 +0100681 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800682 , metavar='file-list'
Chris Brandf1d6b6f2022-07-22 11:49:01 -0700683 , help='These files describe the file list to generate')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800684
Kevin Pengfb1761b2022-05-12 12:11:31 +0800685 parser.add_argument('-c', '--config-files'
686 , nargs='+'
687 , dest='config_files'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800688 , required=True
Kevin Pengfb1761b2022-05-12 12:11:31 +0800689 , metavar='config-files'
690 , help='A header file contains build configurations')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800691
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500692 parser.add_argument('-q', '--quiet'
693 , dest='quiet'
694 , required=False
695 , default=False
696 , action='store_true'
697 , help='Reduce log messages')
Kevin Peng655f2392019-11-27 16:33:02 +0800698
699 args = parser.parse_args()
Kevin Peng655f2392019-11-27 16:33:02 +0800700
Kevin Peng655f2392019-11-27 16:33:02 +0800701 return args
702
703ENV = Environment(
704 loader = TemplateLoader(),
705 autoescape = select_autoescape(['html', 'xml']),
706 lstrip_blocks = True,
707 trim_blocks = True,
708 keep_trailing_newline = True
709 )
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100710
Miklos Balint470919c2018-05-22 17:51:29 +0200711def main():
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100712 """
713 The entry point of the script.
714
715 Generates the output files based on the templates and the manifests.
716 """
Shawn Shana9ad1e02019-08-07 15:49:48 +0800717
Kevin Peng655f2392019-11-27 16:33:02 +0800718 global OUT_DIR
Shawn Shana9ad1e02019-08-07 15:49:48 +0800719
Kevin Peng655f2392019-11-27 16:33:02 +0800720 args = parse_args()
Shawn Shana9ad1e02019-08-07 15:49:48 +0800721
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500722 logging.basicConfig(format='%(message)s'
723 , level=logging.WARNING if args.quiet else logging.INFO)
724
Kevin Peng5bc82d22021-10-19 11:18:40 +0800725 OUT_DIR = os.path.abspath(args.outdir)
Kevin Peng655f2392019-11-27 16:33:02 +0800726
Kevin Peng5bc82d22021-10-19 11:18:40 +0800727 manifest_lists = [os.path.abspath(x) for x in args.manifest_lists]
728 gen_file_lists = [os.path.abspath(x) for x in args.gen_file_args]
Shawn Shana9ad1e02019-08-07 15:49:48 +0800729
Shawn Shana9ad1e02019-08-07 15:49:48 +0800730 """
Kevin Peng655f2392019-11-27 16:33:02 +0800731 Relative path to TF-M root folder is supported in the manifests
732 and default value of manifest list and generated file list are relative to TF-M root folder as well,
733 so first change directory to TF-M root folder.
Shawn Shana9ad1e02019-08-07 15:49:48 +0800734 By doing this, the script can be executed anywhere
Kevin Peng655f2392019-11-27 16:33:02 +0800735 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 +0800736 """
Kevin Peng5bc82d22021-10-19 11:18:40 +0800737 os.chdir(os.path.join(sys.path[0], '..'))
Shawn Shana9ad1e02019-08-07 15:49:48 +0800738
Kevin Peng76c0c162022-02-09 22:49:06 +0800739 context = process_partition_manifests(manifest_lists,
Kevin Pengfb1761b2022-05-12 12:11:31 +0800740 parse_configurations(args.config_files))
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100741
Edison Ai6e3f2a32019-06-11 15:29:05 +0800742 utilities = {}
Mingyang Suna1ca6112021-01-11 11:34:59 +0800743 utilities['donotedit_warning'] = donotedit_warning
Miklos Balint470919c2018-05-22 17:51:29 +0200744
Kevin Peng655f2392019-11-27 16:33:02 +0800745 context['utilities'] = utilities
Mingyang Suneab7eae2021-09-30 13:06:52 +0800746
Ken Liu861b0782021-05-22 13:15:08 +0800747 gen_per_partition_files(context)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800748 gen_summary_files(context, gen_file_lists)
Miklos Balint470919c2018-05-22 17:51:29 +0200749
Kevin Peng5bc82d22021-10-19 11:18:40 +0800750if __name__ == '__main__':
Miklos Balint470919c2018-05-22 17:51:29 +0200751 main()