blob: 6e3e69fc1b6e88e6720c1eec40914f8aa4ecd584 [file] [log] [blame]
Manish Pandeyce2b1ec2020-01-14 11:52:05 +00001#!/usr/bin/python3
J-Alves04e7f802024-01-11 13:35:52 +00002# Copyright (c) 2020-2024, Arm Limited. All rights reserved.
Manish Pandeyce2b1ec2020-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 Pandey07c44472020-05-26 23:59:36 +010014FDT_SOURCES, FIP_ARGS, CRT_ARGS and SPTOOL_ARGS which are used in later build
15steps.
Imre Kis5ac60ea2022-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 Pandeyce2b1ec2020-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 Phipps1e7528e2020-07-24 16:20:57 +010023param4: CoT parameter
Karl Meakin20629b32023-02-14 11:56:02 +000024param5: Generated dts file "sp_list_fragment.dts"
Manish Pandeyce2b1ec2020-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 Pandey07c44472020-05-26 23:59:36 +010031 CRT_ARGS += --sp-pkg1 sp1.pkg
Manish Pandeyce2b1ec2020-01-14 11:52:05 +000032
33A typical SP_LAYOUT_FILE file will look like
34{
35 "SP1" : {
36 "image": "sp1.bin",
37 "pm": "test/sp1.dts"
38 },
39
40 "SP2" : {
41 "image": "sp2.bin",
Imre Kis5ac60ea2022-02-08 18:06:18 +010042 "pm": "test/sp2.dts",
43 "uuid": "1b1820fe-48f7-4175-8999-d51da00b7c9f"
Manish Pandeyce2b1ec2020-01-14 11:52:05 +000044 }
45
46 ...
47}
48
49"""
Manish Pandeyce2b1ec2020-01-14 11:52:05 +000050import json
51import os
52import re
53import sys
54import uuid
J-Alvesa96a07b2022-03-21 14:11:43 +000055from spactions import SpSetupActions
Manish Pandeyce2b1ec2020-01-14 11:52:05 +000056
Ruari Phipps1e7528e2020-07-24 16:20:57 +010057MAX_SP = 8
J-Alvesa96a07b2022-03-21 14:11:43 +000058UUID_LEN = 4
Manish Pandeyce2b1ec2020-01-14 11:52:05 +000059
J-Alvesa96a07b2022-03-21 14:11:43 +000060# Some helper functions to access args propagated to the action functions in
61# SpSetupActions framework.
J-Alvesa96a07b2022-03-21 14:11:43 +000062def check_sp_mk_gen(args :dict):
63 if "sp_gen_mk" not in args.keys():
64 raise Exception(f"Path to file sp_gen.mk needs to be in 'args'.")
Ruari Phipps1e7528e2020-07-24 16:20:57 +010065
J-Alvesa96a07b2022-03-21 14:11:43 +000066def check_out_dir(args :dict):
67 if "out_dir" not in args.keys() or not os.path.isdir(args["out_dir"]):
68 raise Exception("Define output folder with \'out_dir\' key.")
Ruari Phipps1e7528e2020-07-24 16:20:57 +010069
J-Alvesa96a07b2022-03-21 14:11:43 +000070def check_sp_layout_dir(args :dict):
71 if "sp_layout_dir" not in args.keys() or not os.path.isdir(args["sp_layout_dir"]):
72 raise Exception("Define output folder with \'sp_layout_dir\' key.")
Ruari Phipps1e7528e2020-07-24 16:20:57 +010073
J-Alvesa96a07b2022-03-21 14:11:43 +000074def write_to_sp_mk_gen(content, args :dict):
75 check_sp_mk_gen(args)
76 with open(args["sp_gen_mk"], "a") as f:
77 f.write(f"{content}\n")
Manish Pandeyce2b1ec2020-01-14 11:52:05 +000078
J-Alvesa96a07b2022-03-21 14:11:43 +000079def get_sp_manifest_full_path(sp_node, args :dict):
80 check_sp_layout_dir(args)
81 return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["pm"]))
Manish Pandeyce2b1ec2020-01-14 11:52:05 +000082
J-Alvesa96a07b2022-03-21 14:11:43 +000083def get_sp_img_full_path(sp_node, args :dict):
84 check_sp_layout_dir(args)
85 return os.path.join(args["sp_layout_dir"], get_file_from_layout(sp_node["image"]))
86
J-Alves0fe374e2024-11-18 17:49:53 +000087def get_size(sp_node):
88 if not "size" in sp_node:
89 print("WARNING: default image size 0x100000")
90 return 0x100000
91
92 # Try if it was a decimal value.
93 try:
94 return int(sp_node["size"])
95 except ValueError:
96 print("WARNING: trying to parse base 16 size")
97 # Try if it is of base 16
98 return int(sp_node["size"], 16)
99
J-Alvesa96a07b2022-03-21 14:11:43 +0000100def get_sp_pkg(sp, args :dict):
101 check_out_dir(args)
102 return os.path.join(args["out_dir"], f"{sp}.pkg")
103
104def is_line_in_sp_gen(line, args :dict):
105 with open(args["sp_gen_mk"], "r") as f:
106 sppkg_rule = [l for l in f if line in l]
J-Alves1a28f292022-10-07 10:02:33 +0100107 return len(sppkg_rule) != 0
J-Alvesa96a07b2022-03-21 14:11:43 +0000108
109def get_file_from_layout(node):
110 ''' Helper to fetch a file path from sp_layout.json. '''
111 if type(node) is dict and "file" in node.keys():
112 return node["file"]
113 return node
114
115def get_offset_from_layout(node):
116 ''' Helper to fetch an offset from sp_layout.json. '''
117 if type(node) is dict and "offset" in node.keys():
118 return int(node["offset"], 0)
119 return None
120
121def get_image_offset(node):
122 ''' Helper to fetch image offset from sp_layout.json '''
123 return get_offset_from_layout(node["image"])
124
125def get_pm_offset(node):
126 ''' Helper to fetch pm offset from sp_layout.json '''
127 return get_offset_from_layout(node["pm"])
128
Karl Meakin20629b32023-02-14 11:56:02 +0000129def get_uuid(sp_layout, sp, args :dict):
130 ''' Helper to fetch uuid from pm file listed in sp_layout.json'''
131 if "uuid" in sp_layout[sp]:
132 # Extract the UUID from the JSON file if the SP entry has a 'uuid' field
133 uuid_std = uuid.UUID(sp_layout[sp]['uuid'])
134 else:
135 with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
136 uuid_lines = [l for l in pm_f if 'uuid' in l]
137 assert(len(uuid_lines) == 1)
138 # The uuid field in SP manifest is the little endian representation
139 # mapped to arguments as described in SMCCC section 5.3.
140 # Convert each unsigned integer value to a big endian representation
141 # required by fiptool.
142 uuid_parsed = re.findall("0x([0-9a-f]+)", uuid_lines[0])
143 y = list(map(bytearray.fromhex, uuid_parsed))
144 z = [int.from_bytes(i, byteorder='little', signed=False) for i in y]
145 uuid_std = uuid.UUID(f'{z[0]:08x}{z[1]:08x}{z[2]:08x}{z[3]:08x}')
146 return uuid_std
147
148def get_load_address(sp_layout, sp, args :dict):
149 ''' Helper to fetch load-address from pm file listed in sp_layout.json'''
150 with open(get_sp_manifest_full_path(sp_layout[sp], args), "r") as pm_f:
151 load_address_lines = [l for l in pm_f if 'load-address' in l]
J-Alves04e7f802024-01-11 13:35:52 +0000152
J-Alves6a3225e2024-01-17 09:15:28 +0000153 if len(load_address_lines) != 1:
J-Alves04e7f802024-01-11 13:35:52 +0000154 return None
155
Karl Meakin20629b32023-02-14 11:56:02 +0000156 load_address_parsed = re.search("(0x[0-9a-f]+)", load_address_lines[0])
157 return load_address_parsed.group(0)
158
J-Alvesa96a07b2022-03-21 14:11:43 +0000159@SpSetupActions.sp_action(global_action=True)
160def check_max_sps(sp_layout, _, args :dict):
161 ''' Check validate the maximum number of SPs is respected. '''
162 if len(sp_layout.keys()) > MAX_SP:
163 raise Exception(f"Too many SPs in SP layout file. Max: {MAX_SP}")
164 return args
165
166@SpSetupActions.sp_action
167def gen_fdt_sources(sp_layout, sp, args :dict):
168 ''' Generate FDT_SOURCES values for a given SP. '''
169 manifest_path = get_sp_manifest_full_path(sp_layout[sp], args)
170 write_to_sp_mk_gen(f"FDT_SOURCES += {manifest_path}", args)
171 return args
172
J-Alves0fe374e2024-11-18 17:49:53 +0000173def generate_sp_pkg(sp_node, pkg, sp_img, sp_dtb):
174 ''' Generates the rule in case SP is to be generated in an SP Pkg. '''
175 pm_offset = get_pm_offset(sp_node)
176 sptool_args = f" --pm-offset {pm_offset}" if pm_offset is not None else ""
177 image_offset = get_image_offset(sp_node)
178 sptool_args += f" --img-offset {image_offset}" if image_offset is not None else ""
179 sptool_args += f" -o {pkg}"
180 return f'''
181{pkg}: {sp_dtb} {sp_img}
182\t$(Q)echo Generating {pkg}
183\t$(Q)$(PYTHON) $(SPTOOL) -i {sp_img}:{sp_dtb} {sptool_args}
184'''
185
186def generate_tl_pkg(sp_node, pkg, sp_img, sp_dtb, hob_path = None):
187 ''' Generate make rules for a Transfer List type package. '''
188 # TE Type for the FF-A manifest.
189 TE_FFA_MANIFEST = 0x106
190 # TE Type for the SP binary.
191 TE_SP_BINARY = 0x103
192 # TE Type for the HOB List.
193 TE_HOB_LIST = 0x3
194 tlc_add_hob = f"\t$(Q)poetry run tlc add --entry {TE_HOB_LIST} {hob_path} {pkg}" if hob_path is not None else ""
195 return f'''
196{pkg}: {sp_dtb} {sp_img}
197\t$(Q)echo Generating {pkg}
198\t$(Q)$(TLCTOOL) create --size {get_size(sp_node)} --entry {TE_FFA_MANIFEST} {sp_dtb} {pkg} --align 12
199\t$(Q)$(TLCTOOL) add --entry {TE_SP_BINARY} {sp_img} {pkg}
200'''
201
J-Alvesa96a07b2022-03-21 14:11:43 +0000202@SpSetupActions.sp_action
J-Alves0fe374e2024-11-18 17:49:53 +0000203def gen_partition_pkg(sp_layout, sp, args :dict):
J-Alves822c7272022-03-22 16:28:51 +0000204 ''' Generate Sp Pkgs rules. '''
J-Alves0fe374e2024-11-18 17:49:53 +0000205 pkg = get_sp_pkg(sp, args)
206
J-Alves822c7272022-03-22 16:28:51 +0000207 sp_dtb_name = os.path.basename(get_file_from_layout(sp_layout[sp]["pm"]))[:-1] + "b"
J-Alvesa96a07b2022-03-21 14:11:43 +0000208 sp_dtb = os.path.join(args["out_dir"], f"fdts/{sp_dtb_name}")
Jens Wiklander4daeaf32022-10-31 09:17:50 +0100209 sp_img = get_sp_img_full_path(sp_layout[sp], args)
J-Alves822c7272022-03-22 16:28:51 +0000210
211 # Do not generate rule if already there.
J-Alves0fe374e2024-11-18 17:49:53 +0000212 if is_line_in_sp_gen(f'{pkg}:', args):
J-Alves822c7272022-03-22 16:28:51 +0000213 return args
J-Alves822c7272022-03-22 16:28:51 +0000214
J-Alves0fe374e2024-11-18 17:49:53 +0000215 # This should include all packages of all kinds.
216 write_to_sp_mk_gen(f"SP_PKGS += {pkg}\n", args)
217 package_type = sp_layout[sp]["package"] if "package" in sp_layout[sp] else "sp_pkg"
218
219 if package_type == "sp_pkg":
220 partition_pkg_rule = generate_sp_pkg(sp_layout[sp], pkg, sp_img, sp_dtb)
221 elif package_type == "tl_pkg":
222 partition_pkg_rule = generate_tl_pkg(sp_layout[sp], pkg, sp_img, sp_dtb)
223 else:
224 raise ValueError(f"Specified invalid pkg type {package_type}")
225
226 write_to_sp_mk_gen(partition_pkg_rule, args)
J-Alvesa96a07b2022-03-21 14:11:43 +0000227 return args
228
229@SpSetupActions.sp_action(global_action=True, exec_order=1)
230def check_dualroot(sp_layout, _, args :dict):
231 ''' Validate the amount of SPs from SiP and Platform owners. '''
232 if not args.get("dualroot"):
233 return args
234 args["split"] = int(MAX_SP / 2)
235 owners = [sp_layout[sp].get("owner") for sp in sp_layout]
236 args["plat_max_count"] = owners.count("Plat")
J-Alves0fe374e2024-11-18 17:49:53 +0000237
J-Alvesa96a07b2022-03-21 14:11:43 +0000238 # If it is owned by the platform owner, it is assigned to the SiP.
239 args["sip_max_count"] = len(sp_layout.keys()) - args["plat_max_count"]
240 if args["sip_max_count"] > args["split"] or args["sip_max_count"] > args["split"]:
241 print(f"WARN: SiP Secure Partitions should not be more than {args['split']}")
242 # Counters for gen_crt_args.
243 args["sip_count"] = 1
244 args["plat_count"] = 1
245 return args
246
247@SpSetupActions.sp_action
248def gen_crt_args(sp_layout, sp, args :dict):
249 ''' Append CRT_ARGS. '''
250 # If "dualroot" is configured, 'sp_pkg_idx' depends on whether the SP is owned
251 # by the "SiP" or the "Plat".
252 if args.get("dualroot"):
253 # If the owner is not specified as "Plat", default to "SiP".
254 if sp_layout[sp].get("owner") == "Plat":
255 if args["plat_count"] > args["plat_max_count"]:
256 raise ValueError("plat_count can't surpass plat_max_count in args.")
257 sp_pkg_idx = args["plat_count"] + args["split"]
258 args["plat_count"] += 1
Imre Kis5ac60ea2022-02-08 18:06:18 +0100259 else:
J-Alvesa96a07b2022-03-21 14:11:43 +0000260 if args["sip_count"] > args["sip_max_count"]:
261 raise ValueError("sip_count can't surpass sip_max_count in args.")
262 sp_pkg_idx = args["sip_count"]
263 args["sip_count"] += 1
264 else:
265 sp_pkg_idx = [k for k in sp_layout.keys()].index(sp) + 1
266 write_to_sp_mk_gen(f"CRT_ARGS += --sp-pkg{sp_pkg_idx} {get_sp_pkg(sp, args)}\n", args)
267 return args
Manish Pandeyce2b1ec2020-01-14 11:52:05 +0000268
J-Alvesa96a07b2022-03-21 14:11:43 +0000269@SpSetupActions.sp_action
270def gen_fiptool_args(sp_layout, sp, args :dict):
271 ''' Generate arguments for the FIP Tool. '''
Karl Meakin20629b32023-02-14 11:56:02 +0000272 uuid_std = get_uuid(sp_layout, sp, args)
J-Alvesa96a07b2022-03-21 14:11:43 +0000273 write_to_sp_mk_gen(f"FIP_ARGS += --blob uuid={str(uuid_std)},file={get_sp_pkg(sp, args)}\n", args)
274 return args
Olivier Deprezdcdbcdd2021-05-11 09:43:37 +0200275
Karl Meakin20629b32023-02-14 11:56:02 +0000276@SpSetupActions.sp_action
277def gen_fconf_fragment(sp_layout, sp, args: dict):
278 ''' Generate the fconf fragment file'''
279 with open(args["fconf_fragment"], "a") as f:
280 uuid = get_uuid(sp_layout, sp, args)
281 owner = "Plat" if sp_layout[sp].get("owner") == "Plat" else "SiP"
282
283 if "physical-load-address" in sp_layout[sp].keys():
284 load_address = sp_layout[sp]["physical-load-address"]
285 else:
286 load_address = get_load_address(sp_layout, sp, args)
287
J-Alves04e7f802024-01-11 13:35:52 +0000288 if load_address is not None:
289 f.write(
Karl Meakin20629b32023-02-14 11:56:02 +0000290f'''\
291{sp} {{
292 uuid = "{uuid}";
293 load-address = <{load_address}>;
294 owner = "{owner}";
295}};
296
297''')
J-Alves04e7f802024-01-11 13:35:52 +0000298 else:
299 print("Warning: No load-address was found in the SP manifest.")
300
Karl Meakin20629b32023-02-14 11:56:02 +0000301 return args
302
J-Alvesa96a07b2022-03-21 14:11:43 +0000303def init_sp_actions(sys):
J-Alvesa96a07b2022-03-21 14:11:43 +0000304 # Initialize arguments for the SP actions framework
305 args = {}
306 args["sp_gen_mk"] = os.path.abspath(sys.argv[1])
Karl Meakin20629b32023-02-14 11:56:02 +0000307 sp_layout_file = os.path.abspath(sys.argv[2])
J-Alvesa96a07b2022-03-21 14:11:43 +0000308 args["sp_layout_dir"] = os.path.dirname(sp_layout_file)
309 args["out_dir"] = os.path.abspath(sys.argv[3])
310 args["dualroot"] = sys.argv[4] == "dualroot"
Karl Meakin20629b32023-02-14 11:56:02 +0000311 args["fconf_fragment"] = os.path.abspath(sys.argv[5])
312
313
314 with open(sp_layout_file) as json_file:
315 sp_layout = json.load(json_file)
J-Alvesa96a07b2022-03-21 14:11:43 +0000316 #Clear content of file "sp_gen.mk".
317 with open(args["sp_gen_mk"], "w"):
318 None
Karl Meakin20629b32023-02-14 11:56:02 +0000319 #Clear content of file "fconf_fragment".
320 with open(args["fconf_fragment"], "w"):
321 None
322
J-Alvesa96a07b2022-03-21 14:11:43 +0000323 return args, sp_layout
Manish Pandeyce2b1ec2020-01-14 11:52:05 +0000324
J-Alvesa96a07b2022-03-21 14:11:43 +0000325if __name__ == "__main__":
326 args, sp_layout = init_sp_actions(sys)
327 SpSetupActions.run_actions(sp_layout, args)