blob: fe0da5743a1162a5bea21f2cc71cde1a6faa9118 [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 Peng5c3fee72022-02-16 22:25:22 +080089def manifest_validation(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 """
Kevin Peng5bc82d22021-10-19 11:18:40 +080095
Kevin Peng5c3fee72022-02-16 22:25:22 +080096 service_list = manifest.get('services', [])
97 irq_list = manifest.get('irqs', [])
Mingyang Sun294ce2e2021-06-11 11:58:24 +080098
Kevin Peng5c3fee72022-02-16 22:25:22 +080099 # "psa_framework_version" validation
100 if manifest['psa_framework_version'] not in [1.0, 1.1]:
101 raise Exception('Invalid psa_framework_version of {}'.format(manifest['name']))
102
103 # "type" validatoin
104 if manifest['type'] not in ['PSA-ROT', 'APPLICATION-ROT']:
105 raise Exception('Invalid type of {}'.format(manifest['name']))
106
107 # Every PSA Partition must have at least either a secure service or an IRQ
Kevin Pengce99e5d2021-11-09 18:06:53 +0800108 if (pid == None or pid >= TFM_PID_BASE) \
Kevin Peng8849b6a2021-11-09 14:17:35 +0800109 and len(service_list) == 0 and len(irq_list) == 0:
110 raise Exception('{} must declare at least either a secure service or an IRQ!'
Kevin Peng5c3fee72022-02-16 22:25:22 +0800111 .format(manifest['name']))
112
113 if manifest['psa_framework_version'] == 1.0:
114 # For 1.0 Partition, the model is IPC
115 manifest['model'] = 'IPC'
116
117 # "model" validation:
118 model = manifest.get('model', None)
119 if model == None:
120 raise Exception('{} is missing the "model" attribute'.format(manifest['name']))
121
122 # Assign a unified 'entry' for templates
123 if model == 'IPC':
124 # entry_point is mandatory for IPC Partitions
125 if 'entry_point' not in manifest.keys():
126 raise Exception('{} is missing the "entry_point" attribute'.format(manifest['name']))
127 manifest['entry'] = manifest['entry_point']
128 elif model == 'SFN':
129 if 'entry_init' in manifest.keys():
130 manifest['entry'] = manifest['entry_init']
131 else:
132 manifest['entry'] = 0
133 else:
134 raise Exception('Invalid "model" of {}'.format(manifest['name']))
Kevin Peng8849b6a2021-11-09 14:17:35 +0800135
136 # Service FF-M manifest validation
137 for service in service_list:
Kevin Peng5c3fee72022-02-16 22:25:22 +0800138 if manifest['psa_framework_version'] == 1.0:
139 service['connection_based'] = True
140 elif 'connection_based' not in service:
141 raise Exception("'connection_based' is mandatory in FF-M 1.1 service!")
142
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800143 if 'version' not in service.keys():
144 service['version'] = 1
145 if 'version_policy' not in service.keys():
Kevin Peng5bc82d22021-10-19 11:18:40 +0800146 service['version_policy'] = 'STRICT'
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800147
Kevin Peng5bc82d22021-10-19 11:18:40 +0800148 # SID duplication check
149 if service['sid'] in sid_list:
150 raise Exception('Service ID: {} has duplications!'.format(service['sid']))
151 else:
152 sid_list.append(service['sid'])
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100153
Kevin Peng5c3fee72022-02-16 22:25:22 +0800154 return manifest
Mingyang Sun294ce2e2021-06-11 11:58:24 +0800155
Kevin Peng76c0c162022-02-09 22:49:06 +0800156def process_partition_manifests(manifest_lists, isolation_level, backend):
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100157 """
Kevin Peng65064c52021-10-27 17:12:17 +0800158 Parse the input manifest lists, generate the data base for genereated files
Kevin Peng655f2392019-11-27 16:33:02 +0800159 and generate manifest header files.
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100160
161 Parameters
162 ----------
Kevin Peng65064c52021-10-27 17:12:17 +0800163 manifest_lists:
164 A list of Secure Partition manifest lists and their original paths.
165 The manifest lists might be processed by CMake and the paths might be
166 different to the original ones. Original paths are needed to handle
167 relative paths in the lists.
168 The format must be [list A, orignal path A, list B, orignal path B, ...]
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100169
170 Returns
171 -------
Kevin Peng5bc82d22021-10-19 11:18:40 +0800172 The manifest data base.
Edison Ai48b2d9e2019-06-24 14:39:45 +0800173 """
Kevin Peng655f2392019-11-27 16:33:02 +0800174
Kevin Peng5bc82d22021-10-19 11:18:40 +0800175 context = {}
176
Ken Liu861b0782021-05-22 13:15:08 +0800177 partition_list = []
Kevin Peng65064c52021-10-27 17:12:17 +0800178 all_manifests = []
Kevin Peng56b0ea62021-10-18 11:32:57 +0800179 pid_list = []
180 no_pid_manifest_idx = []
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800181 partition_statistics = {
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800182 'connection_based_srv_num': 0,
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800183 'ipc_partition_num': 0,
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800184 'sfn_partition_num': 0,
185 'flih_num': 0,
186 'slih_num': 0
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800187 }
Kevin Peng9f1a7542022-02-07 16:32:27 +0800188 config_impl = {
189 'CONFIG_TFM_SPM_BACKEND_SFN' : '0',
190 'CONFIG_TFM_SPM_BACKEND_IPC' : '0',
191 'CONFIG_TFM_PSA_API_SFN_CALL' : '0',
192 'CONFIG_TFM_PSA_API_CROSS_CALL' : '0',
193 'CONFIG_TFM_PSA_API_SUPERVISOR_CALL' : '0',
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800194 'CONFIG_TFM_CONNECTION_BASED_SERVICE_API' : '0',
195 'CONFIG_TFM_FLIH_API' : '0',
196 'CONFIG_TFM_SLIH_API' : '0'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800197 }
Kevin Peng655f2392019-11-27 16:33:02 +0800198
Kevin Peng65064c52021-10-27 17:12:17 +0800199 # Get all the manifests information as a dictionary
200 for i, item in enumerate(manifest_lists):
201 if i % 2 == 0 and not os.path.isfile(item):
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500202 logging.error('Manifest list item [{}] must be a file'.format(i))
Kevin Peng65064c52021-10-27 17:12:17 +0800203 exit(1)
Kevin Peng655f2392019-11-27 16:33:02 +0800204
Kevin Peng65064c52021-10-27 17:12:17 +0800205 if i % 2 == 1:
206 if not os.path.isdir(item):
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500207 logging.error('Manifest list item [{}] must be a directory'.format(i))
Kevin Peng65064c52021-10-27 17:12:17 +0800208 exit(1)
David Hub2694202021-07-15 14:58:39 +0800209
Kevin Peng65064c52021-10-27 17:12:17 +0800210 # Skip original manifest paths
211 continue
David Hub2694202021-07-15 14:58:39 +0800212
Kevin Peng65064c52021-10-27 17:12:17 +0800213 # The manifest list file generated by configure_file()
214 with open(item) as manifest_list_yaml_file:
215 manifest_dic = yaml.safe_load(manifest_list_yaml_file)['manifest_list']
216 for dict in manifest_dic:
217 # Add original path of manifest list.
218 # The validation will be done in the next loop.
219 dict['list_path'] = manifest_lists[i + 1]
220 all_manifests.append(dict)
221
222 # Parse the manifests
223 for i, manifest_item in enumerate(all_manifests):
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800224 valid_enabled_conditions = ['on', 'true', 'enabled']
Kevin Peng50f413c2021-11-12 10:31:45 +0800225 valid_disabled_conditions = ['off', 'false', 'disabled', '']
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800226 is_enabled = ''
227
228 if 'conditional' in manifest_item.keys():
Kevin Peng50f413c2021-11-12 10:31:45 +0800229 is_enabled = str(manifest_item['conditional']).lower()
Kevin Peng68d9a3a2021-10-18 11:39:54 +0800230 else:
231 # Partitions without 'conditional' is alwasy on
232 is_enabled = 'on'
233
234 if is_enabled in valid_disabled_conditions:
235 continue
236 elif is_enabled not in valid_enabled_conditions:
237 raise Exception('Invalid "conditional" attribute: "{}" for {}. '
238 'Please set to one of {} or {}, case-insensitive.'\
239 .format(manifest_item['conditional'],
240 manifest_item['name'],
241 valid_enabled_conditions, valid_disabled_conditions))
242
Xinyu Zhangc46ee1f2021-04-01 10:10:43 +0800243 # Check if partition ID is manually set
244 if 'pid' not in manifest_item.keys():
245 no_pid_manifest_idx.append(i)
Kevin Peng8849b6a2021-11-09 14:17:35 +0800246 pid = None
Kevin Peng56b0ea62021-10-18 11:32:57 +0800247 else:
Kevin Peng8849b6a2021-11-09 14:17:35 +0800248 pid = manifest_item['pid']
249
250 # Check if partition ID is duplicated
251 if pid in pid_list:
252 raise Exception('PID No. {pid} has already been used!'.format(pid))
253 else:
254 pid_list.append(pid)
Xinyu Zhang19504a52021-03-31 16:26:20 +0800255
Raef Coles558487a2020-10-29 13:09:44 +0000256 # Replace environment variables in the manifest path
Kevin Peng655f2392019-11-27 16:33:02 +0800257 manifest_path = os.path.expandvars(manifest_item['manifest'])
Kevin Peng65064c52021-10-27 17:12:17 +0800258 # Convert to absolute path. If it's already abspath, the path will not be changed.
259 manifest_path = os.path.join(manifest_item['list_path'], manifest_path).replace('\\', '/')
David Hub2694202021-07-15 14:58:39 +0800260
Kevin Peng5bc82d22021-10-19 11:18:40 +0800261 with open(manifest_path) as manifest_file:
Kevin Pengec0e5ce2022-02-17 13:48:51 +0800262 manifest = yaml.safe_load(manifest_file)
263 if manifest.get('model', None) == 'dual':
264 # If a Partition supports both models, it can set the "model" to "backend".
265 # The actual model used follows the backend being used.
266 manifest['model'] = backend
267 manifest = manifest_validation(manifest, pid)
Kevin Peng655f2392019-11-27 16:33:02 +0800268
Kevin Pengce99e5d2021-11-09 18:06:53 +0800269 if pid == None or pid >= TFM_PID_BASE:
Kevin Pengd08f3ba2021-11-18 15:18:56 +0800270 # Count the number of IPC/SFN partitions
271 if manifest['psa_framework_version'] == 1.1 and manifest['model'] == 'SFN':
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800272 partition_statistics['sfn_partition_num'] += 1
Kevin Pengd08f3ba2021-11-18 15:18:56 +0800273 else:
Xinyu Zhang90f08dc2022-01-12 15:55:17 +0800274 partition_statistics['ipc_partition_num'] += 1
Mingyang Suneab7eae2021-09-30 13:06:52 +0800275
Kevin Peng5c3fee72022-02-16 22:25:22 +0800276 # Set initial value to -1 to make (srv_idx + 1) reflect the correct
277 # number (0) when there are no services.
278 srv_idx = -1
279 for srv_idx, service in enumerate(manifest.get('services', [])):
280 if manifest['model'] == 'IPC':
281 # Assign signal value, the first 4 bits are reserved by FF-M
282 service['signal_value'] = (1 << (srv_idx + 4))
283 else:
284 # Signals of SFN Partitions are SPM internal only, does not
285 # need to reserve 4 bits.
286 service['signal_value'] = (1 << srv_idx)
287 if service['connection_based']:
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800288 partition_statistics['connection_based_srv_num'] += 1
Kevin Peng5c3fee72022-02-16 22:25:22 +0800289 logging.debug('{} has {} services'.format(manifest['name'], srv_idx +1))
Xinyu Zhang2bc4d572021-12-27 16:37:46 +0800290
Kevin Peng5c3fee72022-02-16 22:25:22 +0800291 # Set initial value to -1 to make (irq + 1) reflect the correct
292 # number (0) when there are no irqs.
293 irq_idx = -1
294 for irq_idx, irq in enumerate(manifest.get('irqs', [])):
295 # Assign signal value, from the most significant bit
296 irq['signal_value'] = (1 << (31 - irq_idx))
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800297 if irq.get('handling', None) == 'FLIH':
298 partition_statistics['flih_num'] += 1
299 else:
300 partition_statistics['slih_num'] += 1
Kevin Peng5c3fee72022-02-16 22:25:22 +0800301 logging.debug('{} has {} IRQS'.format(manifest['name'], irq_idx +1))
302
303 if ((srv_idx + 1) + (irq_idx + 1)) > 28:
304 raise Exception('Total number of Services and IRQs of {} exceeds the limit (28)'
305 .format(manifest['name']))
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800306
Kevin Peng65064c52021-10-27 17:12:17 +0800307 manifest_out_basename = os.path.splitext(os.path.basename(manifest_path))[0]
Kevin Peng655f2392019-11-27 16:33:02 +0800308
Kevin Peng4fade072021-10-26 17:57:50 +0800309 if 'output_path' in manifest_item:
Kevin Peng4fade072021-10-26 17:57:50 +0800310 output_path = os.path.expandvars(manifest_item['output_path'])
Kevin Peng4fade072021-10-26 17:57:50 +0800311 else:
Kevin Peng65064c52021-10-27 17:12:17 +0800312 output_path = ''
David Hub2694202021-07-15 14:58:39 +0800313
Kevin Peng5bc82d22021-10-19 11:18:40 +0800314 manifest_head_file = os.path.join(OUT_DIR, output_path, 'psa_manifest',
315 '{}.h'.format(manifest_out_basename))\
316 .replace('\\', '/')
317 intermedia_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
318 'intermedia_{}.c'.format(manifest_out_basename))\
319 .replace('\\', '/')
320 load_info_file = os.path.join(OUT_DIR, output_path, 'auto_generated',
321 'load_info_{}.c'.format(manifest_out_basename))\
322 .replace('\\', '/')
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800323 output_dir = os.path.join(OUT_DIR, output_path).replace('\\', '/')
Kevin Peng655f2392019-11-27 16:33:02 +0800324
Kevin Peng5bc82d22021-10-19 11:18:40 +0800325 partition_list.append({'manifest': manifest, 'attr': manifest_item,
326 'manifest_out_basename': manifest_out_basename,
327 'header_file': manifest_head_file,
328 'intermedia_file': intermedia_file,
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800329 'loadinfo_file': load_info_file,
330 'output_dir':output_dir})
Ken Liu861b0782021-05-22 13:15:08 +0800331
Kevin Peng56b0ea62021-10-18 11:32:57 +0800332 # Automatically assign PIDs for partitions without 'pid' attribute
Kevin Pengce99e5d2021-11-09 18:06:53 +0800333 pid = max(pid_list, default = TFM_PID_BASE - 1)
Kevin Peng56b0ea62021-10-18 11:32:57 +0800334 for idx in no_pid_manifest_idx:
Kevin Pengc424eec2021-06-25 17:26:11 +0800335 pid += 1
Kevin Peng65064c52021-10-27 17:12:17 +0800336 all_manifests[idx]['pid'] = pid
Kevin Peng56b0ea62021-10-18 11:32:57 +0800337 pid_list.append(pid)
338
Kevin Peng9f1a7542022-02-07 16:32:27 +0800339 # Set up configurations
Kevin Peng76c0c162022-02-09 22:49:06 +0800340 if backend == 'SFN':
341 if partition_statistics['ipc_partition_num'] > 0:
342 logging.error('SFN backend does not support IPC Partitions.')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800343 exit(1)
Kevin Peng76c0c162022-02-09 22:49:06 +0800344
345 if isolation_level > 1:
346 logging.error('SFN backend does not support high isolation levels.')
347 exit(1)
348
Kevin Peng9f1a7542022-02-07 16:32:27 +0800349 config_impl['CONFIG_TFM_SPM_BACKEND_SFN'] = '1'
350 config_impl['CONFIG_TFM_PSA_API_SFN_CALL'] = '1'
Kevin Peng76c0c162022-02-09 22:49:06 +0800351 elif backend == 'IPC':
Kevin Peng9f1a7542022-02-07 16:32:27 +0800352 config_impl['CONFIG_TFM_SPM_BACKEND_IPC'] = '1'
353 if isolation_level > 1:
354 config_impl['CONFIG_TFM_PSA_API_SUPERVISOR_CALL'] = '1'
355 else:
356 config_impl['CONFIG_TFM_PSA_API_CROSS_CALL'] = '1'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800357
358 if partition_statistics['connection_based_srv_num'] > 0:
359 config_impl['CONFIG_TFM_CONNECTION_BASED_SERVICE_API'] = 1
360
Mingyang Suned5fe7b2022-02-10 17:33:21 +0800361 if partition_statistics['flih_num'] > 0:
362 config_impl['CONFIG_TFM_FLIH_API'] = 1
363 elif partition_statistics['slih_num'] > 0:
364 config_impl['CONFIG_TFM_SLIH_API'] = 1
365
Kevin Peng5bc82d22021-10-19 11:18:40 +0800366 context['partitions'] = partition_list
Kevin Peng9f1a7542022-02-07 16:32:27 +0800367 context['config_impl'] = config_impl
Kevin Pengce99e5d2021-11-09 18:06:53 +0800368 context['stateless_services'] = process_stateless_services(partition_list)
Ruiqi Jiang71d361c2021-06-23 17:45:55 +0100369
Kevin Peng5bc82d22021-10-19 11:18:40 +0800370 return context
Ken Liu861b0782021-05-22 13:15:08 +0800371
372def gen_per_partition_files(context):
373 """
374 Generate per-partition files
375
376 Parameters
377 ----------
378 context:
379 context contains partition infos
380 """
381
Kevin Peng5bc82d22021-10-19 11:18:40 +0800382 partition_context = {}
Sherry Zhangf58f2bd2022-01-10 17:21:11 +0800383 partition_context['utilities'] = context['utilities']
Ken Liu861b0782021-05-22 13:15:08 +0800384
Kevin Peng5bc82d22021-10-19 11:18:40 +0800385 manifesttemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/manifestfilename.template'))
386 memorytemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_intermedia.template'))
387 infotemplate = ENV.get_template(os.path.join(sys.path[0], 'templates/partition_load_info.template'))
Ken Liu861b0782021-05-22 13:15:08 +0800388
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500389 logging.info ("Start to generate partition files:")
Ken Liu861b0782021-05-22 13:15:08 +0800390
391 for one_partition in context['partitions']:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800392 partition_context['manifest'] = one_partition['manifest']
393 partition_context['attr'] = one_partition['attr']
394 partition_context['manifest_out_basename'] = one_partition['manifest_out_basename']
Ken Liu861b0782021-05-22 13:15:08 +0800395
Jianliang Shen785ed5e2022-02-08 14:16:06 +0800396 logging.info ('Generating {} in {}'.format(one_partition['attr']['name'],
397 one_partition['output_dir']))
Ken Liu861b0782021-05-22 13:15:08 +0800398 outfile_path = os.path.dirname(one_partition['header_file'])
Kevin Peng655f2392019-11-27 16:33:02 +0800399 if not os.path.exists(outfile_path):
400 os.makedirs(outfile_path)
401
Kevin Peng5bc82d22021-10-19 11:18:40 +0800402 headerfile = io.open(one_partition['header_file'], 'w', newline=None)
403 headerfile.write(manifesttemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800404 headerfile.close()
Kevin Peng655f2392019-11-27 16:33:02 +0800405
Ken Liu861b0782021-05-22 13:15:08 +0800406 intermediafile_path = os.path.dirname(one_partition['intermedia_file'])
Mingyang Sund20999f2020-10-15 14:53:12 +0800407 if not os.path.exists(intermediafile_path):
408 os.makedirs(intermediafile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800409 intermediafile = io.open(one_partition['intermedia_file'], 'w', newline=None)
410 intermediafile.write(memorytemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800411 intermediafile.close()
Mingyang Sund20999f2020-10-15 14:53:12 +0800412
Ken Liu861b0782021-05-22 13:15:08 +0800413 infofile_path = os.path.dirname(one_partition['loadinfo_file'])
Mingyang Sunf6a78572021-04-02 16:51:05 +0800414 if not os.path.exists(infofile_path):
415 os.makedirs(infofile_path)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800416 infooutfile = io.open(one_partition['loadinfo_file'], 'w', newline=None)
417 infooutfile.write(infotemplate.render(partition_context))
Ken Liu861b0782021-05-22 13:15:08 +0800418 infooutfile.close()
Mingyang Sunf6a78572021-04-02 16:51:05 +0800419
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500420 logging.info ("Per-partition files done:")
Mingyang Sunf6a78572021-04-02 16:51:05 +0800421
Ken Liu861b0782021-05-22 13:15:08 +0800422def gen_summary_files(context, gen_file_lists):
Kevin Peng655f2392019-11-27 16:33:02 +0800423 """
424 Generate files according to the gen_file_list
Edison Ai48b2d9e2019-06-24 14:39:45 +0800425
426 Parameters
427 ----------
Raef Colesf42f0882020-07-10 10:01:58 +0100428 gen_file_lists:
429 The lists of files to generate
Edison Ai48b2d9e2019-06-24 14:39:45 +0800430 """
Kevin Peng655f2392019-11-27 16:33:02 +0800431 file_list = []
Shawn Shana9ad1e02019-08-07 15:49:48 +0800432
Raef Colesf42f0882020-07-10 10:01:58 +0100433 for f in gen_file_lists:
434 with open(f) as file_list_yaml_file:
Kevin Peng655f2392019-11-27 16:33:02 +0800435 file_list_yaml = yaml.safe_load(file_list_yaml_file)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800436 file_list.extend(file_list_yaml['file_list'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800437
Kevin Peng655f2392019-11-27 16:33:02 +0800438 for file in file_list:
Raef Coles558487a2020-10-29 13:09:44 +0000439 # Replace environment variables in the output filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800440 manifest_out_file = os.path.expandvars(file['output'])
Raef Coles558487a2020-10-29 13:09:44 +0000441 # Replace environment variables in the template filepath
Kevin Peng5bc82d22021-10-19 11:18:40 +0800442 templatefile_name = os.path.expandvars(file['template'])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800443
Kevin Peng4fade072021-10-26 17:57:50 +0800444 manifest_out_file = os.path.join(OUT_DIR, manifest_out_file)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800445
Ken Liu861b0782021-05-22 13:15:08 +0800446 outfile_path = os.path.dirname(manifest_out_file)
Kevin Peng655f2392019-11-27 16:33:02 +0800447 if not os.path.exists(outfile_path):
448 os.makedirs(outfile_path)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800449
Kevin Peng655f2392019-11-27 16:33:02 +0800450 template = ENV.get_template(templatefile_name)
Edison Ai6e3f2a32019-06-11 15:29:05 +0800451
Kevin Peng5bc82d22021-10-19 11:18:40 +0800452 outfile = io.open(manifest_out_file, 'w', newline=None)
Kevin Peng655f2392019-11-27 16:33:02 +0800453 outfile.write(template.render(context))
454 outfile.close()
Edison Ai48b2d9e2019-06-24 14:39:45 +0800455
Kevin Pengce99e5d2021-11-09 18:06:53 +0800456def process_stateless_services(partitions):
Mingyang Suna1ca6112021-01-11 11:34:59 +0800457 """
458 This function collects all stateless services together, and allocates
Mingyang Sun4ecea992021-03-30 17:56:26 +0800459 stateless handles for them.
Kevin Pengc05319d2021-04-22 22:59:35 +0800460 Valid stateless handle in service will be converted to an index. If the
461 stateless handle is set as "auto", or not set, framework will allocate a
462 valid index for the service.
463 Framework puts each service into a reordered stateless service list at
464 position of "index". Other unused positions are left None.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800465 """
Kevin Pengce99e5d2021-11-09 18:06:53 +0800466
467 STATIC_HANDLE_CONFIG_FILE = 'secure_fw/spm/cmsis_psa/spm_ipc.h'
468
Kevin Pengc05319d2021-04-22 22:59:35 +0800469 collected_stateless_services = []
Kevin Pengce99e5d2021-11-09 18:06:53 +0800470 stateless_index_max_num = \
471 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_NUM_LIMIT'), base = 10)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800472
473 # Collect all stateless services first.
474 for partition in partitions:
475 # Skip the FF-M 1.0 partitions
476 if partition['manifest']['psa_framework_version'] < 1.1:
477 continue
Kevin Peng8849b6a2021-11-09 14:17:35 +0800478
479 service_list = partition['manifest'].get('services', [])
480
481 for service in service_list:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800482 if service['connection_based'] is False:
Kevin Pengc05319d2021-04-22 22:59:35 +0800483 collected_stateless_services.append(service)
Mingyang Suna1ca6112021-01-11 11:34:59 +0800484
Kevin Pengc05319d2021-04-22 22:59:35 +0800485 if len(collected_stateless_services) == 0:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800486 return []
487
Ken Liu861b0782021-05-22 13:15:08 +0800488 if len(collected_stateless_services) > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800489 raise Exception('Stateless service numbers range exceed {number}.'.format(number=stateless_index_max_num))
Mingyang Suna1ca6112021-01-11 11:34:59 +0800490
491 """
Kevin Pengc05319d2021-04-22 22:59:35 +0800492 Allocate an empty stateless service list to store services.
493 Use "handle - 1" as the index for service, since handle value starts from
494 1 and list index starts from 0.
Mingyang Suna1ca6112021-01-11 11:34:59 +0800495 """
Ken Liu861b0782021-05-22 13:15:08 +0800496 reordered_stateless_services = [None] * stateless_index_max_num
Kevin Pengc05319d2021-04-22 22:59:35 +0800497 auto_alloc_services = []
Mingyang Suna1ca6112021-01-11 11:34:59 +0800498
Kevin Pengc05319d2021-04-22 22:59:35 +0800499 for service in collected_stateless_services:
500 # If not set, it is "auto" by default
501 if 'stateless_handle' not in service:
502 auto_alloc_services.append(service)
503 continue
504
Mingyang Sun4ecea992021-03-30 17:56:26 +0800505 service_handle = service['stateless_handle']
Mingyang Suna1ca6112021-01-11 11:34:59 +0800506
Mingyang Sun4ecea992021-03-30 17:56:26 +0800507 # Fill in service list with specified stateless handle, otherwise skip
508 if isinstance(service_handle, int):
Ken Liu861b0782021-05-22 13:15:08 +0800509 if service_handle < 1 or service_handle > stateless_index_max_num:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800510 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800511 # Convert handle index to reordered service list index
512 service_handle = service_handle - 1
513
514 if reordered_stateless_services[service_handle] is not None:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800515 raise Exception('Duplicated stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800516 reordered_stateless_services[service_handle] = service
Kevin Pengc05319d2021-04-22 22:59:35 +0800517 elif service_handle == 'auto':
518 auto_alloc_services.append(service)
519 else:
Kevin Peng5bc82d22021-10-19 11:18:40 +0800520 raise Exception('Invalid stateless_handle setting: {handle}.'.format(handle=service['stateless_handle']))
Mingyang Sun4ecea992021-03-30 17:56:26 +0800521
Kevin Pengce99e5d2021-11-09 18:06:53 +0800522 STATIC_HANDLE_IDX_BIT_WIDTH = \
523 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_IDX_BIT_WIDTH'), base = 10)
524 STATIC_HANDLE_IDX_MASK = (1 << STATIC_HANDLE_IDX_BIT_WIDTH) - 1
525
526 STATIC_HANDLE_INDICATOR_OFFSET = \
527 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_INDICATOR_OFFSET'), base = 10)
528
529 STATIC_HANDLE_VER_OFFSET = \
530 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_OFFSET'), base = 10)
531
532 STATIC_HANDLE_VER_BIT_WIDTH = \
533 int(get_single_macro_def_from_file(STATIC_HANDLE_CONFIG_FILE, 'STATIC_HANDLE_VER_BIT_WIDTH'), base = 10)
534 STATIC_HANDLE_VER_MASK = (1 << STATIC_HANDLE_VER_BIT_WIDTH) - 1
535
Mingyang Sun4ecea992021-03-30 17:56:26 +0800536 # Auto-allocate stateless handle and encode the stateless handle
Ken Liu861b0782021-05-22 13:15:08 +0800537 for i in range(0, stateless_index_max_num):
Mingyang Sun4ecea992021-03-30 17:56:26 +0800538 service = reordered_stateless_services[i]
539
Kevin Pengc05319d2021-04-22 22:59:35 +0800540 if service == None and len(auto_alloc_services) > 0:
541 service = auto_alloc_services.pop(0)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800542
Mingyang Sun453ad402021-03-17 17:58:33 +0800543 """
544 Encode stateless flag and version into stateless handle
Kevin Pengce99e5d2021-11-09 18:06:53 +0800545 Check STATIC_HANDLE_CONFIG_FILE for details
Mingyang Sun453ad402021-03-17 17:58:33 +0800546 """
Mingyang Sun4ecea992021-03-30 17:56:26 +0800547 stateless_handle_value = 0
548 if service != None:
Kevin Pengce99e5d2021-11-09 18:06:53 +0800549 stateless_index = (i & STATIC_HANDLE_IDX_MASK)
Mingyang Sun4ecea992021-03-30 17:56:26 +0800550 stateless_handle_value |= stateless_index
Kevin Pengce99e5d2021-11-09 18:06:53 +0800551 stateless_handle_value |= (1 << STATIC_HANDLE_INDICATOR_OFFSET)
552 stateless_version = (service['version'] & STATIC_HANDLE_VER_MASK) << STATIC_HANDLE_VER_OFFSET
Mingyang Sun453ad402021-03-17 17:58:33 +0800553 stateless_handle_value |= stateless_version
Mingyang Sun4ecea992021-03-30 17:56:26 +0800554 service['stateless_handle_value'] = '0x{0:08x}'.format(stateless_handle_value)
Ken Liu861b0782021-05-22 13:15:08 +0800555 service['stateless_handle_index'] = stateless_index
Mingyang Suna1ca6112021-01-11 11:34:59 +0800556
Mingyang Sun4ecea992021-03-30 17:56:26 +0800557 reordered_stateless_services[i] = service
558
559 return reordered_stateless_services
Mingyang Suna1ca6112021-01-11 11:34:59 +0800560
Kevin Peng655f2392019-11-27 16:33:02 +0800561def parse_args():
Raef Coles558487a2020-10-29 13:09:44 +0000562 parser = argparse.ArgumentParser(description='Parse secure partition manifest list and generate files listed by the file list',
563 epilog='Note that environment variables in template files will be replaced with their values')
564
Kevin Peng655f2392019-11-27 16:33:02 +0800565 parser.add_argument('-o', '--outdir'
566 , dest='outdir'
Kevin Peng4fade072021-10-26 17:57:50 +0800567 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800568 , metavar='out_dir'
Kevin Peng4fade072021-10-26 17:57:50 +0800569 , help='The root directory for generated files')
Shawn Shana9ad1e02019-08-07 15:49:48 +0800570
Kevin Peng5bc82d22021-10-19 11:18:40 +0800571 parser.add_argument('-m', '--manifest-lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100572 , nargs='+'
Kevin Peng5bc82d22021-10-19 11:18:40 +0800573 , dest='manifest_lists'
Raef Colesf42f0882020-07-10 10:01:58 +0100574 , required=True
Kevin Peng65064c52021-10-27 17:12:17 +0800575 , metavar='manifest list'
576 , help='A list of Secure Partition manifest lists and their original paths.\n\
577 The manifest lists might be processed by CMake and\n\
578 the path might be different to the original one\n\
579 The format must be [list A, orignal path A, list B, orignal path B, ...]')
Kevin Peng655f2392019-11-27 16:33:02 +0800580
581 parser.add_argument('-f', '--file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100582 , nargs='+'
Kevin Peng655f2392019-11-27 16:33:02 +0800583 , dest='gen_file_args'
Raef Colesf42f0882020-07-10 10:01:58 +0100584 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800585 , metavar='file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100586 , help='These files descripe the file list to generate')
Kevin Peng9f1a7542022-02-07 16:32:27 +0800587
588 parser.add_argument('-l', '--isolation-level'
589 , dest='isolation_level'
590 , required=True
591 , choices=['1', '2', '3']
Kevin Peng76c0c162022-02-09 22:49:06 +0800592 , metavar='isolation-level')
593
594 parser.add_argument('-b', '--backend'
595 , dest='backend'
596 , required=True
597 , choices=['IPC', 'SFN']
598 , metavar='spm-backend'
Kevin Peng9f1a7542022-02-07 16:32:27 +0800599 , help='The isolation level')
600
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500601 parser.add_argument('-q', '--quiet'
602 , dest='quiet'
603 , required=False
604 , default=False
605 , action='store_true'
606 , help='Reduce log messages')
Kevin Peng655f2392019-11-27 16:33:02 +0800607
608 args = parser.parse_args()
Kevin Peng655f2392019-11-27 16:33:02 +0800609
Kevin Peng65064c52021-10-27 17:12:17 +0800610 if len(args.manifest_lists) % 2 != 0:
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500611 logging.error('Invalid structure in manifest lists.\n'
Kevin Peng65064c52021-10-27 17:12:17 +0800612 'Each element shall consist of a manifest list and its original path')
613 exit(1)
614
Kevin Peng655f2392019-11-27 16:33:02 +0800615 return args
616
617ENV = Environment(
618 loader = TemplateLoader(),
619 autoescape = select_autoescape(['html', 'xml']),
620 lstrip_blocks = True,
621 trim_blocks = True,
622 keep_trailing_newline = True
623 )
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100624
Miklos Balint470919c2018-05-22 17:51:29 +0200625def main():
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100626 """
627 The entry point of the script.
628
629 Generates the output files based on the templates and the manifests.
630 """
Shawn Shana9ad1e02019-08-07 15:49:48 +0800631
Kevin Peng655f2392019-11-27 16:33:02 +0800632 global OUT_DIR
Shawn Shana9ad1e02019-08-07 15:49:48 +0800633
Kevin Peng655f2392019-11-27 16:33:02 +0800634 args = parse_args()
Shawn Shana9ad1e02019-08-07 15:49:48 +0800635
Jimmy Brisson89d4f8d2021-06-23 10:17:36 -0500636 logging.basicConfig(format='%(message)s'
637 , level=logging.WARNING if args.quiet else logging.INFO)
638
Kevin Peng5bc82d22021-10-19 11:18:40 +0800639 OUT_DIR = os.path.abspath(args.outdir)
Kevin Peng655f2392019-11-27 16:33:02 +0800640
Kevin Peng5bc82d22021-10-19 11:18:40 +0800641 manifest_lists = [os.path.abspath(x) for x in args.manifest_lists]
642 gen_file_lists = [os.path.abspath(x) for x in args.gen_file_args]
Shawn Shana9ad1e02019-08-07 15:49:48 +0800643
Shawn Shana9ad1e02019-08-07 15:49:48 +0800644 """
Kevin Peng655f2392019-11-27 16:33:02 +0800645 Relative path to TF-M root folder is supported in the manifests
646 and default value of manifest list and generated file list are relative to TF-M root folder as well,
647 so first change directory to TF-M root folder.
Shawn Shana9ad1e02019-08-07 15:49:48 +0800648 By doing this, the script can be executed anywhere
Kevin Peng655f2392019-11-27 16:33:02 +0800649 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 +0800650 """
Kevin Peng5bc82d22021-10-19 11:18:40 +0800651 os.chdir(os.path.join(sys.path[0], '..'))
Shawn Shana9ad1e02019-08-07 15:49:48 +0800652
Kevin Peng76c0c162022-02-09 22:49:06 +0800653 context = process_partition_manifests(manifest_lists,
654 int(args.isolation_level),
655 args.backend)
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100656
Edison Ai6e3f2a32019-06-11 15:29:05 +0800657 utilities = {}
Mingyang Suna1ca6112021-01-11 11:34:59 +0800658 utilities['donotedit_warning'] = donotedit_warning
Miklos Balint470919c2018-05-22 17:51:29 +0200659
Kevin Peng655f2392019-11-27 16:33:02 +0800660 context['utilities'] = utilities
Mingyang Suneab7eae2021-09-30 13:06:52 +0800661
Ken Liu861b0782021-05-22 13:15:08 +0800662 gen_per_partition_files(context)
Kevin Peng5bc82d22021-10-19 11:18:40 +0800663 gen_summary_files(context, gen_file_lists)
Miklos Balint470919c2018-05-22 17:51:29 +0200664
Kevin Peng5bc82d22021-10-19 11:18:40 +0800665if __name__ == '__main__':
Miklos Balint470919c2018-05-22 17:51:29 +0200666 main()