blob: ac74f4585027b46b4e6f1eef3ef91cdc0b70ed9c [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 Peng76c0c162022-02-09 22:49:06 +0800120def process_partition_manifests(manifest_lists, isolation_level, backend):
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,
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800148 'sfn_partition_num': 0,
149 'flih_num': 0,
150 'slih_num': 0
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800151 }
Kevin Peng9f1a7542022-02-07 16:32:27 +0800152 config_impl = {
153 'CONFIG_TFM_SPM_BACKEND_SFN' : '0',
154 'CONFIG_TFM_SPM_BACKEND_IPC' : '0',
155 'CONFIG_TFM_PSA_API_SFN_CALL' : '0',
156 'CONFIG_TFM_PSA_API_CROSS_CALL' : '0',
157 'CONFIG_TFM_PSA_API_SUPERVISOR_CALL' : '0',
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800158 'CONFIG_TFM_CONNECTION_BASED_SERVICE_API' : '0',
159 'CONFIG_TFM_FLIH_API' : '0',
160 'CONFIG_TFM_SLIH_API' : '0'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800161 }
Kevin Peng655f2392019-11-27 16:33:02 +0800162
Kevin Peng65064c52021-10-27 17:12:17 +0800163 # Get all the manifests information as a dictionary
164 for i, item in enumerate(manifest_lists):
165 if i % 2 == 0 and not os.path.isfile(item):
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500166 logging.error('Manifest list item [{}] must be a file'.format(i))
Kevin Peng65064c52021-10-27 17:12:17 +0800167 exit(1)
Kevin Peng655f2392019-11-27 16:33:02 +0800168
Kevin Peng65064c52021-10-27 17:12:17 +0800169 if i % 2 == 1:
170 if not os.path.isdir(item):
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500171 logging.error('Manifest list item [{}] must be a directory'.format(i))
Kevin Peng65064c52021-10-27 17:12:17 +0800172 exit(1)
David Hub2694202021-07-15 14:58:39 +0800173
Kevin Peng65064c52021-10-27 17:12:17 +0800174 # Skip original manifest paths
175 continue
David Hub2694202021-07-15 14:58:39 +0800176
Kevin Peng65064c52021-10-27 17:12:17 +0800177 # The manifest list file generated by configure_file()
178 with open(item) as manifest_list_yaml_file:
179 manifest_dic = yaml.safe_load(manifest_list_yaml_file)['manifest_list']
180 for dict in manifest_dic:
181 # Add original path of manifest list.
182 # The validation will be done in the next loop.
183 dict['list_path'] = manifest_lists[i + 1]
184 all_manifests.append(dict)
185
186 # Parse the manifests
187 for i, manifest_item in enumerate(all_manifests):
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800188 valid_enabled_conditions = ['on', 'true', 'enabled']
Kevin Peng50f413c2021-11-12 10:31:45 +0800189 valid_disabled_conditions = ['off', 'false', 'disabled', '']
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800190 is_enabled = ''
191
192 if 'conditional' in manifest_item.keys():
Kevin Peng50f413c2021-11-12 10:31:45 +0800193 is_enabled = str(manifest_item['conditional']).lower()
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800194 else:
195 # Partitions without 'conditional' is alwasy on
196 is_enabled = 'on'
197
198 if is_enabled in valid_disabled_conditions:
199 continue
200 elif is_enabled not in valid_enabled_conditions:
201 raise Exception('Invalid "conditional" attribute: "{}" for {}. '
202 'Please set to one of {} or {}, case-insensitive.'\
203 .format(manifest_item['conditional'],
204 manifest_item['name'],
205 valid_enabled_conditions, valid_disabled_conditions))
206
Xinyu Zhangc46ee1f2021-04-01 10:10:43 +0800207 # Check if partition ID is manually set
208 if 'pid' not in manifest_item.keys():
209 no_pid_manifest_idx.append(i)
Kevin Peng8849b6a2021-11-09 14:17:35 +0800210 pid = None
Kevin Peng56b0ea62021-10-18 11:32:57 +0800211 else:
Kevin Peng8849b6a2021-11-09 14:17:35 +0800212 pid = manifest_item['pid']
213
214 # Check if partition ID is duplicated
215 if pid in pid_list:
216 raise Exception('PID No. {pid} has already been used!'.format(pid))
217 else:
218 pid_list.append(pid)
Xinyu Zhang19504a52021-03-31 16:26:20 +0800219
Raef Coles558487a2020-10-29 13:09:44 +0000220 # Replace environment variables in the manifest path
Kevin Peng655f2392019-11-27 16:33:02 +0800221 manifest_path = os.path.expandvars(manifest_item['manifest'])
Kevin Peng65064c52021-10-27 17:12:17 +0800222 # Convert to absolute path. If it's already abspath, the path will not be changed.
223 manifest_path = os.path.join(manifest_item['list_path'], manifest_path).replace('\\', '/')
David Hub2694202021-07-15 14:58:39 +0800224
Kevin Peng5bc82d22021-10-19 11:18:40 +0800225 with open(manifest_path) as manifest_file:
Kevin Peng8849b6a2021-11-09 14:17:35 +0800226 manifest = manifest_validation(yaml.safe_load(manifest_file), pid)
Kevin Peng655f2392019-11-27 16:33:02 +0800227
Kevin Pengce99e5d2021-11-09 18:06:53 +0800228 if pid == None or pid >= TFM_PID_BASE:
Kevin Pengd08f3ba2021-11-18 15:18:56 +0800229 # Count the number of IPC/SFN partitions
230 if manifest['psa_framework_version'] == 1.1 and manifest['model'] == 'SFN':
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800231 partition_statistics['sfn_partition_num'] += 1
Kevin Pengd08f3ba2021-11-18 15:18:56 +0800232 else:
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800233 partition_statistics['ipc_partition_num'] += 1
Mingyang Suneab7eae2021-09-30 13:06:52 +0800234
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800235 for service in manifest.get('services', []):
236 if 'connection_based' not in service.keys():
237 partition_statistics['connection_based_srv_num'] += 1
238 elif service['connection_based']:
239 partition_statistics['connection_based_srv_num'] += 1
240
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800241 for irq in manifest.get('irqs', []):
242 if irq.get('handling', None) == 'FLIH':
243 partition_statistics['flih_num'] += 1
244 else:
245 partition_statistics['slih_num'] += 1
246
Kevin Peng65064c52021-10-27 17:12:17 +0800247 manifest_out_basename = os.path.splitext(os.path.basename(manifest_path))[0]
Kevin Peng655f2392019-11-27 16:33:02 +0800248
Kevin Peng4fade072021-10-26 17:57:50 +0800249 if 'output_path' in manifest_item:
Kevin Peng4fade072021-10-26 17:57:50 +0800250 output_path = os.path.expandvars(manifest_item['output_path'])
Kevin Peng4fade072021-10-26 17:57:50 +0800251 else:
Kevin Peng65064c52021-10-27 17:12:17 +0800252 output_path = ''
David Hub2694202021-07-15 14:58:39 +0800253
Kevin Peng5bc82d22021-10-19 11:18:40 +0800254 manifest_head_file = os.path.join(OUT_DIR, output_path, 'psa_manifest',
255 '{}.h'.format(manifest_out_basename))\
256 .replace('\\', '/')
257 intermedia_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
258 'intermedia_{}.c'.format(manifest_out_basename))\
259 .replace('\\', '/')
260 load_info_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
261 'load_info_{}.c'.format(manifest_out_basename))\
262 .replace('\\', '/')
Kevin Peng655f2392019-11-27 16:33:02 +0800263
Kevin Peng5bc82d22021-10-19 11:18:40 +0800264 partition_list.append({'manifest': manifest, 'attr': manifest_item,
265 'manifest_out_basename': manifest_out_basename,
266 'header_file': manifest_head_file,
267 'intermedia_file': intermedia_file,
268 'loadinfo_file': load_info_file})
Ken Liu861b0782021-05-22 13:15:08 +0800269
Kevin Peng56b0ea62021-10-18 11:32:57 +0800270 # Automatically assign PIDs for partitions without 'pid' attribute
Kevin Pengce99e5d2021-11-09 18:06:53 +0800271 pid = max(pid_list, default = TFM_PID_BASE - 1)
Kevin Peng56b0ea62021-10-18 11:32:57 +0800272 for idx in no_pid_manifest_idx:
Kevin Pengc424eec2021-06-25 17:26:11 +0800273 pid += 1
Kevin Peng65064c52021-10-27 17:12:17 +0800274 all_manifests[idx]['pid'] = pid
Kevin Peng56b0ea62021-10-18 11:32:57 +0800275 pid_list.append(pid)
276
Kevin Peng9f1a7542022-02-07 16:32:27 +0800277 # Set up configurations
Kevin Peng76c0c162022-02-09 22:49:06 +0800278 if backend == 'SFN':
279 if partition_statistics['ipc_partition_num'] > 0:
280 logging.error('SFN backend does not support IPC Partitions.')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800281 exit(1)
Kevin Peng76c0c162022-02-09 22:49:06 +0800282
283 if isolation_level > 1:
284 logging.error('SFN backend does not support high isolation levels.')
285 exit(1)
286
Kevin Peng9f1a7542022-02-07 16:32:27 +0800287 config_impl['CONFIG_TFM_SPM_BACKEND_SFN'] = '1'
288 config_impl['CONFIG_TFM_PSA_API_SFN_CALL'] = '1'
Kevin Peng76c0c162022-02-09 22:49:06 +0800289 elif backend == 'IPC':
290 if partition_statistics['sfn_partition_num'] > 0:
291 logging.error('IPC backend does not support SFN Partitions.')
292 exit(1)
293
Kevin Peng9f1a7542022-02-07 16:32:27 +0800294 config_impl['CONFIG_TFM_SPM_BACKEND_IPC'] = '1'
295 if isolation_level > 1:
296 config_impl['CONFIG_TFM_PSA_API_SUPERVISOR_CALL'] = '1'
297 else:
298 config_impl['CONFIG_TFM_PSA_API_CROSS_CALL'] = '1'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800299
300 if partition_statistics['connection_based_srv_num'] > 0:
301 config_impl['CONFIG_TFM_CONNECTION_BASED_SERVICE_API'] = 1
302
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800303 if partition_statistics['flih_num'] > 0:
304 config_impl['CONFIG_TFM_FLIH_API'] = 1
305 elif partition_statistics['slih_num'] > 0:
306 config_impl['CONFIG_TFM_SLIH_API'] = 1
307
Kevin Peng5bc82d22021-10-19 11:18:40 +0800308 context['partitions'] = partition_list
Kevin Peng9f1a7542022-02-07 16:32:27 +0800309 context['config_impl'] = config_impl
Kevin Pengce99e5d2021-11-09 18:06:53 +0800310 context['stateless_services'] = process_stateless_services(partition_list)
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100311
Kevin Peng5bc82d22021-10-19 11:18:40 +0800312 return context
Ken Liu861b0782021-05-22 13:15:08 +0800313
314def gen_per_partition_files(context):
315 """
316 Generate per-partition files
317
318 Parameters
319 ----------
320 context:
321 context contains partition infos
322 """
323
Kevin Peng5bc82d22021-10-19 11:18:40 +0800324 partition_context = {}
Sherry Zhangf58f2bd2022-01-10 17:21:11 +0800325 partition_context['utilities'] = context['utilities']
Ken Liu861b0782021-05-22 13:15:08 +0800326
Kevin Peng5bc82d22021-10-19 11:18:40 +0800327 manifesttemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/manifestfilename.template'))
328 memorytemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_intermedia.template'))
329 infotemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_load_info.template'))
Ken Liu861b0782021-05-22 13:15:08 +0800330
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500331 logging.info ("Start to generate partition files:")
Ken Liu861b0782021-05-22 13:15:08 +0800332
333 for one_partition in context['partitions']:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800334 partition_context['manifest'] = one_partition['manifest']
335 partition_context['attr'] = one_partition['attr']
336 partition_context['manifest_out_basename'] = one_partition['manifest_out_basename']
Ken Liu861b0782021-05-22 13:15:08 +0800337
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500338 logging.info ("Generating Header: " + one_partition['header_file'])
Ken Liu861b0782021-05-22 13:15:08 +0800339 outfile_path = os.path.dirname(one_partition['header_file'])
Kevin Peng655f2392019-11-27 16:33:02 +0800340 if not os.path.exists(outfile_path):
341 os.makedirs(outfile_path)
342
Kevin Peng5bc82d22021-10-19 11:18:40 +0800343 headerfile = io.open(one_partition['header_file'], 'w', newline=None)
344 headerfile.write(manifesttemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800345 headerfile.close()
Kevin Peng655f2392019-11-27 16:33:02 +0800346
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500347 logging.info ("Generating Intermedia: " + one_partition['intermedia_file'])
Ken Liu861b0782021-05-22 13:15:08 +0800348 intermediafile_path = os.path.dirname(one_partition['intermedia_file'])
Mingyang Sund20999f2020-10-15 14:53:12 +0800349 if not os.path.exists(intermediafile_path):
350 os.makedirs(intermediafile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800351 intermediafile = io.open(one_partition['intermedia_file'], 'w', newline=None)
352 intermediafile.write(memorytemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800353 intermediafile.close()
Mingyang Sund20999f2020-10-15 14:53:12 +0800354
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500355 logging.info ("Generating Loadinfo: " + one_partition['loadinfo_file'])
Ken Liu861b0782021-05-22 13:15:08 +0800356 infofile_path = os.path.dirname(one_partition['loadinfo_file'])
Mingyang Sunf6a78572021-04-02 16:51:05 +0800357 if not os.path.exists(infofile_path):
358 os.makedirs(infofile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800359 infooutfile = io.open(one_partition['loadinfo_file'], 'w', newline=None)
360 infooutfile.write(infotemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800361 infooutfile.close()
Mingyang Sunf6a78572021-04-02 16:51:05 +0800362
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500363 logging.info ("Per-partition files done:")
Mingyang Sunf6a78572021-04-02 16:51:05 +0800364
Ken Liu861b0782021-05-22 13:15:08 +0800365def gen_summary_files(context, gen_file_lists):
Kevin Peng655f2392019-11-27 16:33:02 +0800366 """
367 Generate files according to the gen_file_list
Edison Ai48b2d9e2019-06-24 14:39:45 +0800368
369 Parameters
370 ----------
Raef Colesf42f0882020-07-10 10:01:58 +0100371 gen_file_lists:
372 The lists of files to generate
Edison Ai48b2d9e2019-06-24 14:39:45 +0800373 """
Kevin Peng655f2392019-11-27 16:33:02 +0800374 file_list = []
Shawn Shana9ad1e02019-08-07 15:49:48 +0800375
Raef Colesf42f0882020-07-10 10:01:58 +0100376 for f in gen_file_lists:
377 with open(f) as file_list_yaml_file:
Kevin Peng655f2392019-11-27 16:33:02 +0800378 file_list_yaml = yaml.safe_load(file_list_yaml_file)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800379 file_list.extend(file_list_yaml['file_list'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800380
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500381 logging.info("Start to generate file from the generated list:")
Kevin Peng655f2392019-11-27 16:33:02 +0800382 for file in file_list:
Raef Coles558487a2020-10-29 13:09:44 +0000383 # Replace environment variables in the output filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800384 manifest_out_file = os.path.expandvars(file['output'])
Raef Coles558487a2020-10-29 13:09:44 +0000385 # Replace environment variables in the template filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800386 templatefile_name = os.path.expandvars(file['template'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800387
Kevin Peng4fade072021-10-26 17:57:50 +0800388 manifest_out_file = os.path.join(OUT_DIR, manifest_out_file)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800389
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500390 logging.info ("Generating " + manifest_out_file)
391
Ken Liu861b0782021-05-22 13:15:08 +0800392 outfile_path = os.path.dirname(manifest_out_file)
Kevin Peng655f2392019-11-27 16:33:02 +0800393 if not os.path.exists(outfile_path):
394 os.makedirs(outfile_path)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800395
Kevin Peng655f2392019-11-27 16:33:02 +0800396 template = ENV.get_template(templatefile_name)
Edison Ai6e3f2a32019-06-11 15:29:05 +0800397
Kevin Peng5bc82d22021-10-19 11:18:40 +0800398 outfile = io.open(manifest_out_file, 'w', newline=None)
Kevin Peng655f2392019-11-27 16:33:02 +0800399 outfile.write(template.render(context))
400 outfile.close()
Edison Ai48b2d9e2019-06-24 14:39:45 +0800401
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500402 logging.info ("Generation of files done")
Edison Ai48b2d9e2019-06-24 14:39:45 +0800403
Kevin Pengce99e5d2021-11-09 18:06:53 +0800404def process_stateless_services(partitions):
Mingyang Suna1ca6112021-01-11 11:34:59 +0800405 """
406 This function collects all stateless services together, and allocates
Mingyang Sun4ecea992021-03-30 17:56:26 +0800407 stateless handles for them.
Kevin Pengc05319d2021-04-22 22:59:35 +0800408 Valid stateless handle in service will be converted to an index. If the
409 stateless handle is set as "auto", or not set, framework will allocate a
410 valid index for the service.
411 Framework puts each service into a reordered stateless service list at
412 position of "index". Other unused positions are left None.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800413 """
Kevin Pengce99e5d2021-11-09 18:06:53 +0800414
415 STATIC_HANDLE_CONFIG_FILE = 'secure_fw/spm/cmsis_psa/spm_ipc.h'
416
Kevin Pengc05319d2021-04-22 22:59:35 +0800417 collected_stateless_services = []
Kevin Pengce99e5d2021-11-09 18:06:53 +0800418 stateless_index_max_num = \
419 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_NUM_LIMIT'), base = 10)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800420
421 # Collect all stateless services first.
422 for partition in partitions:
423 # Skip the FF-M 1.0 partitions
424 if partition['manifest']['psa_framework_version'] < 1.1:
425 continue
Kevin Peng8849b6a2021-11-09 14:17:35 +0800426
427 service_list = partition['manifest'].get('services', [])
428
429 for service in service_list:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800430 if 'connection_based' not in service:
431 raise Exception("'connection_based' is mandatory in FF-M 1.1 service!")
432 if service['connection_based'] is False:
Kevin Pengc05319d2021-04-22 22:59:35 +0800433 collected_stateless_services.append(service)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800434
Kevin Pengc05319d2021-04-22 22:59:35 +0800435 if len(collected_stateless_services) == 0:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800436 return []
437
Ken Liu861b0782021-05-22 13:15:08 +0800438 if len(collected_stateless_services) > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800439 raise Exception('Stateless service numbers range exceed {number}.'.format(number=stateless_index_max_num))
Mingyang Suna1ca6112021-01-11 11:34:59 +0800440
441 """
Kevin Pengc05319d2021-04-22 22:59:35 +0800442 Allocate an empty stateless service list to store services.
443 Use "handle - 1" as the index for service, since handle value starts from
444 1 and list index starts from 0.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800445 """
Ken Liu861b0782021-05-22 13:15:08 +0800446 reordered_stateless_services = [None] * stateless_index_max_num
Kevin Pengc05319d2021-04-22 22:59:35 +0800447 auto_alloc_services = []
Mingyang Suna1ca6112021-01-11 11:34:59 +0800448
Kevin Pengc05319d2021-04-22 22:59:35 +0800449 for service in collected_stateless_services:
450 # If not set, it is "auto" by default
451 if 'stateless_handle' not in service:
452 auto_alloc_services.append(service)
453 continue
454
Mingyang Sun4ecea992021-03-30 17:56:26 +0800455 service_handle = service['stateless_handle']
Mingyang Suna1ca6112021-01-11 11:34:59 +0800456
Mingyang Sun4ecea992021-03-30 17:56:26 +0800457 # Fill in service list with specified stateless handle, otherwise skip
458 if isinstance(service_handle, int):
Ken Liu861b0782021-05-22 13:15:08 +0800459 if service_handle < 1 or service_handle > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800460 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800461 # Convert handle index to reordered service list index
462 service_handle = service_handle - 1
463
464 if reordered_stateless_services[service_handle] is not None:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800465 raise Exception('Duplicated stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800466 reordered_stateless_services[service_handle] = service
Kevin Pengc05319d2021-04-22 22:59:35 +0800467 elif service_handle == 'auto':
468 auto_alloc_services.append(service)
469 else:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800470 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800471
Kevin Pengce99e5d2021-11-09 18:06:53 +0800472 STATIC_HANDLE_IDX_BIT_WIDTH = \
473 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_IDX_BIT_WIDTH'), base = 10)
474 STATIC_HANDLE_IDX_MASK = (1 << STATIC_HANDLE_IDX_BIT_WIDTH) - 1
475
476 STATIC_HANDLE_INDICATOR_OFFSET = \
477 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_INDICATOR_OFFSET'), base = 10)
478
479 STATIC_HANDLE_VER_OFFSET = \
480 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_OFFSET'), base = 10)
481
482 STATIC_HANDLE_VER_BIT_WIDTH = \
483 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_BIT_WIDTH'), base = 10)
484 STATIC_HANDLE_VER_MASK = (1 << STATIC_HANDLE_VER_BIT_WIDTH) - 1
485
Mingyang Sun4ecea992021-03-30 17:56:26 +0800486 # Auto-allocate stateless handle and encode the stateless handle
Ken Liu861b0782021-05-22 13:15:08 +0800487 for i in range(0, stateless_index_max_num):
Mingyang Sun4ecea992021-03-30 17:56:26 +0800488 service = reordered_stateless_services[i]
489
Kevin Pengc05319d2021-04-22 22:59:35 +0800490 if service == None and len(auto_alloc_services) > 0:
491 service = auto_alloc_services.pop(0)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800492
Mingyang Sun453ad402021-03-17 17:58:33 +0800493 """
494 Encode stateless flag and version into stateless handle
Kevin Pengce99e5d2021-11-09 18:06:53 +0800495 Check STATIC_HANDLE_CONFIG_FILE for details
Mingyang Sun453ad402021-03-17 17:58:33 +0800496 """
Mingyang Sun4ecea992021-03-30 17:56:26 +0800497 stateless_handle_value = 0
498 if service != None:
Kevin Pengce99e5d2021-11-09 18:06:53 +0800499 stateless_index = (i & STATIC_HANDLE_IDX_MASK)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800500 stateless_handle_value |= stateless_index
Kevin Pengce99e5d2021-11-09 18:06:53 +0800501 stateless_handle_value |= (1 << STATIC_HANDLE_INDICATOR_OFFSET)
502 stateless_version = (service['version'] & STATIC_HANDLE_VER_MASK) << STATIC_HANDLE_VER_OFFSET
Mingyang Sun453ad402021-03-17 17:58:33 +0800503 stateless_handle_value |= stateless_version
Mingyang Sun4ecea992021-03-30 17:56:26 +0800504 service['stateless_handle_value'] = '0x{0:08x}'.format(stateless_handle_value)
Ken Liu861b0782021-05-22 13:15:08 +0800505 service['stateless_handle_index'] = stateless_index
Mingyang Suna1ca6112021-01-11 11:34:59 +0800506
Mingyang Sun4ecea992021-03-30 17:56:26 +0800507 reordered_stateless_services[i] = service
508
509 return reordered_stateless_services
Mingyang Suna1ca6112021-01-11 11:34:59 +0800510
Kevin Peng655f2392019-11-27 16:33:02 +0800511def parse_args():
Raef Coles558487a2020-10-29 13:09:44 +0000512 parser = argparse.ArgumentParser(description='Parse secure partition manifest list and generate files listed by the file list',
513 epilog='Note that environment variables in template files will be replaced with their values')
514
Kevin Peng655f2392019-11-27 16:33:02 +0800515 parser.add_argument('-o', '--outdir'
516 , dest='outdir'
Kevin Peng4fade072021-10-26 17:57:50 +0800517 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800518 , metavar='out_dir'
Kevin Peng4fade072021-10-26 17:57:50 +0800519 , help='The root directory for generated files')
Shawn Shana9ad1e02019-08-07 15:49:48 +0800520
Kevin Peng5bc82d22021-10-19 11:18:40 +0800521 parser.add_argument('-m', '--manifest-lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100522 , nargs='+'
Kevin Peng5bc82d22021-10-19 11:18:40 +0800523 , dest='manifest_lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100524 , required=True
Kevin Peng65064c52021-10-27 17:12:17 +0800525 , metavar='manifest list'
526 , help='A list of Secure Partition manifest lists and their original paths.\n\
527 The manifest lists might be processed by CMake and\n\
528 the path might be different to the original one\n\
529 The format must be [list A, orignal path A, list B, orignal path B, ...]')
Kevin Peng655f2392019-11-27 16:33:02 +0800530
531 parser.add_argument('-f', '--file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100532 , nargs='+'
Kevin Peng655f2392019-11-27 16:33:02 +0800533 , dest='gen_file_args'
Raef Colesf42f0882020-07-10 10:01:58 +0100534 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800535 , metavar='file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100536 , help='These files descripe the file list to generate')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800537
538 parser.add_argument('-l', '--isolation-level'
539 , dest='isolation_level'
540 , required=True
541 , choices=['1', '2', '3']
Kevin Peng76c0c162022-02-09 22:49:06 +0800542 , metavar='isolation-level')
543
544 parser.add_argument('-b', '--backend'
545 , dest='backend'
546 , required=True
547 , choices=['IPC', 'SFN']
548 , metavar='spm-backend'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800549 , help='The isolation level')
550
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500551 parser.add_argument('-q', '--quiet'
552 , dest='quiet'
553 , required=False
554 , default=False
555 , action='store_true'
556 , help='Reduce log messages')
Kevin Peng655f2392019-11-27 16:33:02 +0800557
558 args = parser.parse_args()
Kevin Peng655f2392019-11-27 16:33:02 +0800559
Kevin Peng65064c52021-10-27 17:12:17 +0800560 if len(args.manifest_lists) % 2 != 0:
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500561 logging.error('Invalid structure in manifest lists.\n'
Kevin Peng65064c52021-10-27 17:12:17 +0800562 'Each element shall consist of a manifest list and its original path')
563 exit(1)
564
Kevin Peng655f2392019-11-27 16:33:02 +0800565 return args
566
567ENV = Environment(
568 loader = TemplateLoader(),
569 autoescape = select_autoescape(['html', 'xml']),
570 lstrip_blocks = True,
571 trim_blocks = True,
572 keep_trailing_newline = True
573 )
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100574
Miklos Balint470919c2018-05-22 17:51:29 +0200575def main():
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100576 """
577 The entry point of the script.
578
579 Generates the output files based on the templates and the manifests.
580 """
Shawn Shana9ad1e02019-08-07 15:49:48 +0800581
Kevin Peng655f2392019-11-27 16:33:02 +0800582 global OUT_DIR
Shawn Shana9ad1e02019-08-07 15:49:48 +0800583
Kevin Peng655f2392019-11-27 16:33:02 +0800584 args = parse_args()
Shawn Shana9ad1e02019-08-07 15:49:48 +0800585
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500586 logging.basicConfig(format='%(message)s'
587 , level=logging.WARNING if args.quiet else logging.INFO)
588
Kevin Peng5bc82d22021-10-19 11:18:40 +0800589 OUT_DIR = os.path.abspath(args.outdir)
Kevin Peng655f2392019-11-27 16:33:02 +0800590
Kevin Peng5bc82d22021-10-19 11:18:40 +0800591 manifest_lists = [os.path.abspath(x) for x in args.manifest_lists]
592 gen_file_lists = [os.path.abspath(x) for x in args.gen_file_args]
Shawn Shana9ad1e02019-08-07 15:49:48 +0800593
Shawn Shana9ad1e02019-08-07 15:49:48 +0800594 """
Kevin Peng655f2392019-11-27 16:33:02 +0800595 Relative path to TF-M root folder is supported in the manifests
596 and default value of manifest list and generated file list are relative to TF-M root folder as well,
597 so first change directory to TF-M root folder.
Shawn Shana9ad1e02019-08-07 15:49:48 +0800598 By doing this, the script can be executed anywhere
Kevin Peng655f2392019-11-27 16:33:02 +0800599 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 +0800600 """
Kevin Peng5bc82d22021-10-19 11:18:40 +0800601 os.chdir(os.path.join(sys.path[0], '..'))
Shawn Shana9ad1e02019-08-07 15:49:48 +0800602
Kevin Peng76c0c162022-02-09 22:49:06 +0800603 context = process_partition_manifests(manifest_lists,
604 int(args.isolation_level),
605 args.backend)
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100606
Edison Ai6e3f2a32019-06-11 15:29:05 +0800607 utilities = {}
Mingyang Suna1ca6112021-01-11 11:34:59 +0800608 utilities['donotedit_warning'] = donotedit_warning
Miklos Balint470919c2018-05-22 17:51:29 +0200609
Kevin Peng655f2392019-11-27 16:33:02 +0800610 context['utilities'] = utilities
Mingyang Suneab7eae2021-09-30 13:06:52 +0800611
Ken Liu861b0782021-05-22 13:15:08 +0800612 gen_per_partition_files(context)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800613 gen_summary_files(context, gen_file_lists)
Miklos Balint470919c2018-05-22 17:51:29 +0200614
Kevin Peng5bc82d22021-10-19 11:18:40 +0800615if __name__ == '__main__':
Miklos Balint470919c2018-05-22 17:51:29 +0200616 main()