blob: 9bf5cd0bfa55a9acdb879dad65c47bbbdf1d8998 [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
90def get_sp_pkg(sp, args :dict):
91 check_out_dir(args)
92 return os.path.join(args["out_dir"], f"{sp}.pkg")
93
94def is_line_in_sp_gen(line, args :dict):
95 with open(args["sp_gen_mk"], "r") as f:
96 sppkg_rule = [l for l in f if line in l]
J-Alves5b97ec32022-10-07 10:02:33 +010097 return len(sppkg_rule) != 0
Olivier Deprez18909842021-05-11 09:43:37 +020098
J-Alvesd10fb032022-03-21 14:11:43 +000099def get_file_from_layout(node):
100 ''' Helper to fetch a file path from sp_layout.json. '''
101 if type(node) is dict and "file" in node.keys():
102 return node["file"]
103 return node
Manish Pandey3f90ad72020-01-14 11:52:05 +0000104
J-Alvesd10fb032022-03-21 14:11:43 +0000105def get_offset_from_layout(node):
106 ''' Helper to fetch an offset from sp_layout.json. '''
107 if type(node) is dict and "offset" in node.keys():
108 return int(node["offset"], 0)
109 return None
110
111def get_image_offset(node):
112 ''' Helper to fetch image offset from sp_layout.json '''
113 return get_offset_from_layout(node["image"])
114
115def get_pm_offset(node):
116 ''' Helper to fetch pm offset from sp_layout.json '''
117 return get_offset_from_layout(node["pm"])
118
Karl Meakinaba46182023-02-14 11:56:02 +0000119def get_uuid(sp_layout, sp, args :dict):
120 ''' Helper to fetch uuid from pm file listed in sp_layout.json'''
121 if "uuid" in sp_layout[sp]:
122 # Extract the UUID from the JSON file if the SP entry has a 'uuid' field
123 uuid_std = uuid.UUID(sp_layout[sp]['uuid'])
124 else:
125 with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
126 uuid_lines = [l for l in pm_f if 'uuid' in l]
127 assert(len(uuid_lines) == 1)
128 # The uuid field in SP manifest is the little endian representation
129 # mapped to arguments as described in SMCCC section 5.3.
130 # Convert each unsigned integer value to a big endian representation
131 # required by fiptool.
132 uuid_parsed = re.findall("0x([0-9a-f]+)", uuid_lines[0])
133 y = list(map(bytearray.fromhex, uuid_parsed))
134 z = [int.from_bytes(i, byteorder='little', signed=False) for i in y]
135 uuid_std = uuid.UUID(f'{z[0]:08x}{z[1]:08x}{z[2]:08x}{z[3]:08x}')
136 return uuid_std
137
138def get_load_address(sp_layout, sp, args :dict):
139 ''' Helper to fetch load-address from pm file listed in sp_layout.json'''
140 with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
141 load_address_lines = [l for l in pm_f if 'load-address' in l]
J-Alvesa890d062024-01-11 13:35:52 +0000142
J-Alves5f10faa2024-01-17 09:15:28 +0000143 if len(load_address_lines) != 1:
J-Alvesa890d062024-01-11 13:35:52 +0000144 return None
145
Karl Meakinaba46182023-02-14 11:56:02 +0000146 load_address_parsed = re.search("(0x[0-9a-f]+)", load_address_lines[0])
147 return load_address_parsed.group(0)
148
149
J-Alvesd10fb032022-03-21 14:11:43 +0000150@SpSetupActions.sp_action(global_action=True)
151def check_max_sps(sp_layout, _, args :dict):
152 ''' Check validate the maximum number of SPs is respected. '''
153 if len(sp_layout.keys()) > MAX_SP:
154 raise Exception(f"Too many SPs in SP layout file. Max: {MAX_SP}")
155 return args
Manish Pandey3f90ad72020-01-14 11:52:05 +0000156
Ben Horganf7deec92024-10-29 17:54:24 +0000157@SpSetupActions.sp_action(global_action=True)
158def count_sps(sp_layout, _, args :dict):
159 ''' Count number of SP and put in NUM_SP '''
160 write_to_sp_mk_gen(f"$(eval $(call add_define_val,NUM_SP,{len(sp_layout.keys())}))", args)
161 return args
162
J-Alvesd10fb032022-03-21 14:11:43 +0000163@SpSetupActions.sp_action
164def gen_fdt_sources(sp_layout, sp, args :dict):
165 ''' Generate FDT_SOURCES values for a given SP. '''
166 manifest_path = get_sp_manifest_full_path(sp_layout[sp], args)
167 write_to_sp_mk_gen(f"FDT_SOURCES += {manifest_path}", args)
168 return args
Manish Pandeyaaaeb312020-05-26 23:59:36 +0100169
J-Alvesd10fb032022-03-21 14:11:43 +0000170@SpSetupActions.sp_action
J-Alvesef8e0982022-03-22 16:28:51 +0000171def gen_sptool_args(sp_layout, sp, args :dict):
172 ''' Generate Sp Pkgs rules. '''
J-Alvesd10fb032022-03-21 14:11:43 +0000173 sp_pkg = get_sp_pkg(sp, args)
J-Alvesef8e0982022-03-22 16:28:51 +0000174 sp_dtb_name = os.path.basename(get_file_from_layout(sp_layout[sp]["pm"]))[:-1] + "b"
J-Alvesd10fb032022-03-21 14:11:43 +0000175 sp_dtb = os.path.join(args["out_dir"], f"fdts/{sp_dtb_name}")
Jens Wiklander6b533252022-10-31 09:17:50 +0100176 sp_img = get_sp_img_full_path(sp_layout[sp], args)
J-Alvesef8e0982022-03-22 16:28:51 +0000177
178 # Do not generate rule if already there.
179 if is_line_in_sp_gen(f'{sp_pkg}:', args):
180 return args
181 write_to_sp_mk_gen(f"SP_PKGS += {sp_pkg}\n", args)
182
Jens Wiklander6b533252022-10-31 09:17:50 +0100183 sptool_args = f" -i {sp_img}:{sp_dtb}"
J-Alvesef8e0982022-03-22 16:28:51 +0000184 pm_offset = get_pm_offset(sp_layout[sp])
185 sptool_args += f" --pm-offset {pm_offset}" if pm_offset is not None else ""
186 image_offset = get_image_offset(sp_layout[sp])
187 sptool_args += f" --img-offset {image_offset}" if image_offset is not None else ""
188 sptool_args += f" -o {sp_pkg}"
189 sppkg_rule = f'''
Jens Wiklander6b533252022-10-31 09:17:50 +0100190{sp_pkg}: {sp_dtb} {sp_img}
J-Alvesef8e0982022-03-22 16:28:51 +0000191\t$(Q)echo Generating {sp_pkg}
192\t$(Q)$(PYTHON) $(SPTOOL) {sptool_args}
193'''
194 write_to_sp_mk_gen(sppkg_rule, args)
J-Alvesd10fb032022-03-21 14:11:43 +0000195 return args
196
197@SpSetupActions.sp_action(global_action=True, exec_order=1)
198def check_dualroot(sp_layout, _, args :dict):
199 ''' Validate the amount of SPs from SiP and Platform owners. '''
200 if not args.get("dualroot"):
201 return args
202 args["split"] = int(MAX_SP / 2)
203 owners = [sp_layout[sp].get("owner") for sp in sp_layout]
204 args["plat_max_count"] = owners.count("Plat")
205 # If it is owned by the platform owner, it is assigned to the SiP.
206 args["sip_max_count"] = len(sp_layout.keys()) - args["plat_max_count"]
207 if args["sip_max_count"] > args["split"] or args["sip_max_count"] > args["split"]:
208 print(f"WARN: SiP Secure Partitions should not be more than {args['split']}")
209 # Counters for gen_crt_args.
210 args["sip_count"] = 1
211 args["plat_count"] = 1
212 return args
213
214@SpSetupActions.sp_action
215def gen_crt_args(sp_layout, sp, args :dict):
216 ''' Append CRT_ARGS. '''
217 # If "dualroot" is configured, 'sp_pkg_idx' depends on whether the SP is owned
218 # by the "SiP" or the "Plat".
219 if args.get("dualroot"):
220 # If the owner is not specified as "Plat", default to "SiP".
221 if sp_layout[sp].get("owner") == "Plat":
222 if args["plat_count"] > args["plat_max_count"]:
223 raise ValueError("plat_count can't surpass plat_max_count in args.")
224 sp_pkg_idx = args["plat_count"] + args["split"]
225 args["plat_count"] += 1
226 else:
227 if args["sip_count"] > args["sip_max_count"]:
228 raise ValueError("sip_count can't surpass sip_max_count in args.")
229 sp_pkg_idx = args["sip_count"]
230 args["sip_count"] += 1
231 else:
232 sp_pkg_idx = [k for k in sp_layout.keys()].index(sp) + 1
233 write_to_sp_mk_gen(f"CRT_ARGS += --sp-pkg{sp_pkg_idx} {get_sp_pkg(sp, args)}\n", args)
234 return args
235
236@SpSetupActions.sp_action
237def gen_fiptool_args(sp_layout, sp, args :dict):
238 ''' Generate arguments for the FIP Tool. '''
Karl Meakinaba46182023-02-14 11:56:02 +0000239 uuid_std = get_uuid(sp_layout, sp, args)
J-Alvesd10fb032022-03-21 14:11:43 +0000240 write_to_sp_mk_gen(f"FIP_ARGS += --blob uuid={str(uuid_std)},file={get_sp_pkg(sp, args)}\n", args)
241 return args
242
Karl Meakinaba46182023-02-14 11:56:02 +0000243@SpSetupActions.sp_action
244def gen_fconf_fragment(sp_layout, sp, args: dict):
245 ''' Generate the fconf fragment file'''
246 with open(args["fconf_fragment"], "a") as f:
247 uuid = get_uuid(sp_layout, sp, args)
248 owner = "Plat" if sp_layout[sp].get("owner") == "Plat" else "SiP"
249
250 if "physical-load-address" in sp_layout[sp].keys():
251 load_address = sp_layout[sp]["physical-load-address"]
252 else:
253 load_address = get_load_address(sp_layout, sp, args)
254
J-Alvesa890d062024-01-11 13:35:52 +0000255 if load_address is not None:
256 f.write(
Karl Meakinaba46182023-02-14 11:56:02 +0000257f'''\
258{sp} {{
259 uuid = "{uuid}";
260 load-address = <{load_address}>;
261 owner = "{owner}";
262}};
263
264''')
J-Alvesa890d062024-01-11 13:35:52 +0000265 else:
266 print("Warning: No load-address was found in the SP manifest.")
267
Karl Meakinaba46182023-02-14 11:56:02 +0000268 return args
269
J-Alvesd10fb032022-03-21 14:11:43 +0000270def init_sp_actions(sys):
J-Alvesd10fb032022-03-21 14:11:43 +0000271 # Initialize arguments for the SP actions framework
272 args = {}
273 args["sp_gen_mk"] = os.path.abspath(sys.argv[1])
Karl Meakinaba46182023-02-14 11:56:02 +0000274 sp_layout_file = os.path.abspath(sys.argv[2])
J-Alvesd10fb032022-03-21 14:11:43 +0000275 args["sp_layout_dir"] = os.path.dirname(sp_layout_file)
276 args["out_dir"] = os.path.abspath(sys.argv[3])
277 args["dualroot"] = sys.argv[4] == "dualroot"
Karl Meakinaba46182023-02-14 11:56:02 +0000278 args["fconf_fragment"] = os.path.abspath(sys.argv[5])
279
280
281 with open(sp_layout_file) as json_file:
282 sp_layout = json.load(json_file)
J-Alvesd10fb032022-03-21 14:11:43 +0000283 #Clear content of file "sp_gen.mk".
284 with open(args["sp_gen_mk"], "w"):
285 None
Karl Meakinaba46182023-02-14 11:56:02 +0000286 #Clear content of file "fconf_fragment".
287 with open(args["fconf_fragment"], "w"):
288 None
289
J-Alvesd10fb032022-03-21 14:11:43 +0000290 return args, sp_layout
Ruari Phipps571ed6b2020-07-24 16:20:57 +0100291
J-Alvesd10fb032022-03-21 14:11:43 +0000292if __name__ == "__main__":
293 args, sp_layout = init_sp_actions(sys)
294 SpSetupActions.run_actions(sp_layout, args)