blob: e788554bdf3a869956bffbae6d0ac7355f919ef9 [file] [log] [blame]
Miklos Balint470919c2018-05-22 17:51:29 +02001#-------------------------------------------------------------------------------
Kevin Peng578a8492020-12-31 10:22:59 +08002# Copyright (c) 2018-2021, 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
Shawn Shana9ad1e02019-08-07 15:49:48 +080010import sys
11import argparse
Ken Liu1f345b02020-05-30 21:11:05 +080012from jinja2 import Environment, BaseLoader, select_autoescape, TemplateNotFound
Miklos Balint470919c2018-05-22 17:51:29 +020013
14try:
15 import yaml
16except ImportError as e:
Mate Toth-Pala99ec6b2019-05-07 11:00:56 +020017 print (str(e) + " To install it, type:")
Mate Toth-Pal36f21842018-11-08 16:12:51 +010018 print ("pip install PyYAML")
Miklos Balint470919c2018-05-22 17:51:29 +020019 exit(1)
20
Edison Ai48b2d9e2019-06-24 14:39:45 +080021donotedit_warning = \
22 "/*********** " + \
23 "WARNING: This is an auto-generated file. Do not edit!" + \
24 " ***********/"
Kevin Peng655f2392019-11-27 16:33:02 +080025
Kevin Peng655f2392019-11-27 16:33:02 +080026OUT_DIR = None # The root directory that files are generated to
Edison Ai48b2d9e2019-06-24 14:39:45 +080027
Mate Toth-Pal36f21842018-11-08 16:12:51 +010028class TemplateLoader(BaseLoader):
29 """
30 Template loader class.
Miklos Balint470919c2018-05-22 17:51:29 +020031
Mate Toth-Pal36f21842018-11-08 16:12:51 +010032 An instance of this class is passed to the template engine. It is
33 responsible for reading the template file
34 """
35 def __init__(self):
36 pass
Miklos Balint470919c2018-05-22 17:51:29 +020037
Mate Toth-Pal36f21842018-11-08 16:12:51 +010038 def get_source(self, environment, template):
39 """
40 This function reads the template files.
41 For detailed documentation see:
42 http://jinja.pocoo.org/docs/2.10/api/#jinja2.BaseLoader.get_source
43
44 Please note that this function always return 'false' as 'uptodate'
45 value, so the output file will always be generated.
46 """
47 if not os.path.isfile(template):
48 raise TemplateNotFound(template)
49 with open(template) as f:
50 source = f.read()
51 return source, template, False
52
Raef Colesf42f0882020-07-10 10:01:58 +010053def process_manifest(manifest_list_files):
Mate Toth-Pal36f21842018-11-08 16:12:51 +010054 """
Kevin Peng655f2392019-11-27 16:33:02 +080055 Parse the input manifest, generate the data base for genereated files
56 and generate manifest header files.
Mate Toth-Pal36f21842018-11-08 16:12:51 +010057
58 Parameters
59 ----------
Raef Colesf42f0882020-07-10 10:01:58 +010060 manifest_list_files:
61 The manifest lists to parse.
Mate Toth-Pal36f21842018-11-08 16:12:51 +010062
63 Returns
64 -------
Kevin Peng578a8492020-12-31 10:22:59 +080065 The partition data base.
Edison Ai48b2d9e2019-06-24 14:39:45 +080066 """
Kevin Peng655f2392019-11-27 16:33:02 +080067
Kevin Peng578a8492020-12-31 10:22:59 +080068 partition_db = []
Kevin Peng655f2392019-11-27 16:33:02 +080069 manifest_list = []
70
Raef Colesf42f0882020-07-10 10:01:58 +010071 for f in manifest_list_files:
72 with open(f) as manifest_list_yaml_file:
73 manifest_dic = yaml.safe_load(manifest_list_yaml_file)
Kevin Peng655f2392019-11-27 16:33:02 +080074 manifest_list.extend(manifest_dic["manifest_list"])
75
Mingyang Sund20999f2020-10-15 14:53:12 +080076 manifesttemplate = ENV.get_template('secure_fw/partitions/manifestfilename.template')
77 memorytemplate = ENV.get_template('secure_fw/partitions/partition_intermedia.template')
Kevin Peng655f2392019-11-27 16:33:02 +080078
edison.ai7b299f52020-07-16 15:44:18 +080079 print("Start to generate PSA manifests:")
Xinyu Zhang19504a52021-03-31 16:26:20 +080080 pid_list = []
Kevin Peng655f2392019-11-27 16:33:02 +080081 for manifest_item in manifest_list:
Xinyu Zhang19504a52021-03-31 16:26:20 +080082 # Check if partition ID is duplicated
83 if manifest_item['pid'] in pid_list:
84 raise Exception("PID No. {pid} has already been used!".format(pid=manifest_item['pid']))
85 pid_list.append(manifest_item['pid'])
86
Raef Coles558487a2020-10-29 13:09:44 +000087 # Replace environment variables in the manifest path
Kevin Peng655f2392019-11-27 16:33:02 +080088 manifest_path = os.path.expandvars(manifest_item['manifest'])
89 file = open(manifest_path)
90 manifest = yaml.safe_load(file)
91
Kevin Peng655f2392019-11-27 16:33:02 +080092 utilities = {}
93 utilities['donotedit_warning']=donotedit_warning
94
95 context = {}
96 context['manifest'] = manifest
97 context['attr'] = manifest_item
98 context['utilities'] = utilities
99
100 manifest_dir, manifest_name = os.path.split(manifest_path)
101 outfile_name = manifest_name.replace('yaml', 'h').replace('json', 'h')
102 context['file_name'] = outfile_name.replace('.h', '')
TTornblom7f92a732020-03-05 13:12:20 +0100103 outfile_name = os.path.join(manifest_dir, "psa_manifest", outfile_name).replace('\\', '/')
Mingyang Sund20999f2020-10-15 14:53:12 +0800104 intermediafile_name = os.path.join(manifest_dir, "auto_generated", 'intermedia_' + context['file_name'] + '.c').replace('\\', '/')
Kevin Peng655f2392019-11-27 16:33:02 +0800105
Mingyang Sun4f012692020-10-16 14:04:49 +0800106 """
107 Remove the `source_path` portion of the filepaths, so that it can be
108 interpreted as a relative path from the OUT_DIR.
109 """
110 if 'source_path' in manifest_item:
Raef Coles558487a2020-10-29 13:09:44 +0000111 # Replace environment variables in the source path
112 source_path = os.path.expandvars(manifest_item['source_path'])
113 outfile_name = os.path.relpath(outfile_name, start = source_path)
Mingyang Sund20999f2020-10-15 14:53:12 +0800114 intermediafile_name = os.path.relpath(intermediafile_name, start = source_path)
Mingyang Sun4f012692020-10-16 14:04:49 +0800115
Kevin Peng578a8492020-12-31 10:22:59 +0800116 partition_db.append({"manifest": manifest, "attr": manifest_item, "header_file": outfile_name})
Kevin Peng655f2392019-11-27 16:33:02 +0800117
118 if OUT_DIR is not None:
119 outfile_name = os.path.join(OUT_DIR, outfile_name)
Mingyang Sund20999f2020-10-15 14:53:12 +0800120 intermediafile_name = os.path.join(OUT_DIR, intermediafile_name)
Kevin Peng655f2392019-11-27 16:33:02 +0800121
122 outfile_path = os.path.dirname(outfile_name)
123 if not os.path.exists(outfile_path):
124 os.makedirs(outfile_path)
125
126 print ("Generating " + outfile_name)
127
TTornblom441a0702020-04-28 12:40:42 +0200128 outfile = io.open(outfile_name, "w", newline=None)
Mingyang Sund20999f2020-10-15 14:53:12 +0800129 outfile.write(manifesttemplate.render(context))
Kevin Peng655f2392019-11-27 16:33:02 +0800130 outfile.close()
131
Mingyang Sund20999f2020-10-15 14:53:12 +0800132 intermediafile_path = os.path.dirname(intermediafile_name)
133 if not os.path.exists(intermediafile_path):
134 os.makedirs(intermediafile_path)
135
136 print ("Generating " + intermediafile_name)
137
138 memoutfile = io.open(intermediafile_name, "w", newline=None)
139 memoutfile.write(memorytemplate.render(context))
140 memoutfile.close()
141
Kevin Peng578a8492020-12-31 10:22:59 +0800142 return partition_db
Kevin Peng655f2392019-11-27 16:33:02 +0800143
Raef Colesf42f0882020-07-10 10:01:58 +0100144def gen_files(context, gen_file_lists):
Kevin Peng655f2392019-11-27 16:33:02 +0800145 """
146 Generate files according to the gen_file_list
Edison Ai48b2d9e2019-06-24 14:39:45 +0800147
148 Parameters
149 ----------
Raef Colesf42f0882020-07-10 10:01:58 +0100150 gen_file_lists:
151 The lists of files to generate
Edison Ai48b2d9e2019-06-24 14:39:45 +0800152 """
Kevin Peng655f2392019-11-27 16:33:02 +0800153 file_list = []
Shawn Shana9ad1e02019-08-07 15:49:48 +0800154
Raef Colesf42f0882020-07-10 10:01:58 +0100155 for f in gen_file_lists:
156 with open(f) as file_list_yaml_file:
Kevin Peng655f2392019-11-27 16:33:02 +0800157 file_list_yaml = yaml.safe_load(file_list_yaml_file)
158 file_list.extend(file_list_yaml["file_list"])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800159
edison.ai7b299f52020-07-16 15:44:18 +0800160 print("Start to generate file from the generated list:")
Kevin Peng655f2392019-11-27 16:33:02 +0800161 for file in file_list:
Raef Coles558487a2020-10-29 13:09:44 +0000162 # Replace environment variables in the output filepath
Kevin Peng655f2392019-11-27 16:33:02 +0800163 outfile_name = os.path.expandvars(file["output"])
Raef Coles558487a2020-10-29 13:09:44 +0000164 # Replace environment variables in the template filepath
Kevin Peng1ec5e7c2019-11-29 10:52:00 +0800165 templatefile_name = os.path.expandvars(file["template"])
Edison Ai48b2d9e2019-06-24 14:39:45 +0800166
Kevin Peng655f2392019-11-27 16:33:02 +0800167 if OUT_DIR is not None:
168 outfile_name = os.path.join(OUT_DIR, outfile_name)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800169
edison.ai7b299f52020-07-16 15:44:18 +0800170 print ("Generating " + outfile_name)
171
Kevin Peng655f2392019-11-27 16:33:02 +0800172 outfile_path = os.path.dirname(outfile_name)
173 if not os.path.exists(outfile_path):
174 os.makedirs(outfile_path)
Edison Ai48b2d9e2019-06-24 14:39:45 +0800175
Kevin Peng655f2392019-11-27 16:33:02 +0800176 template = ENV.get_template(templatefile_name)
Edison Ai6e3f2a32019-06-11 15:29:05 +0800177
TTornblom441a0702020-04-28 12:40:42 +0200178 outfile = io.open(outfile_name, "w", newline=None)
Kevin Peng655f2392019-11-27 16:33:02 +0800179 outfile.write(template.render(context))
180 outfile.close()
Edison Ai48b2d9e2019-06-24 14:39:45 +0800181
Kevin Peng655f2392019-11-27 16:33:02 +0800182 print ("Generation of files done")
Edison Ai48b2d9e2019-06-24 14:39:45 +0800183
Mingyang Suna1ca6112021-01-11 11:34:59 +0800184def process_stateless_services(partitions, static_handle_max_num):
185 """
186 This function collects all stateless services together, and allocates
187 stateless handle for them.
188 If the stateless handle is set to a valid value in yaml file, it is used as
189 the index directly, if the stateless handle is set as "auto" or not set,
190 framework will allocate a valid index for the service.
191 After that, framework puts each service into a stateless service list at
192 position of its "index". Other elements in list are left None.
193 """
194 stateless_services = []
195
196 # Collect all stateless services first.
197 for partition in partitions:
198 # Skip the FF-M 1.0 partitions
199 if partition['manifest']['psa_framework_version'] < 1.1:
200 continue
201 # Skip the Non-IPC partitions
202 if partition['attr']['tfm_partition_ipc'] is not True:
203 continue
204 for service in partition['manifest']['services']:
205 if 'connection_based' not in service:
206 raise Exception("'connection_based' is mandatory in FF-M 1.1 service!")
207 if service['connection_based'] is False:
208 stateless_services.append(service)
209
210 if len(stateless_services) == 0:
211 return []
212
213 if len(stateless_services) > static_handle_max_num:
214 raise Exception("Stateless service numbers range exceed.")
215
216 """
217 Allocate an empty stateless service list to store services and find the
218 service easily by handle.
219 Use service stateless handle values as indexes. Put service in the list
220 at index "handle - 1", since handle value starts from 1 and list index
221 starts from 0.
222 """
223 reordered_stateless_list = [None] * static_handle_max_num
224
225 # Fill in services with specified stateless handle, index is "handle - 1".
226 for service in stateless_services:
227 if service['stateless_handle'] == "auto":
228 continue
229 try:
230 if reordered_stateless_list[service['stateless_handle']-1] is not None:
231 raise Exception("Duplicated stateless service handle.")
232 reordered_stateless_list[service['stateless_handle']-1] = service
233 except IndexError:
234 raise Exception("Stateless service index out of range.")
235 # Remove recorded node from the existing list
236 stateless_services.remove(service)
237
238 # Auto-allocate stateless handle
239 for i in range(0, static_handle_max_num):
Mingyang Sun453ad402021-03-17 17:58:33 +0800240 if reordered_stateless_list[i] == None and len(stateless_services) > 0:
Mingyang Suna1ca6112021-01-11 11:34:59 +0800241 service = stateless_services.pop(0)
242 service['stateless_handle'] = i + 1
243 reordered_stateless_list[i] = service
Mingyang Sun453ad402021-03-17 17:58:33 +0800244 """
245 Encode stateless flag and version into stateless handle
246 bit 30: stateless handle indicator
247 bit 15-8: stateless service version
248 bit 7-0: stateless handle index
249 """
250 if reordered_stateless_list[i] != None:
251 stateless_handle_value = reordered_stateless_list[i]['stateless_handle']
252 stateless_flag = 1 << 30
253 stateless_handle_value |= stateless_flag
254 stateless_version = (reordered_stateless_list[i]['version'] & 0xFF) << 8
255 stateless_handle_value |= stateless_version
256 reordered_stateless_list[i]['stateless_handle'] = '0x%08x' % stateless_handle_value
Mingyang Suna1ca6112021-01-11 11:34:59 +0800257
258 return reordered_stateless_list
259
Kevin Peng655f2392019-11-27 16:33:02 +0800260def parse_args():
Raef Coles558487a2020-10-29 13:09:44 +0000261 parser = argparse.ArgumentParser(description='Parse secure partition manifest list and generate files listed by the file list',
262 epilog='Note that environment variables in template files will be replaced with their values')
263
Kevin Peng655f2392019-11-27 16:33:02 +0800264 parser.add_argument('-o', '--outdir'
265 , dest='outdir'
266 , required=False
267 , default=None
268 , metavar='out_dir'
269 , help='The root directory for generated files, the default is TF-M root folder.')
Shawn Shana9ad1e02019-08-07 15:49:48 +0800270
Kevin Peng655f2392019-11-27 16:33:02 +0800271 parser.add_argument('-m', '--manifest'
Raef Colesf42f0882020-07-10 10:01:58 +0100272 , nargs='+'
Kevin Peng655f2392019-11-27 16:33:02 +0800273 , dest='manifest_args'
Raef Colesf42f0882020-07-10 10:01:58 +0100274 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800275 , metavar='manifest'
Raef Colesf42f0882020-07-10 10:01:58 +0100276 , help='A set of secure partition manifest lists to parse')
Kevin Peng655f2392019-11-27 16:33:02 +0800277
278 parser.add_argument('-f', '--file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100279 , nargs='+'
Kevin Peng655f2392019-11-27 16:33:02 +0800280 , dest='gen_file_args'
Raef Colesf42f0882020-07-10 10:01:58 +0100281 , required=True
Kevin Peng655f2392019-11-27 16:33:02 +0800282 , metavar='file-list'
Raef Colesf42f0882020-07-10 10:01:58 +0100283 , help='These files descripe the file list to generate')
Kevin Peng655f2392019-11-27 16:33:02 +0800284
285 args = parser.parse_args()
286 manifest_args = args.manifest_args
287 gen_file_args = args.gen_file_args
288
Kevin Peng655f2392019-11-27 16:33:02 +0800289 return args
290
291ENV = Environment(
292 loader = TemplateLoader(),
293 autoescape = select_autoescape(['html', 'xml']),
294 lstrip_blocks = True,
295 trim_blocks = True,
296 keep_trailing_newline = True
297 )
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100298
Miklos Balint470919c2018-05-22 17:51:29 +0200299def main():
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100300 """
301 The entry point of the script.
302
303 Generates the output files based on the templates and the manifests.
304 """
Shawn Shana9ad1e02019-08-07 15:49:48 +0800305
Kevin Peng655f2392019-11-27 16:33:02 +0800306 global OUT_DIR
Shawn Shana9ad1e02019-08-07 15:49:48 +0800307
Kevin Peng655f2392019-11-27 16:33:02 +0800308 args = parse_args()
Shawn Shana9ad1e02019-08-07 15:49:48 +0800309
Kevin Peng655f2392019-11-27 16:33:02 +0800310 manifest_args = args.manifest_args
311 gen_file_args = args.gen_file_args
312 OUT_DIR = args.outdir
Kevin Peng655f2392019-11-27 16:33:02 +0800313
Raef Coles558487a2020-10-29 13:09:44 +0000314 manifest_list = [os.path.abspath(x) for x in args.manifest_args]
315 gen_file_list = [os.path.abspath(x) for x in args.gen_file_args]
Shawn Shana9ad1e02019-08-07 15:49:48 +0800316
317 # Arguments could be relative path.
Kevin Peng655f2392019-11-27 16:33:02 +0800318 # Convert to absolute path as we are going to change diretory later
319 if OUT_DIR is not None:
320 OUT_DIR = os.path.abspath(OUT_DIR)
321
Shawn Shana9ad1e02019-08-07 15:49:48 +0800322 """
Kevin Peng655f2392019-11-27 16:33:02 +0800323 Relative path to TF-M root folder is supported in the manifests
324 and default value of manifest list and generated file list are relative to TF-M root folder as well,
325 so first change directory to TF-M root folder.
Shawn Shana9ad1e02019-08-07 15:49:48 +0800326 By doing this, the script can be executed anywhere
Kevin Peng655f2392019-11-27 16:33:02 +0800327 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 +0800328 """
329 os.chdir(os.path.join(sys.path[0], ".."))
330
Kevin Peng578a8492020-12-31 10:22:59 +0800331 partition_db = process_manifest(manifest_list)
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100332
Edison Ai6e3f2a32019-06-11 15:29:05 +0800333 utilities = {}
334 context = {}
335
Mingyang Suna1ca6112021-01-11 11:34:59 +0800336 utilities['donotedit_warning'] = donotedit_warning
Miklos Balint470919c2018-05-22 17:51:29 +0200337
Kevin Peng578a8492020-12-31 10:22:59 +0800338 context['partitions'] = partition_db
Kevin Peng655f2392019-11-27 16:33:02 +0800339 context['utilities'] = utilities
Mingyang Suna1ca6112021-01-11 11:34:59 +0800340 context['stateless_services'] = process_stateless_services(partition_db, 32)
Mate Toth-Pal36f21842018-11-08 16:12:51 +0100341
Raef Colesf42f0882020-07-10 10:01:58 +0100342 gen_files(context, gen_file_list)
Miklos Balint470919c2018-05-22 17:51:29 +0200343
344if __name__ == "__main__":
345 main()