blob: 32b06dd05190db1cd883c643aa0815f086c12bff [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.
Miklos Balint470919c2018-05-22 17:51:29 +02003#
4# SPDX-License-Identifier: BSD-3-Clause
5#
6#-------------------------------------------------------------------------------
7
8import os
Mate Toth-Pal36f21842018-11-08 16:12:51 +01009import io
Kevin Pengce99e5d2021-11-09 18:06:53 +080010import re
Shawn Shana9ad1e02019-08-07 15:49:48 +080011import sys
12import argparse
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -050013import logging
Ken Liu1f345b02020-05-30 21:11:05 +080014from jinja2 import Environment, BaseLoader, select_autoescape, TemplateNotFound
Miklos Balint470919c2018-05-22 17:51:29 +020015
16try:
17 import yaml
18except ImportError as e:
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -050019 logging.error (str(e) + " To install it, type:")
20 logging.error ("pip install PyYAML")
Miklos Balint470919c2018-05-22 17:51:29 +020021 exit(1)
22
Edison Ai48b2d9e2019-06-24 14:39:45 +080023donotedit_warning = \
Sherry Zhangf58f2bd2022-01-10 17:21:11 +080024 ' WARNING: This is an auto-generated file. Do not edit! '
Kevin Peng655f2392019-11-27 16:33:02 +080025
Kevin Pengce99e5d2021-11-09 18:06:53 +080026TFM_ROOT_DIR = os.path.join(sys.path[0], '..')
Kevin Peng655f2392019-11-27 16:33:02 +080027OUT_DIR = None # The root directory that files are generated to
Edison Ai48b2d9e2019-06-24 14:39:45 +080028
Sherry Zhang87e6d2e2021-12-27 14:48:59 +080029# PID[0, TFM_PID_BASE - 1] are reserved for TF-M SPM and test usages
Kevin Pengce99e5d2021-11-09 18:06:53 +080030TFM_PID_BASE = 256
31
Ruiqi Jiang71d361c2021-06-23 17:45:55 +010032# variable for checking for duplicated sid
33sid_list = []
Mate Toth-Pal36f21842018-11-08 16:12:51 +010034class TemplateLoader(BaseLoader):
35 """
36 Template loader class.
Miklos Balint470919c2018-05-22 17:51:29 +020037
Mate Toth-Pal36f21842018-11-08 16:12:51 +010038 An instance of this class is passed to the template engine. It is
39 responsible for reading the template file
40 """
41 def __init__(self):
42 pass
Miklos Balint470919c2018-05-22 17:51:29 +020043
Mate Toth-Pal36f21842018-11-08 16:12:51 +010044 def get_source(self, environment, template):
45 """
46 This function reads the template files.
47 For detailed documentation see:
48 http://jinja.pocoo.org/docs/2.10/api/#jinja2.BaseLoader.get_source
49
50 Please note that this function always return 'false' as 'uptodate'
51 value, so the output file will always be generated.
52 """
53 if not os.path.isfile(template):
54 raise TemplateNotFound(template)
55 with open(template) as f:
56 source = f.read()
57 return source, template, False
58
Kevin Pengce99e5d2021-11-09 18:06:53 +080059def get_single_macro_def_from_file(file_name, macro_name):
60 """
61 This function parses the given file_name to get the definition of the given
62 C Macro (macro_name).
63
64 It assumes that the target Macro has no multiple definitions in different
65 build configurations.
66
67 It supports Macros defined in multi-line, for example:
68 #define SOME_MACRO \
69 the_macro_value
70
71 Inputs:
72 - file_name: the file to get the Macro from
73 - macro_name: the name of the Macro to get
74 Returns:
75 - The Macro definition with '()' stripped, or Exception if not found
76 """
77
78 with open(file_name, 'r') as f:
79 pattern = re.compile(r'#define\s+{}[\\\s]+.*'.format(macro_name))
80 result = pattern.findall(f.read())
81
82 if len(result) != 1:
83 raise Exception('{} not defined or has multiple definitions'.format(macro_name))
84
85 macro_def = result[0].split()[-1].strip('()')
86
87 return macro_def
88
Kevin Peng8849b6a2021-11-09 14:17:35 +080089def manifest_validation(partition_manifest, pid):
Mingyang Sun294ce2e2021-06-11 11:58:24 +080090 """
91 This function validates FF-M compliance for partition manifest, and sets
92 default values for optional attributes.
Kevin Pengce99e5d2021-11-09 18:06:53 +080093 The validation is skipped for TF-M specific Partitions (PID < TFM_PID_BASE).
Mingyang Sun294ce2e2021-06-11 11:58:24 +080094 More validation items will be added.
95 """
Kevin Peng5bc82d22021-10-19 11:18:40 +080096
Kevin Peng8849b6a2021-11-09 14:17:35 +080097 service_list = partition_manifest.get('services', [])
98 irq_list = partition_manifest.get('irqs', [])
Mingyang Sun294ce2e2021-06-11 11:58:24 +080099
Kevin Pengce99e5d2021-11-09 18:06:53 +0800100 if (pid == None or pid >= TFM_PID_BASE) \
Kevin Peng8849b6a2021-11-09 14:17:35 +0800101 and len(service_list) == 0 and len(irq_list) == 0:
102 raise Exception('{} must declare at least either a secure service or an IRQ!'
103 .format(partition_manifest['name']))
104
105 # Service FF-M manifest validation
106 for service in service_list:
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800107 if 'version' not in service.keys():
108 service['version'] = 1
109 if 'version_policy' not in service.keys():
Kevin Peng5bc82d22021-10-19 11:18:40 +0800110 service['version_policy'] = 'STRICT'
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800111
Kevin Peng5bc82d22021-10-19 11:18:40 +0800112 # SID duplication check
113 if service['sid'] in sid_list:
114 raise Exception('Service ID: {} has duplications!'.format(service['sid']))
115 else:
116 sid_list.append(service['sid'])
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100117
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800118 return partition_manifest
119
Kevin Peng9f1a7542022-02-07 16:32:27 +0800120def process_partition_manifests(manifest_lists, isolation_level):
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100121 """
Kevin Peng65064c52021-10-27 17:12:17 +0800122 Parse the input manifest lists, generate the data base for genereated files
Kevin Peng655f2392019-11-27 16:33:02 +0800123 and generate manifest header files.
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100124
125 Parameters
126 ----------
Kevin Peng65064c52021-10-27 17:12:17 +0800127 manifest_lists:
128 A list of Secure Partition manifest lists and their original paths.
129 The manifest lists might be processed by CMake and the paths might be
130 different to the original ones. Original paths are needed to handle
131 relative paths in the lists.
132 The format must be [list A, orignal path A, list B, orignal path B, ...]
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100133
134 Returns
135 -------
Kevin Peng5bc82d22021-10-19 11:18:40 +0800136 The manifest data base.
Edison Ai48b2d9e2019-06-24 14:39:45 +0800137 """
Kevin Peng655f2392019-11-27 16:33:02 +0800138
Kevin Peng5bc82d22021-10-19 11:18:40 +0800139 context = {}
140
Ken Liu861b0782021-05-22 13:15:08 +0800141 partition_list = []
Kevin Peng65064c52021-10-27 17:12:17 +0800142 all_manifests = []
Kevin Peng56b0ea62021-10-18 11:32:57 +0800143 pid_list = []
144 no_pid_manifest_idx = []
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800145 partition_statistics = {
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800146 'connection_based_srv_num': 0,
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800147 'ipc_partition_num': 0,
148 'sfn_partition_num': 0
149 }
Kevin Peng9f1a7542022-02-07 16:32:27 +0800150 config_impl = {
151 'CONFIG_TFM_SPM_BACKEND_SFN' : '0',
152 'CONFIG_TFM_SPM_BACKEND_IPC' : '0',
153 'CONFIG_TFM_PSA_API_SFN_CALL' : '0',
154 'CONFIG_TFM_PSA_API_CROSS_CALL' : '0',
155 'CONFIG_TFM_PSA_API_SUPERVISOR_CALL' : '0',
156 'CONFIG_TFM_CONNECTION_BASED_SERVICE_API' : '0'
157 }
Kevin Peng655f2392019-11-27 16:33:02 +0800158
Kevin Peng65064c52021-10-27 17:12:17 +0800159 # Get all the manifests information as a dictionary
160 for i, item in enumerate(manifest_lists):
161 if i % 2 == 0 and not os.path.isfile(item):
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500162 logging.error('Manifest list item [{}] must be a file'.format(i))
Kevin Peng65064c52021-10-27 17:12:17 +0800163 exit(1)
Kevin Peng655f2392019-11-27 16:33:02 +0800164
Kevin Peng65064c52021-10-27 17:12:17 +0800165 if i % 2 == 1:
166 if not os.path.isdir(item):
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500167 logging.error('Manifest list item [{}] must be a directory'.format(i))
Kevin Peng65064c52021-10-27 17:12:17 +0800168 exit(1)
David Hub2694202021-07-15 14:58:39 +0800169
Kevin Peng65064c52021-10-27 17:12:17 +0800170 # Skip original manifest paths
171 continue
David Hub2694202021-07-15 14:58:39 +0800172
Kevin Peng65064c52021-10-27 17:12:17 +0800173 # The manifest list file generated by configure_file()
174 with open(item) as manifest_list_yaml_file:
175 manifest_dic = yaml.safe_load(manifest_list_yaml_file)['manifest_list']
176 for dict in manifest_dic:
177 # Add original path of manifest list.
178 # The validation will be done in the next loop.
179 dict['list_path'] = manifest_lists[i + 1]
180 all_manifests.append(dict)
181
182 # Parse the manifests
183 for i, manifest_item in enumerate(all_manifests):
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800184 valid_enabled_conditions = ['on', 'true', 'enabled']
Kevin Peng50f413c2021-11-12 10:31:45 +0800185 valid_disabled_conditions = ['off', 'false', 'disabled', '']
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800186 is_enabled = ''
187
188 if 'conditional' in manifest_item.keys():
Kevin Peng50f413c2021-11-12 10:31:45 +0800189 is_enabled = str(manifest_item['conditional']).lower()
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800190 else:
191 # Partitions without 'conditional' is alwasy on
192 is_enabled = 'on'
193
194 if is_enabled in valid_disabled_conditions:
195 continue
196 elif is_enabled not in valid_enabled_conditions:
197 raise Exception('Invalid "conditional" attribute: "{}" for {}. '
198 'Please set to one of {} or {}, case-insensitive.'\
199 .format(manifest_item['conditional'],
200 manifest_item['name'],
201 valid_enabled_conditions, valid_disabled_conditions))
202
Xinyu Zhangc46ee1f2021-04-01 10:10:43 +0800203 # Check if partition ID is manually set
204 if 'pid' not in manifest_item.keys():
205 no_pid_manifest_idx.append(i)
Kevin Peng8849b6a2021-11-09 14:17:35 +0800206 pid = None
Kevin Peng56b0ea62021-10-18 11:32:57 +0800207 else:
Kevin Peng8849b6a2021-11-09 14:17:35 +0800208 pid = manifest_item['pid']
209
210 # Check if partition ID is duplicated
211 if pid in pid_list:
212 raise Exception('PID No. {pid} has already been used!'.format(pid))
213 else:
214 pid_list.append(pid)
Xinyu Zhang19504a52021-03-31 16:26:20 +0800215
Raef Coles558487a2020-10-29 13:09:44 +0000216 # Replace environment variables in the manifest path
Kevin Peng655f2392019-11-27 16:33:02 +0800217 manifest_path = os.path.expandvars(manifest_item['manifest'])
Kevin Peng65064c52021-10-27 17:12:17 +0800218 # Convert to absolute path. If it's already abspath, the path will not be changed.
219 manifest_path = os.path.join(manifest_item['list_path'], manifest_path).replace('\\', '/')
David Hub2694202021-07-15 14:58:39 +0800220
Kevin Peng5bc82d22021-10-19 11:18:40 +0800221 with open(manifest_path) as manifest_file:
Kevin Peng8849b6a2021-11-09 14:17:35 +0800222 manifest = manifest_validation(yaml.safe_load(manifest_file), pid)
Kevin Peng655f2392019-11-27 16:33:02 +0800223
Kevin Pengce99e5d2021-11-09 18:06:53 +0800224 if pid == None or pid >= TFM_PID_BASE:
Kevin Pengd08f3ba2021-11-18 15:18:56 +0800225 # Count the number of IPC/SFN partitions
226 if manifest['psa_framework_version'] == 1.1 and manifest['model'] == 'SFN':
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800227 partition_statistics['sfn_partition_num'] += 1
Kevin Pengd08f3ba2021-11-18 15:18:56 +0800228 else:
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800229 partition_statistics['ipc_partition_num'] += 1
Mingyang Suneab7eae2021-09-30 13:06:52 +0800230
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800231 for service in manifest.get('services', []):
232 if 'connection_based' not in service.keys():
233 partition_statistics['connection_based_srv_num'] += 1
234 elif service['connection_based']:
235 partition_statistics['connection_based_srv_num'] += 1
236
Kevin Peng65064c52021-10-27 17:12:17 +0800237 manifest_out_basename = os.path.splitext(os.path.basename(manifest_path))[0]
Kevin Peng655f2392019-11-27 16:33:02 +0800238
Kevin Peng4fade072021-10-26 17:57:50 +0800239 if 'output_path' in manifest_item:
Kevin Peng4fade072021-10-26 17:57:50 +0800240 output_path = os.path.expandvars(manifest_item['output_path'])
Kevin Peng4fade072021-10-26 17:57:50 +0800241 else:
Kevin Peng65064c52021-10-27 17:12:17 +0800242 output_path = ''
David Hub2694202021-07-15 14:58:39 +0800243
Kevin Peng5bc82d22021-10-19 11:18:40 +0800244 manifest_head_file = os.path.join(OUT_DIR, output_path, 'psa_manifest',
245 '{}.h'.format(manifest_out_basename))\
246 .replace('\\', '/')
247 intermedia_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
248 'intermedia_{}.c'.format(manifest_out_basename))\
249 .replace('\\', '/')
250 load_info_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
251 'load_info_{}.c'.format(manifest_out_basename))\
252 .replace('\\', '/')
Kevin Peng655f2392019-11-27 16:33:02 +0800253
Kevin Peng5bc82d22021-10-19 11:18:40 +0800254 partition_list.append({'manifest': manifest, 'attr': manifest_item,
255 'manifest_out_basename': manifest_out_basename,
256 'header_file': manifest_head_file,
257 'intermedia_file': intermedia_file,
258 'loadinfo_file': load_info_file})
Ken Liu861b0782021-05-22 13:15:08 +0800259
Kevin Peng56b0ea62021-10-18 11:32:57 +0800260 # Automatically assign PIDs for partitions without 'pid' attribute
Kevin Pengce99e5d2021-11-09 18:06:53 +0800261 pid = max(pid_list, default = TFM_PID_BASE - 1)
Kevin Peng56b0ea62021-10-18 11:32:57 +0800262 for idx in no_pid_manifest_idx:
Kevin Pengc424eec2021-06-25 17:26:11 +0800263 pid += 1
Kevin Peng65064c52021-10-27 17:12:17 +0800264 all_manifests[idx]['pid'] = pid
Kevin Peng56b0ea62021-10-18 11:32:57 +0800265 pid_list.append(pid)
266
Kevin Peng9f1a7542022-02-07 16:32:27 +0800267 # Set up configurations
268 if partition_statistics['ipc_partition_num'] == 0 and \
269 partition_statistics['sfn_partition_num'] > 0:
270 if isolation_level > 1:
271 print('High isolation level SFN model is not supported.')
272 exit(1)
273 config_impl['CONFIG_TFM_SPM_BACKEND_SFN'] = '1'
274 config_impl['CONFIG_TFM_PSA_API_SFN_CALL'] = '1'
275 elif partition_statistics['ipc_partition_num'] > 0 and \
276 partition_statistics['sfn_partition_num'] == 0:
277 config_impl['CONFIG_TFM_SPM_BACKEND_IPC'] = '1'
278 if isolation_level > 1:
279 config_impl['CONFIG_TFM_PSA_API_SUPERVISOR_CALL'] = '1'
280 else:
281 config_impl['CONFIG_TFM_PSA_API_CROSS_CALL'] = '1'
282 elif partition_statistics['ipc_partition_num'] > 0 and \
283 partition_statistics['sfn_partition_num'] > 0:
284 print('IPC and SFN co-work not supported yet.')
285 exit(1)
286 else:
287 print('Invalid partition number input, check configurations.')
288 exit(1)
289
290 if partition_statistics['connection_based_srv_num'] > 0:
291 config_impl['CONFIG_TFM_CONNECTION_BASED_SERVICE_API'] = 1
292
Kevin Peng5bc82d22021-10-19 11:18:40 +0800293 context['partitions'] = partition_list
Kevin Peng9f1a7542022-02-07 16:32:27 +0800294 context['config_impl'] = config_impl
Kevin Pengce99e5d2021-11-09 18:06:53 +0800295 context['stateless_services'] = process_stateless_services(partition_list)
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100296
Kevin Peng5bc82d22021-10-19 11:18:40 +0800297 return context
Ken Liu861b0782021-05-22 13:15:08 +0800298
299def gen_per_partition_files(context):
300 """
301 Generate per-partition files
302
303 Parameters
304 ----------
305 context:
306 context contains partition infos
307 """
308
Kevin Peng5bc82d22021-10-19 11:18:40 +0800309 partition_context = {}
Sherry Zhangf58f2bd2022-01-10 17:21:11 +0800310 partition_context['utilities'] = context['utilities']
Ken Liu861b0782021-05-22 13:15:08 +0800311
Kevin Peng5bc82d22021-10-19 11:18:40 +0800312 manifesttemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/manifestfilename.template'))
313 memorytemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_intermedia.template'))
314 infotemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_load_info.template'))
Ken Liu861b0782021-05-22 13:15:08 +0800315
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500316 logging.info ("Start to generate partition files:")
Ken Liu861b0782021-05-22 13:15:08 +0800317
318 for one_partition in context['partitions']:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800319 partition_context['manifest'] = one_partition['manifest']
320 partition_context['attr'] = one_partition['attr']
321 partition_context['manifest_out_basename'] = one_partition['manifest_out_basename']
Ken Liu861b0782021-05-22 13:15:08 +0800322
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500323 logging.info ("Generating Header: " + one_partition['header_file'])
Ken Liu861b0782021-05-22 13:15:08 +0800324 outfile_path = os.path.dirname(one_partition['header_file'])
Kevin Peng655f2392019-11-27 16:33:02 +0800325 if not os.path.exists(outfile_path):
326 os.makedirs(outfile_path)
327
Kevin Peng5bc82d22021-10-19 11:18:40 +0800328 headerfile = io.open(one_partition['header_file'], 'w', newline=None)
329 headerfile.write(manifesttemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800330 headerfile.close()
Kevin Peng655f2392019-11-27 16:33:02 +0800331
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500332 logging.info ("Generating Intermedia: " + one_partition['intermedia_file'])
Ken Liu861b0782021-05-22 13:15:08 +0800333 intermediafile_path = os.path.dirname(one_partition['intermedia_file'])
Mingyang Sund20999f2020-10-15 14:53:12 +0800334 if not os.path.exists(intermediafile_path):
335 os.makedirs(intermediafile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800336 intermediafile = io.open(one_partition['intermedia_file'], 'w', newline=None)
337 intermediafile.write(memorytemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800338 intermediafile.close()
Mingyang Sund20999f2020-10-15 14:53:12 +0800339
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500340 logging.info ("Generating Loadinfo: " + one_partition['loadinfo_file'])
Ken Liu861b0782021-05-22 13:15:08 +0800341 infofile_path = os.path.dirname(one_partition['loadinfo_file'])
Mingyang Sunf6a78572021-04-02 16:51:05 +0800342 if not os.path.exists(infofile_path):
343 os.makedirs(infofile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800344 infooutfile = io.open(one_partition['loadinfo_file'], 'w', newline=None)
345 infooutfile.write(infotemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800346 infooutfile.close()
Mingyang Sunf6a78572021-04-02 16:51:05 +0800347
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500348 logging.info ("Per-partition files done:")
Mingyang Sunf6a78572021-04-02 16:51:05 +0800349
Ken Liu861b0782021-05-22 13:15:08 +0800350def gen_summary_files(context, gen_file_lists):
Kevin Peng655f2392019-11-27 16:33:02 +0800351 """
352 Generate files according to the gen_file_list
Edison Ai48b2d9e2019-06-24 14:39:45 +0800353
354 Parameters
355 ----------
Raef Colesf42f0882020-07-10 10:01:58 +0100356 gen_file_lists:
357 The lists of files to generate
Edison Ai48b2d9e2019-06-24 14:39:45 +0800358 """
Kevin Peng655f2392019-11-27 16:33:02 +0800359 file_list = []
Shawn Shana9ad1e02019-08-07 15:49:48 +0800360
Raef Colesf42f0882020-07-10 10:01:58 +0100361 for f in gen_file_lists:
362 with open(f) as file_list_yaml_file:
Kevin Peng655f2392019-11-27 16:33:02 +0800363 file_list_yaml = yaml.safe_load(file_list_yaml_file)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800364 file_list.extend(file_list_yaml['file_list'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800365
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500366 logging.info("Start to generate file from the generated list:")
Kevin Peng655f2392019-11-27 16:33:02 +0800367 for file in file_list:
Raef Coles558487a2020-10-29 13:09:44 +0000368 # Replace environment variables in the output filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800369 manifest_out_file = os.path.expandvars(file['output'])
Raef Coles558487a2020-10-29 13:09:44 +0000370 # Replace environment variables in the template filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800371 templatefile_name = os.path.expandvars(file['template'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800372
Kevin Peng4fade072021-10-26 17:57:50 +0800373 manifest_out_file = os.path.join(OUT_DIR, manifest_out_file)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800374
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500375 logging.info ("Generating " + manifest_out_file)
376
Ken Liu861b0782021-05-22 13:15:08 +0800377 outfile_path = os.path.dirname(manifest_out_file)
Kevin Peng655f2392019-11-27 16:33:02 +0800378 if not os.path.exists(outfile_path):
379 os.makedirs(outfile_path)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800380
Kevin Peng655f2392019-11-27 16:33:02 +0800381 template = ENV.get_template(templatefile_name)
Edison Ai6e3f2a32019-06-11 15:29:05 +0800382
Kevin Peng5bc82d22021-10-19 11:18:40 +0800383 outfile = io.open(manifest_out_file, 'w', newline=None)
Kevin Peng655f2392019-11-27 16:33:02 +0800384 outfile.write(template.render(context))
385 outfile.close()
Edison Ai48b2d9e2019-06-24 14:39:45 +0800386
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500387 logging.info ("Generation of files done")
Edison Ai48b2d9e2019-06-24 14:39:45 +0800388
Kevin Pengce99e5d2021-11-09 18:06:53 +0800389def process_stateless_services(partitions):
Mingyang Suna1ca6112021-01-11 11:34:59 +0800390 """
391 This function collects all stateless services together, and allocates
Mingyang Sun4ecea992021-03-30 17:56:26 +0800392 stateless handles for them.
Kevin Pengc05319d2021-04-22 22:59:35 +0800393 Valid stateless handle in service will be converted to an index. If the
394 stateless handle is set as "auto", or not set, framework will allocate a
395 valid index for the service.
396 Framework puts each service into a reordered stateless service list at
397 position of "index". Other unused positions are left None.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800398 """
Kevin Pengce99e5d2021-11-09 18:06:53 +0800399
400 STATIC_HANDLE_CONFIG_FILE = 'secure_fw/spm/cmsis_psa/spm_ipc.h'
401
Kevin Pengc05319d2021-04-22 22:59:35 +0800402 collected_stateless_services = []
Kevin Pengce99e5d2021-11-09 18:06:53 +0800403 stateless_index_max_num = \
404 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_NUM_LIMIT'), base = 10)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800405
406 # Collect all stateless services first.
407 for partition in partitions:
408 # Skip the FF-M 1.0 partitions
409 if partition['manifest']['psa_framework_version'] < 1.1:
410 continue
Kevin Peng8849b6a2021-11-09 14:17:35 +0800411
412 service_list = partition['manifest'].get('services', [])
413
414 for service in service_list:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800415 if 'connection_based' not in service:
416 raise Exception("'connection_based' is mandatory in FF-M 1.1 service!")
417 if service['connection_based'] is False:
Kevin Pengc05319d2021-04-22 22:59:35 +0800418 collected_stateless_services.append(service)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800419
Kevin Pengc05319d2021-04-22 22:59:35 +0800420 if len(collected_stateless_services) == 0:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800421 return []
422
Ken Liu861b0782021-05-22 13:15:08 +0800423 if len(collected_stateless_services) > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800424 raise Exception('Stateless service numbers range exceed {number}.'.format(number=stateless_index_max_num))
Mingyang Suna1ca6112021-01-11 11:34:59 +0800425
426 """
Kevin Pengc05319d2021-04-22 22:59:35 +0800427 Allocate an empty stateless service list to store services.
428 Use "handle - 1" as the index for service, since handle value starts from
429 1 and list index starts from 0.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800430 """
Ken Liu861b0782021-05-22 13:15:08 +0800431 reordered_stateless_services = [None] * stateless_index_max_num
Kevin Pengc05319d2021-04-22 22:59:35 +0800432 auto_alloc_services = []
Mingyang Suna1ca6112021-01-11 11:34:59 +0800433
Kevin Pengc05319d2021-04-22 22:59:35 +0800434 for service in collected_stateless_services:
435 # If not set, it is "auto" by default
436 if 'stateless_handle' not in service:
437 auto_alloc_services.append(service)
438 continue
439
Mingyang Sun4ecea992021-03-30 17:56:26 +0800440 service_handle = service['stateless_handle']
Mingyang Suna1ca6112021-01-11 11:34:59 +0800441
Mingyang Sun4ecea992021-03-30 17:56:26 +0800442 # Fill in service list with specified stateless handle, otherwise skip
443 if isinstance(service_handle, int):
Ken Liu861b0782021-05-22 13:15:08 +0800444 if service_handle < 1 or service_handle > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800445 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800446 # Convert handle index to reordered service list index
447 service_handle = service_handle - 1
448
449 if reordered_stateless_services[service_handle] is not None:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800450 raise Exception('Duplicated stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800451 reordered_stateless_services[service_handle] = service
Kevin Pengc05319d2021-04-22 22:59:35 +0800452 elif service_handle == 'auto':
453 auto_alloc_services.append(service)
454 else:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800455 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800456
Kevin Pengce99e5d2021-11-09 18:06:53 +0800457 STATIC_HANDLE_IDX_BIT_WIDTH = \
458 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_IDX_BIT_WIDTH'), base = 10)
459 STATIC_HANDLE_IDX_MASK = (1 << STATIC_HANDLE_IDX_BIT_WIDTH) - 1
460
461 STATIC_HANDLE_INDICATOR_OFFSET = \
462 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_INDICATOR_OFFSET'), base = 10)
463
464 STATIC_HANDLE_VER_OFFSET = \
465 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_OFFSET'), base = 10)
466
467 STATIC_HANDLE_VER_BIT_WIDTH = \
468 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_BIT_WIDTH'), base = 10)
469 STATIC_HANDLE_VER_MASK = (1 << STATIC_HANDLE_VER_BIT_WIDTH) - 1
470
Mingyang Sun4ecea992021-03-30 17:56:26 +0800471 # Auto-allocate stateless handle and encode the stateless handle
Ken Liu861b0782021-05-22 13:15:08 +0800472 for i in range(0, stateless_index_max_num):
Mingyang Sun4ecea992021-03-30 17:56:26 +0800473 service = reordered_stateless_services[i]
474
Kevin Pengc05319d2021-04-22 22:59:35 +0800475 if service == None and len(auto_alloc_services) > 0:
476 service = auto_alloc_services.pop(0)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800477
Mingyang Sun453ad402021-03-17 17:58:33 +0800478 """
479 Encode stateless flag and version into stateless handle
Kevin Pengce99e5d2021-11-09 18:06:53 +0800480 Check STATIC_HANDLE_CONFIG_FILE for details
Mingyang Sun453ad402021-03-17 17:58:33 +0800481 """
Mingyang Sun4ecea992021-03-30 17:56:26 +0800482 stateless_handle_value = 0
483 if service != None:
Kevin Pengce99e5d2021-11-09 18:06:53 +0800484 stateless_index = (i & STATIC_HANDLE_IDX_MASK)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800485 stateless_handle_value |= stateless_index
Kevin Pengce99e5d2021-11-09 18:06:53 +0800486 stateless_handle_value |= (1 << STATIC_HANDLE_INDICATOR_OFFSET)
487 stateless_version = (service['version'] & STATIC_HANDLE_VER_MASK) << STATIC_HANDLE_VER_OFFSET
Mingyang Sun453ad402021-03-17 17:58:33 +0800488 stateless_handle_value |= stateless_version
Mingyang Sun4ecea992021-03-30 17:56:26 +0800489 service['stateless_handle_value'] = '0x{0:08x}'.format(stateless_handle_value)
Ken Liu861b0782021-05-22 13:15:08 +0800490 service['stateless_handle_index'] = stateless_index
Mingyang Suna1ca6112021-01-11 11:34:59 +0800491
Mingyang Sun4ecea992021-03-30 17:56:26 +0800492 reordered_stateless_services[i] = service
493
494 return reordered_stateless_services
Mingyang Suna1ca6112021-01-11 11:34:59 +0800495
Kevin Peng655f2392019-11-27 16:33:02 +0800496def parse_args():
Raef Coles558487a2020-10-29 13:09:44 +0000497 parser = argparse.ArgumentParser(description='Parse secure partition manifest list and generate files listed by the file list',
498 epilog='Note that environment variables in template files will be replaced with their values')
499
Kevin Peng655f2392019-11-27 16:33:02 +0800500 parser.add_argument('-o', '--outdir'
501 , dest='outdir'
Kevin Peng4fade072021-10-26 17:57:50 +0800502 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800503 , metavar='out_dir'
Kevin Peng4fade072021-10-26 17:57:50 +0800504 , help='The root directory for generated files')
Shawn Shana9ad1e02019-08-07 15:49:48 +0800505
Kevin Peng5bc82d22021-10-19 11:18:40 +0800506 parser.add_argument('-m', '--manifest-lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100507 , nargs='+'
Kevin Peng5bc82d22021-10-19 11:18:40 +0800508 , dest='manifest_lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100509 , required=True
Kevin Peng65064c52021-10-27 17:12:17 +0800510 , metavar='manifest list'
511 , help='A list of Secure Partition manifest lists and their original paths.\n\
512 The manifest lists might be processed by CMake and\n\
513 the path might be different to the original one\n\
514 The format must be [list A, orignal path A, list B, orignal path B, ...]')
Kevin Peng655f2392019-11-27 16:33:02 +0800515
516 parser.add_argument('-f', '--file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100517 , nargs='+'
Kevin Peng655f2392019-11-27 16:33:02 +0800518 , dest='gen_file_args'
Raef Colesf42f0882020-07-10 10:01:58 +0100519 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800520 , metavar='file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100521 , help='These files descripe the file list to generate')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800522
523 parser.add_argument('-l', '--isolation-level'
524 , dest='isolation_level'
525 , required=True
526 , choices=['1', '2', '3']
527 , metavar='isolation-level'
528 , help='The isolation level')
529
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500530 parser.add_argument('-q', '--quiet'
531 , dest='quiet'
532 , required=False
533 , default=False
534 , action='store_true'
535 , help='Reduce log messages')
Kevin Peng655f2392019-11-27 16:33:02 +0800536
537 args = parser.parse_args()
Kevin Peng655f2392019-11-27 16:33:02 +0800538
Kevin Peng65064c52021-10-27 17:12:17 +0800539 if len(args.manifest_lists) % 2 != 0:
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500540 logging.error('Invalid structure in manifest lists.\n'
Kevin Peng65064c52021-10-27 17:12:17 +0800541 'Each element shall consist of a manifest list and its original path')
542 exit(1)
543
Kevin Peng655f2392019-11-27 16:33:02 +0800544 return args
545
546ENV = Environment(
547 loader = TemplateLoader(),
548 autoescape = select_autoescape(['html', 'xml']),
549 lstrip_blocks = True,
550 trim_blocks = True,
551 keep_trailing_newline = True
552 )
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100553
Miklos Balint470919c2018-05-22 17:51:29 +0200554def main():
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100555 """
556 The entry point of the script.
557
558 Generates the output files based on the templates and the manifests.
559 """
Shawn Shana9ad1e02019-08-07 15:49:48 +0800560
Kevin Peng655f2392019-11-27 16:33:02 +0800561 global OUT_DIR
Shawn Shana9ad1e02019-08-07 15:49:48 +0800562
Kevin Peng655f2392019-11-27 16:33:02 +0800563 args = parse_args()
Shawn Shana9ad1e02019-08-07 15:49:48 +0800564
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500565 logging.basicConfig(format='%(message)s'
566 , level=logging.WARNING if args.quiet else logging.INFO)
567
Kevin Peng5bc82d22021-10-19 11:18:40 +0800568 OUT_DIR = os.path.abspath(args.outdir)
Kevin Peng655f2392019-11-27 16:33:02 +0800569
Kevin Peng5bc82d22021-10-19 11:18:40 +0800570 manifest_lists = [os.path.abspath(x) for x in args.manifest_lists]
571 gen_file_lists = [os.path.abspath(x) for x in args.gen_file_args]
Shawn Shana9ad1e02019-08-07 15:49:48 +0800572
Shawn Shana9ad1e02019-08-07 15:49:48 +0800573 """
Kevin Peng655f2392019-11-27 16:33:02 +0800574 Relative path to TF-M root folder is supported in the manifests
575 and default value of manifest list and generated file list are relative to TF-M root folder as well,
576 so first change directory to TF-M root folder.
Shawn Shana9ad1e02019-08-07 15:49:48 +0800577 By doing this, the script can be executed anywhere
Kevin Peng655f2392019-11-27 16:33:02 +0800578 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 +0800579 """
Kevin Peng5bc82d22021-10-19 11:18:40 +0800580 os.chdir(os.path.join(sys.path[0], '..'))
Shawn Shana9ad1e02019-08-07 15:49:48 +0800581
Kevin Peng9f1a7542022-02-07 16:32:27 +0800582 context = process_partition_manifests(manifest_lists, int(args.isolation_level))
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100583
Edison Ai6e3f2a32019-06-11 15:29:05 +0800584 utilities = {}
Mingyang Suna1ca6112021-01-11 11:34:59 +0800585 utilities['donotedit_warning'] = donotedit_warning
Miklos Balint470919c2018-05-22 17:51:29 +0200586
Kevin Peng655f2392019-11-27 16:33:02 +0800587 context['utilities'] = utilities
Mingyang Suneab7eae2021-09-30 13:06:52 +0800588
Ken Liu861b0782021-05-22 13:15:08 +0800589 gen_per_partition_files(context)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800590 gen_summary_files(context, gen_file_lists)
Miklos Balint470919c2018-05-22 17:51:29 +0200591
Kevin Peng5bc82d22021-10-19 11:18:40 +0800592if __name__ == '__main__':
Miklos Balint470919c2018-05-22 17:51:29 +0200593 main()