blob: f80050e04eab840842a498453bbf5afe2bc9e3a7 [file] [log] [blame]
Manish Pandey3f90ad72020-01-14 11:52:05 +00001#!/usr/bin/python3
J-Alvesa890d062024-01-11 13:35:52 +00002# Copyright (c) 2020-2024, Arm Limited. All rights reserved.
Manish Pandey3f90ad72020-01-14 11:52:05 +00003#
4# SPDX-License-Identifier: BSD-3-Clause
5
6"""
7This script is invoked by Make system and generates secure partition makefile.
8It expects platform provided secure partition layout file which contains list
9of Secure Partition Images and Partition manifests(PM).
10Layout file can exist outside of TF-A tree and the paths of Image and PM files
11must be relative to it.
12
13This script parses the layout file and generates a make file which updates
Manish Pandeyaaaeb312020-05-26 23:59:36 +010014FDT_SOURCES, FIP_ARGS, CRT_ARGS and SPTOOL_ARGS which are used in later build
15steps.
Imre Kis3f370fd2022-02-08 18:06:18 +010016If the SP entry in the layout file has a "uuid" field the scripts gets the UUID
17from there, otherwise it parses the associated partition manifest and extracts
18the UUID from there.
Manish Pandey3f90ad72020-01-14 11:52:05 +000019
20param1: Generated mk file "sp_gen.mk"
21param2: "SP_LAYOUT_FILE", json file containing platform provided information
22param3: plat out directory
Ruari Phipps571ed6b2020-07-24 16:20:57 +010023param4: CoT parameter
Karl Meakinaba46182023-02-14 11:56:02 +000024param5: Generated dts file "sp_list_fragment.dts"
Manish Pandey3f90ad72020-01-14 11:52:05 +000025
26Generated "sp_gen.mk" file contains triplet of following information for each
27Secure Partition entry
28 FDT_SOURCES += sp1.dts
29 SPTOOL_ARGS += -i sp1.bin:sp1.dtb -o sp1.pkg
30 FIP_ARGS += --blob uuid=XXXXX-XXX...,file=sp1.pkg
Manish Pandeyaaaeb312020-05-26 23:59:36 +010031 CRT_ARGS += --sp-pkg1 sp1.pkg
Manish Pandey3f90ad72020-01-14 11:52:05 +000032
Ben Horganf7deec92024-10-29 17:54:24 +000033It populates the number of SP in the defined macro 'NUM_SP'
34 $(eval $(call add_define_val,NUM_SP,{len(sp_layout.keys())}))
35
Manish Pandey3f90ad72020-01-14 11:52:05 +000036A typical SP_LAYOUT_FILE file will look like
37{
38 "SP1" : {
39 "image": "sp1.bin",
40 "pm": "test/sp1.dts"
41 },
42
43 "SP2" : {
44 "image": "sp2.bin",
Imre Kis3f370fd2022-02-08 18:06:18 +010045 "pm": "test/sp2.dts",
46 "uuid": "1b1820fe-48f7-4175-8999-d51da00b7c9f"
Manish Pandey3f90ad72020-01-14 11:52:05 +000047 }
48
49 ...
50}
51
52"""
Manish Pandey3f90ad72020-01-14 11:52:05 +000053import json
54import os
55import re
56import sys
57import uuid
J-Alvesd10fb032022-03-21 14:11:43 +000058from spactions import SpSetupActions
Manish Pandey3f90ad72020-01-14 11:52:05 +000059
Ruari Phipps571ed6b2020-07-24 16:20:57 +010060MAX_SP = 8
J-Alvesd10fb032022-03-21 14:11:43 +000061UUID_LEN = 4
Manish Pandey3f90ad72020-01-14 11:52:05 +000062
J-Alvesd10fb032022-03-21 14:11:43 +000063# Some helper functions to access args propagated to the action functions in
64# SpSetupActions framework.
J-Alvesd10fb032022-03-21 14:11:43 +000065def check_sp_mk_gen(args :dict):
66 if "sp_gen_mk" not in args.keys():
67 raise Exception(f"Path to file sp_gen.mk needs to be in 'args'.")
Ruari Phipps571ed6b2020-07-24 16:20:57 +010068
J-Alvesd10fb032022-03-21 14:11:43 +000069def check_out_dir(args :dict):
70 if "out_dir" not in args.keys() or not os.path.isdir(args["out_dir"]):
71 raise Exception("Define output folder with \'out_dir\' key.")
Ruari Phipps571ed6b2020-07-24 16:20:57 +010072
J-Alvesd10fb032022-03-21 14:11:43 +000073def check_sp_layout_dir(args :dict):
74 if "sp_layout_dir" not in args.keys() or not os.path.isdir(args["sp_layout_dir"]):
75 raise Exception("Define output folder with \'sp_layout_dir\' key.")
Ruari Phipps571ed6b2020-07-24 16:20:57 +010076
J-Alvesd10fb032022-03-21 14:11:43 +000077def write_to_sp_mk_gen(content, args :dict):
78 check_sp_mk_gen(args)
79 with open(args["sp_gen_mk"], "a") as f:
80 f.write(f"{content}\n")
Manish Pandey3f90ad72020-01-14 11:52:05 +000081
J-Alvesd10fb032022-03-21 14:11:43 +000082def get_sp_manifest_full_path(sp_node, args :dict):
83 check_sp_layout_dir(args)
84 return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["pm"]))
Manish Pandey3f90ad72020-01-14 11:52:05 +000085
J-Alvesd10fb032022-03-21 14:11:43 +000086def get_sp_img_full_path(sp_node, args :dict):
87 check_sp_layout_dir(args)
88 return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["image"]))
89
J-Alvesa62598e2024-11-18 17:49:53 +000090def get_size(sp_node):
91 if not "size" in sp_node:
92 print("WARNING: default image size 0x100000")
93 return 0x100000
94
95 # Try if it was a decimal value.
96 try:
97 return int(sp_node["size"])
98 except ValueError:
99 print("WARNING: trying to parse base 16 size")
100 # Try if it is of base 16
101 return int(sp_node["size"], 16)
102
J-Alvesd10fb032022-03-21 14:11:43 +0000103def get_sp_pkg(sp, args :dict):
104 check_out_dir(args)
105 return os.path.join(args["out_dir"], f"{sp}.pkg")
106
107def is_line_in_sp_gen(line, args :dict):
108 with open(args["sp_gen_mk"], "r") as f:
109 sppkg_rule = [l for l in f if line in l]
J-Alves5b97ec32022-10-07 10:02:33 +0100110 return len(sppkg_rule) != 0
Olivier Deprez18909842021-05-11 09:43:37 +0200111
J-Alvesd10fb032022-03-21 14:11:43 +0000112def get_file_from_layout(node):
113 ''' Helper to fetch a file path from sp_layout.json. '''
114 if type(node) is dict and "file" in node.keys():
115 return node["file"]
116 return node
Manish Pandey3f90ad72020-01-14 11:52:05 +0000117
J-Alvesd10fb032022-03-21 14:11:43 +0000118def get_offset_from_layout(node):
119 ''' Helper to fetch an offset from sp_layout.json. '''
120 if type(node) is dict and "offset" in node.keys():
121 return int(node["offset"], 0)
122 return None
123
124def get_image_offset(node):
125 ''' Helper to fetch image offset from sp_layout.json '''
126 return get_offset_from_layout(node["image"])
127
128def get_pm_offset(node):
129 ''' Helper to fetch pm offset from sp_layout.json '''
130 return get_offset_from_layout(node["pm"])
131
Karl Meakinaba46182023-02-14 11:56:02 +0000132def get_uuid(sp_layout, sp, args :dict):
133 ''' Helper to fetch uuid from pm file listed in sp_layout.json'''
134 if "uuid" in sp_layout[sp]:
135 # Extract the UUID from the JSON file if the SP entry has a 'uuid' field
136 uuid_std = uuid.UUID(sp_layout[sp]['uuid'])
137 else:
138 with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
139 uuid_lines = [l for l in pm_f if 'uuid' in l]
140 assert(len(uuid_lines) == 1)
141 # The uuid field in SP manifest is the little endian representation
142 # mapped to arguments as described in SMCCC section 5.3.
143 # Convert each unsigned integer value to a big endian representation
144 # required by fiptool.
145 uuid_parsed = re.findall("0x([0-9a-f]+)", uuid_lines[0])
146 y = list(map(bytearray.fromhex, uuid_parsed))
147 z = [int.from_bytes(i, byteorder='little', signed=False) for i in y]
148 uuid_std = uuid.UUID(f'{z[0]:08x}{z[1]:08x}{z[2]:08x}{z[3]:08x}')
149 return uuid_std
150
151def get_load_address(sp_layout, sp, args :dict):
152 ''' Helper to fetch load-address from pm file listed in sp_layout.json'''
153 with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
154 load_address_lines = [l for l in pm_f if 'load-address' in l]
J-Alvesa890d062024-01-11 13:35:52 +0000155
J-Alves5f10faa2024-01-17 09:15:28 +0000156 if len(load_address_lines) != 1:
J-Alvesa890d062024-01-11 13:35:52 +0000157 return None
158
Karl Meakinaba46182023-02-14 11:56:02 +0000159 load_address_parsed = re.search("(0x[0-9a-f]+)", load_address_lines[0])
160 return load_address_parsed.group(0)
161
J-Alvesd10fb032022-03-21 14:11:43 +0000162@SpSetupActions.sp_action(global_action=True)
163def check_max_sps(sp_layout, _, args :dict):
164 ''' Check validate the maximum number of SPs is respected. '''
165 if len(sp_layout.keys()) > MAX_SP:
166 raise Exception(f"Too many SPs in SP layout file. Max: {MAX_SP}")
167 return args
Manish Pandey3f90ad72020-01-14 11:52:05 +0000168
Ben Horganf7deec92024-10-29 17:54:24 +0000169@SpSetupActions.sp_action(global_action=True)
170def count_sps(sp_layout, _, args :dict):
171 ''' Count number of SP and put in NUM_SP '''
172 write_to_sp_mk_gen(f"$(eval $(call add_define_val,NUM_SP,{len(sp_layout.keys())}))", args)
173 return args
174
J-Alvesd10fb032022-03-21 14:11:43 +0000175@SpSetupActions.sp_action
176def gen_fdt_sources(sp_layout, sp, args :dict):
177 ''' Generate FDT_SOURCES values for a given SP. '''
178 manifest_path = get_sp_manifest_full_path(sp_layout[sp], args)
179 write_to_sp_mk_gen(f"FDT_SOURCES += {manifest_path}", args)
180 return args
Manish Pandeyaaaeb312020-05-26 23:59:36 +0100181
J-Alvesa62598e2024-11-18 17:49:53 +0000182def generate_sp_pkg(sp_node, pkg, sp_img, sp_dtb):
183 ''' Generates the rule in case SP is to be generated in an SP Pkg. '''
184 pm_offset = get_pm_offset(sp_node)
185 sptool_args = f" --pm-offset {pm_offset}" if pm_offset is not None else ""
186 image_offset = get_image_offset(sp_node)
187 sptool_args += f" --img-offset {image_offset}" if image_offset is not None else ""
188 sptool_args += f" -o {pkg}"
189 return f'''
190{pkg}: {sp_dtb} {sp_img}
191\t$(Q)echo Generating {pkg}
192\t$(Q)$(PYTHON) $(SPTOOL) -i {sp_img}:{sp_dtb} {sptool_args}
193'''
194
195def generate_tl_pkg(sp_node, pkg, sp_img, sp_dtb, hob_path = None):
196 ''' Generate make rules for a Transfer List type package. '''
197 # TE Type for the FF-A manifest.
198 TE_FFA_MANIFEST = 0x106
199 # TE Type for the SP binary.
200 TE_SP_BINARY = 0x103
201 # TE Type for the HOB List.
202 TE_HOB_LIST = 0x3
203 tlc_add_hob = f"\t$(Q)poetry run tlc add --entry {TE_HOB_LIST} {hob_path} {pkg}" if hob_path is not None else ""
204 return f'''
205{pkg}: {sp_dtb} {sp_img}
206\t$(Q)echo Generating {pkg}
207\t$(Q)$(TLCTOOL) create --size {get_size(sp_node)} --entry {TE_FFA_MANIFEST} {sp_dtb} {pkg} --align 12
208\t$(Q)$(TLCTOOL) add --entry {TE_SP_BINARY} {sp_img} {pkg}
209'''
210
J-Alvesd10fb032022-03-21 14:11:43 +0000211@SpSetupActions.sp_action
J-Alvesa62598e2024-11-18 17:49:53 +0000212def gen_partition_pkg(sp_layout, sp, args :dict):
J-Alvesef8e0982022-03-22 16:28:51 +0000213 ''' Generate Sp Pkgs rules. '''
J-Alvesa62598e2024-11-18 17:49:53 +0000214 pkg = get_sp_pkg(sp, args)
215
J-Alvesef8e0982022-03-22 16:28:51 +0000216 sp_dtb_name = os.path.basename(get_file_from_layout(sp_layout[sp]["pm"]))[:-1] + "b"
J-Alvesd10fb032022-03-21 14:11:43 +0000217 sp_dtb = os.path.join(args["out_dir"], f"fdts/{sp_dtb_name}")
Jens Wiklander6b533252022-10-31 09:17:50 +0100218 sp_img = get_sp_img_full_path(sp_layout[sp], args)
J-Alvesef8e0982022-03-22 16:28:51 +0000219
220 # Do not generate rule if already there.
J-Alvesa62598e2024-11-18 17:49:53 +0000221 if is_line_in_sp_gen(f'{pkg}:', args):
J-Alvesef8e0982022-03-22 16:28:51 +0000222 return args
J-Alvesef8e0982022-03-22 16:28:51 +0000223
J-Alvesa62598e2024-11-18 17:49:53 +0000224 # This should include all packages of all kinds.
225 write_to_sp_mk_gen(f"SP_PKGS += {pkg}\n", args)
226 package_type = sp_layout[sp]["package"] if "package" in sp_layout[sp] else "sp_pkg"
227
228 if package_type == "sp_pkg":
229 partition_pkg_rule = generate_sp_pkg(sp_layout[sp], pkg, sp_img, sp_dtb)
230 elif package_type == "tl_pkg":
231 partition_pkg_rule = generate_tl_pkg(sp_layout[sp], pkg, sp_img, sp_dtb)
232 else:
233 raise ValueError(f"Specified invalid pkg type {package_type}")
234
235 write_to_sp_mk_gen(partition_pkg_rule, args)
J-Alvesd10fb032022-03-21 14:11:43 +0000236 return args
237
238@SpSetupActions.sp_action(global_action=True, exec_order=1)
239def check_dualroot(sp_layout, _, args :dict):
240 ''' Validate the amount of SPs from SiP and Platform owners. '''
241 if not args.get("dualroot"):
242 return args
243 args["split"] = int(MAX_SP / 2)
244 owners = [sp_layout[sp].get("owner") for sp in sp_layout]
245 args["plat_max_count"] = owners.count("Plat")
J-Alvesa62598e2024-11-18 17:49:53 +0000246
J-Alvesd10fb032022-03-21 14:11:43 +0000247 # If it is owned by the platform owner, it is assigned to the SiP.
248 args["sip_max_count"] = len(sp_layout.keys()) - args["plat_max_count"]
249 if args["sip_max_count"] > args["split"] or args["sip_max_count"] > args["split"]:
250 print(f"WARN: SiP Secure Partitions should not be more than {args['split']}")
251 # Counters for gen_crt_args.
252 args["sip_count"] = 1
253 args["plat_count"] = 1
254 return args
255
256@SpSetupActions.sp_action
257def gen_crt_args(sp_layout, sp, args :dict):
258 ''' Append CRT_ARGS. '''
259 # If "dualroot" is configured, 'sp_pkg_idx' depends on whether the SP is owned
260 # by the "SiP" or the "Plat".
261 if args.get("dualroot"):
262 # If the owner is not specified as "Plat", default to "SiP".
263 if sp_layout[sp].get("owner") == "Plat":
264 if args["plat_count"] > args["plat_max_count"]:
265 raise ValueError("plat_count can't surpass plat_max_count in args.")
266 sp_pkg_idx = args["plat_count"] + args["split"]
267 args["plat_count"] += 1
268 else:
269 if args["sip_count"] > args["sip_max_count"]:
270 raise ValueError("sip_count can't surpass sip_max_count in args.")
271 sp_pkg_idx = args["sip_count"]
272 args["sip_count"] += 1
273 else:
274 sp_pkg_idx = [k for k in sp_layout.keys()].index(sp) + 1
275 write_to_sp_mk_gen(f"CRT_ARGS += --sp-pkg{sp_pkg_idx} {get_sp_pkg(sp, args)}\n", args)
276 return args
277
278@SpSetupActions.sp_action
279def gen_fiptool_args(sp_layout, sp, args :dict):
280 ''' Generate arguments for the FIP Tool. '''
Karl Meakinaba46182023-02-14 11:56:02 +0000281 uuid_std = get_uuid(sp_layout, sp, args)
J-Alvesd10fb032022-03-21 14:11:43 +0000282 write_to_sp_mk_gen(f"FIP_ARGS += --blob uuid={str(uuid_std)},file={get_sp_pkg(sp, args)}\n", args)
283 return args
284
Karl Meakinaba46182023-02-14 11:56:02 +0000285@SpSetupActions.sp_action
286def gen_fconf_fragment(sp_layout, sp, args: dict):
287 ''' Generate the fconf fragment file'''
288 with open(args["fconf_fragment"], "a") as f:
289 uuid = get_uuid(sp_layout, sp, args)
290 owner = "Plat" if sp_layout[sp].get("owner") == "Plat" else "SiP"
291
292 if "physical-load-address" in sp_layout[sp].keys():
293 load_address = sp_layout[sp]["physical-load-address"]
294 else:
295 load_address = get_load_address(sp_layout, sp, args)
296
J-Alvesa890d062024-01-11 13:35:52 +0000297 if load_address is not None:
298 f.write(
Karl Meakinaba46182023-02-14 11:56:02 +0000299f'''\
300{sp} {{
301 uuid = "{uuid}";
302 load-address = <{load_address}>;
303 owner = "{owner}";
304}};
305
306''')
J-Alvesa890d062024-01-11 13:35:52 +0000307 else:
308 print("Warning: No load-address was found in the SP manifest.")
309
Karl Meakinaba46182023-02-14 11:56:02 +0000310 return args
311
J-Alvesd10fb032022-03-21 14:11:43 +0000312def init_sp_actions(sys):
J-Alvesd10fb032022-03-21 14:11:43 +0000313 # Initialize arguments for the SP actions framework
314 args = {}
315 args["sp_gen_mk"] = os.path.abspath(sys.argv[1])
Karl Meakinaba46182023-02-14 11:56:02 +0000316 sp_layout_file = os.path.abspath(sys.argv[2])
J-Alvesd10fb032022-03-21 14:11:43 +0000317 args["sp_layout_dir"] = os.path.dirname(sp_layout_file)
318 args["out_dir"] = os.path.abspath(sys.argv[3])
319 args["dualroot"] = sys.argv[4] == "dualroot"
Karl Meakinaba46182023-02-14 11:56:02 +0000320 args["fconf_fragment"] = os.path.abspath(sys.argv[5])
321
322
323 with open(sp_layout_file) as json_file:
324 sp_layout = json.load(json_file)
J-Alvesd10fb032022-03-21 14:11:43 +0000325 #Clear content of file "sp_gen.mk".
326 with open(args["sp_gen_mk"], "w"):
327 None
Karl Meakinaba46182023-02-14 11:56:02 +0000328 #Clear content of file "fconf_fragment".
329 with open(args["fconf_fragment"], "w"):
330 None
331
J-Alvesd10fb032022-03-21 14:11:43 +0000332 return args, sp_layout
Ruari Phipps571ed6b2020-07-24 16:20:57 +0100333
J-Alvesd10fb032022-03-21 14:11:43 +0000334if __name__ == "__main__":
335 args, sp_layout = init_sp_actions(sys)
336 SpSetupActions.run_actions(sp_layout, args)